diff --git a/IRaCIS.Core.API.sln b/IRaCIS.Core.API.sln new file mode 100644 index 0000000..ab74854 --- /dev/null +++ b/IRaCIS.Core.API.sln @@ -0,0 +1,61 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.30128.74 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IRaCIS.Core.API", "IRaCIS.Core.API\IRaCIS.Core.API.csproj", "{F15CE209-6039-46A6-AE7F-E81ADA795F28}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IRaCIS.Core.Domain", "IRaCIS.Core.Domain\IRaCIS.Core.Domain.csproj", "{D4DF27AC-3739-4264-BFB8-AED6DC2B84C7}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IRaCIS.Core.Infrastructure", "IRaCIS.Core.Common\IRaCIS.Core.Infrastructure.csproj", "{7EDF1EFA-7BAA-4EB7-B9D6-B06FA22D9DF0}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IRaCIS.Core.Application", "IRaCIS.Core.Application\IRaCIS.Core.Application.csproj", "{037E7DE9-0AE2-4987-8C69-F51D5B9CA19D}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IRaCIS.Core.Infra.EFCore", "IRaCIS.Core.Infra.EF\IRaCIS.Core.Infra.EFCore.csproj", "{3787D877-AEF4-4C7B-8694-49232D9F99AC}" +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.Core.Application.Contracts", "IRaCIS.Core.Application.Contracts\IRaCIS.Core.Application.Contracts.csproj", "{7AA9C49B-9958-4371-B0B3-371391A2A7F7}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {F15CE209-6039-46A6-AE7F-E81ADA795F28}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F15CE209-6039-46A6-AE7F-E81ADA795F28}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F15CE209-6039-46A6-AE7F-E81ADA795F28}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F15CE209-6039-46A6-AE7F-E81ADA795F28}.Release|Any CPU.Build.0 = Release|Any CPU + {D4DF27AC-3739-4264-BFB8-AED6DC2B84C7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D4DF27AC-3739-4264-BFB8-AED6DC2B84C7}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D4DF27AC-3739-4264-BFB8-AED6DC2B84C7}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D4DF27AC-3739-4264-BFB8-AED6DC2B84C7}.Release|Any CPU.Build.0 = Release|Any CPU + {7EDF1EFA-7BAA-4EB7-B9D6-B06FA22D9DF0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {7EDF1EFA-7BAA-4EB7-B9D6-B06FA22D9DF0}.Debug|Any CPU.Build.0 = Debug|Any CPU + {7EDF1EFA-7BAA-4EB7-B9D6-B06FA22D9DF0}.Release|Any CPU.ActiveCfg = Release|Any CPU + {7EDF1EFA-7BAA-4EB7-B9D6-B06FA22D9DF0}.Release|Any CPU.Build.0 = Release|Any CPU + {037E7DE9-0AE2-4987-8C69-F51D5B9CA19D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {037E7DE9-0AE2-4987-8C69-F51D5B9CA19D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {037E7DE9-0AE2-4987-8C69-F51D5B9CA19D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {037E7DE9-0AE2-4987-8C69-F51D5B9CA19D}.Release|Any CPU.Build.0 = Release|Any CPU + {3787D877-AEF4-4C7B-8694-49232D9F99AC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {3787D877-AEF4-4C7B-8694-49232D9F99AC}.Debug|Any CPU.Build.0 = Debug|Any CPU + {3787D877-AEF4-4C7B-8694-49232D9F99AC}.Release|Any CPU.ActiveCfg = Release|Any CPU + {3787D877-AEF4-4C7B-8694-49232D9F99AC}.Release|Any CPU.Build.0 = Release|Any CPU + {7CBC76F5-3817-46B7-8D9D-79253A89B578}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {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 + {7AA9C49B-9958-4371-B0B3-371391A2A7F7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {7AA9C49B-9958-4371-B0B3-371391A2A7F7}.Debug|Any CPU.Build.0 = Debug|Any CPU + {7AA9C49B-9958-4371-B0B3-371391A2A7F7}.Release|Any CPU.ActiveCfg = Release|Any CPU + {7AA9C49B-9958-4371-B0B3-371391A2A7F7}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {BCC2EB19-3914-489B-B1D7-B7303E0218A3} + EndGlobalSection +EndGlobal diff --git a/IRaCIS.Core.API/.config/dotnet-tools.json b/IRaCIS.Core.API/.config/dotnet-tools.json new file mode 100644 index 0000000..23f4f07 --- /dev/null +++ b/IRaCIS.Core.API/.config/dotnet-tools.json @@ -0,0 +1,12 @@ +{ + "version": 1, + "isRoot": true, + "tools": { + "dotnet-ef": { + "version": "6.0.3", + "commands": [ + "dotnet-ef" + ] + } + } +} \ No newline at end of file diff --git a/IRaCIS.Core.API/AnonymizeTagSetting.json b/IRaCIS.Core.API/AnonymizeTagSetting.json new file mode 100644 index 0000000..6576ca0 --- /dev/null +++ b/IRaCIS.Core.API/AnonymizeTagSetting.json @@ -0,0 +1,106 @@ +{ + "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/Auth/AuthMiddleware.cs b/IRaCIS.Core.API/Auth/AuthMiddleware.cs new file mode 100644 index 0000000..7866c07 --- /dev/null +++ b/IRaCIS.Core.API/Auth/AuthMiddleware.cs @@ -0,0 +1,63 @@ +using System; +using System.IdentityModel.Tokens.Jwt; +using System.Net; +using System.Threading.Tasks; +using EasyCaching.Core; +using IRaCIS.Application; +using IRaCIS.Core.Domain.Share; +using Microsoft.AspNetCore.Authentication; +using Microsoft.AspNetCore.Authentication.JwtBearer; +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.Configuration; + +namespace IRaCIS.WX.CoreApi.Auth +{ + public class AuthMiddleware + { + private readonly RequestDelegate _next; + private readonly IEasyCachingProvider _provider; + public AuthMiddleware(RequestDelegate next, IEasyCachingProvider provider) + { + _next = next; + _provider = provider; + } + + public async Task Invoke(HttpContext httpContext) + { + var isLogin = httpContext.Request.Path.ToString().ToLower().Contains("login"); + + var result = await httpContext.AuthenticateAsync(JwtBearerDefaults.AuthenticationScheme); + + if (!isLogin) + { + if (!result.Succeeded) + { + httpContext.Response.StatusCode = (int)HttpStatusCode.Unauthorized; + await httpContext.Response.WriteAsync("Unauthorized"); + } + else + { + var toekn = result.Properties.Items[".Token.access_token"]; + var jwtHandler = new JwtSecurityTokenHandler(); + JwtSecurityToken jwtToken = jwtHandler.ReadJwtToken(toekn); + object userId; + jwtToken.Payload.TryGetValue("id", out userId); + + var cacheValueExist = await _provider.ExistsAsync(userId.ToString()); //Get(userId.ToString()).ToString(); + if (!cacheValueExist) + { + httpContext.Response.StatusCode = (int)HttpStatusCode.Unauthorized; + await httpContext.Response.WriteAsync("Unauthorized"); + } + else + { + await _provider.SetAsync(userId.ToString(), userId.ToString(), TimeSpan.FromMinutes(SystemConfig.LoginExpiredTimeSpan)); + httpContext.User = result.Principal; + await _next.Invoke(httpContext); + } + } + } + else await _next.Invoke(httpContext); + } + } +} diff --git a/IRaCIS.Core.API/Auth/JwtSetting.cs b/IRaCIS.Core.API/Auth/JwtSetting.cs new file mode 100644 index 0000000..d618655 --- /dev/null +++ b/IRaCIS.Core.API/Auth/JwtSetting.cs @@ -0,0 +1,42 @@ +using System.Collections.Generic; +using System.Text; +using Microsoft.IdentityModel.Tokens; + +namespace IRaCIS.WX.CoreApi.Auth +{ + public class JwtSetting + { + /// + /// 颁发者 + /// + public string Issuer { get; set; } + + /// + /// 接收者 + /// + public string Audience { get; set; } + + /// + /// 令牌密码 + /// + public string SecurityKey { get; set; } + + /// + /// 过期时间 + /// + public int TokenExpireDays { get; set; } + + public Dictionary Claims { get; set; } + + /// + /// 签名 + /// + public SigningCredentials Credentials + { + get { + var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(SecurityKey)); + return new SigningCredentials(key, SecurityAlgorithms.HmacSha256); + } + } + } +} diff --git a/IRaCIS.Core.API/Auth/TokenService.cs b/IRaCIS.Core.API/Auth/TokenService.cs new file mode 100644 index 0000000..4b19722 --- /dev/null +++ b/IRaCIS.Core.API/Auth/TokenService.cs @@ -0,0 +1,49 @@ +using System; +using System.IdentityModel.Tokens.Jwt; +using System.Security.Claims; +using IRaCIS.WX.CoreApi.Auth; +using Microsoft.Extensions.Options; + +namespace IRaCIS.Core.API.Auth +{ + + public interface ITokenService + { + string GetToken(UserClaims user); + } + public class TokenService : ITokenService + { + private readonly JwtSetting _jwtSetting; + public TokenService(IOptions option) + { + _jwtSetting = option.Value; + } + + public string GetToken(UserClaims user) + { + //创建用户身份标识,可按需要添加更多信息 + var claims = new Claim[] + { + new Claim(Microsoft.IdentityModel.JsonWebTokens.JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()), + new Claim("id", user.Id.ToString()), + new Claim("name", user.FullName), + new Claim("realName", user.RealName), + new Claim("reviewerCode",user.ReviewerCode), + }; + + ////创建令牌 + var token = new JwtSecurityToken( + issuer: _jwtSetting.Issuer, + audience: _jwtSetting.Audience, + signingCredentials: _jwtSetting.Credentials, + claims: claims, + notBefore: DateTime.Now, + expires: DateTime.Now.AddDays(_jwtSetting.TokenExpireDays) + ); + + string jwtToken = new JwtSecurityTokenHandler().WriteToken(token); + return jwtToken; + + } + } +} diff --git a/IRaCIS.Core.API/Auth/UserClaims.cs b/IRaCIS.Core.API/Auth/UserClaims.cs new file mode 100644 index 0000000..ff720cb --- /dev/null +++ b/IRaCIS.Core.API/Auth/UserClaims.cs @@ -0,0 +1,42 @@ +using System; +using IRaCIS.Application.ViewModels; + +namespace IRaCIS.Core.API.Auth +{ + public class UserClaims + { + public Guid Id { get; set; } + public string[] Role { get; set; } + public string FullName { get; set; } + public string ReviewerCode { get; set; } + public string RealName { get; set; } + public string Phone { get; set; } + public string PhotoPath { get; set; } + + public static UserClaims Create(UserBasicInfo user) + { + string[] roles = { "SysUser" }; + return new UserClaims + { + Id = user.Id, + Role = roles, + FullName = user.UserName, + RealName = user.RealName, + PhotoPath = string.Empty, + ReviewerCode = user.ReviewerCode + }; + } + public static UserClaims Create(DoctorAccountDTO doctor) + { + string[] roles = { "Doctor" }; + return new UserClaims + { + Id = doctor.Id, + Role = roles, + FullName = doctor.FirstName + doctor.LastName, + Phone = doctor.Phone, + PhotoPath = string.Empty + }; + } + } +} \ No newline at end of file diff --git a/IRaCIS.Core.API/Config/AuthConfigure.cs b/IRaCIS.Core.API/Config/AuthConfigure.cs new file mode 100644 index 0000000..b782849 --- /dev/null +++ b/IRaCIS.Core.API/Config/AuthConfigure.cs @@ -0,0 +1,34 @@ +using IRaCIS.WX.CoreApi.Auth; +using Microsoft.AspNetCore.Authentication.JwtBearer; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.IdentityModel.Tokens; +using System; +using System.Text; + +namespace IRaCIS.Core.API +{ + public class AuthConfigure + { + public static void ConfigureAuth(IServiceCollection services, IConfiguration configuration) + { + services.Configure(configuration.GetSection("JwtSetting")); + + var jwtSetting = new JwtSetting(); + configuration.Bind("JwtSetting", jwtSetting); + services + .AddAuthentication(JwtBearerDefaults.AuthenticationScheme) + .AddJwtBearer(options => + { + options.TokenValidationParameters = new TokenValidationParameters + { + ValidIssuer = jwtSetting.Issuer, + ValidAudience = jwtSetting.Audience, + IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(jwtSetting.SecurityKey)), + // 默认 300s + ClockSkew = TimeSpan.Zero + }; + }); + } + } +} diff --git a/IRaCIS.Core.API/Config/AutoMapperConfigure.cs b/IRaCIS.Core.API/Config/AutoMapperConfigure.cs new file mode 100644 index 0000000..9cd9817 --- /dev/null +++ b/IRaCIS.Core.API/Config/AutoMapperConfigure.cs @@ -0,0 +1,16 @@ +using AutoMapper; +using IRaCIS.Core.Application.Contracts.AutoMapper; +using Microsoft.Extensions.DependencyInjection; + +namespace IRaCIS.Core.API +{ + public class AutoMapperConfigure + { + public static void ConfigureSwagger(IServiceCollection services) + { + AutoMapper.IConfigurationProvider config = AutoMapperConfig.RegisterMappings(); + services.AddSingleton(config); + services.AddScoped(); + } + } +} diff --git a/IRaCIS.Core.API/Config/CustomAutofacModule.cs b/IRaCIS.Core.API/Config/CustomAutofacModule.cs new file mode 100644 index 0000000..5ef8431 --- /dev/null +++ b/IRaCIS.Core.API/Config/CustomAutofacModule.cs @@ -0,0 +1,64 @@ +using System; +using System.Reflection; +using Autofac; +using Autofac.Extras.DynamicProxy; +using IRaCIS.Application.Interfaces; +using IRaCIS.Application.Services; +using IRaCIS.Core.API; +using IRaCIS.Core.API.Auth; +using Microsoft.AspNetCore.Mvc; + +namespace IRaCIS.WX.CoreApi.Utility +{ + // ReSharper disable once IdentifierTypo + public class CustomAutofacModule : Autofac.Module + { + protected override void Load(ContainerBuilder containerBuilder) + { + + //containerBuilder.RegisterType().As(); + + //containerBuilder.RegisterType().As().SingleInstance(); + + //containerBuilder.RegisterType().As().InstancePerLifetimeScope().EnableInterfaceInterceptors(); + + //Assembly domain = Assembly.Load("IRaCIS.Core.Domain"); + //containerBuilder.RegisterAssemblyTypes(domain).AsImplementedInterfaces(); + + //Assembly domainShare = Assembly.Load("IRaCIS.Core.Domain.Share"); + //containerBuilder.RegisterAssemblyTypes(domainShare).AsImplementedInterfaces(); + + //Assembly infrastructure = Assembly.Load("IRaCIS.Core.Infra.EFCore"); + //containerBuilder.RegisterAssemblyTypes(infrastructure).AsImplementedInterfaces(); + + //Assembly application = Assembly.LoadFrom(AppDomain.CurrentDomain.BaseDirectory + "IRaCIS.Core.Application.dll"); + //containerBuilder.RegisterAssemblyTypes(application).AsImplementedInterfaces(); + + + #region 指定控制器也由autofac 来进行实例获取 + + #region 老方式 + //var assembly = this.GetType().GetTypeInfo().Assembly; + //var builder = new ContainerBuilder(); + //var manager = new ApplicationPartManager(); + //manager.ApplicationParts.Add(new AssemblyPart(assembly)); + //manager.FeatureProviders.Add(new ControllerFeatureProvider()); + //var feature = new ControllerFeature(); + //manager.PopulateFeature(feature); + //builder.RegisterType().AsSelf().SingleInstance(); + //builder.RegisterTypes(feature.Controllers.Select(ti => ti.AsType()).ToArray()).PropertiesAutowired(); + + + #endregion + + //获取所有控制器类型并使用属性注入 + //var controllerBaseType = typeof(ControllerBase); + //containerBuilder.RegisterAssemblyTypes(typeof(Program).Assembly) + // .Where(t => controllerBaseType.IsAssignableFrom(t) && t != controllerBaseType) + // .PropertiesAutowired(); + #endregion + + + } + } +} \ No newline at end of file diff --git a/IRaCIS.Core.API/Config/EFConfigure.cs b/IRaCIS.Core.API/Config/EFConfigure.cs new file mode 100644 index 0000000..b31e358 --- /dev/null +++ b/IRaCIS.Core.API/Config/EFConfigure.cs @@ -0,0 +1,22 @@ +using IRaCIS.Core.Infra.EFCore; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; + +namespace IRaCIS.Core.API +{ + public class EFConfigure + { + public static void ConfigureEF(IServiceCollection services, IConfiguration configuration) + { + services.AddScoped(); + + //这个注入没有成功--注入是没问题的,构造函数也只是支持参数就好,错在注入的地方不能写DbContext + services.AddDbContext(options => + { + options.UseSqlServer(configuration.GetSection("ConnectionStrings:RemoteNew").Value,contextOptionsBuilder=> contextOptionsBuilder.EnableRetryOnFailure()); + options.EnableSensitiveDataLogging(); + }); + } + } +} diff --git a/IRaCIS.Core.API/Config/MiniProfilerConfigure.cs b/IRaCIS.Core.API/Config/MiniProfilerConfigure.cs new file mode 100644 index 0000000..78e6c9d --- /dev/null +++ b/IRaCIS.Core.API/Config/MiniProfilerConfigure.cs @@ -0,0 +1,81 @@ +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/Config/SwaggerConfigure.cs b/IRaCIS.Core.API/Config/SwaggerConfigure.cs new file mode 100644 index 0000000..4f6e4c3 --- /dev/null +++ b/IRaCIS.Core.API/Config/SwaggerConfigure.cs @@ -0,0 +1,101 @@ +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.OpenApi.Models; +using Swashbuckle.AspNetCore.Filters; +using Swashbuckle.AspNetCore.SwaggerGen; +using Swashbuckle.AspNetCore.SwaggerUI; +using System; +using System.IO; +using System.Linq; +using System.Reflection; + +namespace IRaCIS.Core.API +{ + public class SwaggerConfigure + { + public static void ConfigureSwagger(IServiceCollection services) + { + services.AddSwaggerGen(options => + { + //此处的Name 是控制器上分组的名称 Title是界面的大标题 + //分组 + options.SwaggerDoc("Reviewer", new OpenApiInfo {Title = "医生模块",Version = "Reviewer", }); + options.SwaggerDoc("Trial", new OpenApiInfo { Title = "项目模块", Version = "Trial" }); + options.SwaggerDoc("Enroll", new OpenApiInfo { Title = "入组模块", Version = "Enroll" }); + options.SwaggerDoc("Workload", new OpenApiInfo { Title = "工作量模块", Version = "Workload" }); + options.SwaggerDoc("Common", new OpenApiInfo { Title = "通用信息获取", Version = "Common" }); + options.SwaggerDoc("Institution", new OpenApiInfo { Title = "机构信息模块", Version = "Institution" }); + options.SwaggerDoc("Dashboard&Statistics", new OpenApiInfo { Title = "统计模块", Version = "Dashboard&Statistics" }); + + options.SwaggerDoc("Financial", new OpenApiInfo { Title = "财务模块", Version = "Financial" }); + options.SwaggerDoc("Management", new OpenApiInfo { Title = "管理模块", Version = "Management" }); + options.SwaggerDoc("Image", new OpenApiInfo { Title = "影像模块", Version = "Image" }); + options.SwaggerDoc("Reading", new OpenApiInfo { Title = "读片模块", Version = "Reading" }); + + // 接口排序 + options.OrderActionsBy(o => o.GroupName); + + options.DocInclusionPredicate((docName, apiDes) => + { + if (!apiDes.TryGetMethodInfo(out MethodInfo methodInfo)) return false; + var versions = methodInfo.DeclaringType.GetCustomAttributes(true) + .OfType() + .Select(attr => attr.GroupName); + + return versions.Any(v => v.ToString() == docName); + }); + + var xmlPath = Path.Combine(AppContext.BaseDirectory, "IRaCIS.Core.API.xml");//这个就是刚刚配置的xml文件名 + options.IncludeXmlComments(xmlPath, true); + //默认的第二个参数是false,这个是controller的注释,记得修改 + + + // 在header中添加token,传递到后台 + options.OperationFilter(); + + // Bearer + options.AddSecurityDefinition("oauth2", new OpenApiSecurityScheme + { + Description = "JWT Authorization header using the Bearer scheme.", + Name = "Authorization", + In = ParameterLocation.Header, + Scheme = "bearer", + Type = SecuritySchemeType.Http, + BearerFormat = "JWT" + }); + }); + } + + public static void Configure(IApplicationBuilder app, IWebHostEnvironment env) + { + app.UseSwagger(); + app.UseSwaggerUI(options => + { + //此处的Name 是页面 选择文档下拉框 显示的名称 + options.SwaggerEndpoint($"swagger/Reviewer/swagger.json", "医生模块"); + options.SwaggerEndpoint($"swagger/Trial/swagger.json", "项目模块"); + options.SwaggerEndpoint($"swagger/Enroll/swagger.json", "入组模块"); + options.SwaggerEndpoint($"swagger/Workload/swagger.json", "工作量模块"); + options.SwaggerEndpoint($"swagger/Dashboard&Statistics/swagger.json", "统计模块"); + options.SwaggerEndpoint($"swagger/Common/swagger.json", "通用模块"); + + options.SwaggerEndpoint($"swagger/Financial/swagger.json", "财务模块"); + options.SwaggerEndpoint($"swagger/Institution/swagger.json", "机构信息模块"); + options.SwaggerEndpoint($"swagger/Management/swagger.json", "管理模块"); + options.SwaggerEndpoint($"swagger/Image/swagger.json", "影像模块"); + options.SwaggerEndpoint($"swagger/Reading/swagger.json", "读片模块"); + + //路径配置,设置为空,表示直接在根域名(localhost:8001)访问该文件, + //注意localhost:8001/swagger是访问不到的,去launchSettings.json把launchUrl去掉,如果你想换一个路径,直接写名字即可,比如直接写c.Route = "doc"; + options.RoutePrefix = string.Empty; + //DocExpansion设置为none可折叠所有方法 + options.DocExpansion(DocExpansion.None); + //DefaultModelsExpandDepth设置为 - 1 可不显示models + options.DefaultModelsExpandDepth(-1); + + }); + } + } +} diff --git a/IRaCIS.Core.API/Controllers/Common/DictionaryController.cs b/IRaCIS.Core.API/Controllers/Common/DictionaryController.cs new file mode 100644 index 0000000..f65829a --- /dev/null +++ b/IRaCIS.Core.API/Controllers/Common/DictionaryController.cs @@ -0,0 +1,97 @@ +using System; +using System.Collections.Generic; +using IRaCIS.Application.Interfaces; +using IRaCIS.Application.ViewModels; +using IRaCIS.Core.Application.Contracts.RequestAndResponse; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; + +namespace IRaCIS.Api.Controllers +{ + /// + /// 数据字典-基础数据维护 + /// + [Route("dictionary")] + [ApiController, Authorize, ApiExplorerSettings(GroupName = "Common")] + public class DictionaryController : ControllerBase + { + private IDictionaryService _dictionaryService; + public DictionaryController(IDictionaryService dictionaryService) + { + _dictionaryService = dictionaryService; + } + + /// + /// 获取项目多选字典 + /// + /// Title、Department、Rank、Position、ReadingType、Subspeciality Sponsor CROCompany ReadingStandard ReviewMode ReviewType ProjectState + /// + [HttpPost, Route("getDictionary")] + public IResponseOutput GetDic(string[] searchArray) + { + var dicResult = _dictionaryService.GetDictionaryResult(searchArray); + + return ResponseOutput.Ok(dicResult); + } + + /// + /// 获取所有字典数据 + /// + [HttpGet, Route("getAllDictionary")] + public IResponseOutput GetAllDic() + { + return ResponseOutput.Ok(_dictionaryService.GetAllDictionary()); + } + + + /// + /// 获取下拉框数据 + /// + /// + [HttpGet, Route("getDictionarySelect")] + public IResponseOutput> GetDicSelect() + { + return ResponseOutput.Ok(_dictionaryService.GetDicSelect()); + } + + /// + /// 获取下拉框某个keyName的列表 + /// + /// + [HttpPost, Route("getDictionarySelectList")] + public IResponseOutput> GetDicSelectList(DicQueryDTO dicSearchModel) + { + return ResponseOutput.Ok(_dictionaryService.GetDicSelectList(dicSearchModel)); + } + + /// 添加字典 项 + [HttpPost, Route("addOrUpdateDictionary")] + public IResponseOutput AddOrUpdateDictionaryItem(DicViewModelDTO item) + { + return ResponseOutput.Ok(_dictionaryService.AddOrUpdateDictionary(item)); + + } + + /// + /// 根据Id 删除字典数据 + /// + /// + /// + + [HttpDelete, Route("deleteDictionary/{id:guid}")] + public IResponseOutput DeleteDictionary(Guid id) + { + return _dictionaryService.DeleteDictionary(id); + } + + /// + /// 获取字典Tree + /// + /// + [HttpGet, Route("getDicTree")] + public IResponseOutput> GetDicTree() + { + return ResponseOutput.Ok(_dictionaryService.GetDicTree()); + } + } +} \ No newline at end of file diff --git a/IRaCIS.Core.API/Controllers/Common/FileController.cs b/IRaCIS.Core.API/Controllers/Common/FileController.cs new file mode 100644 index 0000000..6f8398b --- /dev/null +++ b/IRaCIS.Core.API/Controllers/Common/FileController.cs @@ -0,0 +1,354 @@ +using System; +using System.IO; +using System.Net; +using System.Threading.Tasks; +using IRaCIS.Application.Interfaces; +using IRaCIS.Application.ViewModels; +using IRaCIS.Core.API.Controllers.Common; +using IRaCIS.Core.API.Filter; +using IRaCIS.Core.API.Utility; +using IRaCIS.Core.Application.Contracts.RequestAndResponse; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Http.Features; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.WebUtilities; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Logging; +using Microsoft.Net.Http.Headers; + +namespace IRaCIS.Api.Controllers +{ + /// + /// 文件上传 + /// + [Route("file")] + [ApiController, Authorize, ApiExplorerSettings(GroupName = "Common")] + public class FileController : ControllerBase + { + private readonly IFileService _fileService; + private readonly IWebHostEnvironment _webHostEnvironment; + private readonly IHostEnvironment _hostEnvironment; + private ILogger _logger; + + private string _targetFilePath; + private readonly long _fileSizeLimit; + private readonly string[] _permittedExtensions = { ".pdf", ".doc", ".docx" }; + + public string trustedFileNameForFileStorage = ""; + + // Get the default form options so that we can use them to set the default + // limits for request body data. + private static readonly FormOptions _defaultFormOptions = new FormOptions(); + private string defaultUploadFilePath = string.Empty; + public FileController(IFileService fileService, IConfiguration config, + IHostEnvironment hostEnvironment, ILogger logger, + IWebHostEnvironment webHostEnvironment) + { + _fileService = fileService; + _hostEnvironment = hostEnvironment; + _webHostEnvironment = webHostEnvironment; + _fileSizeLimit = config.GetValue("FileSizeLimit"); + defaultUploadFilePath = Directory.GetParent(_hostEnvironment.ContentRootPath).FullName; + + _logger = logger; + _logger.LogError("File Path:"+ defaultUploadFilePath); + // To save physical files to a path provided by configuration: + //_targetFilePath = config.GetValue("StoredFilesPath"); + + // To save physical files to the temporary files folder, use: + //_targetFilePath = Path.GetTempPath(); + } + + + /// + /// 上传文件[FileUpload] + /// + /// 附件类型 + /// 医生Id + /// 返回文件信息 + [HttpPost, Route("uploadFile/{attachmentType}/{doctorId}")] + [DisableFormValueModelBinding] + public async Task UploadOrdinaryFile(string attachmentType, Guid doctorId) + { + _logger.LogError("aaaa"); + #region 官方文档方式 + + + if (!MultipartRequestHelper.IsMultipartContentType(Request.ContentType)) + { + ModelState.AddModelError("File", + $"The request couldn't be processed (Error 1)."); + // Log error + return BadRequest(ModelState); + } + + var boundary = MultipartRequestHelper.GetBoundary( + MediaTypeHeaderValue.Parse(Request.ContentType), + _defaultFormOptions.MultipartBoundaryLengthLimit); + var reader = new MultipartReader(boundary, HttpContext.Request.Body); + var section = await reader.ReadNextSectionAsync(); + + while (section != null) + { + var hasContentDispositionHeader = + ContentDispositionHeaderValue.TryParse( + section.ContentDisposition, out var contentDisposition); + + if (hasContentDispositionHeader) + { + // This check assumes that there's a file + // present without form data. If form data + // is present, this method immediately fails + // and returns the model error. + if (!MultipartRequestHelper + .HasFileContentDisposition(contentDisposition)) + { + ModelState.AddModelError("File", + $"The request couldn't be processed (Error 2)."); + // Log error + return BadRequest(ModelState); + } + else + { + // Don't trust the file name sent by the client. To display + // the file name, HTML-encode the value. + var trustedFileNameForDisplay = WebUtility.HtmlEncode( + contentDisposition.FileName.Value); + + //var trustedFileNameForFileStorage = Path.GetRandomFileName(); + trustedFileNameForFileStorage = contentDisposition.FileName.Value; + + // **WARNING!** + // In the following example, the file is saved without + // scanning the file's contents. In most production + // scenarios, an anti-virus/anti-malware scanner API + // is used on the file before making the file available + // for download or for use by other systems. + // For more information, see the topic that accompanies + // this sample. + + var streamedFileContent = await FileHelpers.ProcessStreamedFile( + section, contentDisposition, ModelState, + _permittedExtensions, _fileSizeLimit); + + if (!ModelState.IsValid) + { + return BadRequest(ModelState); + } + + + //实际文件处理 + string uploadFolderPath = Path.Combine(defaultUploadFilePath, "UploadFile/" + doctorId + "/"); + + var doctorAttachmentUploadFolder = Path.Combine(uploadFolderPath, attachmentType); + + _targetFilePath = doctorAttachmentUploadFolder; + + if (!Directory.Exists(doctorAttachmentUploadFolder)) Directory.CreateDirectory(doctorAttachmentUploadFolder); + + using (var targetStream = System.IO.File.Create( + Path.Combine(_targetFilePath, trustedFileNameForFileStorage))) + { + await targetStream.WriteAsync(streamedFileContent); + + var attachmentPath = $"/UploadFile/{doctorId}/{attachmentType}/{trustedFileNameForFileStorage}"; + + return new JsonResult(ResponseOutput.Ok(new UploadFileInfoDTO() { FilePath = attachmentPath })); + + } + + + } + } + + // Drain any remaining section body that hasn't been consumed and + // read the headers for the next section. + section = await reader.ReadNextSectionAsync(); + } + + + return Created(nameof(FileTestController), null); + + #endregion + } + + + /// + /// 上传文件( 不是医生个人的文件)[FileUpload] + /// 例如:阅片章程等 + /// + /// 文件类型 + /// + + [HttpPost, Route("uploadNonDoctorFile/{type}")] + [DisableFormValueModelBinding] + public async Task UploadNonDoctorFile(string type) + { + #region New Test 实测OK + + //上传根路径 + string uploadFolderPath = Path.Combine(defaultUploadFilePath, "UploadFile"); + + + if (uploadFolderPath != null) + { + //文件类型路径处理 + var uploadTypePath = Path.Combine(uploadFolderPath, type); + if (!Directory.Exists(uploadTypePath)) Directory.CreateDirectory(uploadTypePath); + + + ////实际文件处理 + + _targetFilePath = uploadTypePath; + + //获取boundary + + #region 方式二 + + var boundary = MultipartRequestHelper.GetBoundary( + MediaTypeHeaderValue.Parse(Request.ContentType), + _defaultFormOptions.MultipartBoundaryLengthLimit); + + #endregion + + #region 方式一 + //var boundary = HeaderUtilities.RemoveQuotes(MediaTypeHeaderValue.Parse(Request.ContentType).Boundary).Value; + + #endregion + //得到reader + var reader = new MultipartReader(boundary, HttpContext.Request.Body); + //{ BodyLengthLimit = 2000 };// + var section = await reader.ReadNextSectionAsync(); + + //读取section + while (section != null) + { + var hasContentDispositionHeader = ContentDispositionHeaderValue.TryParse(section.ContentDisposition, out var contentDisposition); + if (hasContentDispositionHeader) + { + trustedFileNameForFileStorage = contentDisposition.FileName.Value; + + + await WriteFileAsync(section.Body, Path.Combine(_targetFilePath, trustedFileNameForFileStorage)); + + #region 方式二 + + //using (var targetStream = System.IO.File.Create( + // Path.Combine(_targetFilePath, trustedFileNameForFileStorage))) + //{ + + // using (var memoryStream = new MemoryStream()) + // { + // await section.Body.CopyToAsync(memoryStream); + + // await targetStream.WriteAsync(memoryStream.ToArray()); + // } + //} + + + #endregion + + + var attachmentPath = $"/UploadFile/{type}/{trustedFileNameForFileStorage}"; + + return new JsonResult(ResponseOutput.Ok(new UploadFileInfoDTO() { FilePath = attachmentPath })); + } + + section = await reader.ReadNextSectionAsync(); + } + return Created(nameof(FileController), null); + + + } + return new JsonResult(ResponseOutput.NotOk("服务器端映射路径操作失败")); + #endregion + } + + + + /// + /// 写文件导到磁盘 + /// + /// 流 + /// 文件保存路径 + /// + public static async Task WriteFileAsync(System.IO.Stream stream, string path) + { + const int FILE_WRITE_SIZE = 84975;//写出缓冲区大小 + int writeCount = 0; + using (FileStream fileStream = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.Write, FILE_WRITE_SIZE, true)) + { + byte[] byteArr = new byte[FILE_WRITE_SIZE]; + int readCount = 0; + while ((readCount = await stream.ReadAsync(byteArr, 0, byteArr.Length)) > 0) + { + await fileStream.WriteAsync(byteArr, 0, readCount); + writeCount += readCount; + } + } + return writeCount; + } + + + + + + + #region 上传无影响部分 + + + /// + /// 下载多个医生的所有附件 + /// + /// + /// + + [HttpPost, Route("downloadDoctorAttachments")] + public IResponseOutput DownloadAttachment(Guid[] doctorIds) + { + + return ResponseOutput.Ok(new UploadFileInfoDTO + { + FilePath = _fileService.CreateDoctorsAllAttachmentZip(doctorIds) + }); + } + + /// + /// 下载医生官方简历 + /// + /// + /// + + [HttpPost, Route("downloadOfficialCV")] + public IResponseOutput DownloadOfficialResume(Guid[] doctorIds) + { + return ResponseOutput.Ok(new UploadFileInfoDTO + { + FilePath = _fileService.CreateOfficialResumeZip(doctorIds) + }); + } + + /// + /// 下载指定医生的指定附件 + /// + /// 医生Id + /// 要下载的附件Id + /// + + [HttpPost, Route("downloadByAttachmentId/{doctorId}")] + public IResponseOutput DownloadAttachmentById(Guid doctorId, Guid[] attachmentIds) + { + return ResponseOutput.Ok(new UploadFileInfoDTO + { + FilePath = _fileService.CreateZipPackageByAttachment(doctorId, attachmentIds) + }); + } + + #endregion + + + + } +} diff --git a/IRaCIS.Core.API/Controllers/Common/FileTestController.cs b/IRaCIS.Core.API/Controllers/Common/FileTestController.cs new file mode 100644 index 0000000..191ce1d --- /dev/null +++ b/IRaCIS.Core.API/Controllers/Common/FileTestController.cs @@ -0,0 +1,124 @@ +using System.IO; +using System.Net; +using System.Threading.Tasks; +using IRaCIS.Core.API.Filter; +using IRaCIS.Core.API.Utility; +using Microsoft.AspNetCore.Http.Features; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.WebUtilities; +using Microsoft.Extensions.Configuration; +using Microsoft.Net.Http.Headers; + +namespace IRaCIS.Core.API.Controllers.Common +{ + public class FileTestController : ControllerBase + { + + private readonly string _targetFilePath; + private readonly long _fileSizeLimit; + private readonly string[] _permittedExtensions = { ".txt" ,".pdf"}; + + // Get the default form options so that we can use them to set the default + // limits for request body data. + private static readonly FormOptions _defaultFormOptions = new FormOptions(); + + + public FileTestController(IConfiguration config) + { + + _fileSizeLimit = config.GetValue("FileSizeLimit"); + + // To save physical files to a path provided by configuration: + _targetFilePath = config.GetValue("StoredFilesPath"); + + // To save physical files to the temporary files folder, use: + //_targetFilePath = Path.GetTempPath(); + } + + #region snippet_UploadPhysical 上传到服务器物理路径 + + + [HttpPost] + [DisableFormValueModelBinding] + [ValidateAntiForgeryToken] + public async Task UploadPhysical() + { + if (!MultipartRequestHelper.IsMultipartContentType(Request.ContentType)) + { + ModelState.AddModelError("File", + $"The request couldn't be processed (Error 1)."); + // Log error + return BadRequest(ModelState); + } + + var boundary = MultipartRequestHelper.GetBoundary( + MediaTypeHeaderValue.Parse(Request.ContentType), + _defaultFormOptions.MultipartBoundaryLengthLimit); + var reader = new MultipartReader(boundary, HttpContext.Request.Body); + var section = await reader.ReadNextSectionAsync(); + + while (section != null) + { + var hasContentDispositionHeader = + ContentDispositionHeaderValue.TryParse( + section.ContentDisposition, out var contentDisposition); + + if (hasContentDispositionHeader) + { + // This check assumes that there's a file + // present without form data. If form data + // is present, this method immediately fails + // and returns the model error. + if (!MultipartRequestHelper + .HasFileContentDisposition(contentDisposition)) + { + ModelState.AddModelError("File", + $"The request couldn't be processed (Error 2)."); + // Log error + return BadRequest(ModelState); + } + else + { + // Don't trust the file name sent by the client. To display + // the file name, HTML-encode the value. + var trustedFileNameForDisplay = WebUtility.HtmlEncode( + contentDisposition.FileName.Value); + var trustedFileNameForFileStorage = Path.GetRandomFileName(); + + // **WARNING!** + // In the following example, the file is saved without + // scanning the file's contents. In most production + // scenarios, an anti-virus/anti-malware scanner API + // is used on the file before making the file available + // for download or for use by other systems. + // For more information, see the topic that accompanies + // this sample. + + var streamedFileContent = await FileHelpers.ProcessStreamedFile( + section, contentDisposition, ModelState, + _permittedExtensions, _fileSizeLimit); + + if (!ModelState.IsValid) + { + return BadRequest(ModelState); + } + + using (var targetStream = System.IO.File.Create( + Path.Combine(_targetFilePath, trustedFileNameForFileStorage))) + { + await targetStream.WriteAsync(streamedFileContent); + + } + } + } + + // Drain any remaining section body that hasn't been consumed and + // read the headers for the next section. + section = await reader.ReadNextSectionAsync(); + } + + return Created(nameof(FileTestController), null); + } + #endregion + } +} diff --git a/IRaCIS.Core.API/Controllers/Common/LogController.cs b/IRaCIS.Core.API/Controllers/Common/LogController.cs new file mode 100644 index 0000000..eceef73 --- /dev/null +++ b/IRaCIS.Core.API/Controllers/Common/LogController.cs @@ -0,0 +1,31 @@ +using IRaCIS.Application.Interfaces; +using IRaCIS.Application.ViewModels; +using System.Collections.Generic; +using IRaCIS.Core.Application.Contracts.RequestAndResponse; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Authorization; + +namespace IRaCIS.Api.Controllers +{ + /// + /// 系统日志 + /// + [Route("log")] + [ApiController, Authorize, ApiExplorerSettings(GroupName = "Common")] + public class LogController : ControllerBase + { + private ILogService _logService; + public LogController(ILogService logService) + { + _logService = logService; + } + + /// 查询系统日志信息 + + [HttpPost, Route("getLogList")] + public IResponseOutput> GetLogList(QueryLogQueryDTO param) + { + return ResponseOutput.Ok(_logService.GetLogList(param)) ; + } + } +} diff --git a/IRaCIS.Core.API/Controllers/Common/MessageController.cs b/IRaCIS.Core.API/Controllers/Common/MessageController.cs new file mode 100644 index 0000000..2d44f8e --- /dev/null +++ b/IRaCIS.Core.API/Controllers/Common/MessageController.cs @@ -0,0 +1,62 @@ +using System.Collections.Generic; +using IRaCIS.Application.Interfaces; +using IRaCIS.Application.ViewModels; +using System; +using IRaCIS.Core.Application.Contracts.RequestAndResponse; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Authorization; + +namespace IRaCIS.Api.Controllers +{ + [Route("message")] + [ApiController, Authorize, ApiExplorerSettings(GroupName = "Common")] + public class MessageController : ControllerBase + { + private IMessageService _app; + public MessageController(IMessageService app) + { + _app = app; + } + + /// + /// 删除消息 + /// + /// 消息Id + /// + + [HttpDelete, Route("deleteMessage/{messageId:guid}")] + public IResponseOutput DeleteSysMessage(Guid messageId) + { + return _app.DeleteSysMessage(messageId); + + } + + /// + /// 分页获取系统消息 + /// + /// 医生Id + /// 分页大小 + /// 也索引 + /// + + [HttpGet, Route("getMessageList/{doctorId:guid}/{pageIndex:int:min(1)}/{pageSize:int:range(1,100)}")] + public IResponseOutput> GetMessageList(Guid doctorId, int pageSize, int pageIndex) + { + return ResponseOutput.Ok(_app.GetMessageList(doctorId, pageSize, pageIndex)) ; + + } + + /// + /// 将消息标记已读 + /// + /// + /// + + [HttpGet, Route("markedAsRead/{messageId:guid}")] + public IResponseOutput MarkedAsRead(Guid messageId) + { + return _app.MarkedAsRead(messageId); + + } + } +} diff --git a/IRaCIS.Core.API/Controllers/Doctor/AttachmentController.cs b/IRaCIS.Core.API/Controllers/Doctor/AttachmentController.cs new file mode 100644 index 0000000..33f9c13 --- /dev/null +++ b/IRaCIS.Core.API/Controllers/Doctor/AttachmentController.cs @@ -0,0 +1,116 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using IRaCIS.Application.Interfaces; +using IRaCIS.Application.ViewModels; +using IRaCIS.Core.Application.Contracts.RequestAndResponse; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; + +namespace IRaCIS.Api.Controllers +{ + /// + /// 医生文档关联关系维护 + /// + [Route("attachment")] + [ApiController, Authorize,ApiExplorerSettings(GroupName ="Reviewer")] + public class DocumentController : ControllerBase + { + private IAttachmentService _attachmentService; + + public DocumentController(IAttachmentService doctorAttachmentApp) + { + _attachmentService = doctorAttachmentApp; + } + + /// + /// 添加多个记录 + /// + /// + /// + + [HttpPost, Route("saveAttachments")] + public IResponseOutput> AddDoctorAttachment(IEnumerable attachment) + { + return ResponseOutput.Ok(_attachmentService.SaveAttachmentRange(attachment)); + } + + + + /// + /// 删除记录 + /// + /// + /// + + [HttpDelete, Route("deleteAttachment")] + public IResponseOutput DeleteAttachment(AttachementCommand param) + { + //var attachment = _doctorAttachmentApp.GetDetailById(id); + //string file = HostingEnvironment.MapPath(attachment.Path); + + //if (File.Exists(file)) + //{ + // File.Delete(file); + //} + //var temp = HostingEnvironment.MapPath(param.Path); + //if (File.Exists(temp)) + //{ + // File.Delete(temp); + //} + return ResponseOutput.Ok(_attachmentService.DeleteAttachment(param.Id)); + } + /// + /// 根据医生Id 和 附件类型,获取记录 + /// + /// 医生Id + /// 附件类型 + /// + + [HttpGet, Route("getAttachmentByType/{doctorId:guid}/{type}")] + public IResponseOutput> GetAttachmentListByType(Guid doctorId, string type) + { + return ResponseOutput.Ok(_attachmentService.GetAttachmentByType(doctorId, type)); + + } + + /// + /// 获取单个医生的多种证书附件 + /// + /// 医生Id + /// 类型数组 + /// + + [HttpPost, Route("getAttachmentByTypes/{doctorId:guid}")] + public IResponseOutput> GetAttachmentListByTypes(Guid doctorId, string[] types) + { + return ResponseOutput.Ok(_attachmentService.GetAttachmentByTypes(doctorId, types)); + } + /// + /// 根据医生Id获取医生附件 + /// + /// 医生Id + /// + + [HttpGet, Route("getAttachments/{doctorId:guid}")] + public IResponseOutput> GetAttachmentList(Guid doctorId) + { + //var a = _attachmentService.GetAttachments(doctorId).ToList(); + return ResponseOutput.Ok(_attachmentService.GetAttachments(doctorId)); + } + + /// + /// 将简历设置为官方简历 + /// + /// + /// + /// + + [HttpPost, Route("setOfficial/{doctorId:guid}/{attachmentId:guid}")] + public IResponseOutput SetOfficial(Guid doctorId, Guid attachmentId) + { + return _attachmentService.SetOfficial(doctorId, attachmentId); + } + + } +} \ No newline at end of file diff --git a/IRaCIS.Core.API/Controllers/Doctor/DoctorController.cs b/IRaCIS.Core.API/Controllers/Doctor/DoctorController.cs new file mode 100644 index 0000000..b6f781d --- /dev/null +++ b/IRaCIS.Core.API/Controllers/Doctor/DoctorController.cs @@ -0,0 +1,226 @@ +using System; +using System.Collections.Generic; + +using IRaCIS.Api.Filter; +using IRaCIS.Application.Interfaces; +using IRaCIS.Application.ViewModels; +using IRaCIS.Core.Application.Contracts.RequestAndResponse; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; + +namespace IRaCIS.Api.Controllers +{ + /// + /// 医生基本信息 、工作信息 专业信息、审核状态 + /// + [Route("doctor")] + [ApiController, Authorize, ApiExplorerSettings(GroupName = "Reviewer")] + public class DoctorController : ControllerBase + { + private readonly IDoctorService _doctorService; + + public DoctorController(IDoctorService doctorService) + { + _doctorService = doctorService; + } + + #region 医生列表查询接口 + /// + /// 分页获取医生列表 (带查询条件) + /// + // + [HttpPost, Route("getDoctorSearchList")] + public IResponseOutput> GetDoctorList([FromServices] IDoctorListQueryService _doctorListQueryService, DoctorSearchDTO doctorSearchModel) + { + var userId = Guid.Parse(User.FindFirst("id").Value); + return ResponseOutput.Ok(_doctorListQueryService.GetReviewerList(doctorSearchModel, userId)) ; + } + #endregion + + #region 医生基本信息管理 + + /// + ///详情、编辑-获取 医生基本信息 BasicInfo + /// + /// ReviewerID + /// + + [HttpGet, Route("getBasicInfo/{doctorId:guid}")] + public IResponseOutput GetDoctorBasicInfoById(Guid doctorId) + { + var doctorInfo = _doctorService.GetDoctorBasicInfo(doctorId); + return ResponseOutput.Ok(doctorInfo); + } + + /// + /// Get Statement of Work list.[New] + /// + /// + /// + + [HttpGet, Route("getDoctorSowList/{doctorId:guid}")] + public IResponseOutput> GetDoctorSow(Guid doctorId) + { + var list = _doctorService.GetDoctorSow(doctorId); + return ResponseOutput.Ok(list); + } + + /// + /// Get Ack Statement of Work[New] + /// + /// + /// + + [HttpGet, Route("getDoctorAckSowList/{doctorId:guid}")] + public IResponseOutput> GetDoctorAckSow(Guid doctorId) + { + var list = _doctorService.GetDoctorAckSow(doctorId); + return ResponseOutput.Ok(list); + } + + /// + /// 添加/更新 医生基本信息 BasicInfo + /// + + [HttpPost, Route("addOrUpdateDoctorBasicInfo")] + public IResponseOutput AddOrUpdateDoctorBasicInfo(DoctorBasicInfoCommand addBasicInfoViewModel) + { + var userId = Guid.Parse(User.FindFirst("id").Value); + return _doctorService.AddOrUpdateDoctorBasicInfo(addBasicInfoViewModel, userId); + } + + #endregion + + #region 医生工作信息 Employment + + /// + /// 详情、编辑-获取医生工作信息 Employment + /// + /// + /// + + [HttpGet, Route("getEmploymentInfo/{doctorId:Guid}")] + public IResponseOutput GetDoctorWorkInfoById(Guid doctorId) + { + var doctorInfo = _doctorService.GetEmploymentInfo(doctorId); + return ResponseOutput.Ok(doctorInfo); + } + + /// 更新-医生工作信息 WorkInfo + + [HttpPost, Route("updateEmploymentInfo")] + public IResponseOutput UpdateEmploymentInfoInfo(EmploymentCommand updateEmploymentInfoViewModel) + { + return _doctorService.UpdateDoctorEmploymentInfo(updateEmploymentInfoViewModel); + } + + #endregion + + #region Reviewer 专业信息 + /// 获取医生专业信息 + + [HttpGet, Route("getSpecialtyInfo/{doctorId:Guid}")] + public IResponseOutput GetDoctorSpecialty(Guid doctorId) + { + var doctorInfo = _doctorService.GetDoctorSpecialty(doctorId); + + return ResponseOutput.Ok(doctorInfo); + } + + /// 更新专业信息 + + [HttpPost, Route("updateSpecialtyInfo")] + public IResponseOutput UpdateDoctorSpecialty(SpecialtyCommand specialtyUpdateModel) + { + return _doctorService.UpdateDoctorSpecialty(specialtyUpdateModel); + //return new IResponseOutput() + //{ + // IsSuccess = success, + // ErrorMessage = success ? "Update Successfully." : "Update Failed." + //}; + } + #endregion + + #region Reviewer 状态 + /// 获取医生审核状态 + + [HttpGet, Route("getAuditState/{doctorId:guid}")] + public IResponseOutput GetResumeAuditState([FromServices] IVacationService _vacationService, Guid doctorId) + { + var result = _doctorService.GetDoctorAuditStatus(doctorId); + result.InHoliday = _vacationService.OnVacation(doctorId).IsSuccess; + return ResponseOutput.Ok(result); + } + + /// + /// 审核简历状态 + /// + /// 复审状态ReviewStatus 0-未复审,1-复审通过,2-未通过 + /// + + [LogFilter] + [HttpPost, Route("updateAuditResume")] + public IResponseOutput AuditResume(ResumeConfirmCommand auditResumeParam) + { + var userId = Guid.Parse(User.FindFirst("id").Value); + return _doctorService.AuditResume(auditResumeParam, userId); + } + /// + /// 获取医生入组信息 正在提交的数量 已同意入组项目个数 正在读的 + /// + + [HttpPost, Route("getDoctorIntoGroupInfo/{doctorId:guid}")] + public IResponseOutput GetDoctorEnrollInfo(Guid doctorId) + { + return ResponseOutput.Ok(_doctorService.GetDoctorEnrollInfo(doctorId)); + } + + + #endregion + + #region 医生详情 + + /// + /// 获取医生详情 + /// + /// + /// 医生Id + /// + /// + /// + /// + /// + [HttpGet, Route("getDetail/{doctorId:guid}")] + public IResponseOutput GetDoctorDetail([FromServices] IAttachmentService attachmentService, [FromServices] IEducationService _educationService, [FromServices] ITrialExperienceService _trialExperienceService, [FromServices] IResearchPublicationService _researchPublicationService, [FromServices] IVacationService _vacationService, Guid doctorId) + { + var education = _educationService.GetEducation(doctorId); + + var sowList = _doctorService.GetDoctorSow(doctorId); + var ackSowList = _doctorService.GetDoctorAckSow(doctorId); + + var doctorDetail = new DoctorDetailDTO + { + AuditView = _doctorService.GetDoctorAuditStatus(doctorId), + BasicInfoView = _doctorService.GetDoctorBasicInfo(doctorId), + EmploymentView = _doctorService.GetEmploymentInfo(doctorId), + AttachmentList = attachmentService.GetAttachments(doctorId), + + EducationList = education.EducationList, + PostgraduateList = education.PostgraduateList, + + TrialExperienceView = _trialExperienceService.GetTrialExperience(doctorId), + ResearchPublicationView = _researchPublicationService.GetResearchPublication(doctorId), + + SpecialtyView = _doctorService.GetDoctorSpecialty(doctorId), + InHoliday = _vacationService.OnVacation(doctorId).IsSuccess, + IntoGroupInfo = _doctorService.GetDoctorEnrollInfo(doctorId), + SowList = sowList, + AckSowList = ackSowList + }; + + return ResponseOutput.Ok(doctorDetail); + } + + #endregion + } +} diff --git a/IRaCIS.Core.API/Controllers/Doctor/EducationController.cs b/IRaCIS.Core.API/Controllers/Doctor/EducationController.cs new file mode 100644 index 0000000..472895f --- /dev/null +++ b/IRaCIS.Core.API/Controllers/Doctor/EducationController.cs @@ -0,0 +1,87 @@ +using System; +using IRaCIS.Application.Interfaces; +using IRaCIS.Application.ViewModels; +using IRaCIS.Core.Application.Contracts.RequestAndResponse; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; + +namespace IRaCIS.Api.Controllers +{ + /// + /// 医生教育经历、继续学习经历 + /// + [Route("doctor")] + [ApiController, Authorize, ApiExplorerSettings(GroupName = "Reviewer")] + public class EducationController : ControllerBase + { + private readonly IEducationService _doctorEducationService; + + public EducationController(IEducationService doctorEducationService) + { + _doctorEducationService = doctorEducationService; + } + + /// + /// 根据医生Id获取医生教育经历和继续学习经历列表 + /// + + [HttpGet, Route("getEducation/{doctorId:Guid}")] + public IResponseOutput GetDoctorEducationList(Guid doctorId) + { + return ResponseOutput.Ok(_doctorEducationService.GetEducation(doctorId)) ; + + } + + #region 教育经历 + + /// + /// 新增医生教育经历 + /// + /// + /// + + [HttpPost, Route("addOrUpdateEducationInfo")] + public IResponseOutput AddEducationInfo(EducationCommand doctorEducationInfoViewModel) + { + return _doctorEducationService.AddOrUpdateEducationInfo(doctorEducationInfoViewModel); + } + + /// + /// 删除医生教育经历 + /// + /// 医生Id + /// + + [HttpDelete, Route("deleteEducationInfo/{doctorId:guid}")] + public IResponseOutput DeleteEducationInfo(Guid doctorId) + { + return _doctorEducationService.DeleteEducationInfo(doctorId); + + } + + #endregion + + #region 继续学习经历 + /// 添加/更新医生继续学习经历 + + [HttpPost, Route("addOrUpdatePostgraduateInfo")] + public IResponseOutput AddPostgraduateInfo(PostgraduateCommand doctorEducationInfoViewModel) + { + return _doctorEducationService.AddOrUpdatePostgraduateInfo(doctorEducationInfoViewModel); + } + + /// + /// 删除医生继续学习经历 + /// + /// 医生Id + /// + + [HttpDelete, Route("deletePostgraduateInfo/{doctorId:guid}")] + public IResponseOutput DeleteContinueLearningInfo(Guid doctorId) + { + return _doctorEducationService.DeletePostgraduateInfo(doctorId); + + } + #endregion + } +} diff --git a/IRaCIS.Core.API/Controllers/Doctor/ResearchPublicationController.cs b/IRaCIS.Core.API/Controllers/Doctor/ResearchPublicationController.cs new file mode 100644 index 0000000..914d7c0 --- /dev/null +++ b/IRaCIS.Core.API/Controllers/Doctor/ResearchPublicationController.cs @@ -0,0 +1,44 @@ +using System; +using IRaCIS.Application.Interfaces; +using IRaCIS.Application.ViewModels; +using IRaCIS.Core.Application.Contracts.RequestAndResponse; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; + +namespace IRaCIS.Api.Controllers +{ + /// + /// 医生科研信息 + /// + [Route("doctor")] + [ApiController, Authorize, ApiExplorerSettings(GroupName = "Reviewer")] + public class ResearchPublicationController : ControllerBase + { + private readonly IResearchPublicationService _researchPublicationService; + public ResearchPublicationController(IResearchPublicationService researchPublicationService) + { + _researchPublicationService = researchPublicationService; + } + + /// + /// 查询-医生科学研究信息 + /// + /// 医生Id + /// + + [HttpGet, Route("getResearchPublication/{doctorId:guid}")] + public IResponseOutput GetDoctorScientificResearch(Guid doctorId) + { + return ResponseOutput.Ok(_researchPublicationService.GetResearchPublication(doctorId)) ; + } + + /// 添加或跟新医生 科研信息 + + [HttpPost, Route("addResearchPublication")] + public IResponseOutput AddOrUpdateScientificResearch( + ResearchPublicationDTO researchPublicationViewModel) + { + return _researchPublicationService.AddOrUpdateResearchPublication(researchPublicationViewModel); + } + } +} diff --git a/IRaCIS.Core.API/Controllers/Doctor/TrialExperienceController.cs b/IRaCIS.Core.API/Controllers/Doctor/TrialExperienceController.cs new file mode 100644 index 0000000..dc02343 --- /dev/null +++ b/IRaCIS.Core.API/Controllers/Doctor/TrialExperienceController.cs @@ -0,0 +1,82 @@ +using System; + + +using IRaCIS.Application; +using IRaCIS.Application.Interfaces; +using IRaCIS.Application.ViewModels; +using IRaCIS.Core.Application.Contracts.RequestAndResponse; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; + +namespace IRaCIS.Api.Controllers +{ + /// + /// 医生临床试验经历 + /// + [Route("doctor")] + [ApiController, Authorize, ApiExplorerSettings(GroupName = "Reviewer")] + public class TrialExperienceController : ControllerBase + { + private readonly ITrialExperienceService _doctorTrialExperienceService; + + public TrialExperienceController(ITrialExperienceService doctorTrialExperienceService) + { + _doctorTrialExperienceService = doctorTrialExperienceService; + } + + /// + /// 根据医生Id,获取临床试验经历 界面所有数据 + /// + + [HttpGet, Route("getTrialExperience/{doctorId:guid}")] + public IResponseOutput GetClinicalTrialExperience(Guid doctorId) + { + return ResponseOutput.Ok(_doctorTrialExperienceService.GetTrialExperience(doctorId)) ; + + } + + /// 添加或更新医生临床经验列表项 + + [HttpPost, Route("addOrUpdateTrialExperience")] + public IResponseOutput AddOrUpdateClinicalTrialExperience(TrialExperienceCommand trialExperienceViewModel) + { + return _doctorTrialExperienceService.AddOrUpdateTrialExperience(trialExperienceViewModel); + } + + + /// + /// 更新-GCP和其他临床经验 + /// + /// + /// + + [HttpPost, Route("updateGcpExperience")] + public IResponseOutput UpdateDoctorGcpAndOtherExperience( + GCPExperienceCommand trialExperienceGcpViewModel) + { + return _doctorTrialExperienceService.UpdateGcpExperience(trialExperienceGcpViewModel); + } + + /// + /// 更新其他技能经验 + /// + + [HttpPost, Route("updateOtherExperience")] + public IResponseOutput UpdateOtherExperience(ClinicalExperienceCommand updateOtherClinicalExperience) + { + return _doctorTrialExperienceService.UpdateOtherExperience(updateOtherClinicalExperience.DoctorId, updateOtherClinicalExperience.OtherClinicalExperience); + + + } + + /// + /// 删除临床经验 + /// + + [HttpDelete, Route("deleteTrialExperience/{doctorId:guid}")] + public IResponseOutput DeleteDoctorTrialExperience(Guid doctorId) + { + return _doctorTrialExperienceService.DeleteTrialExperience(doctorId); + } + } +} diff --git a/IRaCIS.Core.API/Controllers/Doctor/VacationController.cs b/IRaCIS.Core.API/Controllers/Doctor/VacationController.cs new file mode 100644 index 0000000..0f1a30a --- /dev/null +++ b/IRaCIS.Core.API/Controllers/Doctor/VacationController.cs @@ -0,0 +1,57 @@ +using System; +using IRaCIS.Application.Interfaces; +using IRaCIS.Application.ViewModels; +using IRaCIS.Core.Application.Contracts.RequestAndResponse; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; + +namespace IRaCIS.Api.Controllers.Doctor +{ + /// + /// 医生休假安排 + /// + [Route("holiday")] + [ApiController, Authorize, ApiExplorerSettings(GroupName = "Reviewer")] + public class VacationController : ControllerBase + { + private readonly IVacationService _vacationService; + public VacationController(IVacationService vacationService) + { + _vacationService = vacationService; + } + /// + /// 添加休假时间段 + /// + /// Status不传 + /// + + [HttpPost, Route("addOrUpdateVacation")] + public IResponseOutput AddOrUpdateVacation(VacationCommand vacationViewModel) + { + return _vacationService.AddOrUpdateVacation(vacationViewModel); + } + + /// + /// 删除休假时间段 + /// + /// 记录Id + /// + + [HttpDelete, Route("deleteVacation/{holidayId:guid}")] + public IResponseOutput DeleteVacation(Guid holidayId) + { + return _vacationService.DeleteVacation(holidayId); + } + + /// + /// 获取休假时间段列表 + /// + /// + + [HttpGet, Route("getVacationList/{doctorId:guid}/{pageIndex:int}/{pageSize:int}")] + public IResponseOutput> GetVacationList(Guid doctorId, int pageIndex, int pageSize) + { + return ResponseOutput.Ok(_vacationService.GetVacationList(doctorId, pageIndex, pageSize)) ; + } + } +} diff --git a/IRaCIS.Core.API/Controllers/Financial/ExchangeRateController.cs b/IRaCIS.Core.API/Controllers/Financial/ExchangeRateController.cs new file mode 100644 index 0000000..8cf3ff6 --- /dev/null +++ b/IRaCIS.Core.API/Controllers/Financial/ExchangeRateController.cs @@ -0,0 +1,81 @@ +using IRaCIS.Api.Filter; +using IRaCIS.Application.Interfaces; +using IRaCIS.Application.ViewModels; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using System; +using System.Collections.Generic; +using IRaCIS.Core.Application.Contracts.RequestAndResponse; + + +namespace IRaCIS.Api.Controllers.Pay +{ + /// + /// Financial 支撑信息---汇率 + /// + [Route("exchangeRate")] + [ApiController, Authorize, ApiExplorerSettings(GroupName = "Financial")] + public class ExchangeRateController : ControllerBase + { + private readonly IExchangeRateService _exchangeRateService; + private readonly ICalculateService _calculateService; + private readonly IPaymentAdjustmentService _costAdjustmentService; + public ExchangeRateController(IExchangeRateService exchangeRateService, + ICalculateService calculateService, + IPaymentAdjustmentService costAdjustmentService) + { + _exchangeRateService = exchangeRateService; + _calculateService = calculateService; + _costAdjustmentService = costAdjustmentService; + } + + /// + /// 添加或更新汇率(会触发没有对锁定的费用计算) + /// + + [LogFilter] + [HttpPost, Route("addOrUpdateExchangeRate")] + public IResponseOutput AddOrUpdateExchangeRate(ExchangeRateCommand addOrUpdateModel) + { + var result = _exchangeRateService.AddOrUpdateExchangeRate(addOrUpdateModel); + var calcList = _calculateService.GetNeedCalculateReviewerList(Guid.Empty, addOrUpdateModel.YearMonth); + foreach (var item in calcList) + { + if (item != null) + { + _calculateService.CalculateMonthlyPayment(new CalculateDoctorAndMonthDTO() + { + NeedCalculateReviewers = new List() + { + item.DoctorId + }, + CalculateMonth = DateTime.Parse(item.YearMonth) + }, User.FindFirst("id").Value); + } + } + _costAdjustmentService.CalculateCNY(addOrUpdateModel.YearMonth,addOrUpdateModel.Rate); + return result; + } + + /// + /// 分页获取汇率列表 + /// + + [HttpPost, Route("getRateList")] + public IResponseOutput> GetAwardPriceList(ExchangeRateQueryDTO queryParam) + { + return ResponseOutput.Ok(_exchangeRateService.GetExchangeRateList(queryParam)); + } + + /// + /// 根据记录Id,删除汇率记录 + /// + /// 汇率记录Id + + [HttpDelete, Route("deleteExchangeRate/{id:guid}")] + public IResponseOutput DeleteExchangeRate(Guid id) + { + return _exchangeRateService.DeleteExchangeRate(id); + } + } +} \ No newline at end of file diff --git a/IRaCIS.Core.API/Controllers/Financial/FinancialController.cs b/IRaCIS.Core.API/Controllers/Financial/FinancialController.cs new file mode 100644 index 0000000..e53dc35 --- /dev/null +++ b/IRaCIS.Core.API/Controllers/Financial/FinancialController.cs @@ -0,0 +1,158 @@ +using System; +using System.Collections.Generic; +using IRaCIS.Application.Interfaces; +using IRaCIS.Application.ViewModels; +using IRaCIS.Application.ViewModels.Pay; +using IRaCIS.Core.Application.Contracts.RequestAndResponse; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; + +namespace IRaCIS.Api.Controllers +{ + /// + /// 费用查询(月度付费、月度付费明细、历史范围付费、历史范围付费明细、收入、收入支出分析) + /// + [Route("financial")] + [ApiController, Authorize, ApiExplorerSettings(GroupName = "Financial")] + public class FinancialController : ControllerBase + { + private readonly IPaymentService _paymentService; + private readonly IExchangeRateService _exchangeRateService; + private readonly ICalculateService _calculateService; + public FinancialController(IPaymentService paymentService, + IExchangeRateService exchangeRateService, + ICalculateService calculateService) + { + _paymentService = paymentService; + _exchangeRateService = exchangeRateService; + _calculateService = calculateService; + } + + /// + /// 计算医生月度费用,并将计算的结果存入费用表 + /// + + [HttpPost, Route("calculateMonthlyPayment")] + public IResponseOutput CalculateMonthlyPayment(CalculateDoctorAndMonthDTO param) + { + if (!ModelState.IsValid) + { + return ResponseOutput.NotOk("Invalid parameter."); + } + return _calculateService.CalculateMonthlyPayment(param, User.FindFirst("id").Value); + } + + /// + /// Financials /Monthly Payment 列表查询接口 + /// + + [HttpPost, Route("getMonthlyPaymentList")] + public IResponseOutput GetMonthlyPaymentList(MonthlyPaymentQueryDTO queryParam) + { + return ResponseOutput.Ok(new PaymentDTO + { + CostList = _paymentService.GetMonthlyPaymentList(queryParam), + ExchangeRate = _exchangeRateService.GetExchangeRateByMonth(queryParam.StatisticsDate.ToString("yyyy-MM")) + }); + } + + /// + /// Financials /MonthlyPaymentDetail 详情查询接口 + /// + + [HttpPost, Route("getMonthlyPaymentDetailList/{paymentId:guid}/{doctorId:guid}/{yearMonth:datetime}")] + public IResponseOutput GetMonthlyPaymentDetailList(Guid paymentId, Guid doctorId, DateTime yearMonth) + { + return ResponseOutput.Ok(_paymentService.GetMonthlyPaymentDetailList(paymentId, doctorId, yearMonth)); + } + + /// + /// NEW 导出Excel压缩包 数据获取 + /// + /// + /// + [HttpPost, Route("getReviewersMonthlyPaymentDetail")] + public IResponseOutput> GetReviewersMonthlyPaymentDetail(List manyReviewers) + { + return ResponseOutput.Ok(_paymentService.GetReviewersMonthlyPaymentDetail(manyReviewers)); + } + + + /// + /// 获取劳务费用列表 + /// + /// + /// + [HttpPost, Route("getLaborPaymentList")] + public IResponseOutput> GetLaborPaymentList(List paymentIds) + { + return ResponseOutput.Ok(_paymentService.GetLaborPaymentList(paymentIds)); + } + + + + /// + /// 锁定医生费用,锁定后,无法变更该医生对应月份的费用和工作量[New] + /// + + [HttpPost, Route("lockMonthlyPayment")] + public IResponseOutput LockMonthlyPayment(LockPaymentDTO param) + { + var yearMonth = param.Month.ToString("yyyy-MM"); + return _calculateService.UpdateLockStatus(param.ReviewerIdList, yearMonth, true); + + } + + /// + /// Financials / Payment History 列表查询接口(已经支付锁定的数据,包含调整的)[New] + /// + + [HttpPost, Route("getPaymentHistoryList")] + public IResponseOutput> GetPaymentHistoryList(PaymentQueryDTO param) + { + return ResponseOutput.Ok(_paymentService.GetPaymentHistoryList(param)) ; + } + + /// + /// Financials / Payment History 详情接口[New] + /// + + [HttpPost, Route("getPaymentHistoryDetailList")] + public IResponseOutput> GetPaymentHistoryDetailList(VolumeQueryDTO param) + { + var result = _paymentService.GetPaymentHistoryDetailList(param); + return ResponseOutput.Ok(result); + } + + /// + /// Revenues列表接口,收入统计[New] 0是Detail 1是按照项目 2是按照人 3按照月份 + /// + + [HttpPost, Route("getRevenuesStatistics")] + public IResponseOutput> GetRevenuesStatistics(StatisticsQueryDTO param) + { + var result = _paymentService.GetRevenuesList(param); + return ResponseOutput.Ok(result) ; + } + + /// + /// 收入支出分析接口,按照医生维度分析统计 + /// + + [HttpPost, Route("getReviewerAnalysisList")] + public IResponseOutput> GetReviewerAnalysisList(AnalysisQueryDTO param) + { + return ResponseOutput.Ok(_paymentService.GetReviewerAnalysisList(param)); + } + + /// + /// 收入支出分析接口,按照项目维度分析统计 + /// + + [HttpPost, Route("getTrialAnalysisList")] + public IResponseOutput> GetTrialAnalysisList(TrialAnalysisQueryDTO param) + { + return ResponseOutput.Ok(_paymentService.GetTrialAnalysisList(param)); + } + } +} diff --git a/IRaCIS.Core.API/Controllers/Financial/PaymentAdjustmentController.cs b/IRaCIS.Core.API/Controllers/Financial/PaymentAdjustmentController.cs new file mode 100644 index 0000000..d56a804 --- /dev/null +++ b/IRaCIS.Core.API/Controllers/Financial/PaymentAdjustmentController.cs @@ -0,0 +1,71 @@ +using System; +using System.Collections.Generic; + +using IRaCIS.Api.Filter; +using IRaCIS.Application.Interfaces; +using IRaCIS.Application.ViewModels.Pay; +using IRaCIS.Core.Application.Contracts.RequestAndResponse; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; + +namespace IRaCIS.Api.Controllers.Pay +{ + /// + /// Financial 支撑信息---医生月度调整 + /// + [Route("paymentAdjustment")] + [ApiController, Authorize, ApiExplorerSettings(GroupName = "Financial")] + public class PaymentAdjustmentController : ControllerBase + { + private readonly IPaymentAdjustmentService _paymentAdjustmentService; + + public PaymentAdjustmentController(IPaymentAdjustmentService paymentAdjustmentService) + { + _paymentAdjustmentService = paymentAdjustmentService; + } + + /// + /// 获取费用调整列表 + /// + + [HttpPost, Route("getPaymentAdjustmentList")] + public IResponseOutput> GetPaymentAdjustmentList( + PaymentAdjustmentQueryDTO queryParam) + { + var result = _paymentAdjustmentService.GetPaymentAdjustmentList(queryParam); + return ResponseOutput.Ok(result); + } + + /// + /// 添加或更新费用调整[AUTH] + /// + [LogFilter] + + [HttpPost, Route("addOrUpdatePaymentAdjustment")] + public IResponseOutput AddOrUpdatePaymentAdjustment(PaymentAdjustmentCommand addOrUpdateModel) + { + return _paymentAdjustmentService.AddOrUpdatePaymentAdjustment(addOrUpdateModel,Guid.Parse(User.FindFirst("id").Value)); + } + + /// + /// 删除费用调整记录 + /// + + [LogFilter] + [HttpDelete, Route("deletePaymentAdjustment/{id:guid}")] + public IResponseOutput DeleteCostAdjustment(Guid id) + { + return _paymentAdjustmentService.DeleteCostAdjustment(id); + } + + /// + /// 获取医生列表 + /// + + [HttpGet, Route("getReviewerSelectList")] + public IResponseOutput> GetReviewerSelectList() + { + return ResponseOutput.Ok(_paymentAdjustmentService.GetReviewerSelectList()); + } + } +} diff --git a/IRaCIS.Core.API/Controllers/Financial/RankPriceController.cs b/IRaCIS.Core.API/Controllers/Financial/RankPriceController.cs new file mode 100644 index 0000000..35f0103 --- /dev/null +++ b/IRaCIS.Core.API/Controllers/Financial/RankPriceController.cs @@ -0,0 +1,93 @@ +using System; +using System.Collections.Generic; + +using IRaCIS.Api.Filter; +using IRaCIS.Application.Interfaces; +using IRaCIS.Application.ViewModels; +using IRaCIS.Core.Application.Contracts.RequestAndResponse; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; + +namespace IRaCIS.Api.Controllers.Pay +{ + /// + /// Financial 支撑信息---职称付费价格 + /// + [Route("rankPrice")] + [ApiController, Authorize, ApiExplorerSettings(GroupName = "Financial")] + public class RankPriceController : ControllerBase + { + private readonly IRankPriceService _rankPriceService; + private readonly ICalculateService _calculateService; + private readonly IReviewerPayInfoService _reviewerPayInfoService; + public RankPriceController(IRankPriceService rankPriceService, + ICalculateService calculateService, IReviewerPayInfoService reviewerPayInfoService) + { + _rankPriceService = rankPriceService; + _calculateService = calculateService; + _reviewerPayInfoService = reviewerPayInfoService; + } + + /// + /// 添加或更新 职称单价[AUTH] + /// + + [LogFilter] + [HttpPost, Route("addOrUpdateRankPrice")] + public IResponseOutput AddOrUpdateRankPrice(RankPriceCommand addOrUpdateModel) + { + if (addOrUpdateModel.Id != Guid.Empty&& addOrUpdateModel.Id !=null) + { + var needCalReviewerIds = _reviewerPayInfoService.GetReviewerIdByRankId(Guid.Parse(addOrUpdateModel.Id.ToString())); + var calcList = _calculateService.GetNeedCalculateReviewerList(Guid.Empty, string.Empty); + + foreach (var item in calcList) + { + if (item != null && needCalReviewerIds.Contains(item.DoctorId)) + { + _calculateService.CalculateMonthlyPayment(new CalculateDoctorAndMonthDTO() + { + NeedCalculateReviewers = new List() + { + item.DoctorId + }, + CalculateMonth = DateTime.Parse(item.YearMonth) + }, User.FindFirst("id").Value); + } + } + } + var userId = Guid.Parse(User.FindFirst("id").Value); + return _rankPriceService.AddOrUpdateRankPrice(addOrUpdateModel, userId); + } + + /// + /// 获取职称单价列表 + /// + + [HttpPost, Route("getRankPriceList")] + public IResponseOutput> GetRankPriceList(RankPriceQueryDTO queryParam) + { + return ResponseOutput.Ok(_rankPriceService.GetRankPriceList(queryParam)); + } + + /// + /// 删除职称单价记录 + /// + + [HttpDelete, Route("deleteRankPrice/{id:guid}")] + public IResponseOutput DeleteRankPrice(Guid id) + { + return _rankPriceService.DeleteRankPrice(id); + } + + /// + /// 获取职称字典数据 + /// + + [HttpGet, Route("getRankDic")] + public IResponseOutput> GetRankDic() + { + return ResponseOutput.Ok(_rankPriceService.GetRankDic()); + } + } +} diff --git a/IRaCIS.Core.API/Controllers/Financial/ReviewerPayInfomationController.cs b/IRaCIS.Core.API/Controllers/Financial/ReviewerPayInfomationController.cs new file mode 100644 index 0000000..1840dae --- /dev/null +++ b/IRaCIS.Core.API/Controllers/Financial/ReviewerPayInfomationController.cs @@ -0,0 +1,79 @@ +using System; +using System.Collections.Generic; + + +using IRaCIS.Application.Interfaces; +using IRaCIS.Application.ViewModels; +using IRaCIS.Core.Application.Contracts.RequestAndResponse; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; + +namespace IRaCIS.Api.Controllers +{ + /// + /// Financial 支撑信息---医生付费信息及支付标准配置 + /// + [Route("reviewerPayInfomation")] + [ApiController, Authorize, ApiExplorerSettings(GroupName = "Financial")] + public class ReviewerPayInfomationController : ControllerBase + { + private IReviewerPayInfoService _doctorPayInfoService; + private readonly ICalculateService _calculateService; + + public ReviewerPayInfomationController(IReviewerPayInfoService doctorPayInfoService, + ICalculateService calculateService) + { + _doctorPayInfoService = doctorPayInfoService; + _calculateService = calculateService; + } + + /// + /// 添加或更新(替换)医生支付展信息[AUTH] + /// + + [HttpPost, Route("addOrUpdateReviewerPayInfo")] + public IResponseOutput AddOrUpdateReviewerPayInfo(ReviewerPayInfoCommand addOrUpdateModel) + { + var userId = Guid.Parse(User.FindFirst("id").Value); + var result = _doctorPayInfoService.AddOrUpdateReviewerPayInfo(addOrUpdateModel, userId); + var calcList = _calculateService.GetNeedCalculateReviewerList(addOrUpdateModel.DoctorId, string.Empty); + foreach (var item in calcList) + { + if (item != null) + { + _calculateService.CalculateMonthlyPayment(new CalculateDoctorAndMonthDTO() + { + NeedCalculateReviewers = new List() + { + item.DoctorId + }, + CalculateMonth = DateTime.Parse(item.YearMonth) + }, User.FindFirst("id").Value); + } + } + return result; + } + + /// + /// 获取医生支付信息列表 + /// + + [HttpPost, Route("getReviewerPayInfoList")] + public IResponseOutput> GetReviewerPayInfoList(DoctorPaymentInfoQueryDTO queryParam) + { + return ResponseOutput.Ok(_doctorPayInfoService.GetDoctorPayInfoList(queryParam)) ; + } + + /// + /// 根据医生Id获取支付信息 + /// + /// 医生Id + /// + + [HttpGet, Route("getReviewerPayInfo/{doctorId:guid}")] + public IResponseOutput GetReviewerPayInfo(Guid doctorId) + { + return ResponseOutput.Ok(_doctorPayInfoService.GetReviewerPayInfo(doctorId)) ; + } + } +} diff --git a/IRaCIS.Core.API/Controllers/Financial/TrialPaymentPriceController.cs b/IRaCIS.Core.API/Controllers/Financial/TrialPaymentPriceController.cs new file mode 100644 index 0000000..e9bfdc6 --- /dev/null +++ b/IRaCIS.Core.API/Controllers/Financial/TrialPaymentPriceController.cs @@ -0,0 +1,97 @@ +using IRaCIS.Application.Interfaces; +using IRaCIS.Application.ViewModels; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using System; +using System.Collections.Generic; +using IRaCIS.Core.Application.Contracts.RequestAndResponse; + + +namespace IRaCIS.Api.Controllers +{ + /// + /// Financial 支撑信息---项目费用 + /// + [Route("trialPaymentPrice")] + [ApiController, Authorize, ApiExplorerSettings(GroupName = "Financial")] + public class TrialPaymentPriceController : ControllerBase + { + private readonly ITrialPaymentPriceService _trialPaymentPriceService; + private readonly ICalculateService _calculateService; + private readonly ITrialService _trialService; + + public TrialPaymentPriceController(ITrialPaymentPriceService trialPaymentPriceService, + ICalculateService calculateService, + ITrialService trialService) + { + _trialPaymentPriceService = trialPaymentPriceService; + _calculateService = calculateService; + _trialService = trialService; + } + + /// + /// 保存(替换)项目支付价格信息(会触发没有被锁定的费用计算)[AUTH] + /// + + [HttpPost, Route("addOrUpdateTrialPaymentPrice")] + public IResponseOutput AddOrUpdateTrialPaymentPrice(TrialPaymentPriceCommand addOrUpdateModel) + { + var userId = Guid.Parse(User.FindFirst("id").Value); + var result = _trialPaymentPriceService.AddOrUpdateTrialPaymentPrice(addOrUpdateModel, userId); + var needCalReviewerIds = _trialService.GetTrialEnrollmentReviewerIds(addOrUpdateModel.TrialId); + var calcList = _calculateService.GetNeedCalculateReviewerList(Guid.Empty, string.Empty); + + foreach (var item in calcList) + { + if (item != null && needCalReviewerIds.Contains(item.DoctorId)) + { + _calculateService.CalculateMonthlyPayment(new CalculateDoctorAndMonthDTO() + { + NeedCalculateReviewers = new List() + { + item.DoctorId + }, + CalculateMonth = DateTime.Parse(item.YearMonth) + }, User.FindFirst("id").Value); + } + } + + return result; + } + /// + /// 更新项目SOW 协议 [AUTH] + /// + /// + /// + + [HttpPost, Route("uploadTrialSOW")] + public IResponseOutput UploadTrialSOW(TrialSOWPathDTO trialSowPath) + { + var userId = Guid.Parse(User.FindFirst("id").Value); + return _trialPaymentPriceService.UploadTrialSOW(userId, trialSowPath); + } + /// + ///删除项目SOW [AUTH] + /// + /// + /// + + [HttpPost, Route("deleteTrialSOW")] + public IResponseOutput DeleteTrialSOW(DeleteSowPathDTO trialSowPath) + { + var userId = Guid.Parse(User.FindFirst("id").Value); + return _trialPaymentPriceService.DeleteTrialSOW(userId, trialSowPath); + } + /// + /// 获取项目支付价格信息列表 + /// + + [HttpPost, Route("getTrialPaymentPriceList")] + public IResponseOutput> GetTrialPaymentPriceList(TrialPaymentPriceQueryDTO queryParam) + { + return ResponseOutput.Ok(_trialPaymentPriceService.GetTrialPaymentPriceList(queryParam)) ; + } + + + } +} diff --git a/IRaCIS.Core.API/Controllers/Financial/TrialRevenuesPriceController.cs b/IRaCIS.Core.API/Controllers/Financial/TrialRevenuesPriceController.cs new file mode 100644 index 0000000..825f842 --- /dev/null +++ b/IRaCIS.Core.API/Controllers/Financial/TrialRevenuesPriceController.cs @@ -0,0 +1,50 @@ +using IRaCIS.Application.Interfaces; +using IRaCIS.Application.ViewModels; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using System.Collections.Generic; +using IRaCIS.Core.Application.Contracts.RequestAndResponse; + + +namespace IRaCIS.Api.Controllers +{ + /// + /// Financial 支撑信息---项目收入费用 + /// + [Route("trialRevenuesPrice")] + [ApiController, Authorize, ApiExplorerSettings(GroupName = "Financial")] + public class TrialRevenuesPriceController : ControllerBase + { + private readonly ITrialRevenuesPriceService _trialRevenuesPriceService; + + public TrialRevenuesPriceController(ITrialRevenuesPriceService trialRevenuesPriceService) + { + _trialRevenuesPriceService = trialRevenuesPriceService; + } + + + /// + /// 保存(替换)项目费用收入单价信息[New] + /// + /// + /// + + [HttpPost, Route("addOrUpdateTrialRevenuesPrice")] + public IResponseOutput AddOrUpdateTrialRevenuesPrice(TrialRevenuesPriceDTO model) + { + return _trialRevenuesPriceService.AddOrUpdateTrialRevenuesPrice(model); + } + + /// + /// 获取项目收入费用信息列表[New] + /// + /// + /// + + [HttpPost, Route("getTrialRevenuesPriceList")] + public IResponseOutput> GetTrialRevenuesPriceList(TrialRevenuesPriceQueryDTO param) + { + return ResponseOutput.Ok(_trialRevenuesPriceService.GetTrialRevenuesPriceList(param)); + } + } +} diff --git a/IRaCIS.Core.API/Controllers/Financial/TrialRevenuesPriceVerificationController.cs b/IRaCIS.Core.API/Controllers/Financial/TrialRevenuesPriceVerificationController.cs new file mode 100644 index 0000000..e51b34e --- /dev/null +++ b/IRaCIS.Core.API/Controllers/Financial/TrialRevenuesPriceVerificationController.cs @@ -0,0 +1,36 @@ + +using System.Collections.Generic; +using IRaCIS.Application.Interfaces; +using IRaCIS.Core.Application.Contracts.RequestAndResponse; +using IRaCIS.Core.Application.Contracts.Trial.DTO; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; + +namespace IRaCIS.Api.Controllers +{ + /// + /// Financial---项目收入价格验证 + /// + [Route("trialRevenuesPriceVerification")] + [ApiController, Authorize, ApiExplorerSettings(GroupName = "Financial")] + public class TrialRevenuesPriceVerificationController : ControllerBase + { + private readonly ITrialRevenuesPriceVerificationService _trialRevenuesPriceVerificationService; + + public TrialRevenuesPriceVerificationController(ITrialRevenuesPriceVerificationService trialRevenuesPriceVerificationService) + { + _trialRevenuesPriceVerificationService = trialRevenuesPriceVerificationService; + } + + [HttpPost, Route("getRevenuesVerifyList")] + public IResponseOutput> GetRevenuesVerifyList(RevenusVerifyQueryDTO param) + { + return ResponseOutput.Ok(_trialRevenuesPriceVerificationService.GetTrialRevenuesVerifyResultList(param)); + } + [HttpPost, Route("getAnalysisVerifyList")] + public IResponseOutput GetAnalysisVerifyList(RevenusVerifyQueryDTO param) + { + return ResponseOutput.Ok(_trialRevenuesPriceVerificationService.GetAnalysisVerifyList(param)); + } + } +} diff --git a/IRaCIS.Core.API/Controllers/Financial/VolumeRewardController.cs b/IRaCIS.Core.API/Controllers/Financial/VolumeRewardController.cs new file mode 100644 index 0000000..0c5fca5 --- /dev/null +++ b/IRaCIS.Core.API/Controllers/Financial/VolumeRewardController.cs @@ -0,0 +1,71 @@ +using IRaCIS.Api.Filter; +using IRaCIS.Application.Interfaces; +using IRaCIS.Application.ViewModels; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using System; +using System.Collections.Generic; +using IRaCIS.Core.Application.Contracts.RequestAndResponse; + + +namespace IRaCIS.Api.Controllers.Pay +{ + /// + /// Financial 支撑信息---工作量奖励标准 + /// + [Route("volumeReward")] + [ApiController, Authorize, ApiExplorerSettings(GroupName = "Financial")] + public class VolumeRewardController : ControllerBase + { + private readonly IVolumeRewardService _volumeRewardService; + private readonly ICalculateService _calculateService; + + public VolumeRewardController(IVolumeRewardService volumeRewardService, + ICalculateService calculateService) + { + _volumeRewardService = volumeRewardService; + _calculateService = calculateService; + } + + /// + /// 批量更新奖励费用[AUTH] + /// + + [LogFilter] + [HttpPost, Route("addOrUpdatevolumeRewardPriceList")] + public IResponseOutput AddOrUpdateAwardPriceList(IEnumerable addOrUpdateModel) + { + var userId = User.FindFirst("id").Value; + var result = _volumeRewardService.AddOrUpdateVolumeRewardPriceList(addOrUpdateModel, Guid.Parse(userId)); + + var calcList = _calculateService.GetNeedCalculateReviewerList(Guid.Empty, string.Empty); + foreach (var item in calcList) + { + if (item != null) + { + _calculateService.CalculateMonthlyPayment(new CalculateDoctorAndMonthDTO() + { + NeedCalculateReviewers = new List() + { + item.DoctorId + }, + CalculateMonth = DateTime.Parse(item.YearMonth) + }, User.FindFirst("id").Value); + } + } + return result; + } + + /// + /// 分页获取奖励单价列表 + /// + + [HttpPost, Route("getVolumeRewardPriceList")] + public IResponseOutput> GetAwardPriceList(AwardPriceQueryDTO queryParam) + { + return ResponseOutput.Ok(_volumeRewardService.GetVolumeRewardPriceList(queryParam)); + + } + + } +} diff --git a/IRaCIS.Core.API/Controllers/Image/InstanceController.cs b/IRaCIS.Core.API/Controllers/Image/InstanceController.cs new file mode 100644 index 0000000..5e7e59e --- /dev/null +++ b/IRaCIS.Core.API/Controllers/Image/InstanceController.cs @@ -0,0 +1,78 @@ +using IRaCIS.Core.Application.Contracts.Dicom; +using IRaCIS.Core.Application.Contracts.Dicom.DTO; +using IRaCIS.Core.Application.Dicom; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using System; +using System.Collections.Generic; +using System.IO; +using System.Net.Http; +using System.Threading.Tasks; + +namespace IRaCIS.Api.Controllers +{ + /// + /// Instance + /// + [Route("instance")] + [ApiController, Authorize, ApiExplorerSettings(GroupName = "Image")] + public class InstanceController : ControllerBase + { + private readonly IDicomArchiveService _dicomArchiveService; + public InstanceController(IDicomArchiveService dicomArchiveService) + { + _dicomArchiveService = dicomArchiveService; + } + + /// 指定资源Id,获取Dicom序列所属的实例信息列表 + /// Dicom序列的Id + [HttpGet, Route("list/{seriesId:guid}")] + public IEnumerable GetInstanceList(Guid seriesId) + { + return _dicomArchiveService.GetInstanceList(seriesId); + } + + /// 指定资源Id,获取Dicom序列所属的实例Id列表 + /// Dicom序列的Id + /// + /// + [HttpGet, Route("list/id/{seriesId:guid}/{tpCode?}/{key?}")] + public IEnumerable GetInstanceIdList(Guid seriesId, string tpCode, bool? key) + { + return _dicomArchiveService.GetInstanceIdList(seriesId, tpCode, key); + } + + /// 指定资源Id,渲染Dicom实例的Jpeg预览图像 + /// Dicom实例的Id + [HttpGet, Route("preview/{instanceId:guid}")] + [AllowAnonymous] + public FileContentResult GetInstancePreview(Guid instanceId) + { + string path = _dicomArchiveService.GetInstancePreview(instanceId); + using (var sw = DicomRenderingHelper.RenderPreviewJpeg(path)) + { + var bytes = new byte[sw.Length]; + sw.Read(bytes, 0, bytes.Length); + sw.Close(); + return new FileContentResult(bytes, "image/jpeg"); + } + } + + /// 指定资源Id,获取Dicom实例文件的内容 + /// Dicom实例的Id + [HttpGet, Route("content/{instanceId:guid}")] + [AllowAnonymous] + public FileContentResult GetInstanceContent(Guid instanceId) + { + var filePath = _dicomArchiveService.GetInstanceContent(instanceId); + using (var sw = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read)) + { + var bytes = new byte[sw.Length]; + sw.Read(bytes, 0, bytes.Length); + sw.Close(); + return new FileContentResult(bytes, "application/octet-stream"); + } + } + + } +} diff --git a/IRaCIS.Core.API/Controllers/Image/SeriesController.cs b/IRaCIS.Core.API/Controllers/Image/SeriesController.cs new file mode 100644 index 0000000..1ef3e8d --- /dev/null +++ b/IRaCIS.Core.API/Controllers/Image/SeriesController.cs @@ -0,0 +1,72 @@ +using IRaCIS.Core.Application.Contracts.Dicom; +using IRaCIS.Core.Application.Contracts.Dicom.DTO; +using IRaCIS.Core.Application.Contracts.RequestAndResponse; +using IRaCIS.Core.Application.Dicom; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using System; +using System.Collections.Generic; +using System.Net.Http; + +namespace IRaCIS.Api.Controllers +{ + /// + /// Series + /// + [Route("series")] + [ApiController, Authorize, ApiExplorerSettings(GroupName = "Image")] + public class SeriesController : ControllerBase + { + private readonly IDicomArchiveService _dicomArchiveService; + public SeriesController(IDicomArchiveService dicomArchiveService) + { + _dicomArchiveService = dicomArchiveService; + } + + + ///// 指定资源Id,获取Dicom检查所属序列信息列表 + ///// Dicom检查的Id + //[HttpGet, Route("list/{studyId:guid}")] + //[AllowAnonymous] + //public IEnumerable GetSeriesList(Guid studyId) + //{ + // return _dicomArchiveService.GetSeriesList(studyId); + //} + + + /// 指定资源Id,获取Dicom检查所属序列信息列表 + /// Dicom检查的Id + /// + [HttpGet, Route("serieslist/{studyId:guid}")] + [AllowAnonymous] + public IResponseOutput> GetSeriesList(Guid studyId,string tpCode) + { + return ResponseOutput.Ok( _dicomArchiveService.GetSeriesWithLabelList(studyId, tpCode)); + } + + + [HttpGet, Route("list/{studyId:guid}/{tpCode?}")] + [AllowAnonymous] + public IEnumerable GetSeriesWithLabelList(Guid studyId, string tpCode) + { + return _dicomArchiveService.GetSeriesWithLabelList(studyId, tpCode); + } + + + /// 指定资源Id,渲染Dicom序列的Jpeg预览图像 + /// Dicom序列的Id + [HttpGet, Route("preview/{seriesId:guid}")] + [AllowAnonymous] + public FileContentResult GetSeriesPreview(Guid seriesId) + { + string path = _dicomArchiveService.GetSeriesPreview(seriesId); + using (var sw = DicomRenderingHelper.RenderPreviewJpeg(path)) + { + var bytes = new byte[sw.Length]; + sw.Read(bytes, 0, bytes.Length); + sw.Close(); + return new FileContentResult(bytes, "image/jpeg"); + } + } + } +} diff --git a/IRaCIS.Core.API/Controllers/Image/StudyController.cs b/IRaCIS.Core.API/Controllers/Image/StudyController.cs new file mode 100644 index 0000000..5114bb5 --- /dev/null +++ b/IRaCIS.Core.API/Controllers/Image/StudyController.cs @@ -0,0 +1,536 @@ +using IRaCIS.Application.Interfaces; +using IRaCIS.Application.ViewModels; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using System; +using System.Collections.Generic; +using IRaCIS.Core.Application.Contracts.RequestAndResponse; +using IRaCIS.Core.Application.Contracts.Dicom.DTO; +using Microsoft.Net.Http.Headers; +using Microsoft.AspNetCore.WebUtilities; +using System.Threading.Tasks; +using IRaCIS.Core.Application.Contracts.Dicom; +using System.IO; +using System.IO.Compression; +using IRaCIS.Core.API.Filter; +using Microsoft.AspNetCore.Http.Features; +using IRaCIS.Core.Application.Dicom; +using IRaCIS.Core.Domain.Share; +using System.Linq; +using System.Threading; +using Microsoft.AspNetCore.Http; +using IRaCIS.Api.Filter; +using NLog; +using Microsoft.Extensions.Logging; +using System.Text; + +namespace IRaCIS.Api.Controllers +{ + /// + /// Study + /// + [Route("study")] + [ApiController, Authorize, ApiExplorerSettings(GroupName = "Image")] + public class StudyController : ControllerBase + { + private readonly IStudyService _studyService; + private readonly IDicomArchiveService _dicomArchiveService; + private readonly IDoctorService _doctorService; + private static readonly FormOptions _defaultFormOptions = new FormOptions(); + private readonly ILogger _logger; + public StudyController(IStudyService studyService, + IDicomArchiveService dicomArchiveService, IDoctorService doctorService, + ILogger logger + ) + { + _studyService = studyService; + _dicomArchiveService = dicomArchiveService; + _doctorService = doctorService; + _logger = logger; + } + + ///// 根据项目Id,受试者Id,获取受试者检查统计(不分页) + //[HttpGet, Route("getStudyStatList/{trialId:guid}/{subjectId:guid}/{siteId:guid}")] + //public IResponseOutput> GetStudy(Guid trialId, Guid subjectId, Guid siteId) + //{ + // return ResponseOutput.Ok(_studyService.GetStudyStatList(trialId, subjectId, siteId)); + //} + + [HttpPost, Route("getStudyList")] + public IResponseOutput> GetStudyList(StudyQueryDTO queryDto) + { + return ResponseOutput.Ok(_studyService.GetStudyList(queryDto)); + } + + [HttpPost, Route("getDistributeStudyList")] + public IResponseOutput> GetDistributeStudyList( + StudyStatusQueryDTO studyStatusQueryDto) + { + return ResponseOutput.Ok(_studyService.GetDistributeStudyList(studyStatusQueryDto)); + } + + + [HttpPost, Route("updateStudyBinding")] + //[LogFilter] + public IResponseOutput UpdateStudyBinding(StudyEditCommand studyEditCommand) + { + + if (studyEditCommand.SubjectVisitId == Guid.Empty) + { + studyEditCommand.SubjectVisitId = _studyService.AddSubjectVisit(studyEditCommand.SubjectId, studyEditCommand.SiteId, + studyEditCommand.VisitStageId, studyEditCommand.SVSTDTC, studyEditCommand.SVENDTC); + } + else + { + _studyService.UpdateSubjectVisit(studyEditCommand.SubjectVisitId, studyEditCommand.SVSTDTC, + studyEditCommand.SVENDTC); + + } + return ResponseOutput.Ok( _studyService.UpdateStudyBinding(studyEditCommand).Result); + } + + /// + /// 获取受试者 这次访视 对应的study modality 列表 + /// + /// + /// + /// + /// + /// + [HttpPost, Route("getSubjectVisitStudyList/{trialId:guid}/{siteId:guid}/{subjectId:guid}/{subjectVisitId:guid}")] + [AllowAnonymous] + public IResponseOutput> GetSubjectVisitStudyList(Guid trialId, Guid siteId, Guid subjectId, + Guid subjectVisitId) + { + return ResponseOutput.Ok( + _studyService.GetSubjectVisitStudyList(trialId, siteId, subjectId, subjectVisitId)); + } + + /// + /// 提示 该项目是否允许上传该study,如果不允许 提示 已经上传到哪个受试者 哪次方式 studyCode是多少 + /// + /// + /// + /// + /// + [HttpGet, Route("verifyStudyAllowUpload/{trialId:guid}/{studyInstanceUid}/{abandonStudyId?}")] + [AllowAnonymous] + public IResponseOutput VerifyStudyAllowUpload(string studyInstanceUid, Guid trialId, Guid? abandonStudyId) + { + return ResponseOutput.Ok(_studyService.VerifyStudyAllowUpload(studyInstanceUid, trialId, abandonStudyId)); + } + + /// 归档 + //[HttpPost, Route("archiveStudy/{trialId:guid}/{siteId:guid}/{subjectId:guid}/{visitStageId:guid}/{subjectVisitId:guid}/{SVSTDTC?}/{SVENDTC?}/{comment}")] + [HttpPost, Route("archiveStudy")] + [DisableFormValueModelBinding] + [DisableRequestSizeLimit] + [LogFilter] + + //public async Task ArchiveStudy(Guid trialId, Guid siteId, Guid subjectId, Guid visitStageId, Guid subjectVisitId, DateTime? SVSTDTC, DateTime? SVENDTC, string comment) + + public async Task ArchiveStudy([FromForm] ArchiveStudyCommand archiveStudyCommand) + { + + //处理 受试者访视没有记录 系统自动添加 + + #region url方式 + //if (subjectVisitId == Guid.Empty) + //{ + // subjectVisitId = _studyService.AddSubjectVisit(subjectId, visitStageId); + //} + + //string userName = User.FindFirst("realName").Value; + //StudyCommand addtionalInfo = new StudyCommand + //{ + // SiteId = siteId, + // SubjectId = subjectId, + // TrialId = trialId, + // SubjectVisitId = subjectVisitId, + + //}; + + //var savedInfo = _studyService.GetSaveToDicomInfo(addtionalInfo); + ////加入comment + //savedInfo.Comment = comment; + + #endregion + + try + { + + + #region post body 方式 subjectVisitId + + + + ////var subjectVisitStudyOldList = new List(); + // 受试者方式计划一次性添加,因为没有了上传时添加逻辑 + //if (archiveStudyCommand.SubjectVisitId == Guid.Empty) + //{ + // archiveStudyCommand.SubjectVisitId = _studyService.AddSubjectVisit(archiveStudyCommand.SubjectId, archiveStudyCommand.SiteId, + // archiveStudyCommand.VisitStageId.Value, archiveStudyCommand.SVSTDTC, archiveStudyCommand.SVENDTC); + //} + //else + //{ + //_studyService.UpdateSubjectVisit(archiveStudyCommand.SubjectVisitId, archiveStudyCommand.SVSTDTC, + // archiveStudyCommand.SVENDTC); + + //#region 重传和上传放在一起 暂不用 + ////处理 重传 在归档前 事先查出 这次访视已经有的study列表 + ////subjectVisitStudyOldList = _studyService.GetSubjectVisitStudyList(archiveStudyCommand.TrialId, + //// archiveStudyCommand.SiteId, archiveStudyCommand.SubjectId, archiveStudyCommand.SubjectVisitId); + //#endregion + + //} + + + + var userName = User.FindFirst("realName").Value; + StudyCommand addtionalInfo = new StudyCommand + { + SiteId = archiveStudyCommand.SiteId, + SubjectId = archiveStudyCommand.SubjectId, + TrialId = archiveStudyCommand.TrialId, + SubjectVisitId = archiveStudyCommand.SubjectVisitId, + + }; + + var savedInfo = _studyService.GetSaveToDicomInfo(addtionalInfo); + + + #endregion + + + var archiveResult = new DicomArchiveResult(); + var archivedStudyIds = new List(); + + var boundary = HeaderUtilities.RemoveQuotes(MediaTypeHeaderValue.Parse(Request.ContentType).Boundary).Value; + var reader = new MultipartReader(boundary, HttpContext.Request.Body); + var section = await reader.ReadNextSectionAsync(); + while (section != null) + { + var hasContentDispositionHeader = ContentDispositionHeaderValue.TryParse(section.ContentDisposition, out var contentDisposition); + if (hasContentDispositionHeader) + { + string fileName = contentDisposition.FileName.Value; + try + { + //采用post方式 这里多加一个判断 过滤其他参数 + if (string.IsNullOrEmpty(section.ContentType)) + { + break; + } + + string mediaType = section.ContentType; + + if (mediaType.Contains("zip")) + { + var partStream = section.Body; + using (var zipArchive = new ZipArchive(partStream, ZipArchiveMode.Read)) + { + foreach (var entry in zipArchive.Entries) + { + if (entry.FullName.EndsWith("/")) continue; + + try + { + ++archiveResult.ReceivedFileCount; + + using (var memoryStream = new MemoryStream()) + { + await section.Body.CopyToAsync(memoryStream); + + memoryStream.Seek(0, SeekOrigin.Begin); + DicomInstanceDTO instance = await _dicomArchiveService.ArchiveDicomStreamAsync(memoryStream, savedInfo); + if (!archivedStudyIds.Contains(instance.StudyId)) + archivedStudyIds.Add(instance.StudyId); + } + } + catch + { + archiveResult.ErrorFiles.Add($"{fileName}/{entry.FullName}"); + } + } + } + } + + ++archiveResult.ReceivedFileCount; + + if (mediaType.Contains("octet-stream")) + { + using (var memoryStream = new MemoryStream()) + { + await section.Body.CopyToAsync(memoryStream); + memoryStream.Seek(0, SeekOrigin.Begin); + + DicomInstanceDTO instance = await _dicomArchiveService.ArchiveDicomStreamAsync(memoryStream, savedInfo); + if (!archivedStudyIds.Contains(instance.StudyId)) + archivedStudyIds.Add(instance.StudyId); + } + + } + } + catch (Exception e) + { + Console.WriteLine(e); + archiveResult.ErrorFiles.Add(fileName); + } + } + + section = await reader.ReadNextSectionAsync(); + } + + if (archivedStudyIds.Count > 0) + { + //更新受试者访视信息 及上传状态 + _studyService.UpdateSubjectVisit(archiveStudyCommand.SubjectVisitId, archiveStudyCommand.SVSTDTC, + archiveStudyCommand.SVENDTC); + + //更新受试者最新的访视状态,访视号最大的 + _studyService.UpdateSubjectLatestInfo(archiveStudyCommand.SubjectId, archiveStudyCommand.TrialId); + + + + archiveResult.ArchivedDicomStudies = _dicomArchiveService.GetArchivedStudyList(archivedStudyIds); + + //归档完成,插入记录表 + + foreach (var archivedDicomStudy in archiveResult.ArchivedDicomStudies) + { + var seriesModalityList = _dicomArchiveService.GetSeriesList(archivedDicomStudy.Id).Select(u => u.Modality).Distinct(); + StringBuilder sb = new StringBuilder(); + foreach (var item in seriesModalityList) + { + sb.Append(item).Append(","); + } + string ModaliyStr = sb.ToString(); + if (ModaliyStr.Length > 0) + { + ModaliyStr = ModaliyStr.Substring(0, ModaliyStr.Length - 1); + } + + string comment = string.Empty;// 上传或重传完成之后,更新Comment信息 + if (!string.IsNullOrWhiteSpace(archiveStudyCommand.Comment)) + { + comment = archiveStudyCommand.Comment; + } + _studyService.UpdateStudyModaliyAndComment(archivedDicomStudy.Id, ModaliyStr,comment); + + + + //重传 并且不是同一份文件 + if (archiveStudyCommand.AbandonStudyId != null && + archiveStudyCommand.AbandonStudyId != Guid.Empty && archiveStudyCommand.AbandonStudyId != archivedDicomStudy.Id) + { + + //更新状态为废弃 + _studyService.UpdateStudyStatus(new StudyStatusDetailCommand + { + StudyId = archiveStudyCommand.AbandonStudyId.Value, + Status = (int)StudyStatus.Abandon, + Note = string.Empty + }, userName); + + + + //此时归档的新的Study 初始状态设置为 已重传完成 + _studyService.UpdateStudyStatus(new StudyStatusDetailCommand + { + StudyId = archivedDicomStudy.Id, + Status = (int)StudyStatus.QAReuploaded, + Note = string.Empty + }, userName); + + //更新新得study code 为废弃的 + _studyService.UpdateReUploadNewStudyCode(archiveStudyCommand.AbandonStudyId.Value, archivedDicomStudy.Id); + + }//重传 是同一份文件 + else if (archiveStudyCommand.AbandonStudyId != null && + archiveStudyCommand.AbandonStudyId != Guid.Empty && archiveStudyCommand.AbandonStudyId == archivedDicomStudy.Id) + { + //此时归档的新的Study 初始状态设置为 已重传完成 + _studyService.UpdateStudyStatus(new StudyStatusDetailCommand + { + StudyId = archivedDicomStudy.Id, + Status = (int)StudyStatus.QAReuploaded, + Note = string.Empty + }, userName); + }//上传 + else + { + _studyService.UpdateStudyStatus(new StudyStatusDetailCommand + { + StudyId = archivedDicomStudy.Id, + Status = (int)StudyStatus.Uploaded, + Note = string.Empty + }, userName); + } + + } + + } + + return ResponseOutput.Ok(archiveResult); + } + catch (Exception ex) + { + _logger.LogError(ex.Message); + throw; + } + } + + /// 删除检查 + [HttpDelete, Route("deleteStudy/{id:guid}")] + [LogFilter] + public IResponseOutput DeleteStudy(Guid id) + { + return _studyService.DeleteStudy(id); + } + + /// 指定资源Id,渲染Dicom检查的Jpeg预览图像 + /// Dicom检查的Id + [HttpGet, Route("preview/{studyId:guid}")] + [AllowAnonymous] + public FileContentResult GetStudyPreview(Guid studyId) + { + string path = _dicomArchiveService.GetStudyPreview(studyId); + + using (var sw = DicomRenderingHelper.RenderPreviewJpeg(path)) + { + var bytes = new byte[sw.Length]; + sw.Read(bytes, 0, bytes.Length); + sw.Close(); + return new FileContentResult(bytes, "image/jpeg"); + } + } + + /// 指定资源Id,获取Dicom检查信息 + /// Dicom检查的Id + [HttpGet, Route("item/{studyId:guid}")] + public IResponseOutput GetStudyItem(Guid studyId) + { + return ResponseOutput.Ok(_dicomArchiveService.GetStudyItem(studyId)); + } + + /// 更新Study状态,并保存状态变更信息 + /// + [HttpPost, Route("updateStudyStatus")] + [LogFilter] + public IResponseOutput UpdateStudyStatus(StudyStatusDetailCommand studyStatusDetailCommand) + { + string userName = User.FindFirst("realName").Value; ; + return ResponseOutput.Result(_studyService.UpdateStudyStatus(studyStatusDetailCommand, userName)); + } + /// + /// Dicom匿名化 + /// + /// 需要匿名化的检查Id + /// + [HttpPost, Route("dicomAnonymize/{studyId:guid}")] + [LogFilter] + public async Task DicomAnonymize(Guid studyId) + { + string userName = User.FindFirst("realName").Value; ; + return ResponseOutput.Result(await _studyService.DicomAnonymize(studyId, userName)); + } + + /// Study分配 + [HttpPost, Route("studyDistribution")] + [Obsolete] + public IResponseOutput StudyDistribution(StudyReviewerCommand studyReviewerCommand) + { + string userName = User.FindFirst("realName").Value; + var doctorInfo = _doctorService.GetDoctorBasicInfo(studyReviewerCommand.ReviewerId); + List studyStatusCommandList = new List(); + foreach (var study in studyReviewerCommand.StudyList) + { + var studyStatus = new StudyStatusDetailCommand + { + StudyId = study.StudyId, + Status = (int)StudyStatus.Distributed, + Note = doctorInfo.LastName + " " + doctorInfo.FirstName + }; + studyStatusCommandList.Add(studyStatus); + } + + var result = _studyService.DistributeStudy(studyReviewerCommand); + _studyService.UpdateStudyStatus(studyStatusCommandList, userName); + return ResponseOutput.Result(result); + } + + [Obsolete] + [HttpPost, Route("editStudyReviewer")] + public IResponseOutput EditStudyReviewer(StudyReviewerEditCommand studyReviewerEditCommand) + { + return _studyService.EditStudyReviewer(studyReviewerEditCommand); + + } + /// + /// 根据项目Id 获取可选医生列表 + /// + /// + /// + [HttpGet, Route("GetReviewerList/{trialId:guid}")] + public IResponseOutput> GetReviewerListByTrialId(Guid trialId) + { + var result = _studyService.GetReviewerListByTrialId(trialId); + return ResponseOutput.Ok(result); + } + + /// + /// 根据StudyId获取该Study的操作记录,时间倒序 + /// + /// + /// + [HttpGet, Route("getStudyStatusDetailList/{studyId:guid}")] + public IResponseOutput> GetStudyStatusDetailList(Guid studyId) + { + var result = _studyService.GetStudyStatusDetailList(studyId); + return ResponseOutput.Ok(result); + } + + /// + /// 根据TPCode 获取所有的标记 + /// + /// + /// + [HttpGet, Route("getImageLabelList/{tpCode}")] + [AllowAnonymous] + public IResponseOutput> GetImageLabelList(string tpCode) + { + return ResponseOutput.Ok(_dicomArchiveService.GetImageLabel(tpCode)); + } + + /// + /// 保存标记(跟删除合并,每次保存最新的标记),会删除替换之前的标记 + /// 外层的TPcode 必须传,里面的标记数组可为空数组,表示删除该Study的所有标记 + /// + /// + /// + [HttpPost, Route("saveImageLabelList")] + [AllowAnonymous] + [LogFilter] + public IResponseOutput SaveImageLabelList(ImageLabelCommand imageLabelCommand) + { + return ResponseOutput.Result(_dicomArchiveService.SaveImageLabelList(imageLabelCommand)); + } + + /// + /// 获取某个访视的关联访视 + /// 用于获取关联影像(调用之前的接口:/series/list/,根据StudyId,获取访视的序列列表) + /// + /// + /// + /// + [HttpGet, Route("getRelationVisitList/{visitNum}/{tpCode}")] + [AllowAnonymous] + public IResponseOutput> GetRelationVisitList(decimal visitNum, string tpCode) + { + return ResponseOutput.Ok(_studyService.GetRelationVisitList(visitNum, tpCode)); + } + + + + } +} diff --git a/IRaCIS.Core.API/Controllers/Institution/CroController.cs b/IRaCIS.Core.API/Controllers/Institution/CroController.cs new file mode 100644 index 0000000..b8d87bb --- /dev/null +++ b/IRaCIS.Core.API/Controllers/Institution/CroController.cs @@ -0,0 +1,56 @@ +using System; +using System.Collections.Generic; +using IRaCIS.Application.Interfaces; +using IRaCIS.Application.ViewModels; +using IRaCIS.Core.Application.Contracts.RequestAndResponse; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; + +namespace IRaCIS.Api.Controllers +{ + [Route("cro")] + [ApiController, Authorize, ApiExplorerSettings(GroupName = "Institution")] + public class CROController : ControllerBase + { + private readonly ICroService _croService; + + public CROController(ICroService croCompanyService) + { + _croService = croCompanyService; + } + + /// 分页获取CRO列表 + + [HttpPost, Route("getCROPageList")] + public IResponseOutput> GetCROCompanyList(CROCompanyQueryDTO croCompanySearchModel) + { + return ResponseOutput.Ok(_croService.GetCroList(croCompanySearchModel)); + } + + /// 获取所有CRO列表,可根据名称搜索[AUTH] + + + [HttpPost, Route("getAllCROList")] + public IResponseOutput> GetCROCompanySearchList() + { + return ResponseOutput.Ok(_croService.GetCroSearchList()); + + } + + /// 添加CRO[AUTH] + + [HttpPost, Route("addOrUpdateCro")] + public IResponseOutput AddCROCompany(CROCompanyDTO addCroCompanyViewModel) + { + var userId = User.FindFirst("id").Value; + return _croService.AddOrUpdateCro(addCroCompanyViewModel, Guid.Parse(userId)); + } + /// 删除CRO + + [HttpDelete, Route("deleteCROCompany/{croCompanyId:guid}")] + public IResponseOutput DeleteCROCompany(Guid croCompanyId) + { + return _croService.DeleteCro(croCompanyId); + } + } +} diff --git a/IRaCIS.Core.API/Controllers/Institution/HospitalController.cs b/IRaCIS.Core.API/Controllers/Institution/HospitalController.cs new file mode 100644 index 0000000..702775a --- /dev/null +++ b/IRaCIS.Core.API/Controllers/Institution/HospitalController.cs @@ -0,0 +1,62 @@ +using System; +using System.Collections.Generic; + + +using IRaCIS.Application.Interfaces; +using IRaCIS.Application.ViewModels; +using IRaCIS.Core.Application.Contracts.RequestAndResponse; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; + +namespace IRaCIS.Api.Controllers +{ + [Route("hospital")] + [ApiController, Authorize, ApiExplorerSettings(GroupName = "Institution")] + public class HospitalController : ControllerBase + { + private readonly IHospitalService _hospitalService; + + public HospitalController(IHospitalService hospitalService) + { + _hospitalService = hospitalService; + } + + /// 获取所有医院列表 + + [HttpGet, Route("hospitalList")] + public IResponseOutput> GetHospitalList() + { + var result = _hospitalService.GetHospitalList(); + + return ResponseOutput.Ok(result); + + } + + /// 分页获取医院信息列表 + + [HttpPost, Route("getHospitalPageList")] + public IResponseOutput> GetHospitalPageList( + HospitalQueryDTO hospitalSearchModel) + { + + return ResponseOutput.Ok(_hospitalService.GetHospitalPageList(hospitalSearchModel)); + + } + + /// 添加医院信息 + + [HttpPost, Route("addOrUpdateHospital")] + public IResponseOutput AddOrUpdateHospital(HospitalCommand addViewModel) + { + return _hospitalService.AddOrUpdateHospital(addViewModel); + } + + /// 删除医院信息 + + [HttpDelete, Route("deleteHospital/{hospitalId:guid}")] + public IResponseOutput DeleteHospital(Guid hospitalId) + { + return _hospitalService.DeleteHospital(hospitalId); + } + } +} diff --git a/IRaCIS.Core.API/Controllers/Institution/InstitutionController.cs b/IRaCIS.Core.API/Controllers/Institution/InstitutionController.cs new file mode 100644 index 0000000..8ad992f --- /dev/null +++ b/IRaCIS.Core.API/Controllers/Institution/InstitutionController.cs @@ -0,0 +1,32 @@ +using IRaCIS.Application.Interfaces; +using IRaCIS.Application.ViewModels; +using System; +using System.Collections.Generic; +using IRaCIS.Core.Application.Contracts.RequestAndResponse; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Authorization; + +namespace IRaCIS.Api.Controllers +{ + /// + /// 机构列表 + /// + [Route("institution")] + [ApiController, Authorize, ApiExplorerSettings(GroupName = "Institution")] + public class InstitutionController : ControllerBase + { + private readonly IInstitutionService _institutionService; + public InstitutionController(IInstitutionService institutionService) + { + _institutionService = institutionService; + } + /// 根据用户类型或机构类型,获取供选择的机构列表[New] + + [HttpGet, Route("getInstitutionList/{typeId:guid}")] + public IResponseOutput> GetInstitutionSelectionList(Guid typeId) + { + return ResponseOutput.Ok(_institutionService.GetInstitutionSelectionByTypeId(typeId)) ; + } + + } +} diff --git a/IRaCIS.Core.API/Controllers/Institution/SiteController.cs b/IRaCIS.Core.API/Controllers/Institution/SiteController.cs new file mode 100644 index 0000000..457b826 --- /dev/null +++ b/IRaCIS.Core.API/Controllers/Institution/SiteController.cs @@ -0,0 +1,55 @@ +using System; +using System.Collections.Generic; +using IRaCIS.Application.Interfaces; +using IRaCIS.Application.ViewModels; +using IRaCIS.Core.Application.Contracts.RequestAndResponse; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; + +namespace IRaCIS.Api.Controllers +{ + [Route("site")] + [ApiController, Authorize, ApiExplorerSettings(GroupName = "Institution")] + public class SiteController : ControllerBase + { + private readonly ISiteService _siteService; + + public SiteController(ISiteService siteService) + { + _siteService = siteService; + } + + /// 分页获取研究中心列表 + + [HttpPost, Route("getSiteList")] + public IResponseOutput> GetSiteList(SiteQueryParam searchModel) + { + return ResponseOutput.Ok(_siteService.GetSiteList(searchModel)) ; + } + + /// 获取研究中心列表[New] + + [HttpGet, Route("getAllSiteList")] + public IResponseOutput> GetAllSiteList() + { + return ResponseOutput.Ok(_siteService.GetSiteList()) ; + } + + /// 添加研究中心[AUTH] + + [HttpPost, Route("addOrUpdateSite")] + public IResponseOutput AddOrUpdateSite(SiteCommand addModel) + { + var userId = User.FindFirst("id").Value; + return _siteService.AddOrUpdateSite(addModel, Guid.Parse(userId)) ; + } + + /// 删除研究中心[Auth] + + [HttpDelete, Route("deleteSite/{siteId:guid}")] + public IResponseOutput DeleteResearchCenter(Guid siteId) + { + return _siteService.DeleteSite(siteId); + } + } +} diff --git a/IRaCIS.Core.API/Controllers/Institution/SponsorController.cs b/IRaCIS.Core.API/Controllers/Institution/SponsorController.cs new file mode 100644 index 0000000..96676e6 --- /dev/null +++ b/IRaCIS.Core.API/Controllers/Institution/SponsorController.cs @@ -0,0 +1,52 @@ +using System; +using System.Collections.Generic; + +using IRaCIS.Application.Interfaces; +using IRaCIS.Application.ViewModels; +using IRaCIS.Core.Application.Contracts.RequestAndResponse; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; + +namespace IRaCIS.Api.Controllers +{ + [Route("sponsor")] + [ApiController, Authorize, ApiExplorerSettings(GroupName = "Institution")] + public class SponsorController : ControllerBase + { + private readonly ISponsorService _sponsorService; + + public SponsorController(ISponsorService sponsorService) + { + _sponsorService = sponsorService; + } + + /// 分页获取申办方列表 + + [HttpPost, Route("getSponsorPageList")] + public IResponseOutput> GetSponsorList(SponsorQueryDTO sponsorSearchModel) + { + return ResponseOutput.Ok(_sponsorService.GetSponsorList(sponsorSearchModel)); + } + + /// 获取所有申办方列表 下拉框 + [HttpPost, Route("getAllSponsorList")] + public IResponseOutput> GetSponsorSearchList() + { + return ResponseOutput.Ok(_sponsorService.GetSponsorSearchList()); + } + + /// 添加或更新申办方信息 + [HttpPost, Route("addOrUpdateSponsor")] + public IResponseOutput AddSponsor(SponsorCommand addSponsorViewModel) + { + return _sponsorService.AddOrUpdateSponsor(addSponsorViewModel); + } + + /// 删除申办方信息 + [HttpDelete, Route("deleteSponsor/{sponsorId:guid}")] + public IResponseOutput DeleteSponsor(Guid sponsorId) + { + return _sponsorService.DeleteSponsor(sponsorId); + } + } +} diff --git a/IRaCIS.Core.API/Controllers/ManageMent/MenuController.cs b/IRaCIS.Core.API/Controllers/ManageMent/MenuController.cs new file mode 100644 index 0000000..01cf02c --- /dev/null +++ b/IRaCIS.Core.API/Controllers/ManageMent/MenuController.cs @@ -0,0 +1,96 @@ +using System; +using System.Collections.Generic; + +using IRaCIS.Application.Interfaces; +using IRaCIS.Application.ViewModels; +using IRaCIS.Core.Application.Contracts.RequestAndResponse; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; + +namespace IRaCIS.Api.Controllers +{ + [Route("menu")] + [ApiController, Authorize, ApiExplorerSettings(GroupName = "Management")] + public class MenuController : ControllerBase + { + private readonly IMenuService _menuService; + public MenuController(IMenuService menuService) + { + _menuService = menuService; + } + + /// 获取完整菜单功能树形列表 + [HttpGet, Route("getMenuFunction")] + public IResponseOutput> GetMenuTreeAll() + { + + return ResponseOutput.Ok(_menuService.GetTreeAll()); + + + } + + /// 在某个父节点下面 新增子菜单 + [HttpPost, Route("addOrUpdateMenu")] + public IResponseOutput AddOrUpdateMenu(MenuFunctionCommand menuViewModel) + { + if (menuViewModel.ParentId == Guid.Empty) + { + + return ResponseOutput.NotOk("ParentId 不能为空"); + + } + var userId = Guid.Parse(User.FindFirst("id").Value); + return _menuService.AddOrUpdateMenu(menuViewModel, userId); + } + /// 根据Id删除节点 + [HttpDelete, Route("deleteMenuFunction/{menuFunctionId:guid}")] + public IResponseOutput DeleteMenuFunction(Guid menuFunctionId) + { + return _menuService.DeleteMenuFunction(menuFunctionId); + } + /// + /// 获取某角色 菜单树 勾选情况 和 功能勾选情况 + /// + /// + /// + [HttpGet, Route("getRoleMenuFunction/{roleId:guid}")] + public IResponseOutput> GetTreeWithSelect(Guid roleId) + { + var treelist = _menuService.GetMenuFunctionIsSelectByRoleId(roleId); + + return ResponseOutput.Ok(treelist); + } + + /// + /// 获取路由节点下的功能选中情况 + /// + /// + /// + /// + [HttpGet, Route("getRoleFunction/{roleId:guid}/{parentId:guid}")] + public IResponseOutput> GetRoleFunctionTreeWithSelect(Guid roleId, Guid parentId) + { + var treelist = _menuService.GetFunctionIsSelectByRoleId(roleId, parentId); + return ResponseOutput.Ok(treelist); + } + + /// + /// 更新角色拥有的菜单 只传递操作的项 + /// + /// + /// + [HttpPost, Route("updateRoleMenu")] + public IResponseOutput UpdateRoleMenuSelect(RoleMenuFunctionSelectDTO selectModel) + { + return _menuService.UpdateRoleMenuSelect(selectModel.RoleId, selectModel.MenuFunctionId); + } + /// + /// + /// + [HttpPost, Route("updateRoleFunction")] + public IResponseOutput UpdateRoleFunctionSelect(FunctionSelectDTO selectModel) + { + return _menuService.UpdateRoleFunctionSelect(selectModel); + } + } +} diff --git a/IRaCIS.Core.API/Controllers/ManageMent/RoleController.cs b/IRaCIS.Core.API/Controllers/ManageMent/RoleController.cs new file mode 100644 index 0000000..5b64e3f --- /dev/null +++ b/IRaCIS.Core.API/Controllers/ManageMent/RoleController.cs @@ -0,0 +1,69 @@ +using System; +using System.Collections.Generic; +using IRaCIS.Api.Filter; +using IRaCIS.Application.Interfaces; +using IRaCIS.Application.ViewModels; +using IRaCIS.Core.Application.Contracts.RequestAndResponse; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; + +namespace IRaCIS.Api.Controllers +{ + [Route("role")] + [ApiController, Authorize, ApiExplorerSettings(GroupName = "Management")] + public class RoleController : ControllerBase + { + private readonly IRoleService _roleService; + public RoleController(IRoleService roleService) + { + _roleService = roleService; + } + + /// 添加角色 + [HttpPost, Route("addOrUpdateRole")] + [LogFilter] + public IResponseOutput AddOrUpdateRole(RoleCommand role) + { + var userId = Guid.Parse(User.FindFirst("id").Value); + return _roleService.AddOrUpdateRole(role, userId); + } + + ///// 复制角色 + //[HttpPost, Route("copyRole/{sourceRoleId:guid}")] + //public IResponseOutput CopyRole(Guid sourceRoleId, RoleAddOrUpdateModel role) + //{ + // return _roleService.CopyRole(sourceRoleId,role); + //} + + /// 删除角色 + [HttpDelete, Route("deleteRole/{roleId:guid}")] + [LogFilter] + public IResponseOutput DeleteRole(Guid roleId) + { + return _roleService.DeleteRole(roleId); + } + + /// 分页获取角色列表 + [HttpGet, Route("getRoleList/{pageIndex:int}/{pageSize:int}")] + public IResponseOutput> GetRoleListByPage(int pageIndex, int pageSize) + { + return ResponseOutput.Ok(_roleService.GetRoleListByPage(pageIndex, pageSize)); + } + + /// 获取用户角色列表 + [HttpGet, Route("getRoleList/{userId:guid}/{pageIndex:int}/{pageSize:int}")] + public IResponseOutput> GetRoleListByPage(Guid userId, int pageIndex, int pageSize) + { + return ResponseOutput.Ok(_roleService.GetRoleListByPage(userId, pageIndex, pageSize)); + } + + /// 更新用户角色 + [HttpPost, Route("UpdateUserRole")] + [LogFilter] + public IResponseOutput UpdateUserRole(UserRoleSelectDTO userSelectRoleModel) + { + return _roleService.UpdateUserRole(userSelectRoleModel.userId, userSelectRoleModel.roleId, userSelectRoleModel.isSelect); + } + + } +} diff --git a/IRaCIS.Core.API/Controllers/ManageMent/UserController.cs b/IRaCIS.Core.API/Controllers/ManageMent/UserController.cs new file mode 100644 index 0000000..b62f120 --- /dev/null +++ b/IRaCIS.Core.API/Controllers/ManageMent/UserController.cs @@ -0,0 +1,176 @@ +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using EasyCaching.Core; +using IRaCIS.Api.Filter; +using IRaCIS.Application; +using IRaCIS.Application.Interfaces; +using IRaCIS.Application.ViewModels; +using IRaCIS.Core.API.Auth; +using IRaCIS.Core.Application.Contracts.RequestAndResponse; +using IRaCIS.Core.Domain.Share; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; + +namespace IRaCIS.Api.Controllers +{ + [Authorize] + [Route("sysUser")] + [ApiController, ApiExplorerSettings(GroupName = "Management")] + public class UserController : ControllerBase + { + private readonly IUserService _userService; + private readonly ITokenService _tokenService; + public UserController(IUserService userService, ITokenService tokenService) + { + _userService = userService; + _tokenService = tokenService; + } + + + /// + /// 通过邮箱或者手机 发送验证码 + /// + /// + /// + /// + /// + + [HttpGet, Route("sendVerificationCode/{emailOrPhone}/{verificationType:int}/{isReviewer:bool}")] + [AllowAnonymous] + public async Task SendVerificationCode(string emailOrPhone, int verificationType, bool isReviewer) + { + return await _userService.SendVerificationCode(emailOrPhone, verificationType, isReviewer); + } + + /// + /// 通过验证码设置新密码 + /// + /// + /// + [AllowAnonymous] + [HttpPost, Route("setNewPassword")] + public IResponseOutput SetNewPassword(ResetPasswordCommand resetPwdModel) + { + return _userService.SetNewPassword(resetPwdModel.EmailOrPhone, resetPwdModel.VerificationType, resetPwdModel.VerificationCode, resetPwdModel.NewPwd, resetPwdModel.IsReviewer); + } + + /// 系统用户登录接口[New] + [HttpPost, Route("login")] + [AllowAnonymous] + [LogFilter] + public IResponseOutput Login(UserLoginDTO loginUser, [FromServices]IEasyCachingProvider provider) + { + var returnModel = _userService.Login(loginUser.UserName, loginUser.Password); + if (returnModel.IsSuccess) + { + returnModel.Data.JWTStr = _tokenService.GetToken(UserClaims.Create(returnModel.Data.BasicInfo)); + } + + var userId = returnModel.Data.BasicInfo.Id.ToString(); + provider.Set(userId, userId, TimeSpan.FromMinutes(SystemConfig.LoginExpiredTimeSpan)); + return returnModel; + } + + /// 签名认证[New] + [HttpGet, Route("VerifySignature/{userName}/{password}")] + [AllowAnonymous] + [LogFilter] + public IResponseOutput VerifySignature(string userName, string password) + { + var returnModel = _userService.VerifySignature(userName, password); + return returnModel; + //return ResponseOutput.Result(returnModel.IsSuccess); + } + + + /// 分页获取用户列表[New] + [HttpPost, Route("getUserList")] + [Authorize] + public IResponseOutput> GetUserList(UserListQueryDTO param) + { + return ResponseOutput.Ok(_userService.GetUserList(param)); + } + + /// 更新用户状态(1 可用 0 禁用)[New] + [Authorize] + [LogFilter] + [HttpPost, Route("updateUserState/{userId:guid}/{state:int}")] + public IResponseOutput UpdateUserState(Guid userId, int state) + { + return _userService.UpdateUserState(userId, state); + } + + /// 修改密码,当前支持旧密码修改密码,手机及邮箱验证码后续支持[New] + [HttpPost, Route("modifyPassword")] + [Authorize] + [LogFilter] + public IResponseOutput ModifyPassword(EditPasswordCommand editPwModel) + { + return _userService.ModifyPassword(editPwModel); + } + + /// 根据用户Id,获取用户角色列表和当前登录用户的最大权限级别[New][AUTH] + [HttpGet, Route("getUserRoles/{userId:guid}")] + [Authorize] + public IResponseOutput GetUserRolesById(Guid userId) + { + var optUserId = User.FindFirst("id").Value; + return ResponseOutput.Ok(new UserRoleInfoDTO() + { + RoleList = _userService.GetUserRolesById(userId), + MaxPrivilegeLevel = _userService.GetUserRoleMaxPrivilegeLevel(Guid.Parse(optUserId)) + }); + } + + + /// 添加用户[New][AUTH] + [HttpPost, Route("addUser")] + public IResponseOutput AddUser(UserCommand userAddModel) + { + var userId = User.FindFirst("id").Value; + return _userService.AddUser(userAddModel, Guid.Parse(userId)); + } + + /// 更新用户信息[New][AUTH] + [HttpPost, Route("updateUser")] + [LogFilter] + public IResponseOutput UpdateUser(UserCommand userUpdateModel) + { + var userId = User.FindFirst("id").Value; + return _userService.UpdateUser(userUpdateModel, Guid.Parse(userId)); + } + + /// 根据用户Id获取用户详细信息[New] + [HttpGet, Route("getUser/{userId:guid}")] + public IResponseOutput GetUserById(Guid userId) + { + return ResponseOutput.Ok(_userService.GetUserById(userId)); + } + + /// 获取所有用户列表 + [HttpGet, Route("getAllUser")] + public IResponseOutput> GetAllUser() + { + return ResponseOutput.Ok(_userService.GetAllUser()); + } + + ///// 获取当前用户是否有复审权限和编辑权限[New][AUTH] + + //[HttpGet, Route("getUserResumePermission/{reviewerId:guid}")] + + //public IResponseOutput GetUserResumePermission(Guid reviewerId) + //{ + // var userId = User.FindFirst("id").Value; + // return ResponseOutput.Ok(_userService.GetUserResumePermission(reviewerId, Guid.Parse(userId))) ; + //} + + /// 后台重置密码为123456[New] + [HttpGet, Route("resetPassword/{userId:guid}")] + [LogFilter] + public IResponseOutput ResetPassword(Guid userId) + { + return _userService.ResetPassword(userId); + } + } +} diff --git a/IRaCIS.Core.API/Controllers/QA/QARecordController.cs b/IRaCIS.Core.API/Controllers/QA/QARecordController.cs new file mode 100644 index 0000000..6b7a666 --- /dev/null +++ b/IRaCIS.Core.API/Controllers/QA/QARecordController.cs @@ -0,0 +1,94 @@ +using System; +using System.Collections.Generic; +using IRaCIS.Core.Application.Contracts; +using IRaCIS.Core.Application.Contracts.DTO; +using IRaCIS.Core.Application.Contracts.RequestAndResponse; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; + +namespace IRaCIS.Core.API.Controllers.QA +{ + /// + /// QA 记录 和对话管理 + /// + [Route("QARecord")] + [ApiController, Authorize, ApiExplorerSettings(GroupName = "Image")] + [AllowAnonymous] + public class QARecordController : ControllerBase + { + private readonly IQARecordService _qaRecordService; + + public QARecordController(IQARecordService qaRecordService) + { + _qaRecordService = qaRecordService; + } + + /// + ///QA记录表 包含信息 包含两部分 一部分 :字典项问题项 +对应得描述 如 缺少序列 + 5个 + /// 第二部分 额外补充得信息 根据 QARecord 中得Id 是否传递 判断是添加还是更新 + /// + /// + /// + [HttpPost, Route("AddOrUpdateQARecord")] + public IResponseOutput AddOrUpdateQARecord(QAToalCommand qaTotalCommand) + { + return _qaRecordService.AddOrUpdateQARecord(qaTotalCommand); + } + + /// + /// 删除Qa记录 + /// + /// + /// + [HttpDelete, Route("DeleteQARecord/{qaQARecordId:guid}")] + public IResponseOutput DeleteQARecord(Guid qaQARecordId) + { + return _qaRecordService.DeleteQARecord(qaQARecordId); + } + + /// + /// 获取QA记录列表 一个Study 可以进行多次QA 针对每次QA 可以添加回复 + /// + /// + /// + /// + [HttpGet, Route("GetQARecordList/{studyId:guid}/{trialId:guid}")] + public IResponseOutput GetQARecordList(Guid studyId,Guid trialId) + { + return ResponseOutput.Ok(_qaRecordService.GetQARecordList(studyId, trialId)); + } + + /// + /// 针对 某条Qa 添加回复 + /// + /// + /// + [HttpPost, Route("AddQAReply")] + public IResponseOutput AddQAReply(QADialogCommand qaDialogCommand) + { + return _qaRecordService.AddQAReply(qaDialogCommand); + } + + /// + /// 删除QA回复记录 + /// + /// + /// + [HttpDelete, Route("DeleteQAReply/{qaReplyId:guid}")] + public IResponseOutput DeleteQAReply(Guid qaReplyId) + { + return _qaRecordService.DeleteQAReply(qaReplyId); + } + + /// + /// 展开 某一QA下得 聊天记录 + /// + /// + /// + [HttpGet, Route("GetQaRecordDialogList/{qaRecordId:guid}")] + public IResponseOutput> GetQaRecordDialogList(Guid qaRecordId) + { + return ResponseOutput.Ok(_qaRecordService.GetQaRecordDialogList(qaRecordId)); + } + } +} diff --git a/IRaCIS.Core.API/Controllers/QA/QATemplateController.cs b/IRaCIS.Core.API/Controllers/QA/QATemplateController.cs new file mode 100644 index 0000000..233ad09 --- /dev/null +++ b/IRaCIS.Core.API/Controllers/QA/QATemplateController.cs @@ -0,0 +1,101 @@ + +using System; +using System.Collections.Generic; +using IRaCIS.Core.Application.Contracts; +using IRaCIS.Core.Application.Contracts.DTO; +using IRaCIS.Core.Application.Contracts.RequestAndResponse; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; + +namespace IRaCIS.Core.API.Controllers.QA +{ + /// + /// Qa模板管理 + /// + [Route("QATemplate")] + [ApiController, Authorize, ApiExplorerSettings(GroupName = "Image")] + [AllowAnonymous] + public class QATemplateController : ControllerBase + { + private readonly IQATemplateService _qaTemplateService; + + public QATemplateController(IQATemplateService qaTemplateService) + { + _qaTemplateService = qaTemplateService; + } + + [HttpPost, Route("AddOrUpdateQATemplate")] + public IResponseOutput AddOrUpdateQATemplate(QATemplateCommand qaTemplateCommand) + { + return _qaTemplateService.AddOrUpdateQATemplate(qaTemplateCommand); + } + + + + /// + /// 获取QA模板列表 + /// + /// + /// + [HttpPost, Route("GetQaTemplateList")] + public IResponseOutput> GetQaTemplateList(QATemplateQueryDTO qaTemplateQuery) + { + return ResponseOutput.Ok(_qaTemplateService.GetQaTemplateList(qaTemplateQuery)); + } + + /// + /// 添加Qa记录时 需要选择模板 这里是模板 下拉框选择列表 + /// + /// + [HttpGet, Route("GetQaTemplateSelectList")] + public IResponseOutput> GetQaTemplateSelectList() + { + return ResponseOutput.Ok(_qaTemplateService.GetQaTemplateSelectList()); + } + + /// + /// 删除 QA模板 + /// + /// + /// + [HttpDelete, Route("DeleteQATemplate/{qaTemplateId:guid}")] + public IResponseOutput DeleteQATemplate(Guid qaTemplateId) + { + return _qaTemplateService.DeleteQATemplate(qaTemplateId); + } + + /// + /// 获取某一Qa模板已配置项 + /// + /// + /// + [HttpGet, Route("GetQaTemplateItemsById/{qaTemplateId:guid}")] + public IResponseOutput> GetQaTemplateItemsById(Guid qaTemplateId) + { + return ResponseOutput.Ok(_qaTemplateService.GetQaTemplateItemsById(qaTemplateId)); + } + + + /// + /// 获取某一QA模板 配置列表(拥有得Item IsSelect 为true) + /// + /// + /// + [HttpGet, Route("GetQaTemplateConfigList/{qaTemplateId:guid}")] + public IResponseOutput> GetQaTemplateConfigList(Guid qaTemplateId) + { + return ResponseOutput.Ok(_qaTemplateService.GetQaTemplateConfigList(qaTemplateId)); + } + + /// + /// 配置Qa模板 和字典表中基础数据 关联关系 IsSelect 为true 添加 false 删除 + /// + /// + /// + [HttpPost, Route("ConfigQATemplate")] + public IResponseOutput ConfigQATemplate(QATemplateConfigCommand qaTemplateConfigCommand) + { + return _qaTemplateService.ConfigQATemplate(qaTemplateConfigCommand); + } + } +} diff --git a/IRaCIS.Core.API/Controllers/Reading/ReadingController.cs b/IRaCIS.Core.API/Controllers/Reading/ReadingController.cs new file mode 100644 index 0000000..da0dca5 --- /dev/null +++ b/IRaCIS.Core.API/Controllers/Reading/ReadingController.cs @@ -0,0 +1,38 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using IRaCIS.Application.Interfaces; +using IRaCIS.Application.ViewModels; +using IRaCIS.Core.Application.Contracts.RequestAndResponse; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; + +namespace IRaCIS.Core.API.Controllers.Reading +{ + [Route("reading")] + [ApiController, Authorize, ApiExplorerSettings(GroupName = "Reading")] + public class ReadingController : ControllerBase + { + private readonly IReviewerReadingService _reviewerReadingService; + public ReadingController(IReviewerReadingService reviewerReadingService) + { + _reviewerReadingService = reviewerReadingService; + } + + /// + /// 获取医生个人任务列表 + /// WorkloadType 1-tp,2-global,3-ad + /// + /// + /// + [HttpPost, Route("getWorkloadList")] + public IResponseOutput> GetWorkloadList(WorkloadQueryParam param) + { + return ResponseOutput.Ok(_reviewerReadingService.GetWorkloadList(param)); + } + + + } +} \ No newline at end of file diff --git a/IRaCIS.Core.API/Controllers/Report/GlobalReportController.cs b/IRaCIS.Core.API/Controllers/Report/GlobalReportController.cs new file mode 100644 index 0000000..505a807 --- /dev/null +++ b/IRaCIS.Core.API/Controllers/Report/GlobalReportController.cs @@ -0,0 +1,56 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using IRaCIS.Core.Application.Contracts; +using IRaCIS.Core.Application.Contracts.RequestAndResponse; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; + +namespace IRaCIS.Core.API.Controllers.Report +{ + [Route("globalReport")] + [ApiController, ApiExplorerSettings(GroupName = "Reading")] + public class GlobalReportController : ControllerBase + { + private readonly IGlobalService _globalService; + + public GlobalReportController(IGlobalService globalService) + { + _globalService = globalService; + } + + [HttpGet, Route("getHistoryVisitRsList/{trialId}/{subjectId}/{visitNum}/{globalId}/{globalCode}")] + public IResponseOutput> GetHistoryVisitRsList(Guid trialId, Guid subjectId, decimal visitNum, Guid globalId, string globalCode) + { + return ResponseOutput.Ok(_globalService.GetHistoryVisitRsList(trialId, subjectId, visitNum,globalId, globalCode)); + } + + [HttpGet, Route("getHistoryGlobalRsList/{trialId}/{subjectId}/{visitNum}/{globalId}")] + public IResponseOutput GetHistoryGlobalRsList(Guid trialId, Guid subjectId, decimal visitNum, Guid globalId) + { + return ResponseOutput.Ok(_globalService.GetHistoryGlobalRsList(trialId, subjectId, visitNum,globalId)); + } + + [HttpPost, Route("AddGlobalReport")] + public IResponseOutput AddGlobalReport(GlobalTaskReportCommand globalTaskReportCommand) + { + return ResponseOutput.Result(_globalService.AddGlobalReport(globalTaskReportCommand)); + } + + [HttpGet, Route("getAdReport/{adId}")] + public IResponseOutput GetAdReport(Guid adId) + { + return ResponseOutput.Ok(_globalService.GetAdReport(adId)); + } + + [HttpPost, Route("addAdjudicationReport")] + public IResponseOutput AddAdjudicationReport(ADReportCommand adReportCommand) + { + return ResponseOutput.Result(_globalService.AddAdjudicationReport(adReportCommand)); + } + + + } + +} diff --git a/IRaCIS.Core.API/Controllers/Report/ReportController.cs b/IRaCIS.Core.API/Controllers/Report/ReportController.cs new file mode 100644 index 0000000..d28bf09 --- /dev/null +++ b/IRaCIS.Core.API/Controllers/Report/ReportController.cs @@ -0,0 +1,72 @@ +using IRaCIS.Core.Application.Contracts; +using IRaCIS.Core.Application.Contracts.RequestAndResponse; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using System; +using System.Collections.Generic; +using System.Linq; + +namespace IRaCIS.Core.API.Controllers.Reading +{ + [Route("report")] + [ApiController, Authorize, ApiExplorerSettings(GroupName = "Reading")] + public class ReportController : ControllerBase + { + private readonly IReportService _reportService; + public ReportController(IReportService reportService) + { + _reportService = reportService; + } + + /// 获取基线期病灶信息及其他信息 + [AllowAnonymous] + [HttpGet, Route("getBLLineLesion/{trialCode}/{subjectCode}/{tpCode}")] + public IResponseOutput GetBLLineLesion(string trialCode, string subjectCode,string tpCode) + { + return ResponseOutput.Ok(_reportService.GetBaseLineReport(trialCode, subjectCode, tpCode)); + } + + /// 获取其他访视病灶信息 + [AllowAnonymous] + [HttpGet, Route("getVisitLineLesion/{trialCode}/{subjectCode}/{visitNum}/{tpCode}")] + public IResponseOutput GetVisitLesion(string trialCode, string SubjectCode, decimal visitNum,string tpCode) + { + return ResponseOutput.Ok(_reportService.GetVisitLesion(trialCode, SubjectCode, visitNum,tpCode)); + } + + + /// + /// 保存 基线期病灶及测量信息及其他信息,不会改变状态 + /// + [AllowAnonymous] + [HttpPost, Route("addBaseLineLesion")] + public IResponseOutput AddBaseLineLesion(BaseLineReportCommand baseLineReportCommand) + { + // User.FindFirst("reviewerCode").Value; + return ResponseOutput.Result(_reportService.SaveBLReport(baseLineReportCommand)); + } + + /// + /// 添加访视报告信息 + /// LesionInformation 为新病灶及测量信息(包括分裂及合并产生的) + /// TRList 已经存在的病灶的测量信息 + /// RSList 疗效信息 + /// + [AllowAnonymous] + [HttpPost, Route("saveVisitReport")] + public IResponseOutput AddVisitLesion(VisitReportCommand visitReportCommand) + { + return ResponseOutput.Result(_reportService.SaveVisitReport(visitReportCommand)); + } + + /// + /// 提交报告 + /// + [AllowAnonymous] + [HttpPost, Route("submiteReport/{tpId:guid}")] + public IResponseOutput SubmiteReport(Guid tpId) + { + return ResponseOutput.Result(_reportService.SubmiteReport(tpId)); + } + } +} \ No newline at end of file diff --git a/IRaCIS.Core.API/Controllers/StatisticsController.cs b/IRaCIS.Core.API/Controllers/StatisticsController.cs new file mode 100644 index 0000000..914e39e --- /dev/null +++ b/IRaCIS.Core.API/Controllers/StatisticsController.cs @@ -0,0 +1,132 @@ +using System; +using System.Collections.Generic; +using IRaCIS.Application.Interfaces; +using IRaCIS.Application.ViewModels; +using IRaCIS.Core.Application.Contracts.RequestAndResponse; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; + +namespace IRaCIS.Api.Controllers +{ + /// + /// Dashboard统计、全局工作量统计、入组两个维度统计(按照项目、按照人) + /// + [Route("statistics")] + [ApiController, Authorize, ApiExplorerSettings(GroupName = "Dashboard&Statistics")] + public class StatisticsController : ControllerBase + { + private readonly IStatisticsService _statisticsService; + + public StatisticsController(IStatisticsService statisticsService) + { + _statisticsService = statisticsService; + } + + /// 根据项目和医生,分页获取工作量统计[New] + + [HttpPost, Route("getWorkloadByTrialAndReviewer")] + public IResponseOutput> GetWorkloadByTrialAndReviewer( + StatisticsWorkloadQueryParam param) + { + + return ResponseOutput.Ok( + _statisticsService.GetWorkloadByTrialAndReviewer(param, Guid.Parse(User.FindFirst("id").Value))); + + } + + /// 项目入组 医生维度统计[New] + + [HttpPost, Route("getEnrollStatByReviewer")] + public IResponseOutput> GetEnrollStatByReviewer( + EnrollStatByReviewerQueryDTO param) + { + + return ResponseOutput.Ok(_statisticsService.GetEnrollStatByReviewer(param)); + + } + + + [HttpPost, Route("getEnrollStatByTrial")] + public IResponseOutput> GetEnrollStatByTrial( + EnrollStatByTrialQueryDTO param) + { + + return ResponseOutput.Ok(_statisticsService.GetEnrollStatByTrial(param)); + + } + + #region Dashbord + + /// 读片数分类统计[New] + + [HttpGet, Route("getReadingDataByType")] + public IResponseOutput GetReadingDataByType() + { + + + return ResponseOutput.Ok(_statisticsService.GetReadingDataByType()); + + } + + /// 获取最近几个月份的数据[New] + + [HttpGet, Route("getReadingDataByMonth/{monthCount:int}")] + public IResponseOutput> GetReadingDataByMonth(int monthCount) + { + + return ResponseOutput.Ok(_statisticsService.GetReadingDataByMonth(monthCount)); + + } + + /// 读片数量排行前几的数据[New] + + [HttpGet, Route("GetReadingDataRank/{topCount:int}")] + public IResponseOutput> GetReadingDataRank(int topCount) + { + + return ResponseOutput.Ok(_statisticsService.GetReadingDataRank(topCount)); + + } + + /// 按Rank统计Reviewer 数量[New] + + [HttpGet, Route("getReviewersByRank")] + public IResponseOutput> GetReviewersByRank() + { + + return ResponseOutput.Ok(_statisticsService.GetReviewersByRank()); + + } + + /// 最近几个季度入组人次[New] type==0 按照月份 + + [HttpGet, Route("GetEnrollDataByQuarter/{type:int}/{count:int}")] + public IResponseOutput> GetEnrollDataByQuarter(int type, int count) + { + + return ResponseOutput.Ok(_statisticsService.GetEnrollDataByQuarter(type, count)); + + } + + /// 参与项目数排行 [New] + + [HttpGet, Route("getTrialCountRank/{topCount:int}")] + public IResponseOutput> GetTrialCountRank(int topCount) + { + + return ResponseOutput.Ok(_statisticsService.GetTrialCountRank(topCount)); + + } + + /// 最新工作量 (已确定的)[New] + + [HttpGet, Route("getLatestWorkLoadList/{searchCount:int}")] + public IResponseOutput> GetLatestWorkLoadList(int searchCount) + { + + return ResponseOutput.Ok(_statisticsService.GetLatestWorkLoadList(searchCount)); + + } + #endregion + } +} \ No newline at end of file diff --git a/IRaCIS.Core.API/Controllers/Trial/EnrollController.cs b/IRaCIS.Core.API/Controllers/Trial/EnrollController.cs new file mode 100644 index 0000000..34e5dd5 --- /dev/null +++ b/IRaCIS.Core.API/Controllers/Trial/EnrollController.cs @@ -0,0 +1,180 @@ +using IRaCIS.Api.Filter; +using IRaCIS.Application; +using IRaCIS.Application.Interfaces; +using IRaCIS.Application.ViewModels; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using System; +using System.Collections.Generic; +using IRaCIS.Core.Application.Contracts.RequestAndResponse; +using IRaCIS.Core.Domain.Share; +using IRaCIS.Core.Domain.Interfaces; +using System.Linq; + +namespace IRaCIS.Core.API.Controllers +{ + /// + /// 入组具体流程各个医生列表信息、和提交动作 + /// + [Route("enroll")] + [ApiController, Authorize, ApiExplorerSettings(GroupName = "Enroll")] + public class EnrollController : ControllerBase + { + private readonly IFileService _fileService; + private readonly ITrialEnrollmentService _trialEnrollmentService; + private readonly IDoctorListQueryService _doctorListQueryService; + private readonly IEnrollRepository _enrollRepository; + private readonly IDoctorRepository _doctorRepository; + + + + public EnrollController(IFileService fileService, + ITrialEnrollmentService trialEnrollmentService, + IDoctorListQueryService doctorListQueryService, + IEnrollRepository enrollRepository, + IDoctorRepository doctorRepository + + ) + { + _fileService = fileService; + _trialEnrollmentService = trialEnrollmentService; + _doctorListQueryService = doctorListQueryService; + _enrollRepository = enrollRepository; + _doctorRepository = doctorRepository; + + } + + #region Trial 入组相关 + + /// 为项目筛选医生 提交 【select】 + /// 项目Id + /// 医生Id数组 + /// + [LogFilter] + [HttpPost, Route("selectReviewers/{trialId:guid}")] + public IResponseOutput SelectReviewers(Guid trialId, Guid[] doctorIdArray) + { + var userId = Guid.Parse(User.FindFirst("id").Value); + return _trialEnrollmentService.SelectReviewer(userId, trialId, doctorIdArray); + + } + + [LogFilter] + [HttpPost, Route("downloadResume/{trialId:guid}")] + public IResponseOutput DownloadResume(Guid trialId, Guid[] doctorIdArray) + { + var userId = Guid.Parse(User.FindFirst("id").Value); + var zipPath = _fileService.CreateOfficialResumeZip(doctorIdArray); + + return ResponseOutput.Ok(SystemConfig.RootUrl + zipPath); + } + + /// 提交CRO列表 【Submit】 + /// 项目Id + /// 医生Id列表 + /// + /// + [LogFilter] + [HttpPost, Route("submitReviewer/{trialId:guid}/{commitState:int}")] + public IResponseOutput SubmitReviewer(Guid trialId, Guid[] doctorIdArray, int commitState) + { + var userId = Guid.Parse(User.FindFirst("id").Value); + return _trialEnrollmentService.SubmitReviewer(userId, trialId, doctorIdArray, commitState); + + + } + /// 入组名单确认 提交【 Approve】 + /// 项目Id + /// 医生Id列表 + /// + /// + + [LogFilter] + [HttpPost, Route("approveReviewer/{trialId:guid}/{auditState:int}")] + public IResponseOutput ApproveReviewer(Guid trialId, Guid[] doctorIdArray, int auditState) + { + var userId = Guid.Parse(User.FindFirst("id").Value); + return _trialEnrollmentService.ApproveReviewer(userId, trialId, doctorIdArray, auditState); + + } + + /// + /// 获取医生项目列表 + /// + /// + /// + [HttpPost,Route("Enroll/GetTrialDoctorList")] + [LogFilter] + public PageOutput GetTrialDoctorList(EnrollGetQuery challengeQuery) + { + + + return _doctorListQueryService.GetTrialDoctorList(challengeQuery); + //return ResponseOutput.Ok(_doctorListQueryService.GetTrialDoctorList(challengeQuery)); + + } + + /// + /// 添加或更新项目医生项目价格 + /// + [LogFilter] + [HttpPost, Route("addOrUpdateModel")] + public IResponseOutput AddOrUpdateEnroll(EnrollCommand addOrUpdateModel) + { + return ResponseOutput.Ok(_doctorListQueryService.AddOrUpdateEnroll(addOrUpdateModel)); + } + + /// + /// 后台确认医生入组 【Confirm】 + /// + + [LogFilter] + [HttpPost, Route("confirmReviewer/{trialId:guid}/{confirmState:int}")] + public IResponseOutput ConfirmReviewer(Guid trialId, Guid[] doctorIdArray, int confirmState) + { + var userId = Guid.Parse(User.FindFirst("id").Value); + return _trialEnrollmentService.ConfirmReviewer(userId, trialId, doctorIdArray, confirmState); + + } + + #endregion + + #region 入组过程,各个状态的列表接口 + /// + /// 筛选医生列表 [AUTH] + /// + [HttpPost, Route("getSelectionReviewerList")] + public IResponseOutput> GetSelectionReviewerList( + ReviewerSelectionQueryDTO param) + { + + return ResponseOutput.Ok(_doctorListQueryService.GetSelectionReviewerList(param)); + + } + /// + /// 根据状态获取医生列表,入组 相关接口 (提交CRO-1) CRO确认-4 + /// + [HttpPost, Route("getSubmissionOrApprovalReviewerList")] + public IResponseOutput> GetSubmissionOrApprovalReviewerList( + ReviewerSubmissionQueryDTO param) + { + + return ResponseOutput.Ok(_doctorListQueryService.GetSubmissionOrApprovalReviewerList(param)); + + } + + /// + /// 获取项目下医生入组状态列表[Confirmation] + /// + + [HttpPost, Route("getConfirmationReviewerList")] + public IResponseOutput> GetConfirmationReviewerList( + ReviewerConfirmationQueryDTO trialIdPageModel) + { + + return ResponseOutput.Ok(_doctorListQueryService.GetConfirmationReviewerList(trialIdPageModel)); + + } + #endregion + } +} diff --git a/IRaCIS.Core.API/Controllers/Trial/SubjectController.cs b/IRaCIS.Core.API/Controllers/Trial/SubjectController.cs new file mode 100644 index 0000000..a062118 --- /dev/null +++ b/IRaCIS.Core.API/Controllers/Trial/SubjectController.cs @@ -0,0 +1,66 @@ +using IRaCIS.Application.Interfaces; +using IRaCIS.Application.ViewModels; +using System; +using System.Collections.Generic; +using IRaCIS.Core.Application.Contracts.RequestAndResponse; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Authorization; + +namespace IRaCIS.Api.Controllers +{ + /// + /// 临床受试者 + /// + [Route("subject")] + [ApiController, Authorize, ApiExplorerSettings(GroupName = "Trial")] + public class SubjectController : ControllerBase + { + private readonly ISubjectService _subjectsService; + public SubjectController(ISubjectService subjectsService) + { + _subjectsService = subjectsService; + } + + /// + /// 添加或更新受试者信息[New][AUTH] + /// + /// state:1-访视中,2-出组。0-全部 + /// + [HttpPost, Route("addOrUpdate")] + public IResponseOutput AddOrUpdateSubject(SubjectCommand model) + { + return _subjectsService.AddOrUpdateSubject(model); + } + + /// 删除受试者[New] + [HttpDelete, Route("delete/{id:guid}")] + public IResponseOutput DeleteSubject(Guid id) + { + return _subjectsService.DeleteSubject(id); + } + + /// 分页获取受试者列表[New] + /// /// state:1-访视中,2-出组。0-全部 + [HttpPost, Route("getSubjectList")] + public IResponseOutput> GetSubjectList(SubjectQueryParam param) + { + if (param.TrialId == Guid.Empty) + { + return ResponseOutput.NotOk("Trial Id needed.",new PageOutput()); + } + return ResponseOutput.Ok(_subjectsService.GetSubjectList(param)); + } + + /// + /// 上传影像时 获取受试者选择下拉框列表 + /// + /// + /// + /// + [HttpGet, Route("getSubjectListBySiteId/{siteId:guid}/{trialId:guid}")] + public IResponseOutput> GetSubjectListBySiteId(Guid siteId, Guid trialId) + { + return ResponseOutput.Ok(_subjectsService.GetSubjectListBySiteId(siteId, trialId)); + } + } +} diff --git a/IRaCIS.Core.API/Controllers/Trial/SubjectVisitController.cs b/IRaCIS.Core.API/Controllers/Trial/SubjectVisitController.cs new file mode 100644 index 0000000..c68b1ce --- /dev/null +++ b/IRaCIS.Core.API/Controllers/Trial/SubjectVisitController.cs @@ -0,0 +1,68 @@ +using IRaCIS.Application.Interfaces; +using IRaCIS.Application.ViewModels; +using System; +using System.Collections.Generic; +using IRaCIS.Core.Application.Contracts.RequestAndResponse; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Authorization; +using IRaCIS.Core.Application.Contracts.Trial; + +namespace IRaCIS.Api.Controllers +{ + /// + /// 受试者访视 + /// + [Route("subjectVisit")] + [ApiController, Authorize, ApiExplorerSettings(GroupName = "Trial")] + public class SubjectVisitController : ControllerBase + { + private readonly ISubjectVisitService _subjectvisitService; + public SubjectVisitController(ISubjectVisitService subjectvisitService) + { + _subjectvisitService = subjectvisitService; + } + + [HttpPost, Route("getVisitList")] + public IResponseOutput> GetVisitList(SubjectVisitSearchDTO subjectVisitSearch) + { + return ResponseOutput.Ok(_subjectvisitService.GetVisitList(subjectVisitSearch)); + } + /// + /// + /// + /// + /// + [HttpPost, Route("addOrUpdate")] + public IResponseOutput AddOrUpdateSV(SubjectVisitCommand model) + { + return ResponseOutput.Ok(_subjectvisitService.AddOrUpdateSV(model)); + } + + /// 删除受试者访视 + [HttpDelete, Route("delete/{id:guid}")] + public IResponseOutput DeleteSV(Guid id) + { + return _subjectvisitService.DeleteSV(id); + } + + /// + /// 上传影像时 需要选择是属于 受试者访视那个阶段 + /// + /// + /// + /// + /// + [HttpGet, Route("getSubjectVisitSelectList/{trialId:guid}/{siteId:guid}/{subjectId:guid}")] + public IResponseOutput> GetSubjectVisitSelectList(Guid trialId, Guid siteId, Guid subjectId) + { + return ResponseOutput.Ok(_subjectvisitService.GetSubjectVisitSelectList(trialId, siteId,subjectId)); + } + + [HttpGet, Route("getSubjectVisitList/{trialId:guid}/{subjectId:guid}")] + public IResponseOutput> GetSubjectVisitList(Guid trialId, Guid subjectId) + { + return ResponseOutput.Ok(_subjectvisitService.GetSubjectVisitList(trialId, subjectId)); + } + + } +} diff --git a/IRaCIS.Core.API/Controllers/Trial/TrialAttachmentController.cs b/IRaCIS.Core.API/Controllers/Trial/TrialAttachmentController.cs new file mode 100644 index 0000000..2e08585 --- /dev/null +++ b/IRaCIS.Core.API/Controllers/Trial/TrialAttachmentController.cs @@ -0,0 +1,60 @@ +using IRaCIS.Application.Interfaces; +using IRaCIS.Application.ViewModels; +using System; +using System.Collections.Generic; +using IRaCIS.Core.Application.Contracts.RequestAndResponse; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Authorization; + +namespace IRaCIS.Api.Controllers.Trial +{ + /// + /// 影像获取规范 + /// + [Route("acquisitionSpecification")] + [ApiController, Authorize, ApiExplorerSettings(GroupName = "Trial")] + public class TrialAttachmentController : ControllerBase + { + private readonly ITrialAttachmentService _specificationService; + public TrialAttachmentController(ITrialAttachmentService specificationService) + { + _specificationService = specificationService; + } + + /// + /// 添加或更新影像采集规范[New][AUTH] + /// + /// + /// + [HttpPost, Route("addOrUpdate")] + + public IResponseOutput AddOrUpdateSpecification(TrialAttachmentCommand model) + { + var userId = User.FindFirst("id").Value; + return _specificationService.AddOrUpdateSpecification(model, Guid.Parse(userId)); + } + + /// 删除采集规范[New] + + [HttpDelete, Route("delete/{id:guid}")] + public IResponseOutput DeleteSpecification(Guid id) + { + return _specificationService.DeleteSpecification(id); + } + + [HttpPost, Route("list/{trialId:guid}")] + public IResponseOutput> GetAcquisitionSpecificationList(Guid trialId,string type) + { + return ResponseOutput.Ok(_specificationService.GetSpecificationList( trialId, type)); + } + + ///// 分页获取影像采集规范[New] + //[HttpPost, Route("getPageList")] + //[ApiExplorerSettings(IgnoreApi = true)] + //public IResponseOutput> GetSpecificationList(ImageAcquisitionSpecificationQueryDTO param) + //{ + // return ResponseOutput.Ok(_specificationService.GetSpecificationList(param)); + //} + + } +} diff --git a/IRaCIS.Core.API/Controllers/Trial/TrialController.cs b/IRaCIS.Core.API/Controllers/Trial/TrialController.cs new file mode 100644 index 0000000..a5ecc44 --- /dev/null +++ b/IRaCIS.Core.API/Controllers/Trial/TrialController.cs @@ -0,0 +1,234 @@ +using System; +using System.Collections.Generic; +using IRaCIS.Api.Filter; +using IRaCIS.Application.Interfaces; +using IRaCIS.Application.ViewModels; +using IRaCIS.Core.Application.Contracts.RequestAndResponse; +using IRaCIS.Core.Domain.Share.AuthUser; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; + +namespace IRaCIS.Api.Controllers +{ + /// + /// 项目基本信息维护 + /// + [Route("trial")] + [ApiController, Authorize, ApiExplorerSettings(GroupName = "Trial")] + public class TrialController : ControllerBase + { + private readonly ITrialService _trialService; + + private readonly ITrialWorkloadService _trialWorkloadService; + private readonly IUserInfo _userInfo; + private readonly ICalculateService _calculateService; + + public TrialController(ITrialService trialService, + ITrialWorkloadService trialWorkloadService,IUserInfo userInfo,ICalculateService calculateService) + { + _trialService = trialService; + _trialWorkloadService = trialWorkloadService; + _userInfo = userInfo; + _calculateService = calculateService; + } + + #region 项目查询 + /// 分页获取临床实验项目列表(查询条件) + /// 查询参数 + /// + [HttpPost, Route("getTrialList")] + public IResponseOutput> GetTrialList(TrialQueryDTO param) + { + var userId = Guid.Parse(User.FindFirst("id").Value); + return ResponseOutput.Ok(_trialService.GetTrialList(param, userId)) ; + + } + + /// 查询项目基本信息 + /// 项目Id + /// + [HttpGet, Route("getTrialInfo/{trialId:guid}")] + public IResponseOutput GetTrialInfoAndLockState(Guid trialId) + { + var trial = _trialService.GetTrialInfoAndLockState(trialId); + + return ResponseOutput.Ok(trial); + + } + + /// 查询项目基本信息 和项目最大状态, + /// 项目Id + /// + + [HttpGet, Route("getTrialInfoAndMaxTrialState/{trialId:guid}")] + public IResponseOutput GetTrialInfoAndMaxTrialState(Guid trialId) + { + var result = new TrialAndTrialStateVieModel() + { + TrialView = _trialService.GetTrialInfoAndLockState(trialId), + TrialMaxState = _trialService.GetTrialMaxState(trialId) + }; + + return ResponseOutput.Ok(result); + + } + + /// 查询项目加急状态 + /// 项目Id + /// + [HttpGet, Route("getTrialExpeditedState/{trialId:guid}")] + public IResponseOutput GetTrialExpeditedState(Guid trialId) + { + + return ResponseOutput.Ok(_trialService.GetTrialExpeditedState(trialId)); + + } + + /// + /// 根据项目状态获取医生项目列表[New] + /// + /// 5-Submitted,8-Approved,10-Reading + /// + [HttpPost, Route("getDoctorTrialListByStatus")] + [AllowAnonymous] + public IResponseOutput> GetDoctorTrialListByStatus( + TrialByStatusQueryDTO param) + { + return ResponseOutput.Ok(_trialService.GetReviewerTrialListByEnrollmentStatus(param)) ; + } + #endregion + + #region 项目更新删除 + + /// 添加实验项目-返回新增Id[AUTH] + /// + /// 新记录Id + [LogFilter] + [HttpPost, Route("addOrUpdateTrial")] + public IResponseOutput AddOrUpdateTrial(TrialCommand param) + { + var userId = Guid.Parse(User.FindFirst("id").Value); + var result= _trialService.AddOrUpdateTrial(param, userId); + + if (_trialService.TrialExpeditedChange) + { + var needCalReviewerIds = _trialService.GetTrialEnrollmentReviewerIds(param.Id); + var calcList = _calculateService.GetNeedCalculateReviewerList(Guid.Empty, string.Empty); + + calcList.ForEach(t=> { + if (needCalReviewerIds.Contains(t.DoctorId)) + { + _calculateService.CalculateMonthlyPayment(new CalculateDoctorAndMonthDTO() + { + NeedCalculateReviewers = new List() + { + t.DoctorId + }, + CalculateMonth = DateTime.Parse(t.YearMonth) + }, User.FindFirst("id").Value); + + } }); + } + + return result; + } + + [LogFilter] + [HttpPost, Route("confirmTrialVisitPlan/{trialId:guid}")] + public IResponseOutput ConfirmTrialVisitPlan(Guid trialId) + { + return _trialService.ConfirmTrialVisitPlan(trialId); + } + + /// + /// 手动更新项目状态 + /// + /// 项目Id + /// 状态值 + /// + [LogFilter] + [HttpPost, Route("updateTrialStatus/{trialId:guid}/{statusStr}")] + public IResponseOutput UpdateTrialStatusStr(Guid trialId, string statusStr) + { + if (string.IsNullOrWhiteSpace(statusStr)) + { + return ResponseOutput.NotOk("please select status."); + } + var result = _trialService.UpdateTrialStatus(trialId, statusStr); + + return result; + } + + /// 删除临床项目 + /// 临床试验项目Id + [LogFilter] + [HttpDelete, Route("deleteTrial/{trialId:guid}")] + public IResponseOutput DeleteTrial(Guid trialId) + { + return _trialService.DeleteTrial(trialId); + + } + #endregion + + #region ack sow + /// + /// 保存协议- ack Sow [AUTH] + /// + [HttpPost, Route("uploadReviewerAckSOW/{trialId}")] + public IResponseOutput UploadReviewerAckSOW(Guid trialId, ReviewerAckDTO attachmentViewModel) + { + var userId = Guid.Parse(User.FindFirst("id").Value); + return _trialWorkloadService.UploadReviewerAckSOW(userId, trialId, attachmentViewModel); + } + + /// + /// 删除协议 + /// + [HttpDelete, Route("deleteReviewerAckSOW/{trialId}/{doctorId}/{attachmentId}")] + public IResponseOutput DeleteReviewerAckSOW(Guid trialId, Guid doctorId, Guid attachmentId) + { + return _trialWorkloadService.DeleteReviewerAckSOW(trialId, doctorId, attachmentId); + + } + + /// + /// 0代表裁判和Tp 都可以 1、代表Tp 2 代表裁判 + /// + /// + /// + /// + /// + [HttpPost, Route("updateReviewerReadingType/{trialId}/{doctorId}/{reviewerReadingType}")] + public IResponseOutput UpdateReviewerReadingType(Guid trialId, Guid doctorId, int reviewerReadingType) + { + return _trialWorkloadService.UpdateReviewerReadingType(trialId, doctorId, reviewerReadingType); + } + #endregion + + #region 医生用户接口 + /// 分页获取医生参与的临床实验项目列表(查询条件) + /// 查询参数 + /// + [HttpPost, Route("getTrialListByReviewer")] + public IResponseOutput> GetTrialListByReviewer(ReviewerTrialQueryDTO param) + { + var userId = Guid.Parse(User.FindFirst("id").Value); + return ResponseOutput.Ok(_trialService.GetTrialListByReviewer(param, userId)); + } + + + /// + /// 医生确认入组或拒绝入组 + /// + /// 项目Id + /// 9-拒绝入组,10-确认入组 + /// + [HttpPost, Route("updateEnrollStatus/{trialId:guid}/{status:int}")] + public IResponseOutput UpdateTrialStatusStr(Guid trialId, int status) + { + return _trialService.UpdateEnrollStatus(trialId, status); + } + + #endregion + } +} \ No newline at end of file diff --git a/IRaCIS.Core.API/Controllers/Trial/TrialMaintenanceController.cs b/IRaCIS.Core.API/Controllers/Trial/TrialMaintenanceController.cs new file mode 100644 index 0000000..041873e --- /dev/null +++ b/IRaCIS.Core.API/Controllers/Trial/TrialMaintenanceController.cs @@ -0,0 +1,109 @@ +using IRaCIS.Application.Interfaces; +using IRaCIS.Application.ViewModels; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using System; +using System.Collections.Generic; +using IRaCIS.Core.Application.Contracts.RequestAndResponse; + + +namespace IRaCIS.Api.Controllers +{ + /// + /// 项目运维人员 、研究中心CRC 配置 + /// + [Route("trialMaintenance")] + [ApiController, Authorize, ApiExplorerSettings(GroupName = "Trial")] + public class MaintenanceController : ControllerBase + { + private readonly IUserTrialService _userTrialService; + public MaintenanceController(IUserTrialService userTrialService) + { + _userTrialService = userTrialService; + } + + [HttpGet, Route("getTrialSiteSelect/{trialId:guid}")] + public IResponseOutput> GetTrialSiteSelect(Guid trialId) + { + return ResponseOutput.Ok(_userTrialService.GetTrialSiteSelect(trialId)); + } + + /// + /// 获取项目运维人员列表[New] 分页暂时不用 + /// + /// 项目Id必须传 + /// + [HttpPost, Route("GetUserTrialList")] + [ApiExplorerSettings(IgnoreApi = true)] + public IResponseOutput> GetUserTrialList(UserTrialListQueryDTO param) + { + return ResponseOutput.Ok(_userTrialService.GetUserTrialList(param)); + } + + /// + /// 获取项目运维人员列表[New] + /// + /// + /// + [HttpPost, Route("getMaintenanceList")] + public IResponseOutput> GetMaintenanceUserList(TrialMaintenanceQuery param) + { + return ResponseOutput.Ok(_userTrialService.GetMaintenanceUserList(param)); + } + + + /// + /// 获取可用选择用户,用于给项目添加运维人员时的选择列表[New] + /// + /// + [HttpGet, Route("getUserSelectionList/{userTypeId:guid}/{institutionId:guid}")] + + public IResponseOutput> GetUserTrialList(Guid userTypeId,Guid institutionId) + { + return ResponseOutput.Ok(_userTrialService.GetUserSelectionList(userTypeId, institutionId)) ; + } + + /// 添加或更新运维人员[New] + [HttpPost, Route("AddOrUpdateMaintenanceUser")] + + public IResponseOutput AddOrUpdateUserTrial(UserTrialCommand param) + { + return _userTrialService.AddOrUpdateUserTrial(param); + } + + /// 删除运维人员[New] + [HttpDelete, Route("deleteMaintenanceUser/{id:guid}")] + + public IResponseOutput DeleteUserTrial(Guid id) + { + return _userTrialService.DeleteUserTrial(id); + } + + + /// 获取负责研究中心CRC列表 + [HttpPost, Route("getSiteCRCList")] + + public IResponseOutput> GetSiteCRCList(SiteCrcQueryDTO param) + { + return ResponseOutput.Ok(_userTrialService.GetSiteCRCList(param)) ; + } + + /// 添加或更新CRC人员 + [HttpPost, Route("addOrUpdateSiteCRC")] + + + public IResponseOutput AddOrUpdateSiteCRC(SiteCRCCommand param) + { + return _userTrialService.AddOrUpdateSiteCRC(param); + } + + + /// 删除CRC人员 + [HttpDelete, Route("deleteSiteCRC/{id:guid}")] + + public IResponseOutput DeleteSiteCRC(Guid id) + { + return _userTrialService.DeleteSiteCRC(id); + } + } +} diff --git a/IRaCIS.Core.API/Controllers/Trial/VisitPlanController.cs b/IRaCIS.Core.API/Controllers/Trial/VisitPlanController.cs new file mode 100644 index 0000000..e3dc2d4 --- /dev/null +++ b/IRaCIS.Core.API/Controllers/Trial/VisitPlanController.cs @@ -0,0 +1,65 @@ +using IRaCIS.Application.Interfaces; +using IRaCIS.Application.ViewModels; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using System; +using System.Collections.Generic; +using IRaCIS.Core.Application.Contracts.RequestAndResponse; + + +namespace IRaCIS.Api.Controllers +{ + /// + /// 访视计划 + /// + [Route("visitPlan")] + [ApiController, Authorize, ApiExplorerSettings(GroupName = "Trial")] + public class VisitPlanController : ControllerBase + { + private readonly IVisitPlanService _visitPlanService; + public VisitPlanController(IVisitPlanService visitPlanService) + { + _visitPlanService = visitPlanService; + } + + /// 分页获取项目访视计划[New] + [HttpPost, Route("getTrialVisitStageList")] + [ApiExplorerSettings(IgnoreApi = true)] + public IResponseOutput> GetTrialVisitStageList(VisitPlanQueryDTO param) + { + return ResponseOutput.Ok(_visitPlanService.GetTrialVisitStageList(param)); + } + + /// 根据项目Id,获取项目访视计划(不分页)[New] + [HttpGet, Route("getVisitStageList/{trialId:guid}")] + public IResponseOutput> GetVisitStageList(Guid trialId) + { + return ResponseOutput.Ok(_visitPlanService.GetVisitStageList(trialId)) ; + } + /// + /// 获取访视计划下拉框列表 + /// + /// + /// + [HttpGet, Route("getTrialVisitStageSelect/{trialId:guid}")] + public IResponseOutput> GetTrialVisitStageSelect(Guid trialId) + { + return ResponseOutput.Ok(_visitPlanService.GetTrialVisitStageSelect(trialId)); + } + + /// 添加或更新访视计划某项[New] + [HttpPost, Route("addOrUpdateVisitStage")] + + public IResponseOutput AddOrUpdateVisitStage(VisitPlanCommand param) + { + return _visitPlanService.AddOrUpdateVisitStage(param); + } + + /// 删除项目计划某一项[New] + [HttpDelete, Route("deleteVisitStage/{id:guid}")] + public IResponseOutput DeleteVisitStage(Guid id) + { + return _visitPlanService.DeleteVisitStage(id); + } + } +} diff --git a/IRaCIS.Core.API/Controllers/Trial/WorkloadController.cs b/IRaCIS.Core.API/Controllers/Trial/WorkloadController.cs new file mode 100644 index 0000000..7326025 --- /dev/null +++ b/IRaCIS.Core.API/Controllers/Trial/WorkloadController.cs @@ -0,0 +1,127 @@ +using IRaCIS.Api.Filter; +using IRaCIS.Application.Interfaces; +using IRaCIS.Application.ViewModels; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using System; +using System.Collections.Generic; +using IRaCIS.Core.Application.Contracts.RequestAndResponse; + +namespace IRaCIS.Core.API.Controllers +{ + /// + /// 入组之后 工作量维护 + /// + [Route("workload")] + [ApiController, Authorize, ApiExplorerSettings(GroupName = "Workload")] + public class WorkloadController : ControllerBase + { + private readonly ITrialWorkloadService _trialWorkloadService; + private readonly ICalculateService _calculateService; + + public WorkloadController(ITrialWorkloadService trialWorkloadService, ICalculateService calculateService) + { + _trialWorkloadService = trialWorkloadService; + _calculateService = calculateService; + } + /// + /// 查询某个医生是否在某天有某个项目的工作量数据,处理添加来自医生自己的工作量数据 + /// + [HttpPost, Route("existWorkLoad")] + public IResponseOutput WorkLoadExist(WorkloadExistQueryDTO param) + { + return _trialWorkloadService.WorkloadExist(param); + } + + /// 查询项目入组医生的工作量统计信息 + + [HttpPost, Route("getTrialEnrollmentWorkloadStats")] + public IResponseOutput> GetTrialEnrollmentWorkloadStats(WorkLoadDoctorQueryDTO doctorSearchModel) + { + + return ResponseOutput.Ok(_trialWorkloadService.GetTrialEnrollmentWorkloadStats(doctorSearchModel)); + + } + /// + /// 获取医生工作量(带有填充数据) + /// + /// + /// + [HttpPost, Route("getDoctorWorkLoadList")] + public IResponseOutput> GetDoctorWorkLoadList( + WorkLoadStatsQueryDTO workLoadSearch) + { + return ResponseOutput.Ok(_trialWorkloadService.GetEnrollmentWorkloadStatsDetail(workLoadSearch)) ; + } + + /// + /// 获取来自医生端的工作量列表 详情 + /// + /// + /// + + [HttpPost, Route("getReviewerWorkLoadListDetail")] + public IResponseOutput> GetReviewerWorkLoadListDetail( + WorkLoadDetailQueryDTO workLoadSearch) + { + return ResponseOutput.Ok(_trialWorkloadService.GetReviewerWorkLoadListDetail(workLoadSearch)) ; + } + + /// + /// 添加或更新工作量[AUTH] + /// + /// + /// + [LogFilter] + [HttpPost, Route("workLoadAddOrUpdate")] + public IResponseOutput WorkLoadAddOrUpdate(WorkloadCommand workLoadAddOrUpdateModel) + { + var userId = Guid.Parse(User.FindFirst("id").Value); + //var yearMonth = workLoadAddOrUpdateModel.WorkTime.ToString("yyyy-MM"); + var result = _trialWorkloadService.AddOrUpdateWorkload(workLoadAddOrUpdateModel, userId); + //_calculateTaskService.AddCalculateTask(workLoadAddOrUpdateModel.DoctorId, yearMonth); + if (result.IsSuccess && workLoadAddOrUpdateModel.DataFrom == 2) + { + _calculateService.CalculateMonthlyPayment(new CalculateDoctorAndMonthDTO() + { + NeedCalculateReviewers = new List() + { + workLoadAddOrUpdateModel.DoctorId + }, + CalculateMonth = workLoadAddOrUpdateModel.WorkTime + }, User.FindFirst("id").Value); + } + return result; + } + + + [LogFilter] + [HttpDelete, Route("deleteWorkLoad/{id:guid}")] + public IResponseOutput DeleteWorkLoad(Guid id) + { + //先判断该工作量的费用是否被锁定,如果被锁定,则不能删除 + var workload = _trialWorkloadService.GetWorkloadDetailById(id); + var yearMonth = workload.WorkTime.ToString("yyyy-MM"); + var isLock = _calculateService.IsLock(workload.DoctorId, yearMonth); + + if (isLock) + { + return ResponseOutput.NotOk("Expenses have been settled and workload cannot be reset."); + } + + var deleteResult = _trialWorkloadService.DeleteWorkload(id); + if (workload.DataFrom == (int)Domain.Share.WorkLoadFromStatus.FinalConfirm) + { + _calculateService.CalculateMonthlyPayment(new CalculateDoctorAndMonthDTO() + { + NeedCalculateReviewers = new List() + { + workload.DoctorId + }, + CalculateMonth = workload.WorkTime + }, User.FindFirst("id").Value); + } + return deleteResult; + } + } +} diff --git a/IRaCIS.Core.API/Controllers/Trial/WorkloadDistributionController.cs b/IRaCIS.Core.API/Controllers/Trial/WorkloadDistributionController.cs new file mode 100644 index 0000000..1c7d78a --- /dev/null +++ b/IRaCIS.Core.API/Controllers/Trial/WorkloadDistributionController.cs @@ -0,0 +1,114 @@ +using IRaCIS.Application.ViewModels; +using IRaCIS.Core.Application.Contracts; +using IRaCIS.Core.Application.Contracts.RequestAndResponse; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using System; + +namespace IRaCIS.Core.API.Controllers.Trial +{ + /// + /// TP、Global、AD 工作量分配查看 + /// + [Route("workload")] + [ApiController, Authorize, ApiExplorerSettings(GroupName = "Trial")] + public class WorkloadDistributionController : ControllerBase + { + private readonly IWorkloadDistributionService _workloadDistributionService; + + public WorkloadDistributionController(IWorkloadDistributionService workloadDistributionService) + { + _workloadDistributionService = workloadDistributionService; + } + + /// + /// TP 工作量分配列表 + /// + /// + /// + [HttpPost, Route("getWorkloadTPList")] + public IResponseOutput> GetWorkloadTPList(WorkloadDistributionQueryParam param) + { + return ResponseOutput.Ok(_workloadDistributionService.GetWorkloadTPList(param)); + } + + /// + /// 批量分配Tp + /// + /// + /// + [HttpPost, Route("DistributeTP")] + public IResponseOutput DistributeTP(WorkloadTPCommand workloadTPCommand) + { + return _workloadDistributionService.DistributeTP(workloadTPCommand); + } + + //修改单个TP + [HttpPost, Route("UpdateDistributeTP/{tpId:guid}/{reviewerId:guid}/{studyId:guid}")] + public IResponseOutput UpdateDistributeTP(Guid tpId, Guid reviewerId,Guid studyId) + { + return _workloadDistributionService.UpdateDistributeTP(tpId,reviewerId, studyId); + } + + [HttpPost, Route("getWorkloadADList")] + public IResponseOutput> GetWorkloadADList(WorkloadDistributionQueryParam param) + { + return ResponseOutput.Ok(_workloadDistributionService.GetWorkloadADList(param)); + } + + /// + /// 批量分配AD + /// + /// + /// + [HttpPost, Route("DistributeAD")] + public IResponseOutput DistributeAD(WorkloadAdCommand workloadTPCommand) + { + return ResponseOutput.Result(_workloadDistributionService.DistributeAD(workloadTPCommand)); + } + + //修改单个TP + [HttpPost, Route("UpdateDistributeAD/{tpId:guid}/{reviewerId:guid}")] + public IResponseOutput UpdateDistributeAD(Guid tpId, Guid reviewerId) + { + return ResponseOutput.Result(_workloadDistributionService.UpdateDistributeAD(tpId, reviewerId)); + } + + [HttpPost, Route("getWorkloadGlobalList")] + public IResponseOutput> GetWorkloadGlobalList(WorkloadDistributionQueryParam param) + { + return ResponseOutput.Ok(_workloadDistributionService.GetWorkloadGlobalList(param)); + } + + /// + /// 批量分配Global + /// + /// + /// + [HttpPost, Route("DistributeGlobal")] + public IResponseOutput DistributeGlobal(WorkloadGlobalCommand workloadGCommand) + { + return _workloadDistributionService.DistributeGlobal(workloadGCommand); + } + + //修改单个Global + [HttpPost, Route("UpdateDistributeGlobal/{tpId:guid}/{reviewerId:guid}/{subjectId:guid}/{visitNum}")] + public IResponseOutput UpdateDistributeGlobal(Guid tpId, Guid reviewerId,Guid subjectId, decimal visitNum) + { + return _workloadDistributionService.UpdateDistributeGlobal(tpId, reviewerId,subjectId,visitNum); + } + + [HttpGet, Route("GetWorkloadDetailList/{workloadId:guid}")] + [AllowAnonymous] + public IResponseOutput GetWorkloadDetailList(Guid workloadId) + { + return _workloadDistributionService.GetWorkloadDetail(workloadId); + } + + [HttpPost, Route("UpdateGlobalStatus/{globalId:guid}")] + public IResponseOutput UpdateGlobalStatus(Guid globalId) + { + return _workloadDistributionService.UpdateGlobalStatus(globalId); + } + } +} \ No newline at end of file diff --git a/IRaCIS.Core.API/Controllers/ValuesController.cs b/IRaCIS.Core.API/Controllers/ValuesController.cs new file mode 100644 index 0000000..a5efd26 --- /dev/null +++ b/IRaCIS.Core.API/Controllers/ValuesController.cs @@ -0,0 +1,62 @@ +using System; +using IRaCIS.Application.ViewModels; +using IRaCIS.Core.Application; +using IRaCIS.Core.Domain; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; + +namespace EasyCaching.Demo.Interceptors.Controllers +{ + [Route("test")] + [ApiController, AllowAnonymous, ApiExplorerSettings(GroupName = "Common")] + public class ValuesController : ControllerBase + { + //private readonly ITestRepository _testRepository; + + + //public ValuesController( ITestRepository testRepository) + //{ + // _testRepository = testRepository; + //} + + + //[HttpPost] + //[Route("test")] + //public ActionResult test() + //{ + + // var test=new Test(); + // test.Str = "T" + test.AutoIncrease; + // _testRepository.Add(test); + // var cc= _testRepository.SaveChanges(); + // return Ok(); + + //} + + //[HttpPost] + //[Route("castleasync")] + //public async Task CastleAsync(int type = 1) + //{ + // if (type == 1) + // { + // return await _cService.GetUtcTimeAsync(); + // } + // else if (type == 2) + // { + // var res = await _cService.GetDemoAsync(999); + // return $"{res.Id}-{res.Name}-{res.CreateTime}"; + // } + // else if (type == 3) + // { + // var res = await _cService.GetDemoListAsync(999); + // return $"{res.Count}"; + // } + // else + // { + // return await Task.FromResult("wait"); + // } + //} + + + } +} diff --git a/IRaCIS.Core.API/Filter/EnableBufferingAttribute .cs b/IRaCIS.Core.API/Filter/EnableBufferingAttribute .cs new file mode 100644 index 0000000..35d698c --- /dev/null +++ b/IRaCIS.Core.API/Filter/EnableBufferingAttribute .cs @@ -0,0 +1,18 @@ +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc.Filters; +using System; + +namespace IRaCIS.Core.API.Filter +{ + public class EnableBufferingAttribute : Attribute, IResourceFilter + { + public void OnResourceExecuting(ResourceExecutingContext context) + { + context.HttpContext.Request.EnableBuffering(); + } + + public void OnResourceExecuted(ResourceExecutedContext context) + { + } + } +} diff --git a/IRaCIS.Core.API/Filter/LogActionFilter.cs b/IRaCIS.Core.API/Filter/LogActionFilter.cs new file mode 100644 index 0000000..9f3fe2d --- /dev/null +++ b/IRaCIS.Core.API/Filter/LogActionFilter.cs @@ -0,0 +1,68 @@ +using System; +using System.Diagnostics; +using System.Linq; +using System.Threading.Tasks; +using IRaCIS.Application.Interfaces; +using IRaCIS.Application.ViewModels; +using IRaCIS.Core.Application.Contracts.RequestAndResponse; +using IRaCIS.Core.Domain.Share.AuthUser; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.Filters; +using Newtonsoft.Json; + +namespace IRaCIS.Api.Filter +{ + public class LogActionFilter : IAsyncActionFilter + { + private readonly ILogService _logService; + private readonly IUserInfo _userInfo; + + public LogActionFilter(ILogService logService, IUserInfo userInfo) + { + _logService = logService; + _userInfo = userInfo; + } + + public Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next) + { + + if (context.ActionDescriptor.EndpointMetadata.Any(m => m.GetType() == typeof(LogFilter))) + { + return LogAsync(context, next); + } + return next(); + } + + public async Task LogAsync(ActionExecutingContext context, ActionExecutionDelegate next) + { + var sw = new Stopwatch(); + sw.Start(); + + dynamic actionResult = (await next()).Result; + sw.Stop(); + var args = JsonConvert.SerializeObject(context.ActionArguments); + var result = JsonConvert.SerializeObject(actionResult?.Value); + + var attr = (ApiExplorerSettingsAttribute)context.ActionDescriptor.EndpointMetadata.FirstOrDefault(m => m.GetType() == typeof(ApiExplorerSettingsAttribute)); + var groupName = attr?.GroupName; + var res = actionResult?.Value as IResponseOutput; + var input = new SystemLogDTO + { + ClientIP = string.Empty, + OptUserId = _userInfo.Id, + OptUserName = _userInfo.UserName, + ApiPath = context.ActionDescriptor.AttributeRouteInfo.Template.ToLower(), + Params = args, + Result = result, + RequestTime = DateTime.Now, + ElapsedMilliseconds = sw.ElapsedMilliseconds, + Status =res?.IsSuccess?? false, + Message = res?.ErrorMessage, + LogCategory = groupName + }; + + + _logService.SaveLog2Db(input); + } + } +} diff --git a/IRaCIS.Core.API/Filter/LogFilter.cs b/IRaCIS.Core.API/Filter/LogFilter.cs new file mode 100644 index 0000000..1c3dfb5 --- /dev/null +++ b/IRaCIS.Core.API/Filter/LogFilter.cs @@ -0,0 +1,9 @@ +using System; + +namespace IRaCIS.Api.Filter +{ + [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true)] + public class LogFilter : Attribute + { + } +} \ No newline at end of file diff --git a/IRaCIS.Core.API/Filter/ModelBinding.cs b/IRaCIS.Core.API/Filter/ModelBinding.cs new file mode 100644 index 0000000..c954f5d --- /dev/null +++ b/IRaCIS.Core.API/Filter/ModelBinding.cs @@ -0,0 +1,29 @@ +using System; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc.Filters; +using Microsoft.AspNetCore.Mvc.ModelBinding; + +namespace IRaCIS.Core.API.Filter +{ + #region snippet_DisableFormValueModelBindingAttribute + [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)] + public class DisableFormValueModelBindingAttribute : Attribute, IResourceFilter + { + public void OnResourceExecuting(ResourceExecutingContext context) + { + + + var factories = context.ValueProviderFactories; + //factories.RemoveType(); + factories.RemoveType(); + //factories.RemoveType(); + + context.HttpContext.Request.EnableBuffering(); + } + + public void OnResourceExecuted(ResourceExecutedContext context) + { + } + } + #endregion +} diff --git a/IRaCIS.Core.API/Filter/WebApiExceptionFilterAttribute.cs b/IRaCIS.Core.API/Filter/WebApiExceptionFilterAttribute.cs new file mode 100644 index 0000000..a2c905f --- /dev/null +++ b/IRaCIS.Core.API/Filter/WebApiExceptionFilterAttribute.cs @@ -0,0 +1,69 @@ +using System; +using System.Net; +using System.Net.Http; +using System.Web.Http.Filters; +using IRaCIS.Common.Logger; +using IRaCIS.Common.Model; + +namespace IRaCIS.Api.Filter +{ + public class WebApiExceptionFilterAttribute : ExceptionFilterAttribute + { + private ILogger _logger; + + public WebApiExceptionFilterAttribute() + { + _logger = new NLogLogger(); + } + + + + //public override void OnException(ExceptionContext context) + public override void OnException(HttpActionExecutedContext context) + { + string controllerName = context.ActionContext.ControllerContext.ControllerDescriptor.ControllerName; + string actionName = context.ActionContext.ActionDescriptor.ActionName; + + _logger.Error("controller=" + controllerName + " action=" + actionName + " " + context.Exception.Message); + + + if (context.Exception is NotImplementedException) + { + context.Response = new HttpResponseMessage(HttpStatusCode.NotImplemented); + } + else if (context.Exception is CommonException) + { + HttpResponseMessage msg = new HttpResponseMessage(HttpStatusCode.InternalServerError) + { + Content = new StringContent(context.Exception.Message), + }; + context.Response = msg; + + } + else if (context.Exception is TimeoutException) + { + context.Response = new HttpResponseMessage(HttpStatusCode.RequestTimeout); + } + else if (context.Exception is NullReferenceException) + { + HttpResponseMessage msg = new HttpResponseMessage(HttpStatusCode.InternalServerError) + { + Content = new StringContent("NullReferenceException"), + ReasonPhrase = "An unhandled exception was thrown .controller=" + controllerName + " action=" + actionName + }; + context.Response = msg; + } + else + { + HttpResponseMessage msg = new HttpResponseMessage(HttpStatusCode.InternalServerError) + { + Content = new StringContent(context.Exception.Message), + //ReasonPhrase = "An unhandled exception was thrown ." + }; + context.Response = msg; + } + + base.OnException(context); + } + } +} \ No newline at end of file diff --git a/IRaCIS.Core.API/IRaCIS.Core.API.csproj b/IRaCIS.Core.API/IRaCIS.Core.API.csproj new file mode 100644 index 0000000..6bbe318 --- /dev/null +++ b/IRaCIS.Core.API/IRaCIS.Core.API.csproj @@ -0,0 +1,82 @@ + + + + netcoreapp3.1 + false + + + + bin\Debug\IRaCIS.Core.API.xml + 1701;1702;1591; + ..\bin + + + + bin\Release\IRaCIS.Core.API.xml + bin\Release\ + 1701;1702;1591 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PreserveNewest + + + + + + + diff --git a/IRaCIS.Core.API/IRaCIS.Core.API.xml b/IRaCIS.Core.API/IRaCIS.Core.API.xml new file mode 100644 index 0000000..fddb40b --- /dev/null +++ b/IRaCIS.Core.API/IRaCIS.Core.API.xml @@ -0,0 +1,1060 @@ + + + + IRaCIS.Core.API + + + + + 颁发者 + + + + + 接收者 + + + + + 令牌密码 + + + + + 过期时间 + + + + + 签名 + + + + + 入组具体流程各个医生列表信息、和提交动作 + + + + 为项目筛选医生 提交 【select】 + 项目Id + 医生Id数组 + + + + 提交CRO列表 【Submit】 + 项目Id + 医生Id列表 + + + + + 入组名单确认 提交【 Approve】 + 项目Id + 医生Id列表 + + + + + + 后台确认医生入组 【Confirm】 + + + + + 筛选医生列表 [AUTH] + + + + + 根据状态获取医生列表,入组 相关接口 (提交CRO-1) CRO确认-4 + + + + + 获取项目下医生入组状态列表[Confirmation] + + + + + 入组之后 工作量维护 + + + + + 查询某个医生是否在某天有某个项目的工作量数据,处理添加来自医生自己的工作量数据 + + + + 查询项目入组医生的工作量统计信息 + + + + 获取医生工作量(带有填充数据) + + + + + + + 获取来自医生端的工作量列表 详情 + + + + + + + 添加或更新工作量[AUTH] + + + + + + + 获取响应内容 + + + + + + + 创建属性 + + 类型 + 序列化成员 + + + + + 构造函数 + + + + + + + 获取Value + + + + + + + + 设置Value + + + + + + + 上传文件[FileUpload] + + 附件类型 + 医生Id + 返回文件信息 + + + + 上传文件( 不是医生个人的文件)[FileUpload] + 例如:阅片章程等 + + 文件类型 + + + + + 写文件导到磁盘 + + 流 + 文件保存路径 + + + + + 下载多个医生的所有附件 + + + + + + + 下载医生官方简历 + + + + + + + 下载指定医生的指定附件 + + 医生Id + 要下载的附件Id + + + + + 医生文档关联关系维护 + + + + + 添加多个记录 + + + + + + + 删除记录 + + + + + + + 根据医生Id 和 附件类型,获取记录 + + 医生Id + 附件类型 + + + + + 获取单个医生的多种证书附件 + + 医生Id + 类型数组 + + + + + 根据医生Id获取医生附件 + + 医生Id + + + + + 将简历设置为官方简历 + + + + + + + + 医生基本信息 、工作信息 专业信息、审核状态 + + + + + 分页获取医生列表 (带查询条件) + + + + + 详情、编辑-获取 医生基本信息 BasicInfo + + ReviewerID + + + + + Get Statement of Work list.[New] + + + + + + + Get Ack Statement of Work[New] + + + + + + + 添加/更新 医生基本信息 BasicInfo + + + + + 详情、编辑-获取医生工作信息 Employment + + + + + + 更新-医生工作信息 WorkInfo + + + 获取医生专业信息 + + + 更新专业信息 + + + 获取医生审核状态 + + + + 审核简历状态 + + 复审状态ReviewStatus 0-未复审,1-复审通过,2-未通过 + + + + + 获取医生入组信息 正在提交的数量 已同意入组项目个数 正在读的 + + + + + 获取医生详情 + + 医生Id + + + + + 医生教育经历、继续学习经历 + + + + + 根据医生Id获取医生教育经历和继续学习经历列表 + + + + + 新增医生教育经历 + + + + + + + 删除医生教育经历 + + 医生Id + + + + 添加/更新医生继续学习经历 + + + + 删除医生继续学习经历 + + 医生Id + + + + + 医生科研信息 + + + + + 查询-医生科学研究信息 + + 医生Id + + + + 添加或跟新医生 科研信息 + + + + 医生临床试验经历 + + + + + 根据医生Id,获取临床试验经历 界面所有数据 + + + + 添加或更新医生临床经验列表项 + + + + 更新-GCP和其他临床经验 + + + + + + + 更新其他技能经验 + + + + + 删除临床经验 + + + + + 医生休假安排 + + + + + 添加休假时间段 + + Status不传 + + + + + 删除休假时间段 + + 记录Id + + + + + 获取休假时间段列表 + + + + + + Financial 支撑信息---汇率 + + + + + 添加或更新汇率(会触发没有对锁定的费用计算) + + + + + 分页获取汇率列表 + + + + + 根据记录Id,删除汇率记录 + + 汇率记录Id + + + + Financial 支撑信息---医生月度调整 + + + + + 获取费用调整列表 + + + + + 添加或更新费用调整[AUTH] + + + + + 删除费用调整记录 + + + + + 获取医生列表 + + + + + Financial 支撑信息---职称付费价格 + + + + + 添加或更新 职称单价[AUTH] + + + + + 获取职称单价列表 + + + + + 删除职称单价记录 + + + + + 获取职称字典数据 + + + + + Financial 支撑信息---工作量奖励标准 + + + + + 批量更新奖励费用[AUTH] + + + + + 分页获取奖励单价列表 + + + + + 费用查询(月度付费、月度付费明细、历史范围付费、历史范围付费明细、收入、收入支出分析) + + + + + 计算医生月度费用,并将计算的结果存入费用表 + + + + + Financials /Monthly Payment 列表查询接口 + + + + + Financials /MonthlyPaymentDetail 详情查询接口 + + + + + 锁定医生费用,锁定后,无法变更该医生对应月份的费用和工作量[New] + + + + + Financials / Payment History 列表查询接口(已经支付锁定的数据,包含调整的)[New] + + + + + Financials / Payment History 详情接口[New] + + + + + Revenues列表接口,收入统计[New] 0是Detail 1是按照项目 2是按照人 3按照月份 + + + + + 收入支出分析接口,按照医生维度分析统计 + + + + + 收入支出分析接口,按照项目维度分析统计 + + + + + Financial 支撑信息---医生付费信息及支付标准配置 + + + + + 添加或更新(替换)医生支付展信息[AUTH] + + + + + 获取医生支付信息列表 + + + + + 根据医生Id获取支付信息 + + 医生Id + + + + + Financial 支撑信息---项目费用 + + + + + 保存(替换)项目支付价格信息(会触发没有被锁定的费用计算)[AUTH] + + + + + 更新项目SOW 协议 [AUTH] + + + + + + + 删除项目SOW [AUTH] + + + + + + + 获取项目支付价格信息列表 + + + + + Financial 支撑信息---项目收入费用 + + + + + 保存(替换)项目费用收入单价信息[New] + + + + + + + 获取项目收入费用信息列表[New] + + + + + + + 影像信息 + + + + + 添加影像[New] + + + + + + + 删除影像记录[New] + + + + + + + 分页获取影像[New] + + 项目Id必填,State -0,查询所有状态,1-归档完成,2-质询中,3-都片中,4-复审中,5-通过复审 + + + + 分页获取CRO列表 + + + 获取所有CRO列表,可根据名称搜索[AUTH] + + + 添加CRO[AUTH] + + + 删除CRO + + + 获取所有医院列表 + + + 分页获取医院信息列表 + + + 添加医院信息 + + + 删除医院信息 + + + + 机构列表 + + + + 根据用户类型或机构类型,获取供选择的机构列表[New] + + + 分页获取研究中心列表 + + + 获取研究中心列表[New] + + + 添加研究中心[AUTH] + + + 删除研究中心[Auth] + + + 分页获取申办方列表 + + + 获取所有申办方列表 下拉框 + + + 添加或更新申办方信息 + + + 删除申办方信息 + + + + 数据字典-基础数据维护 + + + + + 获取项目多选字典 + + Title、Department、Rank、Position、ReadingType、Subspeciality Sponsor CROCompany ReadingStandard ReviewMode ReviewType ProjectState + + + + + 获取所有字典数据 + + + + + 获取下拉框数据 + + + + + + 获取下拉框某个keyName的列表 + + + + + 添加字典 项 + + + + 根据Id 删除字典数据 + + + + + + + 获取字典Tree + + + + + 查询系统日志信息 + + + 获取完整菜单功能树形列表 + + + 在某个父节点下面 新增子菜单 + + + 根据Id删除节点 + + + + 获取某角色 菜单树 勾选情况 和 功能勾选情况 + + + + + + + 更新角色拥有的菜单 只传递操作的项 + + + + + + + 删除消息 + + 消息Id + + + + + 分页获取系统消息 + + 医生Id + 分页大小 + 也索引 + + + + + 将消息标记已读 + + + + + + 添加角色 + + + 删除角色 + + + 分页获取角色列表 + + + 获取用户角色列表 + + + 更新用户角色 + + + + 通过邮箱或者手机 发送验证码 + + + + + + + + 通过验证码设置新密码 + + + + + + 系统用户登录接口[New] + + + 分页获取用户列表[New] + + + 更新用户状态(1 可用 0 禁用)[New] + + + 修改密码,当前支持旧密码修改密码,手机及邮箱验证码后续支持[New] + + + 根据用户Id,获取用户角色列表和当前登录用户的最大权限级别[New][AUTH] + + + 添加用户[New][AUTH] + + + 更新用户信息[New][AUTH] + + + 根据用户Id获取用户详细信息[New] + + + 获取所有用户列表 + + + 获取当前用户是否有复审权限和编辑权限[New][AUTH] + + + 后台重置密码为123456[New] + + + + Dashboard统计、全局工作量统计、入组两个维度统计(按照项目、按照人) + + + + 根据项目和医生,分页获取工作量统计[New] + + + 项目入组 医生维度统计[New] + + + 读片数分类统计[New] + + + 获取最近几个月份的数据[New] + + + 读片数量排行前几的数据[New] + + + 按Rank统计Reviewer 数量[New] + + + 最近几个季度入组人次[New] type==0 按照月份 + + + 参与项目数排行 [New] + + + 最新工作量 (已确定的)[New] + + + + 临床受试者 + + + + + 添加或更新受试者信息[New][AUTH] + + state:1-访视中,2-出组。0-全部 + + + + 删除受试者[New] + + + 分页获取受试者列表[New] + /// state:1-访视中,2-出组。0-全部 + + + + 影像获取规范 + + + + + 添加或更新影像采集规范[New][AUTH] + + + + + + 删除采集规范[New] + + + 分页获取影像采集规范[New] + + + + 项目基本信息维护 + + + + 分页获取临床实验项目列表(查询条件) + 查询参数 + + + + 查询项目基本信息 + 项目Id + + + + 查询项目基本信息 和项目最大状态, + 项目Id + + + + 查询项目加急状态 + 项目Id + + + + + 根据项目状态获取医生项目列表[New] + + 5-Submitted,8-Approved,10-Reading + + + + 添加实验项目-返回新增Id[AUTH] + + 新记录Id + + + + 手动更新项目状态 + + 项目Id + 状态值 + + + + 删除临床项目 + 临床试验项目Id + + + + 保存协议- ack Sow [AUTH] + + + + + 删除协议 + + + + + 项目运维人员 、研究中心CRC 配置 + + + + + 获取项目运维人员列表[New] + + 项目Id必须传 + + + + + 获取可用选择用户,用于给项目添加运维人员时的选择列表[New] + + + + + 添加或更新运维人员[New] + + + 删除运维人员[New] + + + 获取负责研究中心CRC列表 + + + 添加或更新CRC人员 + + + 删除CRC人员 + + + + 访视计划 + + + + 分页获取项目访视计划[New] + + + 根据项目Id,获取项目访视计划(不分页)[New] + + + 添加或更新运维人员[New] + + + 删除项目访视计划[New] + + + + 访视点 + + + + 根据项目Id,受试者Id,获取项目访视点(不分页)[New] + + + 添加或更新访视点[New] + + + 删除项目访视点[New] + + + diff --git a/IRaCIS.Core.API/NLog.config b/IRaCIS.Core.API/NLog.config new file mode 100644 index 0000000..9f00f0e --- /dev/null +++ b/IRaCIS.Core.API/NLog.config @@ -0,0 +1,22 @@ + + + + + + + + + + \ No newline at end of file diff --git a/IRaCIS.Core.API/Program.cs b/IRaCIS.Core.API/Program.cs new file mode 100644 index 0000000..3144ac3 --- /dev/null +++ b/IRaCIS.Core.API/Program.cs @@ -0,0 +1,58 @@ +using System; +using Autofac.Extensions.DependencyInjection; +using Dicom.Imaging; +using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Logging; +using NLog.Web; + +namespace IRaCIS.Core.API +{ + public class Program + { + public static void Main(string[] args) + { + ImageManager.SetImplementation(WinFormsImageManager.Instance); + var logger = NLog.Web.NLogBuilder.ConfigureNLog("nlog.config").GetCurrentClassLogger(); + try + { + logger.Debug("init main"); + CreateHostBuilder(args).Build().Run(); + } + catch (Exception exception) + { + //NLog: catch setup errors + logger.Error(exception, "Stopped program because of exception"); + throw; + } + finally + { + // Ensure to flush and stop internal timers/threads before application-exit (Avoid segmentation fault on Linux) + NLog.LogManager.Shutdown(); + } + } + + public static IHostBuilder CreateHostBuilder(string[] args) => + Host.CreateDefaultBuilder(args) + .ConfigureWebHostDefaults(webBuilder => + { + webBuilder.ConfigureKestrel((context, options) => + { + //Ӧ÷KestrelΪ1GB // if don't set default value is: 30 MB + options.Limits.MaxRequestBodySize = long.MaxValue; + options.Limits.KeepAliveTimeout = TimeSpan.FromMinutes(30); + options.Limits.RequestHeadersTimeout = TimeSpan.FromMinutes(30); + }); + webBuilder.UseStartup(); + })//ʹAutofac + .UseServiceProviderFactory(new AutofacServiceProviderFactory()). + ConfigureLogging(logging => + { + logging.ClearProviders(); + logging.SetMinimumLevel(Microsoft.Extensions.Logging.LogLevel.Trace); + }) + .UseNLog() + ; // NLog: Setup NLog for Dependency injection; + + } +} diff --git a/IRaCIS.Core.API/Properties/launchSettings.json b/IRaCIS.Core.API/Properties/launchSettings.json new file mode 100644 index 0000000..ecf79bd --- /dev/null +++ b/IRaCIS.Core.API/Properties/launchSettings.json @@ -0,0 +1,28 @@ +{ + "iisSettings": { + "windowsAuthentication": false, + "anonymousAuthentication": true, + "iisExpress": { + "applicationUrl": "http://localhost:57302", + "sslPort": 0 + } + }, + "$schema": "http://json.schemastore.org/launchsettings.json", + "profiles": { + "IIS Express": { + "commandName": "IISExpress", + "launchBrowser": true, + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + }, + "IRaCIS.Core.API": { + "commandName": "Project", + "launchBrowser": true, + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + }, + "applicationUrl": "http://localhost:5000" + } + } +} \ No newline at end of file diff --git a/IRaCIS.Core.API/Startup.cs b/IRaCIS.Core.API/Startup.cs new file mode 100644 index 0000000..7a64c53 --- /dev/null +++ b/IRaCIS.Core.API/Startup.cs @@ -0,0 +1,161 @@ +using Autofac; +using EasyCaching.Core; +using EasyCaching.Interceptor.Castle; +using IRaCIS.Api.Filter; +using IRaCIS.Application; +using IRaCIS.Application.Interfaces; +using IRaCIS.Application.Services; +using IRaCIS.Core.API.Auth; +using IRaCIS.Core.Domain.Share; +using IRaCIS.WX.CoreApi.Utility; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Http.Features; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using Newtonsoft.Json; +using System; +using System.Reflection; + +namespace IRaCIS.Core.API +{ + public class Startup + { + public Startup(IConfiguration configuration) + { + Configuration = configuration; + + } + + public IConfiguration Configuration { get; } + + //// ConfigureContainer is where you can register things directly + //// with Autofac. This runs after ConfigureServices so the things + //// here will override registrations made in ConfigureServices. + //// Don't build the container; that gets done for you by the factory. + // for castle + public void ConfigureContainer(ContainerBuilder containerBuilder) + { + containerBuilder.RegisterType().As(); + + containerBuilder.RegisterType().As().SingleInstance(); + + Assembly domain = Assembly.Load("IRaCIS.Core.Domain"); + containerBuilder.RegisterAssemblyTypes(domain).AsImplementedInterfaces(); + + Assembly domainShare = Assembly.Load("IRaCIS.Core.Domain.Share"); + containerBuilder.RegisterAssemblyTypes(domainShare).AsImplementedInterfaces(); + + Assembly infrastructure = Assembly.Load("IRaCIS.Core.Infra.EFCore"); + containerBuilder.RegisterAssemblyTypes(infrastructure).AsImplementedInterfaces(); + + Assembly application = Assembly.LoadFrom(AppDomain.CurrentDomain.BaseDirectory + "IRaCIS.Core.Application.dll"); + containerBuilder.RegisterAssemblyTypes(application).AsImplementedInterfaces(); + + //containerBuilder.RegisterModule(); + + containerBuilder.ConfigureCastleInterceptor(); + } + + // This method gets called by the runtime. Use this method to add services to the container. + public void ConfigureServices(IServiceCollection services) + { + + services.AddControllers().AddNewtonsoftJson(options => + { + // ѭ + options.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Serialize; + // ʹշ + options.SerializerSettings.ContractResolver = new NullToEmptyStringResolver(); //new DefaultContractResolver();// new NullToEmptyStringResolver(); + // ʱʽ + options.SerializerSettings.DateFormatString = "yyyy-MM-dd HH:mm:ss"; + }); + + services.Configure(options => + { + options.ValueCountLimit = int.MaxValue; + options.ValueLengthLimit = int.MaxValue; + }); + if (SystemConfig.OpenLog) + { + services.AddControllers(options => + { + options.Filters.Add(); + }); + } + + services.AddLogging(); + + #region EasyCaching + + services.AddEasyCaching(options => + { + options.UseInMemory(); + }); + services.ConfigureCastleInterceptor(options => options.CacheProviderName = EasyCachingConstValue.DefaultInMemoryName); + + #endregion + + + //MiniProfilerConfigure.ConfigureMiniProfiler(services); + + AuthConfigure.ConfigureAuth(services, Configuration); + + AutoMapperConfigure.ConfigureSwagger(services); + EFConfigure.ConfigureEF(services, Configuration); + SwaggerConfigure.ConfigureSwagger(services); + + //services.Configure(options => + //{ + // options.MaxRequestBodySize = int.MaxValue; + //}); + + } + + // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. + public void Configure(IApplicationBuilder app, IWebHostEnvironment env) + { + if (env.IsDevelopment()) + { + ////ܷھ̬ + //app.UseSwaggerUI(options => + //{ + // options.IndexStream = () => + // GetType().GetTypeInfo().Assembly + // .GetManifestResourceStream("IRaCIS.Core.API.index.html"); + //}); + //app.UseMiniProfiler(); + } + app.UseDeveloperExceptionPage(); + SwaggerConfigure.Configure(app, env); + + app.UseStaticFiles(); + + //app.UseStaticFiles(new StaticFileOptions() + //{ + // FileProvider = new PhysicalFileProvider( + // Path.Combine(Directory.GetCurrentDirectory(), @"UploadFile")), + // RequestPath = new PathString("/UploadFile") + //}); + + //app.UseMiddleware(); + + + //app.Use(async (context, next) => + //{ + // context.Request.EnableBuffering(); + // await next(); + //}); + + app.UseRouting(); + app.UseAuthentication(); + app.UseAuthorization(); + + app.UseEndpoints(endpoints => + { + endpoints.MapControllers(); + }); + } + } +} diff --git a/IRaCIS.Core.API/Utility/FileHelpers.cs b/IRaCIS.Core.API/Utility/FileHelpers.cs new file mode 100644 index 0000000..a77ac04 --- /dev/null +++ b/IRaCIS.Core.API/Utility/FileHelpers.cs @@ -0,0 +1,270 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.IO; +using System.Linq; +using System.Net; +using System.Reflection; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc.ModelBinding; +using Microsoft.AspNetCore.WebUtilities; +using Microsoft.Net.Http.Headers; + +namespace IRaCIS.Core.API.Utility +{ + public static class FileHelpers + { + private static readonly byte[] _allowedChars = { }; + // For more file signatures, see the File Signatures Database (https://www.filesignatures.net/) + // and the official specifications for the file types you wish to add. + private static readonly Dictionary> _fileSignature = new Dictionary> + { + { ".gif", new List { new byte[] { 0x47, 0x49, 0x46, 0x38 } } }, + { ".png", new List { new byte[] { 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A } } }, + { ".jpeg", new List + { + new byte[] { 0xFF, 0xD8, 0xFF, 0xE0 }, + new byte[] { 0xFF, 0xD8, 0xFF, 0xE2 }, + new byte[] { 0xFF, 0xD8, 0xFF, 0xE3 }, + } + }, + { ".jpg", new List + { + new byte[] { 0xFF, 0xD8, 0xFF, 0xE0 }, + new byte[] { 0xFF, 0xD8, 0xFF, 0xE1 }, + new byte[] { 0xFF, 0xD8, 0xFF, 0xE8 }, + } + }, + { ".zip", new List + { + new byte[] { 0x50, 0x4B, 0x03, 0x04 }, + new byte[] { 0x50, 0x4B, 0x4C, 0x49, 0x54, 0x45 }, + new byte[] { 0x50, 0x4B, 0x53, 0x70, 0x58 }, + new byte[] { 0x50, 0x4B, 0x05, 0x06 }, + new byte[] { 0x50, 0x4B, 0x07, 0x08 }, + new byte[] { 0x57, 0x69, 0x6E, 0x5A, 0x69, 0x70 }, + } + }, + }; + + // **WARNING!** + // In the following file processing methods, the file's content isn't scanned. + // In most production scenarios, an anti-virus/anti-malware scanner API is + // used on the file before making the file available to users or other + // systems. For more information, see the topic that accompanies this sample + // app. + + public static async Task ProcessFormFile(IFormFile formFile, + ModelStateDictionary modelState, string[] permittedExtensions, + long sizeLimit) + { + var fieldDisplayName = string.Empty; + + // Use reflection to obtain the display name for the model + // property associated with this IFormFile. If a display + // name isn't found, error messages simply won't show + // a display name. + MemberInfo property = + typeof(T).GetProperty( + formFile.Name.Substring(formFile.Name.IndexOf(".", + StringComparison.Ordinal) + 1)); + + if (property != null) + { + if (property.GetCustomAttribute(typeof(DisplayAttribute)) is + DisplayAttribute displayAttribute) + { + fieldDisplayName = $"{displayAttribute.Name} "; + } + } + + // Don't trust the file name sent by the client. To display + // the file name, HTML-encode the value. + var trustedFileNameForDisplay = WebUtility.HtmlEncode( + formFile.FileName); + + // Check the file length. This check doesn't catch files that only have + // a BOM as their content. + if (formFile.Length == 0) + { + modelState.AddModelError(formFile.Name, + $"{fieldDisplayName}({trustedFileNameForDisplay}) is empty."); + + return new byte[0]; + } + + if (formFile.Length > sizeLimit) + { + var megabyteSizeLimit = sizeLimit / 1048576; + modelState.AddModelError(formFile.Name, + $"{fieldDisplayName}({trustedFileNameForDisplay}) exceeds " + + $"{megabyteSizeLimit:N1} MB."); + + return new byte[0]; + } + + try + { + using (var memoryStream = new MemoryStream()) + { + await formFile.CopyToAsync(memoryStream); + + // Check the content length in case the file's only + // content was a BOM and the content is actually + // empty after removing the BOM. + if (memoryStream.Length == 0) + { + modelState.AddModelError(formFile.Name, + $"{fieldDisplayName}({trustedFileNameForDisplay}) is empty."); + } + + if (!IsValidFileExtensionAndSignature( + formFile.FileName, memoryStream, permittedExtensions)) + { + modelState.AddModelError(formFile.Name, + $"{fieldDisplayName}({trustedFileNameForDisplay}) file " + + "type isn't permitted or the file's signature " + + "doesn't match the file's extension."); + } + else + { + return memoryStream.ToArray(); + } + } + } + catch (Exception ex) + { + modelState.AddModelError(formFile.Name, + $"{fieldDisplayName}({trustedFileNameForDisplay}) upload failed. " + + $"Please contact the Help Desk for support. Error: {ex.HResult}"); + } + return new byte[0]; + } + + public static async Task ProcessStreamedFile( + MultipartSection section, ContentDispositionHeaderValue contentDisposition, + ModelStateDictionary modelState, string[] permittedExtensions, long sizeLimit) + { + try + { + using (var memoryStream = new MemoryStream()) + { + await section.Body.CopyToAsync(memoryStream); + + // Check if the file is empty or exceeds the size limit. + if (memoryStream.Length == 0) + { + modelState.AddModelError("File", "The file is empty."); + } + else if (memoryStream.Length > sizeLimit) + { + var megabyteSizeLimit = sizeLimit / 1048576; + modelState.AddModelError("File", + $"The file exceeds {megabyteSizeLimit:N1} MB."); + } + else if (!IsValidFileExtensionAndSignature( + contentDisposition.FileName.Value, memoryStream, + permittedExtensions)) + { + modelState.AddModelError("File", + "The file type isn't permitted or the file's " + + "signature doesn't match the file's extension."); + } + else + { + return memoryStream.ToArray(); + } + } + } + catch (Exception ex) + { + modelState.AddModelError("File", + "The upload failed. Please contact the Help Desk " + + $" for support. Error: {ex.HResult}"); + // Log the exception + } + + return new byte[0]; + } + + private static bool IsValidFileExtensionAndSignature(string fileName, Stream data, string[] permittedExtensions) + { + if (string.IsNullOrEmpty(fileName) || data == null || data.Length == 0) + { + return false; + } + + var ext = Path.GetExtension(fileName).ToLowerInvariant(); + + if (string.IsNullOrEmpty(ext) || !permittedExtensions.Contains(ext)) + { + return false; + } + + data.Position = 0; + + using (var reader = new BinaryReader(data)) + { + if (ext.Equals(".txt") || ext.Equals(".csv") || ext.Equals(".prn")) + { + if (_allowedChars.Length == 0) + { + // Limits characters to ASCII encoding. + for (var i = 0; i < data.Length; i++) + { + if (reader.ReadByte() > sbyte.MaxValue) + { + return false; + } + } + } + else + { + // Limits characters to ASCII encoding and + // values of the _allowedChars array. + for (var i = 0; i < data.Length; i++) + { + var b = reader.ReadByte(); + if (b > sbyte.MaxValue || + !_allowedChars.Contains(b)) + { + return false; + } + } + } + + return true; + } + + // Uncomment the following code block if you must permit + // files whose signature isn't provided in the _fileSignature + // dictionary. We recommend that you add file signatures + // for files (when possible) for all file types you intend + // to allow on the system and perform the file signature + // check. + + //if (!_fileSignature.ContainsKey(ext)) + //{ + // return true; + //} + + + // File signature check + // -------------------- + // With the file signatures provided in the _fileSignature + // dictionary, the following code tests the input content's + // file signature. + + //var signatures = _fileSignature[ext]; + //var headerBytes = reader.ReadBytes(signatures.Max(m => m.Length)); + + //return signatures.Any(signature => + // headerBytes.Take(signature.Length).SequenceEqual(signature)); + + //test + return true; + } + } + } +} diff --git a/IRaCIS.Core.API/Utility/MultipartRequestHelper.cs b/IRaCIS.Core.API/Utility/MultipartRequestHelper.cs new file mode 100644 index 0000000..6be5c7b --- /dev/null +++ b/IRaCIS.Core.API/Utility/MultipartRequestHelper.cs @@ -0,0 +1,53 @@ +using System; +using System.IO; +using Microsoft.Net.Http.Headers; + +namespace IRaCIS.Core.API.Utility +{ + public static class MultipartRequestHelper + { + // Content-Type: multipart/form-data; boundary="----WebKitFormBoundarymx2fSWqWSd0OxQqq" + // The spec at https://tools.ietf.org/html/rfc2046#section-5.1 states that 70 characters is a reasonable limit. + public static string GetBoundary(MediaTypeHeaderValue contentType, int lengthLimit) + { + var boundary = HeaderUtilities.RemoveQuotes(contentType.Boundary).Value; + + if (string.IsNullOrWhiteSpace(boundary)) + { + throw new InvalidDataException("Missing content-type boundary."); + } + + if (boundary.Length > lengthLimit) + { + throw new InvalidDataException( + $"Multipart boundary length limit {lengthLimit} exceeded."); + } + + return boundary; + } + + public static bool IsMultipartContentType(string contentType) + { + return !string.IsNullOrEmpty(contentType) + && contentType.IndexOf("multipart/", StringComparison.OrdinalIgnoreCase) >= 0; + } + + public static bool HasFormDataContentDisposition(ContentDispositionHeaderValue contentDisposition) + { + // Content-Disposition: form-data; name="key"; + return contentDisposition != null + && contentDisposition.DispositionType.Equals("form-data") + && string.IsNullOrEmpty(contentDisposition.FileName.Value) + && string.IsNullOrEmpty(contentDisposition.FileNameStar.Value); + } + + public static bool HasFileContentDisposition(ContentDispositionHeaderValue contentDisposition) + { + // Content-Disposition: form-data; name="myfile1"; filename="Misc 002.jpg" + return contentDisposition != null + && contentDisposition.DispositionType.Equals("form-data") + && (!string.IsNullOrEmpty(contentDisposition.FileName.Value) + || !string.IsNullOrEmpty(contentDisposition.FileNameStar.Value)); + } + } +} diff --git a/IRaCIS.Core.API/Utility/NullToEmptyStringResolver.cs b/IRaCIS.Core.API/Utility/NullToEmptyStringResolver.cs new file mode 100644 index 0000000..6b01306 --- /dev/null +++ b/IRaCIS.Core.API/Utility/NullToEmptyStringResolver.cs @@ -0,0 +1,54 @@ +using Newtonsoft.Json; +using Newtonsoft.Json.Serialization; +using System; +using System.Collections.Generic; +using System.Linq; + +namespace IRaCIS.Core.API +{ + public class NullToEmptyStringResolver : DefaultContractResolver + { + /// + /// 创建属性 + /// + /// 类型 + /// 序列化成员 + /// + //protected override IList CreateProperties(Type type, MemberSerialization memberSerialization) + //{ + // IList properties = base.CreateProperties(type, memberSerialization); + + + // foreach (var jsonProperty in properties) + // { + // jsonProperty.DefaultValue = new NullToEmptyStringValueProvider(jsonProperty); + // } + + // return properties; + + //} + + protected override IList CreateProperties(Type type, MemberSerialization memberSerialization) + { + IList properties = base.CreateProperties(type, memberSerialization); + + var list= type.GetProperties() + .Select(p => + { + var jp = base.CreateProperty(p, memberSerialization); + jp.ValueProvider = new NullToEmptyStringValueProvider(p); + return jp; + }).ToList(); + + var uu = list.Select(t => t.PropertyName).ToList(); + + //获取复杂对象属性 + properties = properties.TakeWhile(t => !uu.Contains(t.PropertyName)).ToList(); + + list.AddRange(properties); + return list; + } + + + } +} diff --git a/IRaCIS.Core.API/Utility/NullToEmptyStringValueProvider.cs b/IRaCIS.Core.API/Utility/NullToEmptyStringValueProvider.cs new file mode 100644 index 0000000..24df517 --- /dev/null +++ b/IRaCIS.Core.API/Utility/NullToEmptyStringValueProvider.cs @@ -0,0 +1,75 @@ +using System; +using System.Reflection; +using Newtonsoft.Json.Serialization; + +namespace IRaCIS.Core.API +{ + //public class NullToEmptyStringValueProvider : IValueProvider + //{ + // private readonly JsonProperty _memberInfo; + + // /// + // /// 构造函数 + // /// + // /// + // public NullToEmptyStringValueProvider(JsonProperty memberInfo) + // { + // _memberInfo = memberInfo; + // } + + // /// + // /// 获取Value + // /// + // public object GetValue(object target) + // { + // var result = _memberInfo.DefaultValue; + // if (_memberInfo.PropertyType == typeof(string) && result == null) + // { + // result = string.Empty; + // } + // else if (_memberInfo.PropertyType == typeof(double?) && result == null) + // { + // result = 0; + // } + // else if (_memberInfo.PropertyType == typeof(double?) && result == null) + // { + // result = 0; + // } + + // return result; + // } + + // /// + // /// 设置Value + // /// + // public void SetValue(object target, object value) + // { + // //_memberInfo.SetValue(target, value); + // _memberInfo.DefaultValue = value; + // } + //} + + public class NullToEmptyStringValueProvider : Newtonsoft.Json.Serialization.IValueProvider + { + PropertyInfo _MemberInfo; + public NullToEmptyStringValueProvider(PropertyInfo memberInfo) + { + _MemberInfo = memberInfo; + } + public object GetValue(object target) + { + object result = _MemberInfo.GetValue(target); + if (_MemberInfo.PropertyType == typeof(string) && result == null) result = ""; + else if (_MemberInfo.PropertyType == typeof(String[]) && result == null) result = new string[] { }; + else if (_MemberInfo.PropertyType == typeof(Nullable) && result == null) result = 0; + else if (_MemberInfo.PropertyType == typeof(Nullable) && result == null) result = 0.00M; + + return result; + } + public void SetValue(object target, object value) + { + _MemberInfo.SetValue(target, value); + } + } + +} diff --git a/IRaCIS.Core.API/appsettings.Development.json b/IRaCIS.Core.API/appsettings.Development.json new file mode 100644 index 0000000..8983e0f --- /dev/null +++ b/IRaCIS.Core.API/appsettings.Development.json @@ -0,0 +1,9 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft": "Warning", + "Microsoft.Hosting.Lifetime": "Information" + } + } +} diff --git a/IRaCIS.Core.API/appsettings.json b/IRaCIS.Core.API/appsettings.json new file mode 100644 index 0000000..439e104 --- /dev/null +++ b/IRaCIS.Core.API/appsettings.json @@ -0,0 +1,47 @@ +{ + "ConnectionStrings": { + "RemoteNew": "Server=123.56.181.144,14333\\MSSQLExpress14;Database=IRaCIS_B;User ID=sa;Password=dev123456DEV;", + "hang": "Server=ZHOU;Database=IRaCIS;User ID=sa;Password=sa123456;" + //"RemoteTest": "Server=123.56.181.144,14333\\MSSQLExpress14;Database=IRaCIS_B;User ID=sa;Password=dev123456DEV;" + }, + "Logging": { + "IncludeScopes": false, + "LogLevel": { + "Default": "Trace", + "Microsoft": "Warning", + "Microsoft.Hosting.Lifetime": "Information" + } + }, + "AllowedHosts": "*", + "JwtSetting": { + "SecurityKey": "3e6dbfa227234a03977a2f421bdb7f4f", // Կ + "Issuer": "jwtIssuertest1", // ䷢ + "Audience": "jwtAudiencetest1", // + "TokenExpireDays": "7" // ʱ䣨7day + }, + "RootUrl": "http://123.56.181.144:8000", + "CodePrefix": "RE", + "UserCodePrefix": "U", + "VisitPlanNumPrefix": "VT", + "StoredFilesPath": "D:\\Upload", //ýڵûõ + "DicomFileArchivedPath": "D:\\Upload", // + "Share": false, // + "FileSizeLimit": 1073741824, + "LoginExpiredTimeSpan": "15", // Minute + "OpenLog": true, + "AddClinicalInfo": true, + "easycaching": { + "inmemory": { + "MaxRdSecond": 120, + "EnableLogging": false, + "LockMs": 5000, + "SleepMs": 300, + "DBConfig": { + "SizeLimit": 10000, + "ExpirationScanFrequency": 60, + "EnableReadDeepClone": true, + "EnableWriteDeepClone": false + } + } + } +} \ No newline at end of file diff --git a/IRaCIS.Core.API/index.html b/IRaCIS.Core.API/index.html new file mode 100644 index 0000000..de15228 --- /dev/null +++ b/IRaCIS.Core.API/index.html @@ -0,0 +1,89 @@ + + + + + + + + + %(DocumentTitle) + + + + + %(HeadContent) + + + +
+ + + + + + + + + \ No newline at end of file diff --git a/IRaCIS.Core.API/web.config b/IRaCIS.Core.API/web.config new file mode 100644 index 0000000..cd48e31 --- /dev/null +++ b/IRaCIS.Core.API/web.config @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/IRaCIS.Core.Application.Contracts/AutoMapper/AutoMapperConfig.cs b/IRaCIS.Core.Application.Contracts/AutoMapper/AutoMapperConfig.cs new file mode 100644 index 0000000..61c8fa7 --- /dev/null +++ b/IRaCIS.Core.Application.Contracts/AutoMapper/AutoMapperConfig.cs @@ -0,0 +1,32 @@ +using AutoMapper; + +namespace IRaCIS.Core.Application.Contracts.AutoMapper +{ + public class AutoMapperConfig + { + public static void Config() + { + //Mapper.Initialize(cfg => + //{ + // cfg.AddProfile(); + // cfg.AddProfile(new ViewModelToDomainMappingProfile()); + // cfg.AddProfile(new LogicChangeMappingProfile()); + // cfg.ForAllMaps((a, b) => b.ForAllMembers(opt => opt.Condition((src, dest, sourceMember) => sourceMember != null))); + //}); + } + + public static MapperConfiguration RegisterMappings() + { + //创建AutoMapperConfiguration, 提供静态方法Configure,一次加载所有层中Profile定义 + //MapperConfiguration实例可以静态存储在一个静态字段中,也可以存储在一个依赖注入容器中。 一旦创建,不能更改/修改。 + + return new MapperConfiguration(cfg => + { + cfg.AddProfile(); + cfg.AddProfile(new ViewModelToDomainMappingProfile()); + cfg.AddProfile(new LogicChangeMappingProfile()); + cfg.ForAllMaps((a, b) => b.ForAllMembers(opt => opt.Condition((src, dest, sourceMember) => sourceMember != null))); + }); + } + } +} diff --git a/IRaCIS.Core.Application.Contracts/AutoMapper/DomainToViewModelMappingProfile.cs b/IRaCIS.Core.Application.Contracts/AutoMapper/DomainToViewModelMappingProfile.cs new file mode 100644 index 0000000..b912d74 --- /dev/null +++ b/IRaCIS.Core.Application.Contracts/AutoMapper/DomainToViewModelMappingProfile.cs @@ -0,0 +1,118 @@ +using AutoMapper; +using IRaCIS.Application.Interfaces; +using IRaCIS.Application.ViewModels; +using IRaCIS.Application.ViewModels.Pay; +using IRaCIS.Core.Application.Contracts.Dicom.DTO; +using IRaCIS.Core.Application.Contracts.DTO; +using IRaCIS.Core.Domain.Models; +using System.Linq; + +namespace IRaCIS.Core.Application.Contracts.AutoMapper +{ + public class DomainToViewModelMappingProfile : Profile + { + public DomainToViewModelMappingProfile() + { + #region Reviewer + + CreateMap(); + CreateMap(); + + CreateMap(); + CreateMap(); + CreateMap(); + CreateMap(); + CreateMap(); + CreateMap(); + + CreateMap(); + + CreateMap(); + CreateMap(); + + CreateMap(); + + #endregion + + #region Management + + CreateMap(); + CreateMap(); + CreateMap(); + CreateMap(); + + CreateMap(); + + #endregion + + #region institution + + CreateMap(); + CreateMap(); + CreateMap(); + CreateMap(); + CreateMap(); + CreateMap(); + + #endregion + + #region WrokLoad + + CreateMap(); + + #endregion + + CreateMap(); + + CreateMap(); + + #region finacial + + CreateMap(); + CreateMap(); + CreateMap(); + CreateMap(); + CreateMap(); + + CreateMap(); + CreateMap(); + + CreateMap (); + #endregion + + #region image + + CreateMap(); + CreateMap(); + CreateMap(); + + CreateMap(); + CreateMap(); + CreateMap(); + CreateMap(); + #endregion + + #region QA + CreateMap(); + CreateMap(); + + CreateMap(); + + + CreateMap(); + #endregion + CreateMap(); + CreateMap(); + CreateMap(); + CreateMap(); + + CreateMap() + .ForMember(t => t.TrialCode, u => u.MapFrom(t => t.Trial.Code)) + .ForMember(t => t.ReviewMode, u => u.MapFrom(t => t.Trial.ReviewMode.Value)) + .ForMember(t => t.Cro, u => u.MapFrom(t => t.Trial.CRO.CROName)) + .ForMember(t => t.Indication, u => u.MapFrom(t => t.Trial.Indication)) + .ForMember(t => t.Expedited, u => u.MapFrom(t => t.Trial.Expedited)) + .ForMember(t => t.DoctorsNames, u => u.MapFrom(t => string.Join(",", t.Trial.EnrollList.Select(x => x.Doctor.ChineseName)))); + } + } +} diff --git a/IRaCIS.Core.Application.Contracts/AutoMapper/LogicChangeMappingProfile.cs b/IRaCIS.Core.Application.Contracts/AutoMapper/LogicChangeMappingProfile.cs new file mode 100644 index 0000000..4e679c9 --- /dev/null +++ b/IRaCIS.Core.Application.Contracts/AutoMapper/LogicChangeMappingProfile.cs @@ -0,0 +1,42 @@ +using AutoMapper; +using IRaCIS.Application.ViewModels; +using IRaCIS.Application.ViewModels.Pay; +using IRaCIS.Core.Domain.Models; + +namespace IRaCIS.Core.Application.Contracts.AutoMapper +{ + public class LogicChangeMappingProfile : Profile + { + public LogicChangeMappingProfile() + { + + + //医生列表、项目显示列表模型转换 + CreateMap(); + + + CreateMap() + .ForMember(o => o.MessageTime, t => t.MapFrom(u => u.MessageTime.ToString())); + + + CreateMap() + .ForMember(o => o.InstitutionName, t => t.MapFrom(u => u.CROName)); + CreateMap() + .ForMember(o => o.InstitutionName, t => t.MapFrom(u => u.SponsorName)); + CreateMap() + .ForMember(o => o.InstitutionName, t => t.MapFrom(u => u.HospitalName)); + CreateMap() + .ForMember(o => o.InstitutionName, t => t.MapFrom(u => u.SiteName)); + + CreateMap() + .ForMember(t=>t.YearMonthDate, + u=>u.MapFrom(t=>t.YearMonth)) + .ForMember(t=>t.YearMonth, + u=>u.MapFrom(t=>t.YearMonth.ToString("yyyy-MM"))); + + CreateMap(); + + CreateMap(); + } + } +} \ No newline at end of file diff --git a/IRaCIS.Core.Application.Contracts/AutoMapper/ViewModelToDomainMappingProfile.cs b/IRaCIS.Core.Application.Contracts/AutoMapper/ViewModelToDomainMappingProfile.cs new file mode 100644 index 0000000..274a3f7 --- /dev/null +++ b/IRaCIS.Core.Application.Contracts/AutoMapper/ViewModelToDomainMappingProfile.cs @@ -0,0 +1,168 @@ +using AutoMapper; +using IRaCIS.Application.Interfaces; +using IRaCIS.Application.ViewModels; +using IRaCIS.Application.ViewModels.Pay; +using IRaCIS.Core.Application.Contracts.Dicom.DTO; +using IRaCIS.Core.Application.Contracts.DTO; +using IRaCIS.Core.Domain.Models; + +namespace IRaCIS.Core.Application.Contracts.AutoMapper +{ + public class ViewModelToDomainMappingProfile : Profile + { + public ViewModelToDomainMappingProfile() + { + + #region reviewer + + //基本信息 工作信息 添加时转换使用 + CreateMap(); + + //学习经历 添加时转换使用 + CreateMap(); + CreateMap(); + CreateMap(); + CreateMap(); + + //医生账户 + CreateMap(); + CreateMap(); + + CreateMap(); + + + CreateMap(); + + CreateMap(); + + #endregion + + + #region trial + + + //临床项目 + CreateMap(); + + #endregion + + + #region workLoad + + //工作量 + + + CreateMap(); + + #endregion + + + + CreateMap(); + + CreateMap(); + + CreateMap(); + + CreateMap(); + + + #region management + + CreateMap(); + + CreateMap(); + + CreateMap(); + + CreateMap(); + + //CreateMap(); + + #endregion + + #region institution + CreateMap(); + CreateMap(); + CreateMap(); + CreateMap(); + + + + //CreateMap(); + + //CreateMap(); + + //CreateMap(); + + + #endregion + + + + #region financial + CreateMap(); + CreateMap(); + + CreateMap(); + + CreateMap(); + + CreateMap(); + + CreateMap(); + CreateMap(); + + CreateMap(); + + CreateMap(); + + CreateMap(); + + + + + #endregion + + + + + #region image + + CreateMap(); + CreateMap(); + CreateMap(); + CreateMap(); + CreateMap(); + CreateMap(); + + CreateMap(); + + + + #endregion + + #region QA + CreateMap(); + + CreateMap(); + + CreateMap(); + + CreateMap(); + + CreateMap(); + + + + #endregion + + CreateMap(); + CreateMap(); + + CreateMap(); + + + } + } +} \ No newline at end of file diff --git a/IRaCIS.Core.Application.Contracts/CastleService.cs b/IRaCIS.Core.Application.Contracts/CastleService.cs new file mode 100644 index 0000000..f45da99 --- /dev/null +++ b/IRaCIS.Core.Application.Contracts/CastleService.cs @@ -0,0 +1,65 @@ +using EasyCaching.Core.Interceptor; +using IRaCIS.Application.ViewModels; +using IRaCIS.Core.Domain.Interfaces; +using IRaCIS.Core.Domain.Share; +using System; +using System.Linq; + +namespace IRaCIS.Core.Application +{ + public interface ICastleService + { + + [EasyCachingAble(Expiration = 10)] + DoctorBasicInfoDTO GetDoctorBasicInfo(Guid doctorId); + } + + public class CastleService : ICastleService + { + private readonly IDoctorRepository _doctorRepository; + + public CastleService(IDoctorRepository doctorRepository) + { + _doctorRepository = doctorRepository; + } + + public DoctorBasicInfoDTO GetDoctorBasicInfo(Guid doctorId) + { + var doctorQueryable = _doctorRepository + .Find(t => t.Id == doctorId) + .Select(doctor => new DoctorBasicInfoDTO() + { + Id = doctor.Id, + Code = doctor.Code, + ChineseName = doctor.ChineseName, + EMail = doctor.EMail, + FirstName = doctor.FirstName, + Introduction = doctor.Introduction, + LastName = doctor.LastName, + Phone = doctor.Phone, + Sex = doctor.Sex, + WeChat = doctor.WeChat, + TitleIds = doctor.DoctorDicList + .Where(t => t.KeyName == StaticData.Title).Select(t => t.DictionaryId).ToList() + }); + + var doctorBasicInfo = doctorQueryable.FirstOrDefault(); + + + return doctorBasicInfo; + } + + + } + //[ProtoContract] + //[System.Serializable] + public class Demo + { + //[ProtoMember(1)] + public int Id { get; set; } + //[ProtoMember(2)] + public string Name { get; set; } + //[ProtoMember(3)] + public System.DateTime CreateTime { get; set; } + } +} \ No newline at end of file diff --git a/IRaCIS.Core.Application.Contracts/Common/DTO/DictionaryViewModel.cs b/IRaCIS.Core.Application.Contracts/Common/DTO/DictionaryViewModel.cs new file mode 100644 index 0000000..a7f555a --- /dev/null +++ b/IRaCIS.Core.Application.Contracts/Common/DTO/DictionaryViewModel.cs @@ -0,0 +1,32 @@ +using System; +using System.Collections.Generic; +using IRaCIS.Core.Application.Contracts.RequestAndResponse; + +namespace IRaCIS.Application.ViewModels +{ + public class DicViewModelDTO + { + public Guid Id { get; set; } + public string KeyName { get; set; } + public string Value { get; set; } + public int ShowOrder { get; set; } + public string Type { get; set; } + } + + public class DicQueryDTO : PageInput + { + public string KeyName { get; set; } + } + + public class KeyNameType + { + public Guid KeyId { get; set; } + public string KeyName { get; set; } + public string Type { get; set; } + } + + public class DicResultDTO + { + public Dictionary> DicList = new Dictionary>(); + } +} diff --git a/IRaCIS.Core.Application.Contracts/Common/DTO/FileViewModel.cs b/IRaCIS.Core.Application.Contracts/Common/DTO/FileViewModel.cs new file mode 100644 index 0000000..02dbf42 --- /dev/null +++ b/IRaCIS.Core.Application.Contracts/Common/DTO/FileViewModel.cs @@ -0,0 +1,17 @@ +using IRaCIS.Core.Domain.Share; +using System; + +namespace IRaCIS.Application.ViewModels +{ + + + public class UploadFileInfoDTO + { + public Guid Id { get; set; } + public string FilePath { get; set; } + public string FullFilePath => SystemConfig.RootUrl + FilePath; + + } + + +} \ No newline at end of file diff --git a/IRaCIS.Core.Application.Contracts/Common/DTO/MessageViewModel.cs b/IRaCIS.Core.Application.Contracts/Common/DTO/MessageViewModel.cs new file mode 100644 index 0000000..c92a1d4 --- /dev/null +++ b/IRaCIS.Core.Application.Contracts/Common/DTO/MessageViewModel.cs @@ -0,0 +1,11 @@ +namespace IRaCIS.Application.ViewModels +{ + public class MessageViewModel + { + + } + + + + +} \ No newline at end of file diff --git a/IRaCIS.Core.Application.Contracts/Common/DTO/SysMessageViewModel.cs b/IRaCIS.Core.Application.Contracts/Common/DTO/SysMessageViewModel.cs new file mode 100644 index 0000000..0e74ed2 --- /dev/null +++ b/IRaCIS.Core.Application.Contracts/Common/DTO/SysMessageViewModel.cs @@ -0,0 +1,16 @@ +using System; + +namespace IRaCIS.Application.ViewModels +{ + public class SysMessageDTO + { + public int Id { get; set; } + public int ToDoctorId { get; set; } + public int FromUserId { get; set; } + public string Title { get; set; } = string.Empty; + public string Content { get; set; } = string.Empty; + public string MessageTime { get; set; } + public bool HasRead { get; set; } + public string Memo { get; set; } = string.Empty; + } +} diff --git a/IRaCIS.Core.Application.Contracts/Common/DTO/SystemLog.cs b/IRaCIS.Core.Application.Contracts/Common/DTO/SystemLog.cs new file mode 100644 index 0000000..4957728 --- /dev/null +++ b/IRaCIS.Core.Application.Contracts/Common/DTO/SystemLog.cs @@ -0,0 +1,29 @@ +using System; +using IRaCIS.Core.Application.Contracts.RequestAndResponse; + +namespace IRaCIS.Application.ViewModels +{ + public class SystemLogDTO + { + public Guid Id { get; set; } + public string ApiPath { get; set; } = string.Empty; + public string Params { get; set; } = string.Empty; + public string Result { get; set; } = string.Empty; + public DateTime RequestTime { get; set; } = DateTime.Now; + public long ElapsedMilliseconds { get; set; } = 0; + public Guid OptUserId { get; set; } = Guid.Empty; + public string OptUserName { get; set; } = string.Empty; + public string ClientIP { get; set; } = string.Empty; + public bool Status { get; set; } = true; + public string Message { get; set; } = string.Empty; + public string LogCategory { get; set; } = string.Empty; + } + + public class QueryLogQueryDTO : PageInput + { + public string Keyword { get; set; } = string.Empty; + public string LogCategory { get; set; } = string.Empty; + public DateTime BeginTime { get; set; } = DateTime.Now; + public DateTime EndTime { get; set; } = DateTime.Now; + } +} diff --git a/IRaCIS.Core.Application.Contracts/Common/IDictionaryService.cs b/IRaCIS.Core.Application.Contracts/Common/IDictionaryService.cs new file mode 100644 index 0000000..056fecd --- /dev/null +++ b/IRaCIS.Core.Application.Contracts/Common/IDictionaryService.cs @@ -0,0 +1,23 @@ +using System; +using System.Collections.Generic; +using EasyCaching.Core.Interceptor; +using IRaCIS.Application.ViewModels; +using IRaCIS.Core.Application.Contracts.RequestAndResponse; + +namespace IRaCIS.Application.Interfaces +{ + public interface IDictionaryService + { + + IEnumerable GetDicSelect(); + PageOutput GetDicSelectList(DicQueryDTO dicSearchModel); + + IResponseOutput DeleteDictionary(Guid id); + DicResultDTO GetDictionaryResult(string[] searchArray); + DicResultDTO GetAllDictionary(); + IResponseOutput AddOrUpdateDictionary(DicViewModelDTO viewModel); + [EasyCachingAble(Expiration = 10)] + List GetDicTree(); + DicViewModelDTO GetDetailById(Guid Id); + } +} diff --git a/IRaCIS.Core.Application.Contracts/Common/IFileService.cs b/IRaCIS.Core.Application.Contracts/Common/IFileService.cs new file mode 100644 index 0000000..08d19a2 --- /dev/null +++ b/IRaCIS.Core.Application.Contracts/Common/IFileService.cs @@ -0,0 +1,17 @@ +using System; + +namespace IRaCIS.Application.Interfaces +{ + public interface IFileService + { + + //IResponseOutput DownloadOfficialResume(Guid[] doctorIds); + + + string CreateOfficialResumeZip(Guid[] doctorIds); + + string CreateDoctorsAllAttachmentZip(Guid[] doctorIds); + + string CreateZipPackageByAttachment(Guid doctorId, Guid[] attachmentIds); + } +} diff --git a/IRaCIS.Core.Application.Contracts/Common/ILogService.cs b/IRaCIS.Core.Application.Contracts/Common/ILogService.cs new file mode 100644 index 0000000..9f373f1 --- /dev/null +++ b/IRaCIS.Core.Application.Contracts/Common/ILogService.cs @@ -0,0 +1,12 @@ +using IRaCIS.Application.ViewModels; +using System.Collections.Generic; +using IRaCIS.Core.Application.Contracts.RequestAndResponse; + +namespace IRaCIS.Application.Interfaces +{ + public interface ILogService + { + IResponseOutput SaveLog2Db(SystemLogDTO viewModel); + PageOutput GetLogList(QueryLogQueryDTO param); + } +} diff --git a/IRaCIS.Core.Application.Contracts/Common/IMessageService.cs b/IRaCIS.Core.Application.Contracts/Common/IMessageService.cs new file mode 100644 index 0000000..b4d5f5e --- /dev/null +++ b/IRaCIS.Core.Application.Contracts/Common/IMessageService.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; + +using IRaCIS.Application.ViewModels; +using IRaCIS.Core.Application.Contracts.RequestAndResponse; + +namespace IRaCIS.Application.Interfaces +{ + public interface IMessageService + { + int GetUnReadMessageCount(Guid doctorId); + IResponseOutput DeleteSysMessage(Guid messageId); + IResponseOutput MarkedAsRead(Guid messageId); + + PageOutput GetMessageList(Guid doctorId, int pageSize, int pageIndex); + } +} \ No newline at end of file diff --git a/IRaCIS.Core.Application.Contracts/Dicom/DTO/DicomArchiveResult.cs b/IRaCIS.Core.Application.Contracts/Dicom/DTO/DicomArchiveResult.cs new file mode 100644 index 0000000..6078a99 --- /dev/null +++ b/IRaCIS.Core.Application.Contracts/Dicom/DTO/DicomArchiveResult.cs @@ -0,0 +1,18 @@ +using System.Collections.Generic; + +namespace IRaCIS.Core.Application.Contracts.Dicom.DTO +{ + public sealed class DicomArchiveResult + { + public int ReceivedFileCount { get; set; } + public ICollection ErrorFiles { get; set; } + public ICollection ArchivedDicomStudies { get; set; } + + public DicomArchiveResult() + { + ReceivedFileCount = 0; + ErrorFiles = new List(); + ArchivedDicomStudies = new List(); + } + } +} diff --git a/IRaCIS.Core.Application.Contracts/Dicom/DTO/DicomInstanceViewModel.cs b/IRaCIS.Core.Application.Contracts/Dicom/DTO/DicomInstanceViewModel.cs new file mode 100644 index 0000000..3759770 --- /dev/null +++ b/IRaCIS.Core.Application.Contracts/Dicom/DTO/DicomInstanceViewModel.cs @@ -0,0 +1,69 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace IRaCIS.Core.Application.Contracts.Dicom.DTO +{ + public class DicomInstanceDTO + { + public Guid Id { get; set;} + public Guid StudyId { get; set; } + public Guid SeriesId { get; set; } + public string StudyInstanceUid { get; set; } + public string SeriesInstanceUid { get; set; } + public string SopInstanceUid { get; set; } + public int InstanceNumber { get; set; } + public DateTime InstanceTime { get; set; } + public bool CPIStatus { get; set; } + public int ImageRows { get; set; } + public int ImageColumns { get; set; } + public int SliceLocation { get; set; } + + public Guid TrialId { get; set; } + public Guid SiteId { get; set; } + public Guid SubjectId { get; set; } + public Guid SubjectVisitId { get; set; } + + public Guid CreateUserId { get; set; } + public DateTime CreateTime { get; set; } + public Guid UpdateUserId { get; set; } + public DateTime UpdateTime { get; set; } + } + + + public class DicomTrialSiteSubjectInfo + { + public string SiteCode { get; set; } + public string SiteName { get; set; } + + public string SubjectCode { get; set; } + public string SubjectName { get; set; } + + public int SubjectAge { get; set; } + + public string SubjectSex { get; set; } + + public string TrialCode { get; set; } + + + + public string ReviewMode { get; set; } + public bool IsDoubleReview { get; set; } + + public string TrialIndication { get; set; } + + public decimal SubjectVisitNum { get; set; } + + public string SubjectVisitSVUPDES { get; set; } + + public string SubjectVisitVisitName { get; set; } + + public string Sponsor { get; set; } + + public string Comment { get; set; }=String.Empty; + public Guid TrialId { get; set; } + public Guid SiteId { get; set; } + public Guid SubjectId { get; set; } + public Guid SubjectVisitId { get; set; } + } +} diff --git a/IRaCIS.Core.Application.Contracts/Dicom/DTO/DicomSeriesViewModel.cs b/IRaCIS.Core.Application.Contracts/Dicom/DTO/DicomSeriesViewModel.cs new file mode 100644 index 0000000..d628aeb --- /dev/null +++ b/IRaCIS.Core.Application.Contracts/Dicom/DTO/DicomSeriesViewModel.cs @@ -0,0 +1,36 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace IRaCIS.Core.Application.Contracts.Dicom.DTO +{ + public class DicomSeriesDTO + { + public Guid Id { get; set; } + public Guid StudyId { get; set; } + public string StudyInstanceUid { get; set; } + public string SeriesInstanceUid { get; set; } + public int SeriesNumber { get; set; } + public DateTime SeriesTime { get; set; } + public string Modality { get; set; } + public string Description { get; set; } + public int InstanceCount { get; set; } + public string SliceThickness { get; set; } + + public Guid TrialId { get; set; } + public Guid SiteId { get; set; } + public Guid SubjectId { get; set; } + public Guid SubjectVisitId { get; set; } + public List InstanceList { get; set; } = new List(); + public Guid CreateUserId { get; set; } + public DateTime CreateTime { get; set; } + public Guid UpdateUserId { get; set; } + public DateTime UpdateTime { get; set; } + } + + public class DicomSeriesWithLabelDTO : DicomSeriesDTO + { + public bool HasLabel { get; set; } = false; + public bool KeySeries { get; set; } = false; + } +} diff --git a/IRaCIS.Core.Application.Contracts/Dicom/DTO/DicomStudyViewModel.cs b/IRaCIS.Core.Application.Contracts/Dicom/DTO/DicomStudyViewModel.cs new file mode 100644 index 0000000..e0c15a7 --- /dev/null +++ b/IRaCIS.Core.Application.Contracts/Dicom/DTO/DicomStudyViewModel.cs @@ -0,0 +1,48 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace IRaCIS.Core.Application.Contracts.Dicom.DTO +{ + public class DicomStudyDTO + { + public Guid Id { get; set; } + public Guid TrialId { get; set; } + public Guid SiteId { get; set; } + + public Guid SubjectId { get; set; } + public Guid SubjectVisitId { get; set; } + + public string StudyCode { get; set; } = string.Empty; + + public int Status { get; set; } = 1; + + public string StudyInstanceUid { get; set; } = string.Empty; + public DateTime? StudyTime { get; set; } + public string Modalities { get; set; } = string.Empty; + + public string Description { get; set; } = string.Empty; + public int SeriesCount { get; set; } = 0; + public int InstanceCount { get; set; } = 0; + + public bool SoftDelete { get; set; } = false; + + public string InstitutionName { get; set; } = string.Empty; + public string PatientId { get; set; } = string.Empty; + public string PatientName { get; set; } = string.Empty; + public string PatientAge { get; set; } = string.Empty; + public string PatientSex { get; set; } = string.Empty; + + public Guid UpdateUserId { get; set; } + public DateTime UpdateTime { get; set; } + public Guid CreateUserId { get; set; } + public DateTime CreateTime { get; set; } + } + + public class RelationVisitDTO + { + public string VisitName { get; set; } + public string TpCode { get; set; } + public Guid StudyId { get; set; } + } +} diff --git a/IRaCIS.Core.Application.Contracts/Dicom/DTO/ImageLabelViewModel.cs b/IRaCIS.Core.Application.Contracts/Dicom/DTO/ImageLabelViewModel.cs new file mode 100644 index 0000000..419304e --- /dev/null +++ b/IRaCIS.Core.Application.Contracts/Dicom/DTO/ImageLabelViewModel.cs @@ -0,0 +1,29 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace IRaCIS.Core.Application.Contracts.Dicom.DTO +{ + public class ImageLabelDTO + { + public Guid Id { get; set; } = Guid.Empty; + public string TpCode { get; set; } = string.Empty; + public Guid StudyId { get; set; } = Guid.Empty; + public Guid SeriesId { get; set; } = Guid.Empty; + public Guid InstanceId { get; set; } = Guid.Empty; + public string LabelValue { get; set; } = string.Empty; + } + public class ImageLabelInfo + { + public Guid StudyId { get; set; } = Guid.Empty; + public Guid SeriesId { get; set; } = Guid.Empty; + public Guid InstanceId { get; set; } = Guid.Empty; + public string LabelValue { get; set; } = string.Empty; + } + + public class ImageLabelCommand + { + public string TpCode { get; set; } = string.Empty; + public List ImageLabelList { get; set; } = new List(); + } +} diff --git a/IRaCIS.Core.Application.Contracts/Dicom/DTO/StudyReviewerViewModel.cs b/IRaCIS.Core.Application.Contracts/Dicom/DTO/StudyReviewerViewModel.cs new file mode 100644 index 0000000..8101ff5 --- /dev/null +++ b/IRaCIS.Core.Application.Contracts/Dicom/DTO/StudyReviewerViewModel.cs @@ -0,0 +1,50 @@ +using System; +using System.Collections.Generic; +using IRaCIS.Application.ViewModels; + +namespace IRaCIS.Core.Application.Contracts.Dicom.DTO +{ + public class StudyReviewerDTO + { + public Guid Id { get; set; } + public Guid StudyId { get; set; } + public Guid ReviewerId { get; set; } + + } + + public class StudyDistributeInfo + { + public Guid StudyId { get; set; } + public int Status { get; set; } + //public int ReviewerCount { get; set; } + } + + public class StudyReviewerCommand + { + public List StudyList { get; set; } = new List(); + //public List StudyIdList { get; set; } + public Guid ReviewerId { get; set; } + //public int WorkloadType { get; set; } + public Guid TrialId { get; set; } + //public bool IsDoubleReview { get; set; } + } + + public class StudyReviewerEditCommand + { + public Guid TrialId { get; set; } + public Guid StudyId { get; set; } + public bool IsDoubleReview { get; set; } + + public Guid? ReviewerId1 { get; set; } + public Guid? ReviewerId2 { get; set; } + public Guid? ReviewerIdForAD { get; set; } + } + + public class ReviewerDistributionDTO + { + public Guid ReviewerId { get; set; } + public string FirstName { get; set; } + public string LastName { get; set; } + public string Code { get; set; } + } +} diff --git a/IRaCIS.Core.Application.Contracts/Dicom/DTO/StudyStatusDetailViewModel.cs b/IRaCIS.Core.Application.Contracts/Dicom/DTO/StudyStatusDetailViewModel.cs new file mode 100644 index 0000000..f3422ec --- /dev/null +++ b/IRaCIS.Core.Application.Contracts/Dicom/DTO/StudyStatusDetailViewModel.cs @@ -0,0 +1,22 @@ +using System; + +namespace IRaCIS.Core.Application.Contracts.Dicom.DTO +{ + public class StudyStatusDetailDTO + { + public Guid Id { get; set; } + public Guid StudyId { get; set; } + public int Status { get; set; } + public string OptUserName { get; set; } + public DateTime OptTime { get; set; } + public string Note { get; set; } = string.Empty; + } + + public class StudyStatusDetailCommand + { + public Guid StudyId { get; set; } + public int Status { get; set; } + public string Note { get; set; } = string.Empty; + public string QAComment { get; set; } = string.Empty; + } +} diff --git a/IRaCIS.Core.Application.Contracts/Dicom/IDicomArchiveService.cs b/IRaCIS.Core.Application.Contracts/Dicom/IDicomArchiveService.cs new file mode 100644 index 0000000..016dd99 --- /dev/null +++ b/IRaCIS.Core.Application.Contracts/Dicom/IDicomArchiveService.cs @@ -0,0 +1,43 @@ +using EasyCaching.Core.Interceptor; +using IRaCIS.Core.Application.Contracts.Dicom.DTO; +using System; +using System.Collections.Generic; +using System.IO; +using System.Net.Http; +using System.Text; +using System.Threading.Tasks; + +namespace IRaCIS.Core.Application.Contracts.Dicom +{ + public interface IDicomArchiveService + { + Task ArchiveDicomStreamAsync(Stream dicomStream, DicomTrialSiteSubjectInfo addtionalInfo); + ICollection GetArchivedStudyList(List archivedStudyIds); + + DicomStudyDTO GetStudyItem(Guid studyId); + + [EasyCachingAble(Expiration = 6000)] + string GetStudyPreview(Guid studyId); + + IEnumerable GetSeriesList(Guid studyId); + IEnumerable GetSeriesWithLabelList(Guid studyId,string tpCode); + + [EasyCachingAble(Expiration = 6000)] + string GetSeriesPreview(Guid seriesId); + + IEnumerable GetInstanceList(Guid seriesId); + + IEnumerable GetInstanceIdList(Guid seriesId, string tpCode, bool? key); + + [EasyCachingAble(Expiration = 6000)] + string GetInstancePreview(Guid instanceId); + + + string GetInstanceContent(Guid instanceId); + + + IEnumerable GetImageLabel(string tpCode); + //bool SaveImageLabel(ImageLabelDTO label); + bool SaveImageLabelList(ImageLabelCommand imageLabelCommand); + } +} diff --git a/IRaCIS.Core.Application.Contracts/Doctor/DTO/AttachmentViewModel.cs b/IRaCIS.Core.Application.Contracts/Doctor/DTO/AttachmentViewModel.cs new file mode 100644 index 0000000..954244a --- /dev/null +++ b/IRaCIS.Core.Application.Contracts/Doctor/DTO/AttachmentViewModel.cs @@ -0,0 +1,62 @@ +using IRaCIS.Core.Domain.Share; +using System; + +namespace IRaCIS.Application.ViewModels +{ + public class AttachmentDTO + { + public Guid Id { get; set; } + public Guid DoctorId { get; set; } + public bool IsOfficial { get; set; } + public string Type { get; set; } + public string Path { get; set; } + public string FullPath => SystemConfig.RootUrl + Path; + public string FileName { get; set; } = string.Empty; + public DateTime? CreateTime { get; set; } + + } + + public class ReviewerAckDTO + { + public Guid Id { get; set; } + public Guid DoctorId { get; set; } + public string Type { get; set; } + public string Path { get; set; } + public string FullPath => SystemConfig.RootUrl + Path; + public string FileName { get; set; } = string.Empty; + } + + + public class TrialSOWPathDTO + { + public Guid TrialId { get; set; } + + public string SowName { get; set; } + public string SowPath { get; set; } + } + + public class DeleteSowPathDTO + { + public Guid TrialId { get; set; } + public string Path { get; set; } + + } + + public class UploadAgreementAttachmentDTO + { + public Guid Id { get; set; } + + public Guid DoctorId { get; set; } + public string Type { get; set; } + public string Path { get; set; } + public string FullPath => SystemConfig.RootUrl + Path; + + public string FileName { get; set; } = string.Empty; + } + + public class AttachementCommand + { + public Guid Id { get; set; } + public string Path { get; set; } + } +} diff --git a/IRaCIS.Core.Application.Contracts/Doctor/DTO/DoctorAccountRegisterDTO.cs b/IRaCIS.Core.Application.Contracts/Doctor/DTO/DoctorAccountRegisterDTO.cs new file mode 100644 index 0000000..aa1d2a6 --- /dev/null +++ b/IRaCIS.Core.Application.Contracts/Doctor/DTO/DoctorAccountRegisterDTO.cs @@ -0,0 +1,12 @@ +using System; + +namespace IRaCIS.Application.ViewModels +{ + public class DoctorAccountRegisterDTO : DoctorAccountLoginDTO + { + public string FirstName { get; set; } + public string LastName { get; set; } + public string EMail { get; set; } + public DateTime RegisterTime { get; set; } + } +} \ No newline at end of file diff --git a/IRaCIS.Core.Application.Contracts/Doctor/DTO/DoctorViewModel.cs b/IRaCIS.Core.Application.Contracts/Doctor/DTO/DoctorViewModel.cs new file mode 100644 index 0000000..5d379b4 --- /dev/null +++ b/IRaCIS.Core.Application.Contracts/Doctor/DTO/DoctorViewModel.cs @@ -0,0 +1,524 @@ +using System; +using System.Collections.Generic; +using IRaCIS.Core.Application.Contracts.RequestAndResponse; +using IRaCIS.Core.Domain.Share; + +namespace IRaCIS.Application.ViewModels +{ + + #region 医生管理列表 + + public class DoctorDTO + { + public DoctorDTO() + { + TitleList = new List(); + TitleIdList = new List(); + ReadingTypeList = new List(); + ReadingTypeIds = new List(); + SubspecialityList = new List(); + SubspecialityIds = new List(); + } + + public Guid Id { get; set; } + public DateTime CreateTime { get; set; } + public string Code { get; set; }//GUID + public string FirstName { get; set; } = string.Empty; + public string LastName { get; set; } = string.Empty; + public string ChineseName { get; set; } = string.Empty; + public List TitleIdList { get; set; } + public List TitleList { get; set; } + public string Phone { get; set; } = string.Empty; + public string Introduction { get; set; } = string.Empty; + public string EMail { get; set; } = string.Empty; + public string WeChat { get; set; } = string.Empty; + + //部门 + public string Department { get; set; } = string.Empty; + public Guid DepartmentId { get; set; } + public string DepartmentOther { get; set; } + + //增加的 + public Guid SpecialityId { get; set; } = Guid.Empty; + public string Speciality { get; set; } = string.Empty; + public string SpecialityOther { get; set; } = string.Empty; + + //职称 + public string Rank { get; set; } = string.Empty; + public Guid RankId { get; set; } + public string RankOther { get; set; } + + //职位 + public string Position { get; set; } = string.Empty; + public Guid PositionId { get; set; } + public string PositionOther { get; set; } + + //医院 + public string HospitalName { get; set; } = string.Empty; + public string HospitalOther { get; set; } + public Guid HospitalId { get; set; } + + //临床实践中使用的模式 + public List ReadingTypeList { get; set; } + + public List ReadingTypeIds { get; set; } + public string ReadingTypeOther { get; set; } + + //第二专业 + + public List SubspecialityList { get; set; } + public List SubspecialityIds { get; set; } + public string SubspecialityOther { get; set; } + + public int GCP { get; set; } + public Guid GCPId { get; set; } + public string ResumePath { get; set; } = string.Empty; + public bool HasResume + { + get; set; + } + public bool Reconfirmed { get; set; } + public int CooperateStatus { get; set; } + public int ResumeStatus { get; set; } + public bool AcceptingNewTrial { get; set; } = false; + public bool ActivelyReading { get; set; } = false; + public string City { get; set; } + public string Country { get; set; } + public int Reading { get; set; } + public int Approved { get; set; } + public int Submitted { get; set; } + } + + /// + /// Reviewer 列表查询参数 + /// + + public class DoctorSearchDTO : PageInput + { + public DoctorSearchDTO() + { + ReadingTypeIdList = new List(); + SubspecialityIdList = new List(); + TitleIdList = new List(); + } + public string Name { get; set; } + public List ReadingTypeIdList { get; set; } + public List SubspecialityIdList { get; set; } + public List TitleIdList { get; set; } + public Guid? DepartmentId { get; set; } = Guid.Empty; + public Guid? SpecialityId { get; set; } = Guid.Empty; + public Guid? PositionId { get; set; } = Guid.Empty; + public Guid? RankId { get; set; } = Guid.Empty; + public Guid? HospitalId { get; set; } = Guid.Empty; + + //合作状态 + public int? ContractorStatus { get; set; } + + // 简历审核状态 + public int? InformationConfirmed { get; set; } + public int? EnrollStatus { get; set; } //入组状态 + + public bool? AcceptingNewTrial { get; set; }//是否接受新的项目 + public bool? ActivelyReading { get; set; }// 是否接受新的读片任务 + public int? Nation { get; set; }// 0-中国医生,2-美国医生,3-全部 + } + + /// + /// 入组 Selection 列表查询参数 + /// + public class ReviewerSelectionQueryDTO : DoctorSearchDTO + { + public Guid TrialId { get; set; } = Guid.Empty; + } + + public class ReviewerSubmissionQueryDTO : PageInput + { + public Guid TrialId { get; set; } = Guid.Empty; + public int IntoGroupSearchState { get; set; } + } + + public class ReviewerConfirmationQueryDTO : PageInput + { + public Guid TrialId { get; set; } = Guid.Empty; + } + + public class EnrollGetQuery : PageInput + { + public Guid TrialId { get; set; } + + } + + public class EnrollCommand + { + public Guid Id { get; set; } + + + public decimal? Training { get; set; } + + public decimal? RefresherTraining { get; set; } + + public decimal? Timepoint { get; set; } + + public decimal? Timepoint48H { get; set; } + + public decimal? Timepoint24H { get; set; } + + public decimal? Adjudication { get; set; } + + public decimal? Adjudication48H { get; set; } + + public decimal? Adjudication24H { get; set; } + + public decimal? Global { get; set; } + + + public decimal? Downtime { get; set; } + + + } + + public class EnrollViewModel + { + + public string ChineseName { get; set; } = string.Empty; + + + public string FirstName { get; set; } = string.Empty; + + + + public string LastName { get; set; } = string.Empty; + + public decimal? AdjustmentMultiple { get; set; } = 0; + + public Guid? DoctorId { get; set; } + + public Guid? TrialId { get; set; } + + public Guid? Id { get; set; } + + public int? Training { get; set; } + + public int? RefresherTraining { get; set; } + + public int? Timepoint { get; set; } + + public int? Timepoint48H { get; set; } + + public int? Timepoint24H { get; set; } + + public int? Adjudication { get; set; } + + public int? Adjudication48H { get; set; } + + public int? Adjudication24H { get; set; } + + public int? Global { get; set; } + + + public int? Downtime { get; set; } + + public string ReviewerCode { get; set; } = string.Empty; + + public string Code { get; set; } + + } + + public class SelectionReviewerDTO : DoctorDTO + { + public int DoctorTrialState { get; set; } + public string OptUserName { get; set; } = string.Empty; + public DateTime? OptTime { get; set; } + public string OptTimeStr => OptTime?.ToString("yyyy-MM-dd HH:mm:ss"); + } + + public class DoctorOptDTO + { + public Guid Id { get; set; } + public string Code { get; set; }//GUID + public string FirstName { get; set; } = string.Empty; + public string LastName { get; set; } = string.Empty; + public string ChineseName { get; set; } = string.Empty; + + public string City { get; set; } = string.Empty; + public string HospitalName { get; set; } = string.Empty; + public string Country { get; set; } = string.Empty; + } + + + public class ConfirmationReviewerDTO : DoctorOptDTO + { + public int DoctorTrialState { get; set; } + public string OptUserName { get; set; } = string.Empty; + public DateTime? OptTime { get; set; } + public string OptTimeStr => OptTime?.ToString("yyyy-MM-dd HH:mm:ss"); + } + public class DoctorStateModelDTO + { + public Guid DoctorId { get; set; } + public int IntoGroupState { get; set; } + public string OptUserName { get; set; } + public DateTime? OptTime { get; set; } + + } + + #endregion + + public class DoctorDetailDTO + { + public DoctorBasicInfoDTO BasicInfoView { get; set; } + public EmploymentDTO EmploymentView { get; set; } + public SpecialtyDTO SpecialtyView { get; set; } + public IEnumerable EducationList { get; set; } + public IEnumerable PostgraduateList { get; set; } + public ResearchPublicationDTO ResearchPublicationView { get; set; } + public TrialExperienceViewModel TrialExperienceView { get; set; } + public ResumeConfirmDTO AuditView { get; set; } + public IEnumerable AttachmentList { get; set; } + + public List SowList { get; set; } + public List AckSowList { get; set; } + + public DoctorEnrollInfoDTO IntoGroupInfo { get; set; } + + public bool InHoliday { get; set; } + public DoctorDetailDTO() + { + BasicInfoView = new DoctorBasicInfoDTO(); + EmploymentView = new EmploymentDTO(); + SpecialtyView = new SpecialtyDTO(); + EducationList = new List(); + PostgraduateList = new List(); + ResearchPublicationView = new ResearchPublicationDTO(); + TrialExperienceView = new TrialExperienceViewModel(); + AuditView = new ResumeConfirmDTO(); + AttachmentList = new List(); + IntoGroupInfo = new DoctorEnrollInfoDTO(); + SowList = new List(); + AckSowList = new List(); + } + } + + public class DoctorEnrollInfoDTO + { + public Guid DoctorId { get; set; } + public int Submitted { get; set; } + public int Approved { get; set; } + public int Reading { get; set; } + } + + + + #region 基本信息模型 + + public class DoctorBasicInfo + { + public Guid? Id { get; set; } + public string Code { get; set; } = string.Empty; + public string FirstName { get; set; } + public string LastName { get; set; } + public string ChineseName { get; set; } + public int Sex { get; set; } + public string Phone { get; set; } + public string Introduction { get; set; } + public string EMail { get; set; } + public string WeChat { get; set; } + public int Nation { get; set; } + } + + public class DoctorBasicInfoCommand: DoctorBasicInfo + { + public DoctorBasicInfoCommand() + { + TitleIds = new List(); + } + + //职称 + public List TitleIds { get; set; } + } + + public class DoctorBasicInfoDTO : DoctorBasicInfo + { + //public Guid DoctorId { get; set; } + public DoctorBasicInfoDTO() + { + TitleList = new List(); + TitleIds = new List(); + } + //职称 + public List TitleIds { get; set; } + public List TitleList { get; set; } + } + + public class SowDTO + { + public string FileName { get; set; } + public string TrialCode { get; set; } + public string FilePath { get; set; } + public string FullPath { get { return SystemConfig.RootUrl + FilePath; } } + public DateTime CreateTime { get; set; } + } + + + #endregion + + + #region 工作信息模型 + + public class EmploymentDTO : EmploymentInfo + { + public string Department { get; set; } + + public string Rank { get; set; } + + public string Position { get; set; } + + #region 医院信息 + public string HospitalName { get; set; } + + public string UniversityAffiliated { get; set; } + public string Country { get; set; } + + public string Province { get; set; } + + public string City { get; set; } + + #endregion + } + + public class EmploymentCommand : EmploymentInfo + { + + } + + public class EmploymentInfo + { + public Guid Id { get; set; } + //部门 + public Guid DepartmentId { get; set; } = Guid.Empty; + public string DepartmentOther { get; set; } + //职称 + public Guid RankId { get; set; } = Guid.Empty; + public string RankOther { get; set; } + //职位 主席 副主席 + public Guid PositionId { get; set; } = Guid.Empty; + public string PositionOther { get; set; } + + public Guid HospitalId { get; set; } = Guid.Empty; + + } + + #endregion + + #region Specialty模型 + public class SpecialtyDTO : SpecialtyCommand + { + public SpecialtyDTO() + { + ReadingTypeList = new List(); + SubspecialityList = new List(); + } + + public List ReadingTypeList { get; set; } + public List SubspecialityList { get; set; } + } + + public class SpecialtyCommand + { + public SpecialtyCommand() + { + ReadingTypeIds = new List(); + SubspecialityIds = new List(); + } + + public Guid Id { get; set; } + public string OtherSkills { get; set; } = string.Empty; + //临床实践中使用的模式 + public List ReadingTypeIds { get; set; } + public string ReadingTypeOther { get; set; } = string.Empty; + //亚专科 + public List SubspecialityIds { get; set; } + public string SubspecialityOther { get; set; } = string.Empty; + + public Guid SpecialityId { get; set; } = Guid.Empty; + public string Speciality { get; set; } = string.Empty; + public string SpecialityOther { get; set; } = string.Empty; + + //public Guid DepartmentId { get; set; } = Guid.Empty; + //public string DepartmentName { get; set; } = string.Empty; + //public string DepartmentOther { get; set; } = string.Empty; + + } + + + #endregion + + #region 医生账户 + public class DoctorAccountLoginDTO + { + public string Phone { get; set; } + public string Password { get; set; } + } + + public class DoctorAccountDTO + { + public Guid Id { get; set; } + public string FirstName { get; set; } + public string LastName { get; set; } + public string Phone { get; set; } + public string PhotoPath { get; set; } + } + + public class DoctorAccountUpdatePasswordCommand + { + public string Phone { get; set; } + public string OldPassword { get; set; } + public string NewPassword { get; set; } + } + #endregion + + #region 审核模型 + + public class ResumeConfirmCommand + { + //int userId, int doctorId, int status, string memo + //public Guid FromUserId { get; set; } + public Guid Id { get; set; } + public int ResumeStatus { get; set; } + public int ReviewStatus { get; set; } + public bool AcceptingNewTrial { get; set; } = false; + public bool ActivelyReading { get; set; } = false; + public string AdminComment { get; set; } + public string MessageContent { get; set; } + public int CooperateStatus { get; set; } + } + + public class ResumeConfirmDTO + { + public Guid Id { get; set; } + public int CooperateStatus { get; set; } + public int ResumeStatus { get; set; } + public int ReviewStatus { get; set; } //复审状态 + public bool AcceptingNewTrial { get; set; } + public bool ActivelyReading { get; set; } + public string AdminComment { get; set; } + public bool InHoliday { get; set; } + } + + #endregion + + + public class TrialPaymentPriceQueryDTO : PageInput + { + public string KeyWord { get; set; } + + public Guid? CroId { get; set; } + + } + + public class DoctorPaymentInfoQueryDTO : PageInput + { + public string SearchName { get; set; } + public Guid? HospitalId { get; set; } = Guid.Empty; + } +} diff --git a/IRaCIS.Core.Application.Contracts/Doctor/DTO/EducationViewModel.cs b/IRaCIS.Core.Application.Contracts/Doctor/DTO/EducationViewModel.cs new file mode 100644 index 0000000..7968dd8 --- /dev/null +++ b/IRaCIS.Core.Application.Contracts/Doctor/DTO/EducationViewModel.cs @@ -0,0 +1,69 @@ +using System; +using System.Collections.Generic; + +namespace IRaCIS.Application.ViewModels +{ + public class EducationCommand + { + public Guid? Id { get; set; } + public Guid DoctorId { get; set; } + public DateTime BeginDate { get; set; } + public DateTime EndDate { get; set; } + public string Degree { get; set; } + public string Major { get; set; } + public string Organization { get; set; } + public string Country { get; set; } + public string Province { get; set; } + public string City { get; set; } + + } + + public class EducationInfoViewModel : EducationCommand + { + public DateTime? CreateTime { get; set; } + public string BeginDateStr => BeginDate.ToString("yyyy-MM"); + public string EndDateStr => EndDate.ToString("yyyy-MM"); + + } + public class PostgraduateCommand + { + public Guid? Id { get; set; } + public Guid DoctorId { get; set; } + + public DateTime BeginDate { get; set; } + + public DateTime EndDate { get; set; } + + public string Training { get; set; } + + public string Major { get; set; } + + public string Hospital { get; set; } + + public string School { get; set; } + + public string Country { get; set; } + + public string Province { get; set; } + + public string City { get; set; } + + + } + + + public class PostgraduateViewModel: PostgraduateCommand + { + public DateTime? CreateTime { get; set; } + public string BeginDateStr => BeginDate.ToString("yyyy-MM"); + + public string EndDateStr => EndDate.ToString("yyyy-MM"); + } + public class DoctorEducationExperienceDTO + { + public IEnumerable EducationList=new List(); + + public IEnumerable PostgraduateList = new List(); + } + +} \ No newline at end of file diff --git a/IRaCIS.Core.Application.Contracts/Doctor/DTO/HolidayViewModel.cs b/IRaCIS.Core.Application.Contracts/Doctor/DTO/HolidayViewModel.cs new file mode 100644 index 0000000..1476af2 --- /dev/null +++ b/IRaCIS.Core.Application.Contracts/Doctor/DTO/HolidayViewModel.cs @@ -0,0 +1,13 @@ +using System; + +namespace IRaCIS.Application.ViewModels +{ + public class VacationCommand + { + public Guid? Id { get; set; } + public Guid DoctorId { get; set; } + public DateTime StartDate { get; set; } + public DateTime EndDate { get; set; } + public int Status { get; set; } = 1; + } +} diff --git a/IRaCIS.Core.Application.Contracts/Doctor/DTO/ResearchPublicationViewModel.cs b/IRaCIS.Core.Application.Contracts/Doctor/DTO/ResearchPublicationViewModel.cs new file mode 100644 index 0000000..09bf639 --- /dev/null +++ b/IRaCIS.Core.Application.Contracts/Doctor/DTO/ResearchPublicationViewModel.cs @@ -0,0 +1,14 @@ +using System; + +namespace IRaCIS.Application.ViewModels +{ + public class ResearchPublicationDTO + { + public Guid? Id { get; set; } + public Guid DoctorId { get; set; } + public string Research { get; set; } + public string Grants { get; set; } + public string Publications { get; set; } + public string AwardsHonors { get; set; } + } +} \ No newline at end of file diff --git a/IRaCIS.Core.Application.Contracts/Doctor/DTO/TrialExperienceViewModel.cs b/IRaCIS.Core.Application.Contracts/Doctor/DTO/TrialExperienceViewModel.cs new file mode 100644 index 0000000..924b56f --- /dev/null +++ b/IRaCIS.Core.Application.Contracts/Doctor/DTO/TrialExperienceViewModel.cs @@ -0,0 +1,63 @@ +using IRaCIS.Core.Domain.Share; +using System; +using System.Collections.Generic; + +namespace IRaCIS.Application.ViewModels +{ + public class TrialExperienceCommand + { + public Guid? Id { get; set; } + + public Guid DoctorId { get; set; } + + public string Term { get; set; } + + public string EvaluationCriteria { get; set; } + + public string EvaluationContent { get; set; } + } + + + public class TrialExperienceViewModel: GcpAndOtherExperienceDTO + { + public List ClinicalTrialExperienceList=new List(); + + public string ExpiryDateStr { get; set; } = string.Empty; + public string GCPFullPath => SystemConfig.RootUrl + Path; + + } + + + public class GcpAndOtherExperienceDTO + { + public Guid Id { get; set; } + + public int GCP { get; set; } + + public Guid GCPId { get; set; } + + public string OtherClinicalExperience { get; set; } + + public string Type { get; set; } = string.Empty; + + public string Path { get; set; } = string.Empty; + + public string FileName { get; set; } = string.Empty; + + } + + public class GCPExperienceCommand + { + public Guid Id { get; set; } + public int GCP { get; set; } + + public Guid GCPId { get; set; } + } + + public class ClinicalExperienceCommand + { + public Guid DoctorId { get; set; } + + public string OtherClinicalExperience { get; set; } + } +} \ No newline at end of file diff --git a/IRaCIS.Core.Application.Contracts/Doctor/IAttachmentService.cs b/IRaCIS.Core.Application.Contracts/Doctor/IAttachmentService.cs new file mode 100644 index 0000000..11f882b --- /dev/null +++ b/IRaCIS.Core.Application.Contracts/Doctor/IAttachmentService.cs @@ -0,0 +1,22 @@ +using System; +using System.Collections.Generic; + +using IRaCIS.Application.ViewModels; +using IRaCIS.Core.Application.Contracts.RequestAndResponse; + +namespace IRaCIS.Application.Interfaces +{ + public interface IAttachmentService + { + IEnumerable SaveAttachmentRange(IEnumerable attachmentList); + + IResponseOutput DeleteAttachment(Guid attachmentId); + AttachmentDTO GetDetailById(Guid attachmentId); + IEnumerable GetAttachmentByType(Guid doctorId,string type); + IEnumerable GetAttachmentByTypes(Guid doctorId, string[] types); + IEnumerable GetAttachments(Guid doctorId); + string GetDoctorOfficialCV(Guid doctorId); + + IResponseOutput SetOfficial(Guid doctorId, Guid attachmentId); + } +} diff --git a/IRaCIS.Core.Application.Contracts/Doctor/IDoctorAccountService.cs b/IRaCIS.Core.Application.Contracts/Doctor/IDoctorAccountService.cs new file mode 100644 index 0000000..67c3408 --- /dev/null +++ b/IRaCIS.Core.Application.Contracts/Doctor/IDoctorAccountService.cs @@ -0,0 +1,14 @@ +using System; + +using IRaCIS.Application.ViewModels; +using IRaCIS.Core.Application.Contracts.RequestAndResponse; + +namespace IRaCIS.Application.Interfaces +{ + public interface IDoctorAccountService + { + IResponseOutput Register(DoctorAccountRegisterDTO doctorAccount); + DoctorAccountDTO Login(DoctorAccountLoginDTO doctorAccount); + IResponseOutput UpdatePassword(DoctorAccountUpdatePasswordCommand doctorAccount); + } +} diff --git a/IRaCIS.Core.Application.Contracts/Doctor/IDoctorListQueryService.cs b/IRaCIS.Core.Application.Contracts/Doctor/IDoctorListQueryService.cs new file mode 100644 index 0000000..505fbd5 --- /dev/null +++ b/IRaCIS.Core.Application.Contracts/Doctor/IDoctorListQueryService.cs @@ -0,0 +1,39 @@ +using IRaCIS.Application.ViewModels; +using System; +using EasyCaching.Core.Interceptor; +using IRaCIS.Core.Application.Contracts.RequestAndResponse; + +namespace IRaCIS.Application.Interfaces +{ + public interface IDoctorListQueryService + { + + bool AddOrUpdateEnroll(EnrollCommand addOrUpdateModel); + PageOutput GetTrialDoctorList(EnrollGetQuery challengeQuery); + + /// + /// 医生多条件查询 + /// + PageOutput GetReviewerList(DoctorSearchDTO param,Guid reviewerId); + + /// + /// 筛选医生列表 + /// + /// + /// + // + PageOutput GetSelectionReviewerList( + ReviewerSelectionQueryDTO doctorSearchModel); + + /// + /// //入组 相关接口 (提交CRO-1) CRO确认-4 + /// + PageOutput GetSubmissionOrApprovalReviewerList( + ReviewerSubmissionQueryDTO doctorIntoGroupSearchModel); + + + //医生确认状态列表 + PageOutput GetConfirmationReviewerList( + ReviewerConfirmationQueryDTO trialIdPageModel); + } +} diff --git a/IRaCIS.Core.Application.Contracts/Doctor/IDoctorService.cs b/IRaCIS.Core.Application.Contracts/Doctor/IDoctorService.cs new file mode 100644 index 0000000..97b6608 --- /dev/null +++ b/IRaCIS.Core.Application.Contracts/Doctor/IDoctorService.cs @@ -0,0 +1,77 @@ +using System; +using System.Collections.Generic; +using EasyCaching.Core.Interceptor; +using IRaCIS.Application.ViewModels; +using IRaCIS.Core.Application.Contracts.RequestAndResponse; + +namespace IRaCIS.Application.Interfaces +{ + public interface IDoctorService + { + #region 医生 基本信息 + + /// + /// 基本信息详情展示、编辑使用 + /// + /// + /// + DoctorBasicInfoDTO GetDoctorBasicInfo(Guid doctorId); + + /// + /// 添加医生基本信息 + /// + /// + /// + /// + /// + IResponseOutput AddOrUpdateDoctorBasicInfo(DoctorBasicInfoCommand addBasicInfoParam, Guid userId); + + #endregion + + #region 医生 工作信息 + + /// + /// 获取医生 工作信息 + /// + /// + /// + EmploymentDTO GetEmploymentInfo(Guid doctorId); + /// + /// 更新医生 工作信息 + /// + /// + /// + IResponseOutput UpdateDoctorEmploymentInfo(EmploymentCommand updateDoctorWorkInfoViewModel); + + #endregion + + /// + /// 获取医生技能信息 + /// + SpecialtyDTO GetDoctorSpecialty(Guid doctorId); + + /// + /// 更新医生技能信息 + /// + IResponseOutput UpdateDoctorSpecialty(SpecialtyCommand specialtyUpdateModel); + + /// + /// 获取医生 审核状态 + /// + ResumeConfirmDTO GetDoctorAuditStatus(Guid doctorId); + + /// + /// 审核简历 和合作关系 + /// + IResponseOutput AuditResume(ResumeConfirmCommand auditResumeParam,Guid userId); + + /// 医生详情 入组信息 + DoctorEnrollInfoDTO GetDoctorEnrollInfo(Guid doctorId); + + /// 获取医生参与项目的Sow协议 + List GetDoctorSow(Guid doctorId); + + /// 获取医生入组的 ack Sow + List GetDoctorAckSow(Guid doctorId); + } +} diff --git a/IRaCIS.Core.Application.Contracts/Doctor/IEducationService.cs b/IRaCIS.Core.Application.Contracts/Doctor/IEducationService.cs new file mode 100644 index 0000000..3a47afc --- /dev/null +++ b/IRaCIS.Core.Application.Contracts/Doctor/IEducationService.cs @@ -0,0 +1,29 @@ +using System; +using IRaCIS.Application.ViewModels; +using IRaCIS.Core.Application.Contracts.RequestAndResponse; + +namespace IRaCIS.Application.Interfaces +{ + public interface IEducationService + { + + DoctorEducationExperienceDTO GetEducation(Guid doctorId); + + #region 教育经历 + IResponseOutput AddOrUpdateEducationInfo(EducationCommand doctorEducationInfoViewModel); + + IResponseOutput DeleteEducationInfo(Guid doctorId); + + #endregion + + + + + #region 继续教育经历 + IResponseOutput AddOrUpdatePostgraduateInfo(PostgraduateCommand doctorContinueLearningViewModel); + IResponseOutput DeletePostgraduateInfo(Guid doctorId); + + #endregion + + } +} \ No newline at end of file diff --git a/IRaCIS.Core.Application.Contracts/Doctor/IResearchPublicationService.cs b/IRaCIS.Core.Application.Contracts/Doctor/IResearchPublicationService.cs new file mode 100644 index 0000000..cbf8797 --- /dev/null +++ b/IRaCIS.Core.Application.Contracts/Doctor/IResearchPublicationService.cs @@ -0,0 +1,12 @@ +using System; +using IRaCIS.Application.ViewModels; +using IRaCIS.Core.Application.Contracts.RequestAndResponse; + +namespace IRaCIS.Application.Interfaces +{ + public interface IResearchPublicationService + { + ResearchPublicationDTO GetResearchPublication(Guid doctorId); + IResponseOutput AddOrUpdateResearchPublication(ResearchPublicationDTO param); + } +} \ No newline at end of file diff --git a/IRaCIS.Core.Application.Contracts/Doctor/ITrialExperienceService.cs b/IRaCIS.Core.Application.Contracts/Doctor/ITrialExperienceService.cs new file mode 100644 index 0000000..1d409ec --- /dev/null +++ b/IRaCIS.Core.Application.Contracts/Doctor/ITrialExperienceService.cs @@ -0,0 +1,15 @@ +using System; +using IRaCIS.Application.ViewModels; +using IRaCIS.Core.Application.Contracts.RequestAndResponse; + +namespace IRaCIS.Application.Interfaces +{ + public interface ITrialExperienceService + { + TrialExperienceViewModel GetTrialExperience(Guid doctorId); + IResponseOutput AddOrUpdateTrialExperience(TrialExperienceCommand model); + IResponseOutput DeleteTrialExperience(Guid id); + IResponseOutput UpdateGcpExperience(GCPExperienceCommand model); + IResponseOutput UpdateOtherExperience(Guid doctorId, string otherClinicalExperience); + } +} \ No newline at end of file diff --git a/IRaCIS.Core.Application.Contracts/Doctor/IVacationService.cs b/IRaCIS.Core.Application.Contracts/Doctor/IVacationService.cs new file mode 100644 index 0000000..3b2080c --- /dev/null +++ b/IRaCIS.Core.Application.Contracts/Doctor/IVacationService.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; + +using IRaCIS.Application.ViewModels; +using IRaCIS.Core.Application.Contracts.RequestAndResponse; + +namespace IRaCIS.Application.Interfaces +{ + public interface IVacationService + { + IResponseOutput AddOrUpdateVacation(VacationCommand vacationViewModel); + IResponseOutput DeleteVacation(Guid id); + PageOutput GetVacationList(Guid doctorId, int pageIndex, int pageSize); + + /// 判断当前时间是否在休假 + IResponseOutput OnVacation(Guid reviewerId); + } +} diff --git a/IRaCIS.Core.Application.Contracts/Financial/DTO/AwardPriceViewModel.cs b/IRaCIS.Core.Application.Contracts/Financial/DTO/AwardPriceViewModel.cs new file mode 100644 index 0000000..953c6c1 --- /dev/null +++ b/IRaCIS.Core.Application.Contracts/Financial/DTO/AwardPriceViewModel.cs @@ -0,0 +1,37 @@ +using System; +using IRaCIS.Application.ViewModels; +using IRaCIS.Core.Application.Contracts.RequestAndResponse; + +namespace IRaCIS.Application.Interfaces +{ + public class AwardPriceDTO: AwardPriceCalculateDTO + { + public Guid Id { get; set; } + } + + public class AwardPriceCalculateDTO + { + public decimal Price { get; set; } + public int Max { get; set; } + public int Min { get; set; } + } + + public class AwardPriceCommand + { + public Guid Id { get; set; } + public decimal Price { get; set; } + public int Min { get; set; } + public int Max { get; set; } + public Guid OptUserId { get; set; } + } + + public class AwardPriceQueryDTO : PageInput + { + } + + public class ExchangeRateQueryDTO : PageInput + { + public DateTime? SearchMonth { get; set; } + } + +} \ No newline at end of file diff --git a/IRaCIS.Core.Application.Contracts/Financial/DTO/CalculateViewModel.cs b/IRaCIS.Core.Application.Contracts/Financial/DTO/CalculateViewModel.cs new file mode 100644 index 0000000..70c126d --- /dev/null +++ b/IRaCIS.Core.Application.Contracts/Financial/DTO/CalculateViewModel.cs @@ -0,0 +1,44 @@ +using System; + +namespace IRaCIS.Application.ViewModels +{ + public class CalculateNeededDTO + { + public Guid Id { get; set; } + public Guid DoctorId { get; set; } + public string YearMonth { get; set; } + public bool IsLock { get; set; } + } + + public class DoctorPrice + { + public decimal? AdjustmentMultiple { get; set; } + + public Guid? DoctorId { get; set; } + + public Guid? TrialId { get; set; } + + public bool? IsNewTrial { get; set; } + + public int? Training { get; set; } + + public int? RefresherTraining { get; set; } + + public int? Timepoint { get; set; } + + public int? Timepoint48H { get; set; } + + public int? Timepoint24H { get; set; } + + public int? Adjudication { get; set; } + + public int? Adjudication48H { get; set; } + + public int? Adjudication24H { get; set; } + + public int? Global { get; set; } + + + public int? Downtime { get; set; } + } +} diff --git a/IRaCIS.Core.Application.Contracts/Financial/DTO/ExchangeRateViewModel.cs b/IRaCIS.Core.Application.Contracts/Financial/DTO/ExchangeRateViewModel.cs new file mode 100644 index 0000000..1543d36 --- /dev/null +++ b/IRaCIS.Core.Application.Contracts/Financial/DTO/ExchangeRateViewModel.cs @@ -0,0 +1,13 @@ +using System; + +namespace IRaCIS.Application.ViewModels +{ + public class ExchangeRateCommand + { + public Guid? Id { get; set; } + public string YearMonth { get; set; } + public decimal Rate { get; set; } + + public DateTime UpdateTime { get; set; } + } +} diff --git a/IRaCIS.Core.Application.Contracts/Financial/DTO/PaymentAdjustmentViewModel.cs b/IRaCIS.Core.Application.Contracts/Financial/DTO/PaymentAdjustmentViewModel.cs new file mode 100644 index 0000000..b5e2231 --- /dev/null +++ b/IRaCIS.Core.Application.Contracts/Financial/DTO/PaymentAdjustmentViewModel.cs @@ -0,0 +1,54 @@ +using System; +using IRaCIS.Core.Application.Contracts.RequestAndResponse; + +namespace IRaCIS.Application.ViewModels.Pay +{ + public class PaymentAdjustmentCommand + { + public Guid? Id { get; set; } + public Guid ReviewerId { get; set; } + public DateTime YearMonth { get; set; } + public decimal AdjustPaymentUSD { get; set; } + public decimal AdjustPaymentCNY { get; set; } + public string Note { get; set; } = string.Empty; + } + + public class PaymentAdjustmentDTO + { + public Guid Id { get; set; } + public Guid ReviewerId { get; set; } + public string YearMonth { get; set; } + public DateTime YearMonthDate { get; set; } + public bool IsLock { get; set; } + public decimal AdjustPaymentUSD { get; set; } + public decimal AdjustPaymentCNY { get; set; } + public string Note { get; set; } + } + + public class PaymentAdjustmentDetailDTO: PaymentAdjustmentDTO + { + public string ReviewerCode { get; set; } + public string FirstName { get; set; } + public string LastName { get; set; } + public string FullName => LastName + " / " + FirstName; + public string ChineseName { get; set; } + } + + public class PaymentAdjustmentQueryDTO:PageInput + { + public string TrialCode { get; set; } = string.Empty; + public string Reviewer { get; set; } = string.Empty; + public DateTime BeginMonth { get; set; } + public DateTime EndMonth { get; set; } + } + + public class DoctorSelectDTO + { + public Guid Id { get; set; } + public string Code { get; set; } = string.Empty; + public string FirstName { get; set; } + public string LastName { get; set; } + public string FullName => LastName + " / " + FirstName; + public string ChineseName { get; set; } + } +} \ No newline at end of file diff --git a/IRaCIS.Core.Application.Contracts/Financial/DTO/PaymentDetailViewModel.cs b/IRaCIS.Core.Application.Contracts/Financial/DTO/PaymentDetailViewModel.cs new file mode 100644 index 0000000..91898ab --- /dev/null +++ b/IRaCIS.Core.Application.Contracts/Financial/DTO/PaymentDetailViewModel.cs @@ -0,0 +1,195 @@ +using System; +using System.Collections.Generic; +using IRaCIS.Core.Application.Contracts.RequestAndResponse; + +namespace IRaCIS.Application.ViewModels.Pay +{ + public class PaymentDetailDTO + { + public Guid Id { get; set; } + public Guid PaymentId { get; set; } + public string YearMonth { get; set; } + public Guid DoctorId { get; set; } + public Guid TrialId { get; set; } + public string TrialCode { get; set; } + public string PaymentType { get; set; } + public int Count { get; set; } + public decimal BasePrice { get; set; } + public decimal PersonalAdditional { get; set; } + public decimal TrialAdditional { get; set; } + public int ShowTypeOrder { get; set; } + public int ShowCodeOrder { get; set; } + + public decimal ExchangeRate { get; set; } + + public decimal PaymentUSD { get; set; } + public decimal PaymentCNY { get; set; } + + public bool? IsNewTrial { get; set; } + + public decimal? NewPersonalAdditional { get; set; } + + public decimal TotalUnitPrice => BasePrice + PersonalAdditional + TrialAdditional; + + public AdjustmentDTO AdjustmentView { get; set; } + + } + + public class AdjustmentDTO + { + public decimal AdjustPaymentUSD { get; set; } + + public decimal AdjustPaymentCNY { get; set; } + + public string AdjustType + { + get + { + if (AdjustPaymentUSD > 0) + { + return "+"; + } + else if (AdjustPaymentUSD < 0) + { + return "-"; + } + else { return string.Empty; } + } + } + public string Note { get; set; } + } + + + public class PaymentDetailCommand : PaymentDetailDTO + { + + } + + public class PayDetailDTO + { + public IEnumerable DetailList { get; set; } = new List(); + public DoctorPayInfo DoctorInfo { get; set; } = new DoctorPayInfo(); + } + + public class LockPaymentDTO + { + public List ReviewerIdList { get; set; } + public DateTime Month { get; set; } + } + + public class DoctorPayInfo + { + public Guid DoctorId { get; set; } + public string ChineseName { get; set; } + public string FirstName { get; set; } + public string LastName { get; set; } + public string Phone { get; set; } + public string PayTitle { get; set; } + public string Code { get; set; } + public string YearMonth { get; set; } + + + } + + + + + + + + public class ReviewerPaymentUSD + { + public Guid RecordId { get; set; } + public Guid DoctorId { get; set; } + public decimal PaymentUSD { get; set; } + } + + public class PaymentQueryDTO : PageInput + { + public string Reviewer { get; set; } + public DateTime BeginMonth { get; set; } + public DateTime EndMonth { get; set; } + public int? Nation { get; set; } + } + public class MonthlyPaymentDTO + { + public Guid ReviewerId { get; set; } + public string ReviewerCode { get; set; } + public string ChineseName { get; set; } + public string FirstName { get; set; } + public string LastName { get; set; } + + public decimal AdjustmentUSD { get; set; } + public decimal AdjustmentCNY { get; set; } + public decimal PaymentUSD { get; set; } + public decimal PaymentCNY { get; set; } + + public decimal TotalUSD { get; set; } + public decimal TotalCNY { get; set; } + + } + + public class VolumeStatisticsDTO + { + public Guid StatisticsId { get; set; } + public string Month { get; set; } + public decimal VolumeReward { get; set; } + public decimal ExchangeRate { get; set; } + + public decimal AdjustmentUSD { get; set; } + public decimal AdjustmentCNY { get; set; } + public decimal PaymentUSD { get; set; } + public decimal PaymentCNY { get; set; } + public decimal TotalCNY => AdjustmentCNY + PaymentCNY; + public decimal TotalUSD => AdjustmentUSD + PaymentUSD; + + public List TrialPaymentList = new List(); + } + + public class TrialPaymentDTO + { + public Guid TrialId { get; set; } + public string TrialCode { get; set; } + public decimal TrialPayment { get; set; } + + } + public class VolumeQueryDTO + { + public DateTime BeginMonth { get; set; } + public DateTime EndMonth { get; set; } + public Guid ReviewerId { get; set; } + } + + public class RevenuesDTO + { + public List MissingTrialCodes = new List(); + public Guid Id { get; set; } + public string TrialCode { get; set; } + public Guid TrialId { get; set; } + public string Indication { get; set; } + public Guid CroId { get; set; } + public string Cro { get; set; } = string.Empty; + + public int Expedited { get; set; } + public string ChineseName { get; set; } = string.Empty; + + public string FirstName { get; set; } = string.Empty; + public string LastName { get; set; } = string.Empty; + public string ReviewerCode { get; set; } = string.Empty; + + public decimal Training { get; set; } + public decimal Downtime { get; set; } + public decimal Timepoint { get; set; } + public decimal TimepointIn24H { get; set; } + public decimal TimepointIn48H { get; set; } + public decimal Adjudication { get; set; } + public decimal AdjudicationIn24H { get; set; } + public decimal AdjudicationIn48H { get; set; } + public decimal Global { get; set; } + public decimal Total { get; set; } + + public string YearMonth { get; set; } + } + + +} \ No newline at end of file diff --git a/IRaCIS.Core.Application.Contracts/Financial/DTO/PaymentViewModel.cs b/IRaCIS.Core.Application.Contracts/Financial/DTO/PaymentViewModel.cs new file mode 100644 index 0000000..63b4534 --- /dev/null +++ b/IRaCIS.Core.Application.Contracts/Financial/DTO/PaymentViewModel.cs @@ -0,0 +1,179 @@ +using System; +using System.Collections.Generic; +using IRaCIS.Core.Application.Contracts.RequestAndResponse; + +namespace IRaCIS.Application.ViewModels +{ + public class PaymentDTO + { + public PageOutput CostList { get; set; } + public decimal ExchangeRate { get; set; } + } + public class PaymentViewModel + { + public Guid Id { get; set; } + public string RankName { get; set; } + public Guid DoctorId { get; set; } + public string YearMonth { get; set; } + public DateTime YearMonthDate { get; set; } + public DateTime? CalculateTime { get; set; } + public string CalculateUser { get; set; } + + //额外信息 + public string Code { get; set; } + public string FirstName { get; set; } + public string LastName { get; set; } + + public string ChineseName { get; set; } + public string Phone { get; set; } + public string DoctorNameInBank { get; set; } + public string IDCard { get; set; } + public string BankCardNumber { get; set; } + public string BankName { get; set; } + + public bool IsLock { get; set; } = false; + + public decimal ExchangeRate { get; set; } + + public decimal PaymentCNY { get; set; } + + public decimal AdjustPaymentCNY { get; set; } + public decimal TotalPaymentCNY { get; set; } + public decimal PaymentUSD { get; set; } + + public decimal AdjustPaymentUSD { get; set; } + public decimal TotalPaymentUSD { get; set; } + } + + public class PaymentCommand + { + public Guid Id { get; set; } + public Guid DoctorId { get; set; } + public string YearMonth => new DateTime(Year, Month, 1).ToString("yyyy-MM"); + public int Year { get; set; } + public int Month { get; set; } + public decimal PaymentUSD { get; set; } + public DateTime CalculateTime { get; set; } + public decimal PaymentCNY { get; set; } + public decimal ExchangeRate { get; set; } + public string CalculateUser { get; set; } + } + + public class MonthlyPaymentQueryDTO : PageInput + { + public DateTime StatisticsDate { get; set; } + public string KeyWord { get; set; } + public int? Nation { get; set; } + } + + public class MonthlyPaymentDetailQuery + { + public Guid PaymentId { get; set; } + public Guid ReviewerId { get; set; } + + public DateTime YearMonth { get; set; } + } + + //public class LaborPaymentQuery + //{ + // public Guid PaymentId { get; set; } + // public Guid ReviewerId { get; set; } + + // public DateTime YearMonth { get; set; } + //} + + + public class TrialAnalysisDTO + { + public Guid TrialId { get; set; } + public string Indication { get; set; } + + public string TrialCode { get; set; } + public string Cro { get; set; } = string.Empty; + + public int Expedited { get; set; } + + public string Type { get; set; } + + public decimal PaymentUSD { get; set; } + public decimal RevenusUSD { get; set; } + public decimal GrossProfit => RevenusUSD - PaymentUSD; + public decimal GrossProfitMargin + { + get { + if (RevenusUSD == 0) + return 0; + else + { + return GrossProfit / RevenusUSD; + } + } + } + + } + + public class LaborPayment + { + public string ChineseName { get; set; } + public string FirstName { get; set; } + public string LastName { get; set; } + + public string ResidentId { get; set; } + + public string Phone { get; set; } + + public string AccountNumber { get; set; } + + public string Bank { get; set; } + public string YearMonth { get; set; } + + public decimal PaymentCNY { get; set; } + public decimal TaxCNY { get; set; } + public decimal ActuallyPaidCNY { get; set; } + public decimal BankTransferCNY { get; set; } + } + public class ReviewerAnalysisDTO + { + public List MissingTrialCodes = new List(); + public string ChineseName { get; set; } + public string FirstName { get; set; } + public string LastName { get; set; } + + public Guid ReviewerId { get; set; } + public string ReviewerCode { get; set; } + + public decimal PaymentUSD { get; set; } + public decimal RevenusUSD { get; set; } + public decimal GrossProfit => RevenusUSD - PaymentUSD; + + public decimal GrossProfitMargin + { + get { + if (RevenusUSD == 0) + return 0; + else + { + return GrossProfit / RevenusUSD; + } + } + } + } + public class AnalysisQueryDTO + { + public string Reviewer { get; set; } + public DateTime BeginDate { get; set; } + public DateTime EndDate { get; set; } + + public int? Nation { get; set; } + } + + public class TrialAnalysisQueryDTO + { + public Guid? CroId { get; set; } + public string TrialCode { get; set; } + public DateTime BeginDate { get; set; } + public DateTime EndDate { get; set; } + + public int? AttendedReviewerType { get; set; } + } +} \ No newline at end of file diff --git a/IRaCIS.Core.Application.Contracts/Financial/DTO/RankPriceViewModel.cs b/IRaCIS.Core.Application.Contracts/Financial/DTO/RankPriceViewModel.cs new file mode 100644 index 0000000..554fd1a --- /dev/null +++ b/IRaCIS.Core.Application.Contracts/Financial/DTO/RankPriceViewModel.cs @@ -0,0 +1,50 @@ +using System; +using IRaCIS.Core.Application.Contracts.RequestAndResponse; + +namespace IRaCIS.Application.ViewModels +{ + public class RankPriceDTO + { + public Guid Id { get; set; } + public string RankName { get; set; } + public decimal Timepoint { get; set; } + public decimal TimepointIn24H { get; set; } + public decimal TimepointIn48H { get; set; } + public decimal Adjudication { get; set; } + public decimal AdjudicationIn24H { get; set; } + public decimal AdjudicationIn48H { get; set; } + public decimal Global { get; set; } + public decimal Training { get; set; } + public decimal Downtime { get; set; } + + public decimal RefresherTraining { get; set; } + public int ShowOrder { get; set; } + } + + public class RankDic + { + public Guid Id { get; set; } + public string RankName { get; set; } + } + + public class RankPriceCommand + { + public Guid? Id { get; set; } + public string RankName { get; set; } + public decimal Timepoint { get; set; } + public decimal TimepointIn24H { get; set; } + public decimal TimepointIn48H { get; set; } + public decimal Adjudication { get; set; } + public decimal AdjudicationIn24H { get; set; } + public decimal AdjudicationIn48H { get; set; } + public decimal Global { get; set; } + public decimal Training { get; set; } + public decimal Downtime { get; set; } + public decimal RefresherTraining { get; set; } + + + } + public class RankPriceQueryDTO : PageInput + { + } +} \ No newline at end of file diff --git a/IRaCIS.Core.Application.Contracts/Financial/DTO/ReviewerPayInfoViewModel.cs b/IRaCIS.Core.Application.Contracts/Financial/DTO/ReviewerPayInfoViewModel.cs new file mode 100644 index 0000000..283c53f --- /dev/null +++ b/IRaCIS.Core.Application.Contracts/Financial/DTO/ReviewerPayInfoViewModel.cs @@ -0,0 +1,40 @@ +using System; + +namespace IRaCIS.Application.ViewModels +{ + public class ReviewerPayInfoQueryDTO + { + public Guid DoctorId { get; set; } + public string FirstName { get; set; } + public string LastName { get; set; } + public string ChineseName { get; set; } + public string Code { get; set; } + public string Phone { get; set; } + public string DoctorNameInBank { get; set; } + public string IDCard { get; set; } + public string BankCardNumber { get; set; } + public string BankName { get; set; } + public Guid? RankId { get; set; } + public decimal? Additional { get; set; } + public DateTime? CreateTime { get; set; } + } + + public class DoctorPayInfoQueryListDTO : ReviewerPayInfoQueryDTO + { + public string Hospital { get; set; } + public string RankName { get; set; } + } + + public class ReviewerPayInfoCommand + { + //public Guid Id { get; set; } + public Guid DoctorId { get; set; } + public string DoctorNameInBank { get; set; } + public string IDCard { get; set; } + public string BankCardNumber { get; set; } + public string BankName { get; set; } + public Guid RankId { get; set; } + public decimal? Additional { get; set; } + } +} + diff --git a/IRaCIS.Core.Application.Contracts/Financial/DTO/TrialPaymentPriceViewModel.cs b/IRaCIS.Core.Application.Contracts/Financial/DTO/TrialPaymentPriceViewModel.cs new file mode 100644 index 0000000..37631ea --- /dev/null +++ b/IRaCIS.Core.Application.Contracts/Financial/DTO/TrialPaymentPriceViewModel.cs @@ -0,0 +1,37 @@ +using IRaCIS.Core.Domain.Share; +using System; + +namespace IRaCIS.Application.ViewModels +{ + public class TrialPaymentPriceDTO + { + public Guid TrialId { get; set; } + public string TrialCode { get; set; } + public string Indication { get; set; } + public string Cro { get; set; } + public int Expedited { get; set; } + public decimal? TrialAdditional { get; set; } + public DateTime? CreateTime { get; set; } + public string SowName { get; set; } + public string SowPath { get; set; } + public string SowFullPath => SystemConfig.RootUrl + SowPath; + + public string DoctorsNames { get; set; } = String.Empty; + + public string ReviewMode { get; set; } = String.Empty; + public decimal AdjustmentMultiple { get; set; } = 1; + + public bool? IsNewTrial { get; set; } + } + + public class TrialPaymentPriceCommand + { + public Guid TrialId { get; set; } + public decimal TrialAdditional { get; set; } + public decimal AdjustmentMultiple { get; set; } + + public bool? IsNewTrial { get; set; } + + + } +} diff --git a/IRaCIS.Core.Application.Contracts/Financial/ICalculateService.cs b/IRaCIS.Core.Application.Contracts/Financial/ICalculateService.cs new file mode 100644 index 0000000..256015e --- /dev/null +++ b/IRaCIS.Core.Application.Contracts/Financial/ICalculateService.cs @@ -0,0 +1,17 @@ +using IRaCIS.Application.ViewModels; +using IRaCIS.Application.ViewModels.Pay; +using System; +using System.Collections.Generic; +using IRaCIS.Core.Application.Contracts.RequestAndResponse; + +namespace IRaCIS.Application.Interfaces +{ + public interface ICalculateService + { + IResponseOutput CalculateMonthlyPayment(CalculateDoctorAndMonthDTO param, string token); + IResponseOutput UpdateLockStatus(List reviewerIds, string yearMonth, bool isLock); + List GetNeedCalculateReviewerList(Guid reviewerId, string yearMonth); + bool IsLock(Guid reviewerId, string yearMonth); + //bool ResetMonthlyPayment(Guid reviewerId, Guid trialId,string yearMonth); + } +} diff --git a/IRaCIS.Core.Application.Contracts/Financial/IDoctorPayInfoService.cs b/IRaCIS.Core.Application.Contracts/Financial/IDoctorPayInfoService.cs new file mode 100644 index 0000000..399ff9b --- /dev/null +++ b/IRaCIS.Core.Application.Contracts/Financial/IDoctorPayInfoService.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; + +using IRaCIS.Application.ViewModels; +using IRaCIS.Core.Application.Contracts.RequestAndResponse; + +namespace IRaCIS.Application.Interfaces +{ + public interface IReviewerPayInfoService + { + IResponseOutput AddOrUpdateReviewerPayInfo(ReviewerPayInfoCommand addOrUpdateModel, Guid userId); + PageOutput GetDoctorPayInfoList(DoctorPaymentInfoQueryDTO queryParam); + DoctorPayInfoQueryListDTO GetReviewerPayInfo(Guid doctorId); + List GetReviewerIdByRankId(Guid rankId); + } +} diff --git a/IRaCIS.Core.Application.Contracts/Financial/IExchangeRateService.cs b/IRaCIS.Core.Application.Contracts/Financial/IExchangeRateService.cs new file mode 100644 index 0000000..ec3df0b --- /dev/null +++ b/IRaCIS.Core.Application.Contracts/Financial/IExchangeRateService.cs @@ -0,0 +1,15 @@ +using IRaCIS.Application.ViewModels; +using System; +using IRaCIS.Core.Application.Contracts.RequestAndResponse; + +namespace IRaCIS.Application.Interfaces +{ + public interface IExchangeRateService + { + IResponseOutput AddOrUpdateExchangeRate(ExchangeRateCommand model); + decimal GetExchangeRateByMonth(string month); + PageOutput GetExchangeRateList(ExchangeRateQueryDTO queryParam); + + IResponseOutput DeleteExchangeRate(Guid id); + } +} diff --git a/IRaCIS.Core.Application.Contracts/Financial/IPaymentAdjustmentService.cs b/IRaCIS.Core.Application.Contracts/Financial/IPaymentAdjustmentService.cs new file mode 100644 index 0000000..1cbb9bf --- /dev/null +++ b/IRaCIS.Core.Application.Contracts/Financial/IPaymentAdjustmentService.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using IRaCIS.Application.ViewModels.Pay; +using IRaCIS.Core.Application.Contracts.RequestAndResponse; + +namespace IRaCIS.Application.Interfaces +{ + public interface IPaymentAdjustmentService + { + PageOutput GetPaymentAdjustmentList(PaymentAdjustmentQueryDTO queryParam); + IResponseOutput AddOrUpdatePaymentAdjustment(PaymentAdjustmentCommand addOrUpdateModel,Guid optUseId); + IResponseOutput DeleteCostAdjustment(Guid id); + void CalculateCNY(string yearMonth, decimal rate); + List GetReviewerSelectList(); + } +} \ No newline at end of file diff --git a/IRaCIS.Core.Application.Contracts/Financial/IPaymentService.cs b/IRaCIS.Core.Application.Contracts/Financial/IPaymentService.cs new file mode 100644 index 0000000..3a975b8 --- /dev/null +++ b/IRaCIS.Core.Application.Contracts/Financial/IPaymentService.cs @@ -0,0 +1,30 @@ +using System; +using System.Collections.Generic; +using IRaCIS.Application.ViewModels; +using IRaCIS.Application.ViewModels.Pay; +using IRaCIS.Core.Application.Contracts.RequestAndResponse; + +namespace IRaCIS.Application.Interfaces +{ + public interface IPaymentService + { + PageOutput GetMonthlyPaymentList(MonthlyPaymentQueryDTO queryParam); + PayDetailDTO GetMonthlyPaymentDetailList(Guid PaymentId, Guid doctorId, DateTime yearMonth); + + List GetLaborPaymentList(List paymentId); + + //导出多个医生的付费详细 + List GetReviewersMonthlyPaymentDetail(List manyReviewers); + + PageOutput GetPaymentHistoryList(PaymentQueryDTO param); + List GetPaymentHistoryDetailList(VolumeQueryDTO param); + + PageOutput GetRevenuesList(StatisticsQueryDTO param); + List GetTrialAnalysisList(TrialAnalysisQueryDTO param); + List GetReviewerAnalysisList(AnalysisQueryDTO param); + + + + + } +} \ No newline at end of file diff --git a/IRaCIS.Core.Application.Contracts/Financial/IRankPriceService.cs b/IRaCIS.Core.Application.Contracts/Financial/IRankPriceService.cs new file mode 100644 index 0000000..133ebc4 --- /dev/null +++ b/IRaCIS.Core.Application.Contracts/Financial/IRankPriceService.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using IRaCIS.Application.ViewModels; +using IRaCIS.Core.Application.Contracts.RequestAndResponse; + +namespace IRaCIS.Application.Interfaces +{ + public interface IRankPriceService + { + IResponseOutput AddOrUpdateRankPrice(RankPriceCommand addOrUpdateModel, Guid userId); + + PageOutput GetRankPriceList(RankPriceQueryDTO queryParam); + + IResponseOutput DeleteRankPrice( Guid id); + + List GetRankDic(); + } +} \ No newline at end of file diff --git a/IRaCIS.Core.Application.Contracts/Financial/ITrialPaymentPriceService.cs b/IRaCIS.Core.Application.Contracts/Financial/ITrialPaymentPriceService.cs new file mode 100644 index 0000000..07e6429 --- /dev/null +++ b/IRaCIS.Core.Application.Contracts/Financial/ITrialPaymentPriceService.cs @@ -0,0 +1,24 @@ +using System; +using System.Collections.Generic; + +using IRaCIS.Application.ViewModels; +using IRaCIS.Core.Application.Contracts.RequestAndResponse; + +namespace IRaCIS.Application.Interfaces +{ + public interface ITrialPaymentPriceService + { + IResponseOutput AddOrUpdateTrialPaymentPrice(TrialPaymentPriceCommand addOrUpdateModel, Guid userId);//新增也不需要返回Id,TrialId 也是唯一 + PageOutput GetTrialPaymentPriceList(TrialPaymentPriceQueryDTO queryParam); + + + /// + /// 上传入组后的Ack-SOW + /// + IResponseOutput UploadTrialSOW(Guid userId, TrialSOWPathDTO trialSowPath); + + + + IResponseOutput DeleteTrialSOW(Guid userId, DeleteSowPathDTO trialSowPath); + } +} diff --git a/IRaCIS.Core.Application.Contracts/Financial/ITrialRevenuesPriceService.cs b/IRaCIS.Core.Application.Contracts/Financial/ITrialRevenuesPriceService.cs new file mode 100644 index 0000000..49541c1 --- /dev/null +++ b/IRaCIS.Core.Application.Contracts/Financial/ITrialRevenuesPriceService.cs @@ -0,0 +1,15 @@ +using IRaCIS.Application.ViewModels; +using System; +using System.Collections.Generic; +using IRaCIS.Core.Application.Contracts.RequestAndResponse; + +namespace IRaCIS.Application.Interfaces +{ + public interface ITrialRevenuesPriceService + { + IResponseOutput AddOrUpdateTrialRevenuesPrice(TrialRevenuesPriceDTO model); + bool DeleteTrialCost(Guid Id); + PageOutput GetTrialRevenuesPriceList(TrialRevenuesPriceQueryDTO param); + + } +} diff --git a/IRaCIS.Core.Application.Contracts/Financial/IVolumeRewardService.cs b/IRaCIS.Core.Application.Contracts/Financial/IVolumeRewardService.cs new file mode 100644 index 0000000..9ac2109 --- /dev/null +++ b/IRaCIS.Core.Application.Contracts/Financial/IVolumeRewardService.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using IRaCIS.Core.Application.Contracts.RequestAndResponse; + +namespace IRaCIS.Application.Interfaces +{ + public interface IVolumeRewardService + { + IResponseOutput AddOrUpdateVolumeRewardPriceList(IEnumerable addOrUpdateModels,Guid userId); + PageOutput GetVolumeRewardPriceList(AwardPriceQueryDTO queryParam); + List GetVolumeRewardPriceList(); + } +} \ No newline at end of file diff --git a/IRaCIS.Core.Application.Contracts/IRaCIS.Core.Application.Contracts.csproj b/IRaCIS.Core.Application.Contracts/IRaCIS.Core.Application.Contracts.csproj new file mode 100644 index 0000000..c7cbd90 --- /dev/null +++ b/IRaCIS.Core.Application.Contracts/IRaCIS.Core.Application.Contracts.csproj @@ -0,0 +1,31 @@ + + + + netstandard2.0 + + + + ..\bin + + + + + + + + + + + + + + + + + + + + + + + diff --git a/IRaCIS.Core.Application.Contracts/IStatisticsService.cs b/IRaCIS.Core.Application.Contracts/IStatisticsService.cs new file mode 100644 index 0000000..7a92924 --- /dev/null +++ b/IRaCIS.Core.Application.Contracts/IStatisticsService.cs @@ -0,0 +1,39 @@ +using System; +using System.Collections.Generic; +using IRaCIS.Application.ViewModels; +using IRaCIS.Core.Application.Contracts.RequestAndResponse; + +namespace IRaCIS.Application.Interfaces +{ + public interface IStatisticsService + { + PageOutput GetWorkloadByTrialAndReviewer(StatisticsWorkloadQueryParam param,Guid userId); + + PageOutput GetEnrollStatByTrial(EnrollStatByTrialQueryDTO param); + + #region Dashboard 数据统计 + /// 按类型统计读片数量 + ReadingDataDTO GetReadingDataByType(); + + /// 按月份统计读片数量 + List GetReadingDataByMonth(int monthCount); + + /// 读片数量排行 + List GetReadingDataRank(int topCount); + + /// 按Position统计 Reviewers 数量 + List GetReviewersByRank(); + + /// 每月入组人次 + List GetEnrollDataByQuarter(int quarterCount, int monthCount); + + /// 参与项目数排行 + List GetTrialCountRank(int topCount); + + /// 最新工作量 (已确定的) + List GetLatestWorkLoadList( int searchCount); + #endregion + + PageOutput GetEnrollStatByReviewer(EnrollStatByReviewerQueryDTO enrollTrialStatisticsQueryParam); + } +} diff --git a/IRaCIS.Core.Application.Contracts/Institution/DTO/CROCompanyViewModel.cs b/IRaCIS.Core.Application.Contracts/Institution/DTO/CROCompanyViewModel.cs new file mode 100644 index 0000000..947fe1d --- /dev/null +++ b/IRaCIS.Core.Application.Contracts/Institution/DTO/CROCompanyViewModel.cs @@ -0,0 +1,29 @@ +using System; +using IRaCIS.Core.Application.Contracts.RequestAndResponse; + +namespace IRaCIS.Application.ViewModels +{ + public class CROCompanyDTO + { + public Guid? Id { get; set; } + public string CROName { get; set; } = string.Empty; + public string CROCode { get; set; } + } + + public class CroSelectDTO + { + public Guid Id { get; set; } + public string CROName { get; set; } = string.Empty; + public string CROCode { get; set; } + } + + public class CROCompanyQueryDTO : PageInput + { + public string CROName { get; set; } = string.Empty; + } + + public class CROCompanySelectSearchDTO + { + public string CROName { get; set; } = string.Empty; + } +} \ No newline at end of file diff --git a/IRaCIS.Core.Application.Contracts/Institution/DTO/HospitalViewModel.cs b/IRaCIS.Core.Application.Contracts/Institution/DTO/HospitalViewModel.cs new file mode 100644 index 0000000..35f7132 --- /dev/null +++ b/IRaCIS.Core.Application.Contracts/Institution/DTO/HospitalViewModel.cs @@ -0,0 +1,27 @@ +using System; +using IRaCIS.Core.Application.Contracts.RequestAndResponse; + +namespace IRaCIS.Application.ViewModels +{ + public class HospitalDTO : HospitalCommand + { + + } + + public class HospitalCommand + { + public Guid? Id { get; set; } + public string HospitalName { get; set; } + public string UniversityAffiliated { get; set; } + public string Country { get; set; } + public string Province { get; set; } + public string City { get; set; } + } + + public class HospitalQueryDTO : PageInput + { + public string HospitalName { get; set; } = string.Empty; + public string Province { get; set; } = string.Empty; + public string City { get; set; } = string.Empty; + } +} diff --git a/IRaCIS.Core.Application.Contracts/Institution/DTO/SiteViewModel.cs b/IRaCIS.Core.Application.Contracts/Institution/DTO/SiteViewModel.cs new file mode 100644 index 0000000..7d5e090 --- /dev/null +++ b/IRaCIS.Core.Application.Contracts/Institution/DTO/SiteViewModel.cs @@ -0,0 +1,44 @@ +using System; +using IRaCIS.Core.Application.Contracts.RequestAndResponse; + +namespace IRaCIS.Application.ViewModels +{ + public class SiteDTO: SiteCommand + { + + } + + public class SiteCommand + { + public Guid? Id { get; set; } + public string SiteName { get; set; } + public string SiteCode { get; set; } + public string City { get; set; } = string.Empty; + public string Country { get; set; } = string.Empty; + public Guid HospitalId { get; set; } + public string DirectorName { get; set; } = string.Empty; + public string DirectorPhone { get; set; } = string.Empty; + public string ContactName { get; set; } = string.Empty; + public string ContactPhone { get; set; } = string.Empty; + } + + public class SiteSelectionDTO + { + public Guid Id { get; set; } + public string SiteName { get; set; } + public string City { get; set; } + public string Country { get; set; } + } + + public class SiteSelectDTO : SiteDTO + { + public string HospitalName { get; set; } + public bool IsSelect { get; set; } + } + + public class SiteQueryParam : PageInput + { + public string SiteName { get; set; } + public Guid UserId { get; set; } = Guid.Empty; + } +} \ No newline at end of file diff --git a/IRaCIS.Core.Application.Contracts/Institution/DTO/SponsorViewModel.cs b/IRaCIS.Core.Application.Contracts/Institution/DTO/SponsorViewModel.cs new file mode 100644 index 0000000..a55db09 --- /dev/null +++ b/IRaCIS.Core.Application.Contracts/Institution/DTO/SponsorViewModel.cs @@ -0,0 +1,28 @@ +using System; +using IRaCIS.Core.Application.Contracts.RequestAndResponse; + +namespace IRaCIS.Application.ViewModels +{ + public class SponsorDTO + { + public Guid Id { get; set; } + public string SponsorName { get; set; } = string.Empty; + } + + public class SponsorCommand + { + public Guid? Id { get; set; } + public string SponsorName { get; set; } = string.Empty; + } + + public class SponsorQueryDTO : PageInput + { + public string SponsorName { get; set; } = string.Empty; + } + + public class SponsorSelectDTO + { + public Guid Id { get; set; } + public string SponsorName { get; set; } = string.Empty; + } +} \ No newline at end of file diff --git a/IRaCIS.Core.Application.Contracts/Institution/ICROService.cs b/IRaCIS.Core.Application.Contracts/Institution/ICROService.cs new file mode 100644 index 0000000..bace75d --- /dev/null +++ b/IRaCIS.Core.Application.Contracts/Institution/ICROService.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using IRaCIS.Application.ViewModels; +using IRaCIS.Core.Application.Contracts.RequestAndResponse; + +namespace IRaCIS.Application.Interfaces +{ + public interface ICroService + { + PageOutput GetCroList(CROCompanyQueryDTO queryModel); + IEnumerable GetCroSearchList(); + IResponseOutput AddOrUpdateCro(CROCompanyDTO addCroCompanyViewModel,Guid userId); + IResponseOutput DeleteCro(Guid croCompanyId); + } +} \ No newline at end of file diff --git a/IRaCIS.Core.Application.Contracts/Institution/IHospitalService.cs b/IRaCIS.Core.Application.Contracts/Institution/IHospitalService.cs new file mode 100644 index 0000000..4c7fdc3 --- /dev/null +++ b/IRaCIS.Core.Application.Contracts/Institution/IHospitalService.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using IRaCIS.Application.ViewModels; +using IRaCIS.Core.Application.Contracts.RequestAndResponse; + +namespace IRaCIS.Application.Interfaces +{ + public interface IHospitalService + { + /// 获取医院列表 + IEnumerable GetHospitalList(); + PageOutput GetHospitalPageList(HospitalQueryDTO queryModel); + IResponseOutput AddOrUpdateHospital(HospitalCommand model); + IResponseOutput DeleteHospital(Guid hospitalId); + + } +} \ No newline at end of file diff --git a/IRaCIS.Core.Application.Contracts/Institution/ISiteService.cs b/IRaCIS.Core.Application.Contracts/Institution/ISiteService.cs new file mode 100644 index 0000000..45e1c07 --- /dev/null +++ b/IRaCIS.Core.Application.Contracts/Institution/ISiteService.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using IRaCIS.Application.ViewModels; +using IRaCIS.Core.Application.Contracts.RequestAndResponse; + +namespace IRaCIS.Application.Interfaces +{ + public interface ISiteService + { + PageOutput GetSiteList(SiteQueryParam queryModel); + IEnumerable GetSiteList(); + IResponseOutput AddOrUpdateSite(SiteCommand AddModel, Guid userId); + IResponseOutput DeleteSite(Guid researchCenterId); + + + } +} \ No newline at end of file diff --git a/IRaCIS.Core.Application.Contracts/Institution/ISponsorService.cs b/IRaCIS.Core.Application.Contracts/Institution/ISponsorService.cs new file mode 100644 index 0000000..5d6eed6 --- /dev/null +++ b/IRaCIS.Core.Application.Contracts/Institution/ISponsorService.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using IRaCIS.Application.ViewModels; +using IRaCIS.Core.Application.Contracts.RequestAndResponse; + +namespace IRaCIS.Application.Interfaces +{ + public interface ISponsorService + { + PageOutput GetSponsorList(SponsorQueryDTO queryParam); + IEnumerable GetSponsorSearchList(); + IResponseOutput AddOrUpdateSponsor(SponsorCommand model); + IResponseOutput DeleteSponsor(Guid sponsorId); + } +} \ No newline at end of file diff --git a/IRaCIS.Core.Application.Contracts/Management/DTO/InstitutionViewModel.cs b/IRaCIS.Core.Application.Contracts/Management/DTO/InstitutionViewModel.cs new file mode 100644 index 0000000..b56e645 --- /dev/null +++ b/IRaCIS.Core.Application.Contracts/Management/DTO/InstitutionViewModel.cs @@ -0,0 +1,10 @@ +using System; + +namespace IRaCIS.Application.ViewModels +{ + public class InstitutionDTO + { + public Guid Id { get; set; } + public string InstitutionName { get; set; } + } +} \ No newline at end of file diff --git a/IRaCIS.Core.Application.Contracts/Management/DTO/MenuViewModel.cs b/IRaCIS.Core.Application.Contracts/Management/DTO/MenuViewModel.cs new file mode 100644 index 0000000..6d3de6e --- /dev/null +++ b/IRaCIS.Core.Application.Contracts/Management/DTO/MenuViewModel.cs @@ -0,0 +1,53 @@ +using System; +using System.Collections.Generic; + +namespace IRaCIS.Application.ViewModels +{ + public class MenuFunctionCommand : MenuFunctionDTO + { + + } + + + + public class MenuFunctionDTO + { + public Guid Id { get; set; } = Guid.Empty; + public Guid ParentId { get; set; } = Guid.Empty; + public string RouteName { get; set; } = string.Empty; + public string MenuName { get; set; } + public string Component { get; set; } = string.Empty; + public string Redirect { get; set; } = string.Empty; + public string Path { get; set; } = string.Empty; + public string MetaTitle { get; set; } = string.Empty; + public bool MetaBreadcrumb { get; set; } + public string MetaIcon { get; set; } = string.Empty; + public string MetaActiveMenu { get; set; } = string.Empty; + public string FunctionName { get; set; } = string.Empty; + public bool IsFunction { get; set; } = false; + public string Note { get; set; } = string.Empty; + public int ShowOrder { get; set; } + public int Status { get; set; } = 1; + public bool Hidden { get; set; } + public bool SuperAdmin { get; set; } = true; + //public DateTime CreateTime { get; set; } = DateTime.Now; + //public Guid CreateUserId { get; set; } = Guid.Empty; + //public DateTime UpdateTime { get; set; } = DateTime.Now; + //public Guid UpdateUserId { get; set; } = Guid.Empty; + } + + public class RoleMenuFunctionSelectDTO + { + public Guid RoleId { get; set; } + public List MenuFunctionId { get; set; } + } + + + public class FunctionSelectDTO + { + public Guid RoleId { get; set; } + public Guid FunctionId { get; set; } + public bool IsSelect { get; set; } + } + +} diff --git a/IRaCIS.Core.Application.Contracts/Management/DTO/RoleViewModel.cs b/IRaCIS.Core.Application.Contracts/Management/DTO/RoleViewModel.cs new file mode 100644 index 0000000..26fd04e --- /dev/null +++ b/IRaCIS.Core.Application.Contracts/Management/DTO/RoleViewModel.cs @@ -0,0 +1,30 @@ +using System; + +namespace IRaCIS.Application.ViewModels +{ + public class RoleDTO + { + public Guid? Id { get; set; } = Guid.Empty; + public string RoleName { get; set; } + public string RoleDescription { get; set; } = string.Empty; + public int PrivilegeLevel { get; set; } + } + + public class UserRoleSelectDTO + { + public Guid userId { get; set; } + public Guid roleId { get; set; } + public bool isSelect { get; set; } + } + + + public class UserSelectRoleDTO : RoleDTO + { + public bool IsSelect { get; set; } + } + + public class RoleCommand : RoleDTO + { + + } +} diff --git a/IRaCIS.Core.Application.Contracts/Management/DTO/SysUserViewModel.cs b/IRaCIS.Core.Application.Contracts/Management/DTO/SysUserViewModel.cs new file mode 100644 index 0000000..f312d22 --- /dev/null +++ b/IRaCIS.Core.Application.Contracts/Management/DTO/SysUserViewModel.cs @@ -0,0 +1,172 @@ +using System; +using System.Collections.Generic; +using IRaCIS.Core.Application.Contracts.RequestAndResponse; +using Newtonsoft.Json; + + +namespace IRaCIS.Application.ViewModels +{ + public class UserLoginDTO + { + public string UserName { get; set; } + public string Password { get; set; } + } + + public class LoginReturnDTO + { + public UserBasicInfo BasicInfo { get; set; } = new UserBasicInfo(); + public string JWTStr { get; set; } + + public List MenuTree = new List(); + + //public List FuncTree = new List(); + + public Dictionary> FuncDictionary=new Dictionary>(); + + } + + public class UserBasicInfo + { + public Guid Id { get; set; } + public string UserName { get; set; } + public string RealName { get; set; } + public int Sex { get; set; } // 1-男 2-女 + public bool IsAdmin { get; set; } = false; + public bool IsReviewer { get; set; } = false; + public string ReviewerCode { get; set; } = string.Empty; + } + + public class MenuFuncTreeNodeView + { + [JsonIgnore] + public Guid Id { get; set; } + [JsonIgnore] + public Guid ParentId { get; set; } = Guid.Empty; + [JsonIgnore] + public int ShowOrder { get; set; } + public string routeName { get; set; } = string.Empty; + public string component { get; set; } = string.Empty; + public string redirect { get; set; } = string.Empty; + public string path { get; set; } = string.Empty; + public Meta meta { get; set; } + public bool hidden { get; set; } + public List Childrens { get; set; } + } + + public class Meta + { + public string MetaTitle { get; set; } = string.Empty; + public bool MetaBreadcrumb { get; set; } = false; + public string MetaIcon { get; set; } = string.Empty; + public string MetaActiveMenu { get; set; } = string.Empty; + } + + + public class FunctionTreeNodeDTO + { + [JsonIgnore] + public Guid Id { get; set; } + [JsonIgnore] + public Guid ParentId { get; set; } = Guid.Empty; + [JsonIgnore] + public int ShowOrder { get; set; } + + public string RouteName { get; set; } = string.Empty; + public string FunctionName { get; set; } = string.Empty; + + public List Childrens { get; set; } + } + + + + public class UserDetailDTO : UserInfo + { + public string UserTypeName { get; set; } + } + + public class UserInfo + { + public Guid Id { get; set; } + public string UserName { get; set; } + public string Password { get; set; } + public string RealName { get; set; } + public int Sex { get; set; } // 1-男 2-女 + + public int Status { get; set; } = 1; // 0-已删除 1-正常 + + public string Phone { get; set; } = string.Empty; + public string EMail { get; set; } = string.Empty; + public Guid UserTypeId { get; set; } = Guid.Empty; + public string OrganizationName { get; set; } = string.Empty; + public Guid OrganizationId { get; set; } + public string Code { get; set; } + + public bool IsZhiZhun { get; set; } + + public string UserType { get; set; } + public Guid OrganizationTypeId { get; set; } = Guid.Empty; + public string OrganizationType { get; set; } = String.Empty; + public string DepartmentName { get; set; } = String.Empty; + public string PositionName { get; set; } = String.Empty; + } + + /// + /// 添加用户是的返回模型 + /// + public class UserAddedReturnDTO + { + public Guid Id { get; set; } + public string Code { get; set; } + } + + + public class UserCommand : UserInfo + { + } + + public class EditPasswordCommand + { + public string NewPassWord { get; set; } + public string OldPassWord { get; set; } + } + + public class UserListQueryDTO : PageInput + { + public string UserName { get; set; } = string.Empty; + public string Phone { get; set; } = string.Empty; + public string OrganizationName { get; set; } = string.Empty; + public Guid? UserType { get; set; } = Guid.Empty; + public int? UserState { get; set; } + } + + public class UserRoleInfoDTO + { + public List RoleList { get; set; } = new List(); + public int MaxPrivilegeLevel { get; set; } + } + + public class UserListDTO : UserInfo + { + public IEnumerable RoleNameList { get; set; } = new List(); + } + + + public class UserIdRoleName : RoleDTO + { + public Guid UserId { get; set; } + } + public class UserIdRoleNameList + { + public Guid UserId { get; set; } + public IEnumerable RoleList { get; set; } + } + public class ResetPasswordCommand + { + public string EmailOrPhone { get; set; } + public int VerificationType { get; set; } + public string VerificationCode { get; set; } + public string NewPwd { get; set; } + + public bool IsReviewer { get; set; } = false; + } +} diff --git a/IRaCIS.Core.Application.Contracts/Management/IInstitutionService.cs b/IRaCIS.Core.Application.Contracts/Management/IInstitutionService.cs new file mode 100644 index 0000000..4f4e3d8 --- /dev/null +++ b/IRaCIS.Core.Application.Contracts/Management/IInstitutionService.cs @@ -0,0 +1,12 @@ +using IRaCIS.Application.ViewModels; +using System; +using System.Collections.Generic; + +namespace IRaCIS.Application.Interfaces +{ + public interface IInstitutionService + { + IEnumerable GetInstitutionSelectionByTypeId(Guid userTypeId); + + } +} diff --git a/IRaCIS.Core.Application.Contracts/Management/IMenuService.cs b/IRaCIS.Core.Application.Contracts/Management/IMenuService.cs new file mode 100644 index 0000000..4fd99f9 --- /dev/null +++ b/IRaCIS.Core.Application.Contracts/Management/IMenuService.cs @@ -0,0 +1,28 @@ +using IRaCIS.Application.ViewModels; +using System; +using System.Collections.Generic; +using IRaCIS.Core.Application.Contracts.RequestAndResponse; + +namespace IRaCIS.Application.Interfaces +{ + public interface IMenuService + { + + + + + /// 在某个父节点下面 新增子菜单 + IResponseOutput AddOrUpdateMenu(MenuFunctionCommand menuAddModel,Guid userId); + + /// 根据菜单Id 递归删除子菜单 + IResponseOutput DeleteMenuFunction(Guid menuId); + + List GetTreeAll(); + List GetMenuFunctionIsSelectByRoleId(Guid roleId); + List GetFunctionIsSelectByRoleId(Guid roleId, Guid parentId); + + IResponseOutput UpdateRoleMenuSelect(Guid roleId, List menuId); + IResponseOutput UpdateRoleFunctionSelect(FunctionSelectDTO functionSelect); + + } +} diff --git a/IRaCIS.Core.Application.Contracts/Management/IRoleService.cs b/IRaCIS.Core.Application.Contracts/Management/IRoleService.cs new file mode 100644 index 0000000..4b3a13e --- /dev/null +++ b/IRaCIS.Core.Application.Contracts/Management/IRoleService.cs @@ -0,0 +1,20 @@ +using System; +using IRaCIS.Application.ViewModels; +using IRaCIS.Core.Application.Contracts.RequestAndResponse; + +namespace IRaCIS.Application.Interfaces +{ + public interface IRoleService + { + IResponseOutput AddOrUpdateRole(RoleCommand role,Guid userId); + IResponseOutput DeleteRole(Guid roleId); + PageOutput GetRoleListByPage(int pageIndex, int pageSize); + + PageOutput GetRoleListByPage(Guid userId, int pageIndex, int pageSize); + + IResponseOutput UpdateUserRole(Guid userId, Guid roleId, bool isSelect); + + + + } +} diff --git a/IRaCIS.Core.Application.Contracts/Management/IUserService.cs b/IRaCIS.Core.Application.Contracts/Management/IUserService.cs new file mode 100644 index 0000000..6af8eca --- /dev/null +++ b/IRaCIS.Core.Application.Contracts/Management/IUserService.cs @@ -0,0 +1,40 @@ +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using IRaCIS.Application.ViewModels; +using IRaCIS.Core.Application.Contracts.RequestAndResponse; + +namespace IRaCIS.Application.Interfaces +{ + public interface IUserService + { + + Task SendVerificationCode(string emailOrPhone, int verificationType,bool isReviewer=false); + + IResponseOutput SetNewPassword(string emailOrPhone, int verificationType, + string verificationCode, string newPwd,bool isReviewer); + + IResponseOutput Login(string userName, string password); + IResponseOutput VerifySignature(string userName, string password); + IEnumerable GetAllUser(); + + + PageOutput GetUserList(UserListQueryDTO userQueryModel); + + IResponseOutput UpdateUserState(Guid userId, int state); + UserDetailDTO GetUserById(Guid id); + + IResponseOutput AddUser(UserCommand userAddModel, Guid userId); + + IResponseOutput UpdateUser(UserCommand userUpdateModel, Guid userId); + + IResponseOutput ResetPassword(Guid userId); + + List GetUserRolesById(Guid userId); + int GetUserRoleMaxPrivilegeLevel(Guid userId); + IResponseOutput ModifyPassword(EditPasswordCommand editPwModel); + + + + } +} diff --git a/IRaCIS.Core.Application.Contracts/Report/DTO/GlobalReportDTO.cs b/IRaCIS.Core.Application.Contracts/Report/DTO/GlobalReportDTO.cs new file mode 100644 index 0000000..97886c9 --- /dev/null +++ b/IRaCIS.Core.Application.Contracts/Report/DTO/GlobalReportDTO.cs @@ -0,0 +1,93 @@ +using System; +using System.Collections.Generic; +using IRaCIS.Core.Domain.Models; + +namespace IRaCIS.Core.Application.Contracts +{ + public class HistoryVisitRSDTO + { + + public Guid StudyId { get; set; } + public string StudyCode { get; set; } + + public decimal VisitNum { get; set; } + + public string VisitName { get; set; } + + public string OverallResponse { get; set; } + + public string TpCode { get; set; } + + public GlobalRSSelectView GlobalRSSelect { get; set; } + + } + + public class GlobalRSSelectView + { + public bool? Agree { get; set; } + public string NewRS { get; set; } + public string Note { get; set; } + } + + public class HistoryGlobalRsDTO + { + + public decimal VisitNum { get; set; } + + public string VisitName { get; set; } + + public string OverallResponse { get; set; } + } + + public class PreviousGlobalReadsView + { + public string SubjectNote { get; set; } + + public List PreviousGlobalReadsList { get; set; } = new List(); + } + + + public class GlobalTaskReportCommand + { + public Guid GlobalId { get; set; } + public string SubjectNote { get; set; } + public string SubjectCode { get; set; } + public Guid SubjectId { get; set; } + + public List GlobalRSReportList { get; set; }=new List(); + } + + public class GlobalReportCommand + { + public Guid GlobalId { get; set; } + public string TpCode { get; set; } + public int VisitNum { get; set; } + public bool? Agree { get; set; } + public string NewRS { get; set; } + public string Note { get; set; } + + } + + + public class AdReportDTO + { + public WorkloadAD ADInfo { get; set; } + public PreviousGlobalReadsView Global1 { get; set; } + public PreviousGlobalReadsView Global2 { get; set; } + + public IEnumerable Global1VisitRS { get; set; }=new List(); + public IEnumerable Global2VisitRS { get; set; } = new List(); + + } + + + public class ADReportCommand + { + + public Guid AdId { get; set; } + public Guid SelectGlobalId { get; set; } + public string ADNote { get; set; } + } + + +} \ No newline at end of file diff --git a/IRaCIS.Core.Application.Contracts/Report/DTO/ReportDTO.cs b/IRaCIS.Core.Application.Contracts/Report/DTO/ReportDTO.cs new file mode 100644 index 0000000..7818ce4 --- /dev/null +++ b/IRaCIS.Core.Application.Contracts/Report/DTO/ReportDTO.cs @@ -0,0 +1,280 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace IRaCIS.Core.Application.Contracts +{ + public class LesionInformation + { + public Guid TUId { get; set; } + public int LesionType { get; set; } //病灶类型 + public string STUDYID { get; set; } // 项目ID + public string USUBJID { get; set; } // 受试者ID + public int TUSEQ { get; set; } // 病灶序号 + + // 病灶分组,主要是用于将分裂或者结合在一起的已经被标识的肿瘤分类 + public string TUGRPID { get; set; } = string.Empty; + + //内部或外部的肿瘤/病灶标识。 例如:医学影像 ID + public string TUREFID { get; set; } = string.Empty; + + public string TUSPID { get; set; } = string.Empty;// 申办方标识 + + // 关联测量结果,及TUGRPID一起,标识分裂及合并 + public string TULNKID { get; set; } = string.Empty; + + /// + /// 检查项目 + /// TUMIDENT (Tumor Identification ) + /// TUSPLIT (Tumor Split ) + /// TUMERGE (Tumor Merged) + /// + public string TUTESTCD { get; set; } = string.Empty; + public string TUTEST { get; set; } = string.Empty; + + public string TUORRES { get; set; } = string.Empty;//TARGET, NON-TARGET, NEW + + public string TUSTRESC { get; set; } = string.Empty;//包含从 TUORRES拷贝的所有发现的结果 + public string TUNAM { get; set; } = string.Empty;//完成肿瘤标识的供应商名称或标识 + + public string LocDescription { get; set; } = string.Empty;// 部位描述 + public string TULOC { get; set; } = string.Empty; // 解剖学部位 + public string TULAT { get; set; } = string.Empty;//解剖学部位或者样本更详细的偏侧性修饰语,比如,左侧, 右侧,双侧。 + public string TUDIR { get; set; } = string.Empty;//解剖学部位或者样本更详细的方向性修饰语,比如,上边的 ,里面的。 + public string TUPORTOT { get; set; } = string.Empty;//解剖学部位或者样本更详细的分布,安排,分配的修饰语, 比如,全部的,单一的,部分的,多数的。 + + public string TUMETHOD { get; set; } = string.Empty; //用来标识肿瘤的办法。 例如,核磁共振,CT扫描。 + + public string TUEVAL { get; set; } = string.Empty; //评估者的角色。 例如:研究者,独立评估者。 + public string TUEVALID { get; set; } = string.Empty;//这个特定的评估者变量是与 TUEVAL一起使用来提供更详 细的信息 + public string TUACPTFL { get; set; } = string.Empty; + + // 访视信息 + public decimal VISITNUM { get; set; } = 0; + public string VISIT { get; set; } = string.Empty; + public int VISITDY { get; set; } + public string EPOCH { get; set; } = string.Empty; + public string TUDTC { get; set; } = string.Empty; + public int TUDY { get; set; } = 0; + + //TR + + public string TRTESTCD { get; set; } + public string TRTEST { get; set; } + public string TRORRES { get; set; } = string.Empty;//原始收到或采集的肿瘤测量/评估结 + public string TRORRESU { get; set; } = string.Empty;//原始单位 + public string TRSTRESC { get; set; } = string.Empty;//标准化结 果 + public double TRSTRESN { get; set; }//标准化结 果(N) + public string TRSTRESU { get; set; } // 标准化单位 + public string TRSTAT { get; set; } // 未做状态 + public string TRREASND { get; set; } // 未做原因 + public string Note { get; set; } + public string TRGRPID { get; set; } + public string TRDTC { get; set; } = string.Empty; + public int TRDY { get; set; } = 0; + ////RS + //public string RSCAT { get; set; } // 类别,用来识别对反应评估中使用的标准,以及适当时提供版本号 + //public string RSORRES { get; set; } //原始接收、采集或者计算的肿瘤反应评估的结果。 + //public string RSSTRESC { get; set; } //标准化结果 + + public bool CoveredLesion { get; set; } + } + public class VisitLesion : LesionInformation + { + public LesionInformation CurrentLesion { get; set; } = new LesionInformation(); + } + + public class EfficacyAssessment + { + public string TargetLesion { get; set; } = string.Empty; + public string Non_targetLesion { get; set; } = string.Empty; + public string OverallAssessment { get; set; } = string.Empty; + + public string TargetLesionNote { get; set; } = string.Empty; + public string Non_targetLesionNote { get; set; } = string.Empty; + public string OverallAssessmentNote { get; set; } = string.Empty; + } + + public class PreviousOverallAssessment + { + public string VisitName { get; set; } + public string OverallAssessment { get; set; } + } + public class VisitLesionInfo + { + //基线病灶信息及本次访视测量信息 + public IList BLLesionList { get; set; } = new List(); + // public IList BLVisitLesionList { get; set; } = new List(); + //public IList CurrentVisitLesionList { get; set; } = new List(); + + // 以往病灶信息 + public IList PreviousNewLesionList { get; set; } = new List(); + //本次疑似新病灶 + public IList EquivocalNewLesionList { get; set; } = new List(); + public IList UnequivocalNewLesionList { get; set; } = new List(); + public ReportDTO ReportResult { get; set; } = new ReportDTO(); + public EfficacyAssessment Efficacy { get; set; } = new EfficacyAssessment(); + public List PreviousOverallAssessment { get; set; } = new List(); + + public MinVisit MinVisitInfo { get; set; } + } + + public class MinVisit + { + public double MinSum { get; set; } = 0.0; + public string MinVistName { get; set; } = string.Empty; + } + public class ReportCommand + { + public List LesionInformationList { get; set; } + + //RS + public string RSCAT { get; set; } // 类别,用来识别对反应评估中使用的标准,以及适当时提供版本号 + public string RSORRES { get; set; } //原始接收、采集或者计算的肿瘤反应评估的结果。 + public string RSSTRESC { get; set; } //标准化结果 + } + public class TUDTO + { + public int LesionType { get; set; } + public string STUDYID { get; set; } + public string USUBJID { get; set; } + public int TUSEQ { get; set; } + public string TUGRPID { get; set; } = string.Empty; + public string TUREFID { get; set; } = string.Empty;//内部或外部的肿瘤/病灶标识。 例如:医学影像 ID + public string TUSPID { get; set; } = string.Empty; + public string TULNKID { get; set; } = string.Empty; + public string TUTESTCD { get; set; } = string.Empty; + public string TUTEST { get; set; } = string.Empty; + + public double TUORRES { get; set; } = 0; + public string TUSTRESC { get; set; } = string.Empty; + public string TUNAM { get; set; } = string.Empty; + public string TULOC { get; set; } = string.Empty; + public string TULAT { get; set; } = string.Empty; + public string TUDIR { get; set; } = string.Empty; + public string TUPORTOT { get; set; } = string.Empty; + public string TUMETHOD { get; set; } = string.Empty; + public string TUEVAL { get; set; } = string.Empty; + public string TUEVALID { get; set; } = string.Empty; + public string TUACPTFL { get; set; } = string.Empty; + public double VISITNUM { get; set; } = 0; + public string VISIT { get; set; } = string.Empty; + public string VISITDY { get; set; } = string.Empty; + public string EPOCH { get; set; } = string.Empty; + public string TUDTC { get; set; } = string.Empty; + public int TUDY { get; set; } = 0; + } + public class TRDTO + { + public string STUDYID { get; set; } = string.Empty; + public string DOMAIN { get; set; } = string.Empty; + public string USUBJID { get; set; } = string.Empty; + public int TRSEQ { get; set; } + public string TRGRPID { get; set; } = string.Empty; + public string TRREFID { get; set; } = string.Empty; + public string TRSPID { get; set; } = string.Empty; + public string TRLNKID { get; set; } = string.Empty; + public string TRLNKGRP { get; set; } = string.Empty; + public string TRTESTCD { get; set; } = string.Empty; + public string TRTEST { get; set; } = string.Empty; + public string TRORRES { get; set; } = string.Empty; + public string TRORRESU { get; set; } = string.Empty; + public string TRSTRESC { get; set; } = string.Empty; + public double TRSTRESN { get; set; } = 0; + public string TRSTRESU { get; set; } = string.Empty; + public string TRSTAT { get; set; } = string.Empty; + public string TRREASND { get; set; } = string.Empty; + public string TRNAM { get; set; } = string.Empty; + public string TRMETHOD { get; set; } = string.Empty; + public string TREVAL { get; set; } = string.Empty; + public string TREVALID { get; set; } = string.Empty; + public string TRACPTFL { get; set; } = string.Empty; + public decimal VISITNUM { get; set; } = 0; + public string VISIT { get; set; } = string.Empty; + public int VISITDY { get; set; } = 0; + public string EPOCH { get; set; } = string.Empty; + public string TRDTC { get; set; } = string.Empty; + public int TRDY { get; set; } = 0; + public string Note { get; set; } = string.Empty; + public bool CoveredLesion { get; set; } = true; + } + + public class RSDTO + { + public string STUDYID { get; set; } = string.Empty; + public string DOMAIN { get; set; } = string.Empty; + public string USUBJID { get; set; } = string.Empty; + public int RSSEQ { get; set; } + public string RSGRPID { get; set; } = string.Empty; + public string RSREFID { get; set; } = string.Empty; + public string RSSPID { get; set; } = string.Empty; + public string RSLNKID { get; set; } = string.Empty; + public string RSLNKGRP { get; set; } = string.Empty; + public string RSTESTCD { get; set; } = string.Empty; + public string RSTEST { get; set; } = string.Empty; + public string RSCAT { get; set; } = string.Empty; + public string RSORRES { get; set; } = string.Empty; + public string RSSTRESC { get; set; } = string.Empty; + public string RSSTAT { get; set; } = string.Empty; + public string RSREASND { get; set; } = string.Empty; + public string RSNAM { get; set; } = string.Empty; + + public string RSEVAL { get; set; } = string.Empty; + public string RSEVALID { get; set; } = string.Empty; + public string RSACPTFL { get; set; } = string.Empty; + public decimal VISITNUM { get; set; } = 0; + public string VISIT { get; set; } = string.Empty; + public int VISITDY { get; set; } = 0; + public string EPOCH { get; set; } = string.Empty; + public string RSDTC { get; set; } = string.Empty; + public int RSDY { get; set; } = 0; + public Guid StudyGuid { get; set; } = Guid.Empty; + public Guid TrialGuid { get; set; } = Guid.Empty; + public Guid SubjectGuid { get; set; } = Guid.Empty; + + public string Note { get; set; } = string.Empty; + } + public class ReportDTO + { + public bool Qualified { get; set; } = true; + public string DiseaseProgression { get; set; } = string.Empty; + public string NotEvaluable { get; set; } = string.Empty; + public string Timepoint { get; set; } = string.Empty; + public string TrialCode { get; set; } = string.Empty; + public string SubjectCode { get; set; } = string.Empty; + public decimal? VisitNum { get; set; } + public string VisitName { get; set; } = string.Empty; + public int? DiseaseSituation { get; set; } + public string Comment { get; set; } + public Guid? TPId { get; set; } + public Guid? DicomStudyId { get; set; } + public string TpCode { get; set; } = string.Empty; + + public bool AffectRead { get; set; }//是否影响读片 + public string AffectReadNote { get; set; }//备注说明 + } + + + public class VisitReportCommand + { + public List LesionInformation { get; set; } = new List(); + public List TRList { get; set; } = new List(); + public List RSList { get; set; } = new List(); + public ReportDTO ReportResult { get; set; } = new ReportDTO(); + } + + public class BaseLineReportCommand + { + //public Guid TimepointId { get; set; } + public string SumOfDiameter { get; set; } + public string SumDiameterOfNonLymphNode { get; set; } + public IList LesionInformation { get; set; } = new List(); + public ReportDTO ReportResult { get; set; } = new ReportDTO(); + } + + public class BaseLineReportDTO + { + public IList LesionInformation { get; set; } = new List(); + public ReportDTO ReportResult { get; set; } = new ReportDTO(); + } +} diff --git a/IRaCIS.Core.Application.Contracts/Report/IGlobalService.cs b/IRaCIS.Core.Application.Contracts/Report/IGlobalService.cs new file mode 100644 index 0000000..85907a2 --- /dev/null +++ b/IRaCIS.Core.Application.Contracts/Report/IGlobalService.cs @@ -0,0 +1,23 @@ +using System; +using System.Collections.Generic; + +namespace IRaCIS.Core.Application.Contracts +{ + public interface IGlobalService + { + //string GetCommentsForSubject(Guid globalId); + IEnumerable GetHistoryVisitRsList(Guid trialId, Guid subjectId, decimal visitNum, Guid globalId,string globalCode); + + PreviousGlobalReadsView GetHistoryGlobalRsList(Guid trialId, Guid subjectId, decimal visitNum, Guid globalId); + + bool AddGlobalReport(GlobalTaskReportCommand globalTaskReportCommand); + + + + AdReportDTO GetAdReport(Guid adId); + bool AddAdjudicationReport(ADReportCommand adReportCommand); + } + + + +} \ No newline at end of file diff --git a/IRaCIS.Core.Application.Contracts/Report/IReportService.cs b/IRaCIS.Core.Application.Contracts/Report/IReportService.cs new file mode 100644 index 0000000..7c38718 --- /dev/null +++ b/IRaCIS.Core.Application.Contracts/Report/IReportService.cs @@ -0,0 +1,27 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace IRaCIS.Core.Application.Contracts +{ + public interface IReportService + { + //bool SaveReport(ReportCommand reportCommand); + + /// 添加基线期病灶标识及测量信息 + bool AddLesion(List lesionInformation, ReportDTO report); + /// 获取基线期信息 + //IList GetBLLesion(string trialCode, string subjectCode); + + /// + /// 获取访视病灶信息 + /// + VisitLesionInfo GetVisitLesion(string trialCode, string subjectCode, decimal visitNum,string tpCode); + + bool SaveVisitReport(VisitReportCommand visitReportCommand); + bool SaveBLReport(BaseLineReportCommand baseLineReportCommand); + BaseLineReportDTO GetBaseLineReport(string trialCode, string subjectCode, string tpCode); + + bool SubmiteReport(Guid tpId); + } +} diff --git a/IRaCIS.Core.Application.Contracts/ReviewerReading/DTO/WorkloadReadingDTO.cs b/IRaCIS.Core.Application.Contracts/ReviewerReading/DTO/WorkloadReadingDTO.cs new file mode 100644 index 0000000..472699e --- /dev/null +++ b/IRaCIS.Core.Application.Contracts/ReviewerReading/DTO/WorkloadReadingDTO.cs @@ -0,0 +1,40 @@ +using IRaCIS.Core.Application.Contracts.RequestAndResponse; +using System; + +namespace IRaCIS.Application.ViewModels +{ + public class WorkloadReadingDTO + { + public Guid Id { get; set; } + + public Guid StudyId { get; set; } + public Guid TrialId { get; set; } + public string TrialCode { get; set; } + public string TrialIndication { get; set; } + public string Sponsor { get; set; } + public int Expedited { get; set; } + + public Guid SubjectId { get; set; } + public string SubjectCode { get; set; } + + public string VisitName { get; set; } + public decimal VisitNum { get; set; } + + + public Guid WorkloadId { get; set; } + public string WorkloadCode { get; set; } + public int WorkloadType { get; set; } + public int Status { get; set; } + + public DateTime UpdateTime { get; set; } + } + + public class WorkloadQueryParam : PageInput + { + public Guid? TrialId { get; set; } = Guid.Empty; + public string SubjectCode { get; set; } = string.Empty; + public int? Status { get; set; } + public int WorkloadType { get; set; } + public int? Expedited { get; set; } + } +} diff --git a/IRaCIS.Core.Application.Contracts/ReviewerReading/IReviewerReadingService.cs b/IRaCIS.Core.Application.Contracts/ReviewerReading/IReviewerReadingService.cs new file mode 100644 index 0000000..9261533 --- /dev/null +++ b/IRaCIS.Core.Application.Contracts/ReviewerReading/IReviewerReadingService.cs @@ -0,0 +1,10 @@ +using IRaCIS.Application.ViewModels; +using IRaCIS.Core.Application.Contracts.RequestAndResponse; + +namespace IRaCIS.Application.Interfaces +{ + public interface IReviewerReadingService + { + PageOutput GetWorkloadList(WorkloadQueryParam param); + } +} diff --git a/IRaCIS.Core.Application.Contracts/StatisticsViewModel.cs b/IRaCIS.Core.Application.Contracts/StatisticsViewModel.cs new file mode 100644 index 0000000..d907062 --- /dev/null +++ b/IRaCIS.Core.Application.Contracts/StatisticsViewModel.cs @@ -0,0 +1,243 @@ +using System; +using System.Collections.Generic; +using IRaCIS.Core.Application.Contracts.RequestAndResponse; + +namespace IRaCIS.Application.ViewModels +{ + + public class EnrollStatByReviewerDTO + { + public Guid Id { get; set; } + public string Hospital { get; set; } + public string ChineseName { get; set; } = string.Empty; + + public string FirstName { get; set; } = string.Empty; + public string LastName { get; set; } = string.Empty; + public string ReviewerCode { get; set; } = string.Empty; + + public int Pending { get; set; } + public int Approved { get; set; } + public int Reading { get; set; } + public int Finished { get; set; } + public int Total { get; set; } + public double EntryRate + { + get + { + if (Total == 0) + { + return 0; + } + return Math.Round(((Reading + Finished) / (double)Total) * 100, 1, MidpointRounding.AwayFromZero); + ; + } + } + + } + + + public class EnrollStatByTrialDTO + { + public string TrialCode { get; set; } + public Guid TrialId { get; set; } + public string Indication { get; set; } + //public Guid CroId { get; set; } + public string Cro { get; set; } = string.Empty; + + public DateTime CreateTime { get; set; } + + public int Expedited { get; set; } + + public int EnrollCount { get; set; } + + public List ReviewerNameCNList=new List(); + + public List ReviewerNameList=new List(); + } + + + #region 统计 20200413 add by dingke + public class WorkloadByTrialAndReviewerDTO + { + public Guid Id { get; set; } + public string TrialCode { get; set; } + public Guid TrialId { get; set; } + public string Indication { get; set; } + public Guid CroId { get; set; } + public string Cro { get; set; } = string.Empty; + public string ChineseName { get; set; } = string.Empty; + + public string FirstName { get; set; } = string.Empty; + public string LastName { get; set; } = string.Empty; + public string ReviewerCode { get; set; } = string.Empty; + + public int Training { get; set; } + public int Downtime { get; set; } + public int Timepoint { get; set; } + public int TimepointIn24H { get; set; } + public int TimepointIn48H { get; set; } + public int Adjudication { get; set; } + public int AdjudicationIn24H { get; set; } + public int AdjudicationIn48H { get; set; } + public int Global { get; set; } + + public int RefresherTraining { get; set; } + + public int PersonalTotal { get; set; } + } + + + public class StatisticsQueryDTO : PageInput + { + public Guid? CroId { get; set; } = Guid.Empty; + public string TrialCode { get; set; } = string.Empty; + public string Reviewer { get; set; } = string.Empty; + public DateTime BeginDate { get; set; } = DateTime.Now; + public DateTime EndDate { get; set; } = DateTime.Now; + public int StatType { get; set; } + + //医生付费类型 CN US + public int? Nation { get; set; } + public int? AttendedReviewerType { get; set; } + } + + public class StatisticsWorkloadQueryParam : PageInput + { + public Guid? CroId { get; set; } = Guid.Empty; + public string TrialCode { get; set; } = string.Empty; + public string Reviewer { get; set; } = string.Empty; + public DateTime BeginDate { get; set; } = DateTime.Now; + public DateTime EndDate { get; set; } = DateTime.Now; + public int StatType { get; set; } + + public Guid? HospitalId { get; set; } = Guid.Empty; + } + + public class RevenuesStatQueryDTO : PageInput + { + public Guid CroId { get; set; } = Guid.Empty; + + public string Reviewer { get; set; } = string.Empty; + public string TrialCode { get; set; } = string.Empty; + public DateTime BeginDate { get; set; } = DateTime.Now; + public DateTime EndDate { get; set; } = DateTime.Now; + + public int StatType { get; set; } + } + + + public class EnrollStatByReviewerQueryDTO : PageInput + { + public Guid? HospitalId { get; set; } = Guid.Empty; + public string Reviewer { get; set; } = string.Empty; + public DateTime BeginDate { get; set; } = DateTime.Now; + public DateTime EndDate { get; set; } = DateTime.Now; + } + + + public class EnrollStatByTrialQueryDTO : PageInput + { + public string TrialCode { get; set; } + + public string Indication { get; set; } + public DateTime? BeginDate { get; set; } = DateTime.Now; + public DateTime? EndDate { get; set; } = DateTime.Now; + + public Guid? CROId { get; set; } + + public int? Expedited { get; set; } + } + #endregion + + #region dashbord + + /// + /// 读片数量分类统计 + /// + public class ReadingDataDTO + { + public int Timepoint { get; set; } + public int Adjudication { get; set; } + public int Global { get; set; } + } + + public class ReadingDataMonthDTO : ReadingDataDTO + { + public string Month { get; set; } + } + + public class ReadingDataRankDTO : ReadingDataDTO + { + public int TotalReadingCount { get; set; } + public Guid ReviewerId { get; set; } + public string ReviewerCode { get; set; } + public string FirstName { get; set; } + public string LastName { get; set; } + public string ChineseName { get; set; } + } + + public class RankReviewersDTO + { + public Guid RankId { get; set; } + public string RankName { get; set; } + public string RankNameAbbreviation + { + get + { + var arr = RankName.Split(' '); + return arr[0]; + } + } + public int ReviewerCount { get; set; } + } + + public class EnrollDataDTO + { + public int Year { get; set; } + public int Month { get; set; } + public string QuarterStr => Year + "-Q" + (Month / 3 + (Month % 3 == 0 ? 0 : 1)); + public string YearMonth => new DateTime(Year, Month, 1).ToString("yyyy-MM"); + public int EnrollCount { get; set; } + } + + + public class EnrollQuartDataDTO + { + //public int Year { get; set; } + + public string ViewStr { get; set; } + + public int EnrollCount { get; set; } + } + + public class LatestWorkLoadDTO : ReadingDataDTO + { + public int TotalReadingCount => Timepoint + Adjudication + Global; + public Guid ReviewerId { get; set; } + public string ReviewerCode { get; set; } + public string FirstName { get; set; } + public string LastName { get; set; } + public string ChineseName { get; set; } + public string TrialCode { get; set; } + } + + + + + public class TrialDataRankDTO + { + public Guid ReviewerId { get; set; } + public string ReviewerCode { get; set; } + public string FirstName { get; set; } + public string LastName { get; set; } + public string ChineseName { get; set; } + + public int TrialCount { get; set; } + } + + #endregion + + + + +} diff --git a/IRaCIS.Core.Application.Contracts/TreeNode.cs b/IRaCIS.Core.Application.Contracts/TreeNode.cs new file mode 100644 index 0000000..c8f0b22 --- /dev/null +++ b/IRaCIS.Core.Application.Contracts/TreeNode.cs @@ -0,0 +1,67 @@ +using System; +using System.Collections.Generic; + +namespace IRaCIS.Application.ViewModels +{ + + public class DictionaryTreeNode + { + public Guid Id { get; set; } + public string KeyName { get; set; } = string.Empty; + public string Type { get; set; } + public List Children { get; set; } + } + + public class MenuTreeNodeSelect + { + public Guid Id { get; set; } + public Guid ParentId { get; set; } + public string RouteName { get; set; } + public string MenuName { get; set; } + //public string Component { get; set; } + //public string Redirect { get; set; } + //public string Path { get; set; } + //public string MetaTitle { get; set; } + //public bool MetaBreadcrumb { get; set; } + //public string MetaIcon { get; set; } + //public string MetaActiveMenu { get; set; } + public string FunctionName { get; set; } + //public bool IsFunction { get; set; } + public string Note { get; set; } + public int ShowOrder { get; set; } + //public int Status { get; set; } + //public DateTime CreateTime { get; set; } + //public Guid CreateUserId { get; set; } + //public DateTime UpdateTime { get; set; } + //public Guid UpdateUserId { get; set; } + //public bool Hidden { get; set; } + public List Children { get; set; } + public bool IsSelect { get; set; } = false; + } + public class MenuTreeNode + { + public Guid Id { get; set; } + public Guid ParentId { get; set; } + public string RouteName { get; set; } + public string MenuName { get; set; } + public string Component { get; set; } + public string Redirect { get; set; } + public string Path { get; set; } + public string MetaTitle { get; set; } + public bool MetaBreadcrumb { get; set; } + public string MetaIcon { get; set; } + public string MetaActiveMenu { get; set; } + public string FunctionName { get; set; } + public bool IsFunction { get; set; } + public string Note { get; set; } + public int ShowOrder { get; set; } + public int Status { get; set; } + public DateTime CreateTime { get; set; } + public Guid CreateUserId { get; set; } + public DateTime UpdateTime { get; set; } + public Guid UpdateUserId { get; set; } + public bool Hidden { get; set; } + public List Children { get; set; } + } + +} \ No newline at end of file diff --git a/IRaCIS.Core.Application.Contracts/Trial/DTO/ClinicalStudySubjects.cs b/IRaCIS.Core.Application.Contracts/Trial/DTO/ClinicalStudySubjects.cs new file mode 100644 index 0000000..709e290 --- /dev/null +++ b/IRaCIS.Core.Application.Contracts/Trial/DTO/ClinicalStudySubjects.cs @@ -0,0 +1,65 @@ +using System; +using IRaCIS.Core.Application.Contracts.RequestAndResponse; + +namespace IRaCIS.Application.ViewModels +{ + public class SubjectDTO: SubjectCommand + { + public Guid SubjectVisitId { get; set; } + public int StudyCount { get; set; } + + public int VisitCount { get; set; } + public int PlanVisitCount { get; set; } + public string Modalities { get; set; } + } + + public class SubjectCommand + { + public Guid? Id { get; set; } + public string Code { get; set; }//患者匿名编码 + public string Name { get; set; } + public int Age { get; set; } + public string Sex { get; set; } + public Guid SiteId { get; set; } + public Guid TrialId { get; set; } + public string MedicalNo { get; set; } + public int Status { get; set; } + public string Reason { get; set; } + } + + public class SubjectQueryModel: SubjectDTO + { + public DateTime? CreateTime { get; set; } + public DateTime? UpdateTime { get; set; } + public string SiteName { get; set; } + public string VisitName { get; set; } + } + + public class SubjectQueryParam : PageInput + { + public Guid TrialId { get; set; } = Guid.Empty; + public string Code { get; set; } = string.Empty; + + public string Name { get; set; } = string.Empty; + + public string Sex { get; set; } = string.Empty; + + public Guid? SiteId { get; set; } + //public Guid? SubjectVisitId { get; set; } = Guid.Empty; + public int? Status { get; set; } + } + + + public class SubjectSelect + { + public Guid SubjectId { get; set; } + + public string Name { get; set; } + + public string Code { get; set; } + + public string Sex { get; set; } + + public int Age { get; set; } + } +} diff --git a/IRaCIS.Core.Application.Contracts/Trial/DTO/DoctorWorkLoadViewModel.cs b/IRaCIS.Core.Application.Contracts/Trial/DTO/DoctorWorkLoadViewModel.cs new file mode 100644 index 0000000..de4a00e --- /dev/null +++ b/IRaCIS.Core.Application.Contracts/Trial/DTO/DoctorWorkLoadViewModel.cs @@ -0,0 +1,234 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.Linq; +using IRaCIS.Core.Application.Contracts.RequestAndResponse; +using IRaCIS.Core.Domain.Share; + +namespace IRaCIS.Application.ViewModels +{ + /// + ///后台 工作量审核视图模型 + /// + public class WorkLoadDetailDTO : WorkloadDTO + { + public DateTime CreateTime { get; set; } + public string ChineseName { get; set; } + + public string FirstName { get; set; } + public string LastName { get; set; } + public string Code { get; set; } + public string Indication { get; set; } + public int RowIntId { get; set; } + public Guid RowGuid { get; set; } + public string YearMonthStr { get; set; } + + public string WorkTimeStr => YearMonthStr; + + public bool IsLock { get; set; } = false; + } + + public class WorkLoadDetailViewModel : WorkloadDTO + { + public DateTime CreateTime { get; set; } + public string ChineseName { get; set; } + public string FirstName { get; set; } + public string LastName { get; set; } + public string Code { get; set; } + public string Indication { get; set; } + + public Guid RowGuid { get; set; } + public string YearMonthStr { get; set; } + + public bool IsLock { get; set; } = false; + public string DeclareTimeStr => CreateTime.ToString("yyyy-MM-dd"); + + public string WorkTimeStr => WorkTime.ToString("yyyy-MM-dd"); + } + + + + public class CalculatePaymentDTO : WorkloadDTO + { + public string TrialCode { get; set; } + public decimal? TrialAdditional { get; set; } + public decimal AdjustmentMultiple { get; set; } + //public double RankPrice { get; set; } + public decimal PersonalAdditional { get; set; } + public decimal TimepointPrice { get; set; } + public decimal TimepointIn24HPrice { get; set; } + public decimal TimepointIn48HPrice { get; set; } + public decimal AdjudicationPrice { get; set; } + public decimal AdjudicationIn24HPrice { get; set; } + public decimal AdjudicationIn48HPrice { get; set; } + public decimal GlobalPrice { get; set; } + public decimal TrainingPrice { get; set; } + public decimal DowntimePrice { get; set; } + public decimal RefresherTrainingPrice { get; set; } + } + + /// + /// 工作量审核数据库查询模型 + /// + public class WorkloadDTO + { + public Guid? Id { get; set; } + + public Guid TrialId { get; set; } + + public Guid DoctorId { get; set; } + + public int DataFrom { get; set; } + + public DateTime WorkTime { get; set; } + + public int Training { get; set; } + + public int Downtime { get; set; } + + public int Timepoint { get; set; } + + public int TimepointIn24H { get; set; } + + public int TimepointIn48H { get; set; } + + public int Adjudication { get; set; } + + public int AdjudicationIn24H { get; set; } + + public int AdjudicationIn48H { get; set; } + + public int Global { get; set; } + public int RefresherTraining { get; set; } + + + } + + /// + /// 工作量分页列表模型 医生端查询模型 + /// + public class WorkLoadQueryDTO : PageInput + { + public Guid TrialId { get; set; } + public int WorkLoadFromStatus { get; set; } // 关联枚举 + public DateTime? SearchBeginDateTime { get; set; } + public DateTime? SearchEndDateTime { get; set; } + } + + /// + /// 后台查询模型 + /// + public class WorkLoadStatsQueryDTO : PageInput + { + public Guid? TrialId { get; set; } + public Guid? DoctorId { get; set; } = Guid.Empty; + public List WorkLoadFromStatus { get; set; } = new List(); // 关联枚举 + public DateTime? SearchBeginDateTime { get; set; } + public DateTime? SearchEndDateTime { get; set; } + } + + + public class WorkLoadDetailQueryDTO + { + public Guid TrialId { get; set; } = Guid.Empty; + public Guid DoctorId { get; set; } = Guid.Empty; + public string YearMonthStr { get; set; } + } + + public class CalculateDoctorAndMonthDTO + { + [Required(ErrorMessage = "需要有效的时间")] + public DateTime CalculateMonth { get; set; } + + [Required(ErrorMessage = "需要有效的医生列表")] + public List NeedCalculateReviewers { get; set; } + } + + public class WorkLoadDoctorQueryDTO : PageInput + { + public Guid TrialId { get; set; } = Guid.Empty; + } + + public class WorkLoadCommand : WorkloadDTO + { + public Guid CreateUserId { get; set; } + public int CreateUserType { get; set; } + public Guid UpdateUserId { get; set; } + } + + + public class ExistWorkloadViewModel + { + public bool IsExist { get; set; } + public WorkloadDTO WorkLoad { get; set; } + } + + public class WorkloadCommand : WorkloadDTO + { + } + + public class WorkloadExistQueryDTO + { + public Guid TrialId { get; set; } + public Guid DoctorId { get; set; } + public DateTime WorkDate { get; set; } + } + + + + public class WorkLoadAndTrainingDTO + { + + public Guid DoctorId { get; set; }/*=Guid.Empty;*/ + public string Code { get; set; } + public string FirstName { get; set; } + public string LastName { get; set; } + public string ChineseName { get; set; } + + public DateTime? EnrollTime { get; set; } + + public int ReviewerReadingType { get; set; } + + public string EnrollTimeStr => EnrollTime?.ToString("yyyy-MM-dd HH:mm:ss"); + + public DateTime? UpdateTime { get; set; } + + public string UpdateTimeStr => UpdateTime?.ToString("yyyy-MM-dd HH:mm:ss"); + + public int TrainingTimes { get; set; } + public int Downtime { get; set; } + + //读片点 + public int Timepoint { get; set; } + public int TimepointIn24H { get; set; } + public int TimepointIn48H { get; set; } + + //裁判阅片 + public int Adjudication { get; set; } + public int AdjudicationIn24H { get; set; } + public int AdjudicationIn48H { get; set; } + + //全局阅片 + public int Global { get; set; } + + public int RefresherTraining { get; set; } + + + + } + + + public class WorkLoadAndAgreementDTO : WorkLoadAndTrainingDTO + { + public Guid AgreementId { get; set; } + + public string AgreementPath { get; set; } + + public string AgreementFileName => AgreementPath?.Split('/').Last(); + + public string AgreementFullPath => SystemConfig.RootUrl + AgreementPath; + } + + + +} \ No newline at end of file diff --git a/IRaCIS.Core.Application.Contracts/Trial/DTO/ImageAcquisitionSpecificationViewModel.cs b/IRaCIS.Core.Application.Contracts/Trial/DTO/ImageAcquisitionSpecificationViewModel.cs new file mode 100644 index 0000000..b4e5fac --- /dev/null +++ b/IRaCIS.Core.Application.Contracts/Trial/DTO/ImageAcquisitionSpecificationViewModel.cs @@ -0,0 +1,40 @@ +using System; +using IRaCIS.Core.Application.Contracts.RequestAndResponse; +using IRaCIS.Core.Domain.Share; + +namespace IRaCIS.Application.ViewModels +{ + /// + /// 影像采集规范 + /// + public class TrialAttachmentCommand + { + public Guid? Id { get; set; } + public Guid TrialId { get; set; } + public string Type { get; set; } + + public string DocumentName { get; set; } + public string DocumentPath { get; set; } + public string DocumentFullPath + { + get { return SystemConfig.RootUrl + DocumentPath; } + } + + } + + + + public class AcquisitionSpecificationDTO : TrialAttachmentCommand + { + public string TrialCode { get; set; } + public string Indication { get; set; } + public string OptUserName { get; set; } + + public DateTime CreateTime { get; set; } + } + + public class ImageAcquisitionSpecificationQueryDTO : PageInput + { + public Guid TrialId { get; set; } + } +} diff --git a/IRaCIS.Core.Application.Contracts/Trial/DTO/TrialInterViewViewModel.cs b/IRaCIS.Core.Application.Contracts/Trial/DTO/TrialInterViewViewModel.cs new file mode 100644 index 0000000..dbb5218 --- /dev/null +++ b/IRaCIS.Core.Application.Contracts/Trial/DTO/TrialInterViewViewModel.cs @@ -0,0 +1,21 @@ +using System; +using IRaCIS.Core.Application.Contracts.RequestAndResponse; + +namespace IRaCIS.Application.ViewModels +{ + public class TrialInterviewDTO + { + public Guid Id { get; set; } + public Guid TrialId { get; set; } + public string Stage { get; set; } + public string InterViewTime { get; set; } + public string Description { get; set; } + public DateTime CreateTime { get; set; } + } + + public class InterviewQueryDTO : PageInput + { + public Guid TrialId { get; set; } = Guid.Empty; + public string Keyword { get; set; } = string.Empty; + } +} diff --git a/IRaCIS.Core.Application.Contracts/Trial/DTO/TrialResearchCenter.cs b/IRaCIS.Core.Application.Contracts/Trial/DTO/TrialResearchCenter.cs new file mode 100644 index 0000000..6135725 --- /dev/null +++ b/IRaCIS.Core.Application.Contracts/Trial/DTO/TrialResearchCenter.cs @@ -0,0 +1,28 @@ +using System; +using IRaCIS.Core.Application.Contracts.RequestAndResponse; + +namespace IRaCIS.Application.ViewModels +{ + public class TrialResearchCenterDTO + { + public Guid Id { get; set; } + public Guid TrialId { get; set; } + public Guid SiteId { get; set; } + public string MainCenter { get; set; } + public DateTime OptTime { get; set; } + public int State { get; set; } + } + + public class TrialResearchCenterDetailDTO : TrialResearchCenterDTO + { + public string TrialCode { get; set; } + public string TrialName { get; set; } + public string ResearchCenterName { get; set; } + } + + public class TrialCenterQueryDTO : PageInput + { + public Guid TrialId { get; set; } + public Guid CenterId { get; set; } + } +} diff --git a/IRaCIS.Core.Application.Contracts/Trial/DTO/TrialRevenuesPriceVerificationDTO.cs b/IRaCIS.Core.Application.Contracts/Trial/DTO/TrialRevenuesPriceVerificationDTO.cs new file mode 100644 index 0000000..55f72d9 --- /dev/null +++ b/IRaCIS.Core.Application.Contracts/Trial/DTO/TrialRevenuesPriceVerificationDTO.cs @@ -0,0 +1,72 @@ +using System; +using System.Collections.Generic; + +namespace IRaCIS.Core.Application.Contracts.Trial.DTO +{ + public class RevenusVerifyQueryDTO + { + public DateTime BeginDate { get; set; } = DateTime.Now; + public DateTime EndDate { get; set; } = DateTime.Now; + + } + + public class AnalysisVerifyQueryDTO + { + public DateTime BeginDate { get; set; } = DateTime.Now; + public DateTime EndDate { get; set; } = DateTime.Now; + } + + + public class AnalysisNeedLockDTO + { + public string YearMonth { get; set; } + + public string ReviewerCode { get; set; } + + public string ReviewerName { get; set; } + + public string ReviewerNameCN { get; set; } + } + + public class AnalysisVerifyResultDTO + { + public List MonthVerifyResult = new List(); + + public List RevenuesVerifyList = new List(); + } + + + + public class MonthlyResult + { + public string YearMonth { get; set; } + public List ReviewerNameList = new List(); + public List ReviewerNameCNList = new List(); + public List ReviewerCodeList = new List(); + } + + + public class RevenusVerifyDTO + { + public string TrialCode { get; set; } + + public bool Training { get; set; } = false; + + public bool Downtime { get; set; } = false; + + public bool Global { get; set; } = false; + + public bool Timepoint { get; set; } = false; + + public bool TimepointIn24H { get; set; } = false; + + public bool TimepointIn48H { get; set; } = false; + + public bool Adjudication { get; set; } = false; + + public bool AdjudicationIn24H { get; set; } = false; + + public bool AdjudicationIn48H { get; set; } = false; + + } +} \ No newline at end of file diff --git a/IRaCIS.Core.Application.Contracts/Trial/DTO/TrialRevenuesPriceViewModel.cs b/IRaCIS.Core.Application.Contracts/Trial/DTO/TrialRevenuesPriceViewModel.cs new file mode 100644 index 0000000..87c9969 --- /dev/null +++ b/IRaCIS.Core.Application.Contracts/Trial/DTO/TrialRevenuesPriceViewModel.cs @@ -0,0 +1,37 @@ +using System; +using IRaCIS.Core.Application.Contracts.RequestAndResponse; + +namespace IRaCIS.Application.ViewModels +{ + public class TrialRevenuesPriceDTO + { + + public Guid TrialId { get; set; } + public decimal Timepoint { get; set; } + public decimal TimepointIn24H { get; set; } + public decimal TimepointIn48H { get; set; } + public decimal Adjudication { get; set; } + public decimal AdjudicationIn24H { get; set; } + public decimal AdjudicationIn48H { get; set; } + public decimal RefresherTraining { get; set; } + + public decimal Global { get; set; } + public decimal Training { get; set; } + public decimal Downtime { get; set; } + } + + public class TrialRevenuesPriceDetialDTO : TrialRevenuesPriceDTO + { + public Guid Id { get; set; } + public string TrialCode { get; set; } + public string Indication { get; set; } + public int Expedited { get; set; } + public string ReviewMode { get; set; } + public string Cro { get; set; } + } + public class TrialRevenuesPriceQueryDTO : PageInput + { + public string KeyWord { get; set; } + public Guid? CroId { get; set; } + } +} diff --git a/IRaCIS.Core.Application.Contracts/Trial/DTO/TrialViewModel.cs b/IRaCIS.Core.Application.Contracts/Trial/DTO/TrialViewModel.cs new file mode 100644 index 0000000..907217f --- /dev/null +++ b/IRaCIS.Core.Application.Contracts/Trial/DTO/TrialViewModel.cs @@ -0,0 +1,167 @@ +using System; +using System.Collections.Generic; +using IRaCIS.Core.Application.Contracts.RequestAndResponse; +using IRaCIS.Core.Domain.Share; + +namespace IRaCIS.Application.ViewModels +{ + public class TrialDTO : TrialDbModel + { + + public string ReviewType { get; set; } + + public string Criterion { get; set; } + + public string CRO { get; set; } + + public string Sponsor { get; set; } + + public int TrialStatus { get; set; } + public string TrialStatusStr { get; set; } = string.Empty; + + public DateTime? CreateTime { get; set; } + + } + + + public class TrialDbModel + { + public Guid Id { get; set; } + public string Code { get; set; } = string.Empty; + public string Indication { get; set; } = string.Empty; + + public string Phase { get; set; } = string.Empty; + public Guid? ReviewTypeId { get; set; } = Guid.Empty; + public Guid? CriterionId { get; set; } = Guid.Empty; + public Guid? CROId { get; set; } = Guid.Empty; + public Guid? SponsorId { get; set; } = Guid.Empty; + public Guid? ReviewModeId { get; set; } = Guid.Empty; + public string Note { get; set; } = string.Empty; + public string TurnaroundTime { get; set; } = string.Empty; + public int ExpectedPatients { get; set; } + public int TimePointsPerPatient { get; set; } + public int GRRReviewers { get; set; } + public int TotalReviewers { get; set; } + public string ReviewProtocol { get; set; } = string.Empty; + public string MessageFromClient { get; set; } = string.Empty; + public string ReviewProtocolName { get; set; } = string.Empty; + public string MessageFromClientName { get; set; } = string.Empty; + public int? Expedited { get; set; } + public int AttendedReviewerType { get; set; } + + public bool VisitPlanConfirmed { get; set; } + + + + } + + + + + public class TrialDetailDTO : TrialDTO + { + public TrialDetailDTO() + { + ModalityIds = new List(); + ModalityList = new List(); + } + + + public string ReviewMode { get; set; } + + public string ReviewProtocolFullPath => SystemConfig.RootUrl + ReviewProtocol; + + public string MessageFromClientFullPath => SystemConfig.RootUrl + MessageFromClient; + public string SowFullPath => SystemConfig.RootUrl + SowPath; + public List ModalityList { get; set; } //成像设备 多选 + public List ModalityIds { get; set; } + + //统计字段 + public string SowName { get; set; } + public string SowPath { get; set; } + + public bool IsLocked { get; set; } + public int EnrollStatus { get; set; } + + //public bool LockTrialCode { get; set; } + + //public int Submitted { get; set; } + //public int Approved { get; set; } + //public int Trained { get; set; } + //public int Reading { get; set; } + + public int SubjectCount { get; set; } + //public int VisitCount { get; set; } + public int StudyCount { get; set; } + public int SiteCount { get; set; } + } + + public class TrialAndTrialStateVieModel + { + public TrialDetailDTO TrialView { get; set; } + + public int TrialMaxState { get; set; } + } + + + + public class TrialCommand : TrialDbModel + { + public Guid UserId { get; set; } + public List ModalityIds { get; set; } = new List(); + } + + + + + + + + public class TrialQueryDTO : PageInput + { + public TrialQueryDTO() + { + ModalityIds = new List(); + } + + public Guid? CriterionId { get; set; } = Guid.Empty; + public Guid? SponsorId { get; set; } = Guid.Empty; + public Guid? CROId { get; set; } = Guid.Empty; + + public Guid? ReviewTypeId { get; set; } = Guid.Empty; + public List ModalityIds { get; set; } + + public string Code { get; set; } = string.Empty; + + public string Indication { get; set; } = string.Empty; + public string Phase { get; set; } = string.Empty; + public string TrialStatus { get; set; } + + public DateTime? BeginDate { get; set; } + public DateTime? EndDate { get; set; } + public int? Expedited { get; set; } + public int? AttendedReviewerType { get; set; } + } + + public class ReviewerTrialQueryDTO : PageInput + { + public string Code { get; set; } = string.Empty; + public string Indication { get; set; } = string.Empty; + public int? EnrollStatus { get; set; } + public int? Expedited { get; set; } + } + + + public class TrialByStatusQueryDTO : PageInput + { + public Guid DoctorId { get; set; } + public int Status { get; set; } + } + + + + + + + +} \ No newline at end of file diff --git a/IRaCIS.Core.Application.Contracts/Trial/DTO/UserTrialViewModel.cs b/IRaCIS.Core.Application.Contracts/Trial/DTO/UserTrialViewModel.cs new file mode 100644 index 0000000..baefd7b --- /dev/null +++ b/IRaCIS.Core.Application.Contracts/Trial/DTO/UserTrialViewModel.cs @@ -0,0 +1,111 @@ +using System; +using System.Collections.Generic; +using IRaCIS.Core.Application.Contracts.RequestAndResponse; + +namespace IRaCIS.Application.ViewModels +{ + + + public class TrialSiteSelect + { + public Guid Id { get; set; } + public string SiteName { get; set; } + } + + public class UserTrialDTO: UserTrialCommand + { + public Guid SiteId { get; set; } + public string Phone { get; set; } + //public Guid OrganizationTypeId { get; set; } + //public string OrganizationType { get; set; } + public DateTime UpdateTime { get; set; } = DateTime.Now; + } + + public class SiteCRCCommand : UserTrialCommand + { + //public Guid OrganizationTypeId { get; set; } + //public string OrganizationType { get; set; } + + public Guid SiteId { get; set; } = Guid.Empty; + } + + public class UserTrialCommand + { + public Guid? Id { get; set; } + public Guid UserId { get; set; } + public Guid TrialId { get; set; } + public Guid UserTypeId { get; set; } + public string UserType { get; set; } + + public Guid OrganizationId { get; set; } + public string OrganizationName { get; set; } + + public string OrganizationType { get; set; } + public Guid OrganizationTypeId { get; set; } + + + public string UserRealName { get; set; } + public string UserName { get; set; } + + } + public class SiteCrcDTO : UserTrialDTO + { + //public Guid SiteId { get; set; } = Guid.Empty; + //public string Phone { get; set; } + //public Guid OrganizationTypeId { get; set; } + //public string OrganizationType { get; set; } + public string Site { get; set; } + public string City { get; set; } + public string Country { get; set; } + + + } + + public class SiteStatDTO + { + public Guid SiteId { get; set; } = Guid.Empty; + public string Site { get; set; } + public string City { get; set; } + public string Country { get; set; } + //public int VisitCount { get; set; } + //public int PlanVisitCount { get; set; } + public int UserCount { get; set; } + public int StudyCount { get; set; } + public int SubjectCount { get; set; } + + public List UserList=new List(); + } + + public class UserSelectionModel + { + public Guid Id { get; set; } + public string RealName { get; set; } + + public string UserName { get; set; } + } + + + public class TrialMaintenanceQuery + { + public Guid TrialId { get; set; } = Guid.Empty; + public string UserName { get; set; } = string.Empty; + public Guid? UserTypeId { get; set; } = Guid.Empty; + } + public class UserTrialListQueryDTO : PageInput + { + public Guid TrialId { get; set; } = Guid.Empty; + public string UserName { get; set; } = string.Empty; + public Guid? UserTypeId { get; set; } = Guid.Empty; + } + + public class SiteCrcQueryDTO : PageInput + { + public Guid TrialId { get; set; } = Guid.Empty; + public string UserRealName { get; set; } = string.Empty; + + //public Guid? OrganizationTypeId { get; set; } = Guid.Empty; + //public Guid SiteId { get; set; } = Guid.Empty; + + public string SiteName { get; set; } = string.Empty; + } +} diff --git a/IRaCIS.Core.Application.Contracts/Trial/DTO/VisitPlanViewModel.cs b/IRaCIS.Core.Application.Contracts/Trial/DTO/VisitPlanViewModel.cs new file mode 100644 index 0000000..f1051f1 --- /dev/null +++ b/IRaCIS.Core.Application.Contracts/Trial/DTO/VisitPlanViewModel.cs @@ -0,0 +1,36 @@ +using System; +using IRaCIS.Core.Application.Contracts.RequestAndResponse; + +namespace IRaCIS.Application.ViewModels +{ + public class VisitStageSelectDTO + { + public Guid Id { get; set; } + public string VisitName { get; set; } + public int VisitDay { get; set; } + } + + public class VisitStageDTO: VisitPlanCommand + { + public DateTime CreateTime { get; set; } + } + + public class VisitPlanCommand + { + public Guid? Id { get; set; } + public Guid TrialId { get; set; } + + public decimal VisitNum { get; set; } + public string VisitName { get; set; } + public int VisitDay { get; set; } + public string Description { get; set; } + public bool NeedGlobal { get; set; } + } + + + public class VisitPlanQueryDTO : PageInput + { + public Guid TrialId { get; set; } = Guid.Empty; + public string Keyword { get; set; } = string.Empty; + } +} diff --git a/IRaCIS.Core.Application.Contracts/Trial/DTO/VisitPointViewModel.cs b/IRaCIS.Core.Application.Contracts/Trial/DTO/VisitPointViewModel.cs new file mode 100644 index 0000000..4ae8834 --- /dev/null +++ b/IRaCIS.Core.Application.Contracts/Trial/DTO/VisitPointViewModel.cs @@ -0,0 +1,318 @@ +using IRaCIS.Core.Application.Contracts.RequestAndResponse; +using System; +using System.Collections.Generic; +using System.Dynamic; + +namespace IRaCIS.Application.ViewModels +{ + + public class SubjectVisitDTO : SubjectVisitCommand + { + public int StudyCount { get; set; } + } + + public class SubjectVisitNewDTO : SubjectVisitDTO + { + public DateTime UpdateTime { get; set; } + + + + public string SubjectCode { get; set; } + public string SubjectName { get; set; } = string.Empty; + + public string SiteName { get; set; } + + public string SiteCode { get; set; } + + //public Guid VisitPlanId { get; set; } + + + + } + + public class SubjectVisitSearchDTO : PageInput + { + public string SubjectInfo { get; set; } + + public string VisitPlanInfo { get; set; } + + public Guid? SubjectId { get; set; } + public Guid TrialId { get; set; } + public Guid? SiteId { get; set; } + } + + public class SubjectVisitSelectDTO + { + public Guid GuidId{get;set;}=Guid.NewGuid(); + public Guid SubjectVisitId { get; set; } = Guid.Empty; + public decimal VisitNum { get; set; } + public string VisitName { get; set; } = string.Empty; + + public string SVUPDES { get; set; } = string.Empty; + + //public Guid VisitStageId { get; set; } = Guid.Empty; + + public DateTime? SVSTDTC { get; set; } + + public DateTime? SVENDTC { get; set; } + + + //public bool IsSubjectVisit { get; set; } = false; + + public bool StudyUploaded { get; set; } + + + + public List StudyList=new List(); + } + public class SubjectVisitCommand + { + public Guid? Id { get; set; } + public Guid TrialId { get; set; } + public Guid SubjectId { get; set; } + public Guid SiteId { get; set; } + + public bool InPlan { get; set; } = true; + + public bool StudyUploaded { get; set; } = false; + + + + public decimal VisitNum { get; set; } + public string VisitName { get; set; } = string.Empty; + public int VisitDay { get; set; } + public string SVUPDES { get; set; } = string.Empty; + public DateTime? SVSTDTC { get; set; } + public DateTime? SVENDTC { get; set; } + } + + public class SubjectVisitStudyDTO + { + public Guid SubjectVisitId { get; set; } + public Guid StudyId { get; set; } + public string StudyCode { get; set; } + + public string Modalities { get; set; } + + public int Status { get; set; } + + } + + + public class ArchiveStudyCommand + { + + public Guid? AbandonStudyId { get; set; } + public Guid TrialId { get; set; } + public Guid SiteId { get; set; } + public Guid SubjectId { get; set; } + //public Guid? VisitStageId { get; set; } + public Guid SubjectVisitId { get; set; } + public DateTime? SVSTDTC { get; set; } + public DateTime? SVENDTC { get; set; } + public string Comment { get; set; } = string.Empty; + + } + + + public class StudyCommand + { + public Guid Id { get; set; } = Guid.Empty; + public Guid TrialId { get; set; } + public Guid SiteId { get; set; } + public Guid SubjectId { get; set; } + public Guid SubjectVisitId { get; set; } + + } + + public class StudyEditCommand: StudyCommand + { + public Guid VisitStageId { get; set; } + public DateTime? SVSTDTC { get; set; } + public DateTime? SVENDTC { get; set; } + public string Comment { get; set; } + } + + + + public class StudyStatDTO + { + + public int StudyCount { get; set; } + public decimal VisitNum { get; set; } + public string VisitName { get; set; } + public int VisitDay { get; set; } + public string Description { get; set; } + public Guid TrialId { get; set; } + public Guid SubjectVisitId { get; set; } + + } + + public class DistributeReviewerStudyStatusDTO + { + public string NameCN { get; set; } + public string Name { get; set; } + public string ReviewerCode { get; set; } + public string StudyCode { get; set; } + + public int Status { get; set; } + + } + + public class StudyStatusQueryDTO:PageInput + { + public Guid TrialId { get; set; } + public Guid? ReviewerId { get; set; } + + public int? StudyStatus { get; set; } + } + + + //public class StudyDTO + //{ + + // public SubjectVisitInfo SubjectVisit { get; set; }=new SubjectVisitInfo(); + // public StudyInfo Study { get; set; }=new StudyInfo(); + + // public SiteInfo Site { get; set; }=new SiteInfo(); + + // public QAInfo QA { get; set; }=new QAInfo(); + + // public class SubjectVisitInfo + // { + // public Guid SubjectVisitId { get; set; } + // public double VisitNum { get; set; } + // public string VisitName { get; set; } + // } + + // public class StudyInfo + // { + // public Guid Id { get; set; } + // public Guid TrialId { get; set; } + // public string StudyCode { get; set; } + // public int StudyStatus { get; set; } + // public DateTime? StudyDate { get; set; } + // public string Modalities { get; set; } + // public int SeriesCount { get; set; } + // public int InstanceCount { get; set; } + // } + + + // public class SiteInfo + // { + // public Guid SiteId { get; set; } + // public string SiteName { get; set; } + // } + + + // public class QAInfo + // { + // public Guid SubjectId { get; set; } + // public string SubjectCode { get; set; } + // public string SubjectName { get; set; } + // public int SubjectAge { get; set; } + // public string SubjectSex { get; set; } + // public string PatientName { get; set; } + // public string PatientAge { get; set; } + // public string PatientSex { get; set; } + // } + + //} + + + public class VerifyStudyUploadResult + { + public bool AllowUpload { get; set; } + + public StudyDTO StudyInfo { get; set; } + + + } + + + public class StudyDTO + { + public Guid SubjectVisitId { get; set; } + public decimal VisitNum { get; set; } + public string VisitName { get; set; } + public int VisitDay { get; set; } + + public string SVUPDES { get; set; } + + public DateTime? SVSTDTC { get; set; } + + public DateTime? SVENDTC { get; set; } + + + public Guid Id { get; set; } + public Guid TrialId { get; set; } + public string StudyCode { get; set; } + public int StudyStatus { get; set; } + public DateTime? StudyDate { get; set; } + public string Modalities { get; set; } + public int SeriesCount { get; set; } + public int InstanceCount { get; set; } + + public bool IsDoubleReview { get; set; } + + public string StudyDescription { get; set; } + + public string BodyPartExamined { get; set; } + + public string Comment { get; set; } + + public DateTime UpdateTime { get; set; } + + //public List DistributeReviewers { get; set; }=new List(); + + + public Guid SiteId { get; set; } + public string SiteName { get; set; } + + public string StudyId { get; set; } //这个Id是dicom文件中的Id + public Guid SubjectId { get; set; } + public string SubjectCode { get; set; } + public string SubjectName { get; set; } + public int SubjectAge { get; set; } + public string SubjectSex { get; set; } + public string PatientId { get; set; } + public string PatientName { get; set; } + public string PatientAge { get; set; } + public string PatientSex { get; set; } + public string AccessionNumber { get; set; } = string.Empty; + public string PatientBirthDate { get; set; } = string.Empty; + } + + public class DistributeReviewer + { + public Guid StudyId { get; set; } + + public Guid ReviewerId { get; set; } + public string NameCN { get; set; } + public string Name { get; set; } + + public int Status { get; set; } + } + + public class StudyQueryDTO : PageInput + { + public Guid? SubjectId { get; set; } + + public Guid? SiteId { get; set; } + public Guid TrialId { get; set; } + public string SubjectInfo { get; set; } + + public string VisitPlanInfo { get; set; } + + public Guid? SubjectVisitId { get; set; } + public int? Status { get; set; } + + public DateTime? StudyTimeBegin { get; set; } + + public DateTime? StudyTimeEnd { get; set; } + + public DateTime? UpdateTimeBegin { get; set; } + + public DateTime?UpdateTimeEnd { get; set; } + } +} diff --git a/IRaCIS.Core.Application.Contracts/Trial/Enrollment/ITrialEnrollmentService.cs b/IRaCIS.Core.Application.Contracts/Trial/Enrollment/ITrialEnrollmentService.cs new file mode 100644 index 0000000..baff1d7 --- /dev/null +++ b/IRaCIS.Core.Application.Contracts/Trial/Enrollment/ITrialEnrollmentService.cs @@ -0,0 +1,21 @@ +using System; +using IRaCIS.Core.Application.Contracts.RequestAndResponse; + +namespace IRaCIS.Application.Interfaces +{ + public interface ITrialEnrollmentService + { + /// 入组流程-筛选医生 [select] + IResponseOutput SelectReviewer(Guid userId, Guid trialId, Guid[] doctorIdArray); + + /// 入组流程-向CRO提交医生[Submit] + IResponseOutput SubmitReviewer(Guid userId, Guid trialId, Guid[] doctorIdArray, int commitState); + + /// 入组流程-CRO确定医生名单 [ Approve] + IResponseOutput ApproveReviewer(Guid userId, Guid trialId, Guid[] doctorIdArray, int auditState); + + /// 入组流程-向CRO提交医生[Submit] + IResponseOutput ConfirmReviewer(Guid userId, Guid trialId, Guid[] doctorIdArray, int confirmState); + + } +} diff --git a/IRaCIS.Core.Application.Contracts/Trial/IStudyService.cs b/IRaCIS.Core.Application.Contracts/Trial/IStudyService.cs new file mode 100644 index 0000000..3e95003 --- /dev/null +++ b/IRaCIS.Core.Application.Contracts/Trial/IStudyService.cs @@ -0,0 +1,63 @@ +using IRaCIS.Application.ViewModels; +using IRaCIS.Core.Application.Contracts.RequestAndResponse; +using System; +using System.Collections.Generic; +using IRaCIS.Core.Application.Contracts.Dicom.DTO; +using System.Threading.Tasks; + +namespace IRaCIS.Application.Interfaces +{ + public interface IStudyService + { + /// 根据项目Id,医生Id,获取受试者访视点(不分页) + IEnumerable GetStudyStatList(Guid trialId, Guid subjectId, Guid siteId); + + + bool UpdateReUploadNewStudyCode(Guid studyId,Guid newStudyId); + + VerifyStudyUploadResult VerifyStudyAllowUpload(string studyInstanceUid, Guid trialId, Guid? studyId); + + PageOutput GetStudyList(StudyQueryDTO queryDto); + + /// 添加或更新访视点 + Task UpdateStudyBinding(StudyEditCommand param); + + /// 删除项目访视计划 + IResponseOutput DeleteStudy(Guid id); + + DicomTrialSiteSubjectInfo GetSaveToDicomInfo(StudyCommand dicomAddtionalCommand); + Guid AddSubjectVisit(Guid subjectId,Guid siteId, Guid visitStageId, DateTime? SVSTDTC, DateTime? SVENDTC); + void UpdateSubjectLatestInfo(Guid subjectId, Guid trialId); + + bool UpdateSubjectVisit(Guid subjectVisitId, DateTime? SVSTDTC, DateTime? SVENDTC); + + bool DistributeStudy(StudyReviewerCommand studyReviewer); + + IResponseOutput EditStudyReviewer(StudyReviewerEditCommand studyReviewerEditCommand); + + List GetReviewerListByTrialId(Guid trialId); + + + + + + /// + /// 更新Study 表中的Status,并且往 StudyStatusDetail详情表中插入一条状态变化记录 + /// + /// + bool UpdateStudyStatus(StudyStatusDetailCommand studyStatusDetailDTO, string optUserName); + bool UpdateStudyModaliyAndComment(Guid studyId,string modaliy,string comment); + + bool UpdateStudyStatus(List studyStatus, string optUserName); + + List GetStudyStatusDetailList(Guid studyId); + + + PageOutput GetDistributeStudyList(StudyStatusQueryDTO studyStatusQueryDto); + + IEnumerable GetRelationVisitList(decimal visitNum, string tpCode); + + List GetSubjectVisitStudyList(Guid trialId, Guid siteId, Guid subjectId, Guid subjectVisitId); + Task DicomAnonymize(Guid studyId,string optuserName); + } +} diff --git a/IRaCIS.Core.Application.Contracts/Trial/ITrialAttachmentService.cs b/IRaCIS.Core.Application.Contracts/Trial/ITrialAttachmentService.cs new file mode 100644 index 0000000..c0cceb2 --- /dev/null +++ b/IRaCIS.Core.Application.Contracts/Trial/ITrialAttachmentService.cs @@ -0,0 +1,25 @@ +using IRaCIS.Application.ViewModels; +using System; +using System.Collections.Generic; +using IRaCIS.Core.Application.Contracts.RequestAndResponse; + +namespace IRaCIS.Application.Interfaces +{ + public interface ITrialAttachmentService + { + IResponseOutput AddOrUpdateSpecification(TrialAttachmentCommand model,Guid userId); + IResponseOutput DeleteSpecification(Guid Id); + + IEnumerable GetSpecificationList( + Guid trialId,string type); + + + ///// + ///// 获取采集规范列表 + ///// + ///// + ///// + //PageOutput GetSpecificationList(ImageAcquisitionSpecificationQueryDTO param); + + } +} diff --git a/IRaCIS.Core.Application.Contracts/Trial/ITrialRevenuesPriceVerificationService.cs b/IRaCIS.Core.Application.Contracts/Trial/ITrialRevenuesPriceVerificationService.cs new file mode 100644 index 0000000..57a0cf2 --- /dev/null +++ b/IRaCIS.Core.Application.Contracts/Trial/ITrialRevenuesPriceVerificationService.cs @@ -0,0 +1,16 @@ + +using System.Collections.Generic; +using IRaCIS.Core.Application.Contracts.Trial.DTO; + + +namespace IRaCIS.Application.Interfaces +{ + public interface ITrialRevenuesPriceVerificationService + { + //List GetRevenuesVerifyResultList(RevenusVerifyQueryDTO param); + + AnalysisVerifyResultDTO GetAnalysisVerifyList(RevenusVerifyQueryDTO param); + + List GetTrialRevenuesVerifyResultList(RevenusVerifyQueryDTO param); + } +} \ No newline at end of file diff --git a/IRaCIS.Core.Application.Contracts/Trial/ITrialService.cs b/IRaCIS.Core.Application.Contracts/Trial/ITrialService.cs new file mode 100644 index 0000000..0c7a058 --- /dev/null +++ b/IRaCIS.Core.Application.Contracts/Trial/ITrialService.cs @@ -0,0 +1,37 @@ +using System; +using System.Collections.Generic; +using IRaCIS.Application.ViewModels; +using IRaCIS.Core.Application.Contracts.RequestAndResponse; + +namespace IRaCIS.Application.Interfaces +{ + public interface ITrialService + { + bool TrialExpeditedChange { get; set; } + //查询 + TrialDetailDTO GetTrialInfoAndLockState(Guid projectId); + int GetTrialExpeditedState(Guid trialId);//获取项目加急状态 + + + int GetTrialMaxState(Guid trialId); + + IResponseOutput ConfirmTrialVisitPlan(Guid trialId); + //添加项目基本信息 + IResponseOutput AddOrUpdateTrial(TrialCommand addTrialModel, Guid userId); + + //手动变更项目状态 + IResponseOutput UpdateTrialStatus(Guid trialId, string statusStr); + //删除 + IResponseOutput DeleteTrial(Guid trialId); + //获取分页项目 列表 多条件查询 + PageOutput GetTrialList(TrialQueryDTO searchModel, Guid userId); + + List GetTrialEnrollmentReviewerIds(Guid trialId); + + PageOutput GetReviewerTrialListByEnrollmentStatus( + TrialByStatusQueryDTO param); + + PageOutput GetTrialListByReviewer(ReviewerTrialQueryDTO searchModel, Guid userId); + IResponseOutput UpdateEnrollStatus(Guid trialId, int status); + } +} \ No newline at end of file diff --git a/IRaCIS.Core.Application.Contracts/Trial/IUserTrialService.cs b/IRaCIS.Core.Application.Contracts/Trial/IUserTrialService.cs new file mode 100644 index 0000000..8529e17 --- /dev/null +++ b/IRaCIS.Core.Application.Contracts/Trial/IUserTrialService.cs @@ -0,0 +1,40 @@ +using IRaCIS.Application.ViewModels; +using System; +using System.Collections.Generic; +using IRaCIS.Core.Application.Contracts.RequestAndResponse; + +namespace IRaCIS.Application.Interfaces +{ + public interface IUserTrialService + { + + IEnumerable GetTrialSiteSelect(Guid trialId); + + + /// 获取项目的维护人员列表 + PageOutput GetUserTrialList(UserTrialListQueryDTO param); + + IEnumerable GetMaintenanceUserList(TrialMaintenanceQuery param); + + /// 获取可供选择的运维人员列表 + IEnumerable GetUserSelectionList(Guid userTypeId,Guid institutionId); + + /// 添加或更新运维人员 + IResponseOutput AddOrUpdateUserTrial(UserTrialCommand param); + + /// 删除运维人员 + IResponseOutput DeleteUserTrial(Guid param); + + + /// 获取负责研究中心CRC列表 + PageOutput GetSiteCRCList(SiteCrcQueryDTO param); + + /// 添加或更新CRC人员 + IResponseOutput AddOrUpdateSiteCRC(SiteCRCCommand param); + + + /// 删除CRC人员 + IResponseOutput DeleteSiteCRC(Guid id); + + } +} diff --git a/IRaCIS.Core.Application.Contracts/Trial/IVisitPlanService.cs b/IRaCIS.Core.Application.Contracts/Trial/IVisitPlanService.cs new file mode 100644 index 0000000..1571a0f --- /dev/null +++ b/IRaCIS.Core.Application.Contracts/Trial/IVisitPlanService.cs @@ -0,0 +1,27 @@ +using IRaCIS.Application.ViewModels; +using System; +using System.Collections.Generic; +using IRaCIS.Core.Application.Contracts.RequestAndResponse; + +namespace IRaCIS.Application.Interfaces +{ + public interface IVisitPlanService + { + /// 分页获取项目访视计划 + PageOutput GetTrialVisitStageList(VisitPlanQueryDTO param); + + + + IEnumerable GetTrialVisitStageSelect(Guid trialId); + + + /// 根据项目Id,获取项目访视计划(不分页) + IEnumerable GetVisitStageList(Guid trialId); + + /// 添加或更新运维人员 + IResponseOutput AddOrUpdateVisitStage(VisitPlanCommand param); + + /// 删除项目访视计划 + IResponseOutput DeleteVisitStage(Guid id); + } +} diff --git a/IRaCIS.Core.Application.Contracts/Trial/Image/DTO/ImageQAViewModel.cs b/IRaCIS.Core.Application.Contracts/Trial/Image/DTO/ImageQAViewModel.cs new file mode 100644 index 0000000..e5a9ff5 --- /dev/null +++ b/IRaCIS.Core.Application.Contracts/Trial/Image/DTO/ImageQAViewModel.cs @@ -0,0 +1,36 @@ +using System; +using System.Collections.Generic; + +namespace IRaCIS.Application.ViewModels +{ + public class ImageQACommand + { + + public Guid TrialId { get; set; } + public Guid SiteId { get; set; } + public Guid StudyId { get; set; } + public Guid? ParentId { get; set; } + public String CommunicationRecord { get; set; } + } + + + + public class ImageQaDTO: ImageQACommand + { + public Guid Id { get; set; } + + public string UserName { get; set; } + + } + + + public class StudyQAView + { + List ImageQAList =new List(); + + List DictionayIds=new List(); + + //List Qa + } + +} \ No newline at end of file diff --git a/IRaCIS.Core.Application.Contracts/Trial/Image/DTO/ImageViewModel.cs b/IRaCIS.Core.Application.Contracts/Trial/Image/DTO/ImageViewModel.cs new file mode 100644 index 0000000..201ed60 --- /dev/null +++ b/IRaCIS.Core.Application.Contracts/Trial/Image/DTO/ImageViewModel.cs @@ -0,0 +1,39 @@ +using System; +using IRaCIS.Core.Application.Contracts.RequestAndResponse; + +namespace IRaCIS.Application.ViewModels +{ + public class ImageCommand + { + public Guid Id { get; set; } + public Guid TrialId { get; set; } + public Guid SubjectId { get; set; } = Guid.Empty; + public Guid SiteId { get; set; } = Guid.Empty; + public Guid SubjectVisitId { get; set; } = Guid.Empty; + public string TrialCode { get; set; } + } + + public class ImageDetailDTO : ImageCommand + { + public int? State { get; set; } + public DateTime StudyDate { get; set; } = DateTime.Now; + public string Modalities { get; set; } = string.Empty; + public Guid StudyId { get; set; } = Guid.Empty; + public string ImageNo { get; set; } = string.Empty; + + + public string SubjectCode { get; set; }//受试者编号 + public string SiteName { get; set; } + public string MedicalNo { get; set; } + public string Period { get; set; } + public DateTime CreateTime { get; set; } + } + + public class ImageQueryDTO : PageInput + { + public Guid TrialId { get; set; } = Guid.Empty; + public string SubjectCode { get; set; } = string.Empty; + public Guid SubjectVisitId { get; set; } = Guid.Empty; + public int State { get; set; } = 0; + } +} diff --git a/IRaCIS.Core.Application.Contracts/Trial/Image/IImageQAService.cs b/IRaCIS.Core.Application.Contracts/Trial/Image/IImageQAService.cs new file mode 100644 index 0000000..2ed64dc --- /dev/null +++ b/IRaCIS.Core.Application.Contracts/Trial/Image/IImageQAService.cs @@ -0,0 +1,12 @@ +using IRaCIS.Application.ViewModels; +using IRaCIS.Core.Application.Contracts.RequestAndResponse; + +namespace IRaCIS.Application.Interfaces +{ + public interface IImageQAService + { + IResponseOutput AddOrUpdateImageQA(ImageQACommand qaCommand); + + + } +} \ No newline at end of file diff --git a/IRaCIS.Core.Application.Contracts/Trial/Image/IImageService.cs b/IRaCIS.Core.Application.Contracts/Trial/Image/IImageService.cs new file mode 100644 index 0000000..4197671 --- /dev/null +++ b/IRaCIS.Core.Application.Contracts/Trial/Image/IImageService.cs @@ -0,0 +1,14 @@ +using IRaCIS.Application.ViewModels; +using System; +using IRaCIS.Core.Application.Contracts.RequestAndResponse; + +namespace IRaCIS.Application.Interfaces +{ + public interface IImageService + { + IResponseOutput AddImage(ImageCommand model,Guid userId); + IResponseOutput DeleteImage(Guid id); + //PageOutput GetImageList(ImageQueryDTO param); + + } +} diff --git a/IRaCIS.Core.Application.Contracts/Trial/QA/DTO/QARecordViewModel.cs b/IRaCIS.Core.Application.Contracts/Trial/QA/DTO/QARecordViewModel.cs new file mode 100644 index 0000000..e9e81e4 --- /dev/null +++ b/IRaCIS.Core.Application.Contracts/Trial/QA/DTO/QARecordViewModel.cs @@ -0,0 +1,143 @@ +using IRaCIS.Application.ViewModels; +using IRaCIS.Core.Application.Contracts.Dicom.DTO; +using IRaCIS.Core.Domain.Models; +using System; +using System.Collections.Generic; + +namespace IRaCIS.Core.Application.Contracts.DTO +{ + + public class QARecordCommand + { + public Guid? Id { get; set; } + public Guid QATemplateId { get; set; } + public Guid StudyId { get; set; } + public string Note { get; set; } + + public DateTime? DeadlineTime { get; set; } + + } + + public class QARecordWithUser: QARecordCommand + { + public string UserName { get; set; } + public DateTime CreateTime { get; set; } + + public int ReplyCount { get; set; } + } + + public class QADictionaryCommand + { + + public string Note { get; set; } + public Guid DictionaryId { get; set; } + + } + + public class QADictionaryDTO : QADictionaryCommand + { + public string DictionaryValue { get; set; } + } + + public class QADicView + { + public Guid QARecordId { get; set; } + public string DictionaryValue { get; set; } + public string Note { get; set; } + public Guid DictionaryId { get; set; } + } + + + public class QAToalCommand + { + public Guid StudyId { get; set; } + public Guid TrialId { get; set; } + public Guid SiteId { get; set; } + public QARecordCommand QARecord { get; set; } + + public List QADictionaryList { get; set; } = new List(); + + } + + public class QADTO + { + public List QARecordList { get; set; } = new List(); + public StudySubjectInfoDTO StudySubjectInfo { get; set; } + public AcquisitionSpecificationDTO Specification { get; set; } + } + + public class QARecordDTO + { + public QARecordWithUser QARecord { get; set; } + + public List QADictionaryList { get; set; } = new List(); + + } + + public class StudySubjectInfoDTO + { + public int StudyStatus { get; set; } + public string SubjectCode { get; set; } + public string SubjectName { get; set; } + public int SubjectAge { get; set; } + public string SubjectSex { get; set; } + + public string PatientName { get; set; } = string.Empty; + public string PatientAge { get; set; } = string.Empty; + public string PatientSex { get; set; } = string.Empty; + + public string Modalities { get; set; } + + public int SeriesCount { get; set; } + + public int InstanceCount { get; set; } + + public string Comment { get; set; } + public string QAComment { get; set; } + public bool Anonymize { get; set; } + + + public decimal VisitNum { get; set; } + public string VisitName { get; set; } = string.Empty; + public DateTime? SVSTDTC { get; set; } + public DateTime? SVENDTC { get; set; } + public bool InPlan { get; set; } + + + } + public class QADialogCommand + { + public string TalkContent { get; set; } + public Guid QARecordId { get; set; } + public Guid? ParentId { get; set; } + } + + + public class DialogDTO + { + public Guid Id { get; set; } + public string TalkContent { get; set; } + //public Guid QARecordId { get; set; } + public string From { get; set; } + public string To { get; set; } + public Guid UserId { get; set; } + + public string PreviousContent { get; set; } + + public DateTime CreateTime { get; set; } + } + + public class DialogNode + { + public Guid Id { get; set; } + public Guid ParentId { get; set; } + public Guid UserId { get; set; } + public string UserName { get; set; } + + public string TalkContent { get; set; } + public Guid QARecordId { get; set; } + + public DateTime CreateTime { get; set; } + } + +} \ No newline at end of file diff --git a/IRaCIS.Core.Application.Contracts/Trial/QA/DTO/QATemplateViewModel.cs b/IRaCIS.Core.Application.Contracts/Trial/QA/DTO/QATemplateViewModel.cs new file mode 100644 index 0000000..c214656 --- /dev/null +++ b/IRaCIS.Core.Application.Contracts/Trial/QA/DTO/QATemplateViewModel.cs @@ -0,0 +1,44 @@ +using System; +using IRaCIS.Core.Application.Contracts.RequestAndResponse; + +namespace IRaCIS.Core.Application.Contracts.DTO +{ + public class QATemplateCommand + { + public Guid? Id { get; set; } + public string Name { get; set; } + + public string Description { get; set; } + } + + public class QATemplateDTO: QATemplateCommand + { + + } + + public class QATemplateQueryDTO : PageInput + { + public string Name { get; set; } + } + + public class QATemplateItemSelect: QATemplateItemDTO + { + public bool IsSelect { get; set; } + } + + public class QATemplateItemDTO + { + public string DictionaryValue { get; set; } + + public Guid DictionaryId { get; set; } + } + + public class QATemplateConfigCommand + { + public Guid DictionaryId { get; set; } + + public Guid QATemplateId { get; set; } + + public bool IsSelect { get; set; } + } +} \ No newline at end of file diff --git a/IRaCIS.Core.Application.Contracts/Trial/QA/IQADictionaryService.cs b/IRaCIS.Core.Application.Contracts/Trial/QA/IQADictionaryService.cs new file mode 100644 index 0000000..ccbdf59 --- /dev/null +++ b/IRaCIS.Core.Application.Contracts/Trial/QA/IQADictionaryService.cs @@ -0,0 +1,8 @@ + +namespace IRaCIS.Core.Application.Contracts +{ + public interface IQADictionaryService + { + + } +} \ No newline at end of file diff --git a/IRaCIS.Core.Application.Contracts/Trial/QA/IQARecordService.cs b/IRaCIS.Core.Application.Contracts/Trial/QA/IQARecordService.cs new file mode 100644 index 0000000..31904fc --- /dev/null +++ b/IRaCIS.Core.Application.Contracts/Trial/QA/IQARecordService.cs @@ -0,0 +1,26 @@ + +using System; +using System.Collections.Generic; +using IRaCIS.Core.Application.Contracts.DTO; +using IRaCIS.Core.Application.Contracts.RequestAndResponse; + +namespace IRaCIS.Core.Application.Contracts +{ + public interface IQARecordService + { + + + IResponseOutput AddOrUpdateQARecord(QAToalCommand qaTotalCommand); + + IResponseOutput DeleteQARecord(Guid qaQARecordId); + + QADTO GetQARecordList(Guid studyId,Guid trialId); + + IResponseOutput AddQAReply(QADialogCommand qaDialogCommand); + + IResponseOutput DeleteQAReply(Guid qaReplyId); + + List GetQaRecordDialogList(Guid qaRecordId); + + } +} \ No newline at end of file diff --git a/IRaCIS.Core.Application.Contracts/Trial/QA/IQATemplateDictionaryService.cs b/IRaCIS.Core.Application.Contracts/Trial/QA/IQATemplateDictionaryService.cs new file mode 100644 index 0000000..8ac0694 --- /dev/null +++ b/IRaCIS.Core.Application.Contracts/Trial/QA/IQATemplateDictionaryService.cs @@ -0,0 +1,9 @@ + + +namespace IRaCIS.Core.Application.Contracts +{ + public interface IQATemplateDictionaryService + { + + } +} \ No newline at end of file diff --git a/IRaCIS.Core.Application.Contracts/Trial/QA/IQATemplateService.cs b/IRaCIS.Core.Application.Contracts/Trial/QA/IQATemplateService.cs new file mode 100644 index 0000000..0bb1d32 --- /dev/null +++ b/IRaCIS.Core.Application.Contracts/Trial/QA/IQATemplateService.cs @@ -0,0 +1,26 @@ + + +using System; +using System.Collections.Generic; +using IRaCIS.Core.Application.Contracts.DTO; +using IRaCIS.Core.Application.Contracts.RequestAndResponse; + +namespace IRaCIS.Core.Application.Contracts +{ + public interface IQATemplateService + { + IResponseOutput AddOrUpdateQATemplate(QATemplateCommand qaTemplateCommand); + + IResponseOutput DeleteQATemplate(Guid qaTemplateId); + + PageOutput GetQaTemplateList(QATemplateQueryDTO qaTemplateQuery); + + List GetQaTemplateItemsById(Guid qaTemplateId); + + List GetQaTemplateSelectList(); + + List GetQaTemplateConfigList(Guid qaTemplateId); + + IResponseOutput ConfigQATemplate(QATemplateConfigCommand qaTemplateConfigCommand); + } +} \ No newline at end of file diff --git a/IRaCIS.Core.Application.Contracts/Trial/Subject/ISubjectService.cs b/IRaCIS.Core.Application.Contracts/Trial/Subject/ISubjectService.cs new file mode 100644 index 0000000..87e83b4 --- /dev/null +++ b/IRaCIS.Core.Application.Contracts/Trial/Subject/ISubjectService.cs @@ -0,0 +1,17 @@ +using IRaCIS.Application.ViewModels; +using System; +using System.Collections.Generic; +using IRaCIS.Core.Application.Contracts.RequestAndResponse; + +namespace IRaCIS.Application.Interfaces +{ + public interface ISubjectService + { + IResponseOutput AddOrUpdateSubject(SubjectCommand model); + IResponseOutput DeleteSubject(Guid id); + PageOutput GetSubjectList(SubjectQueryParam param); + + List GetSubjectListBySiteId(Guid siteId, Guid trialId); + + } +} diff --git a/IRaCIS.Core.Application.Contracts/Trial/Subject/ISubjectVisitService.cs b/IRaCIS.Core.Application.Contracts/Trial/Subject/ISubjectVisitService.cs new file mode 100644 index 0000000..7f58292 --- /dev/null +++ b/IRaCIS.Core.Application.Contracts/Trial/Subject/ISubjectVisitService.cs @@ -0,0 +1,25 @@ +using IRaCIS.Application.ViewModels; +using IRaCIS.Core.Application.Contracts.RequestAndResponse; +using System; +using System.Collections.Generic; + +namespace IRaCIS.Core.Application.Contracts.Trial +{ + public interface ISubjectVisitService + { + + PageOutput GetVisitList(SubjectVisitSearchDTO subjectVisitSearch); + + + IEnumerable GetSubjectVisitList(Guid trialId, Guid subjectId); + + List GetSubjectVisitSelectList(Guid trialId, Guid siteId, Guid subjectId); + + IResponseOutput AddOrUpdateSV(SubjectVisitCommand svCommand); + + + IResponseOutput DeleteSV(Guid id); + + + } +} diff --git a/IRaCIS.Core.Application.Contracts/Trial/Workload/ITrialWorkloadService.cs b/IRaCIS.Core.Application.Contracts/Trial/Workload/ITrialWorkloadService.cs new file mode 100644 index 0000000..a789439 --- /dev/null +++ b/IRaCIS.Core.Application.Contracts/Trial/Workload/ITrialWorkloadService.cs @@ -0,0 +1,39 @@ +using IRaCIS.Application.ViewModels; +using System; +using System.Collections.Generic; +using IRaCIS.Core.Application.Contracts.RequestAndResponse; + +namespace IRaCIS.Application.Interfaces +{ + public interface ITrialWorkloadService + { + /// + /// 上传入组后的Ack-SOW + /// + IResponseOutput UploadReviewerAckSOW(Guid userId, Guid trialId, ReviewerAckDTO attachmentViewModel); + + /// + /// 删除Ack-SOW + /// + IResponseOutput DeleteReviewerAckSOW(Guid trialId, Guid doctorId, Guid attachmentId); + + IResponseOutput UpdateReviewerReadingType(Guid trialId, Guid doctorId, int type); + + /// + /// 获取某个项目入组的医生工作量统计列表 + /// + PageOutput GetTrialEnrollmentWorkloadStats(WorkLoadDoctorQueryDTO doctorSearchModel); + + PageOutput GetEnrollmentWorkloadStatsDetail( + WorkLoadStatsQueryDTO workLoadSearch); + + List GetReviewerWorkLoadListDetail( + WorkLoadDetailQueryDTO workLoadSearch); + + /// 判断医生是否存在当天的工作量数据 + IResponseOutput WorkloadExist(WorkloadExistQueryDTO param); + IResponseOutput AddOrUpdateWorkload(WorkloadCommand workLoadAddOrUpdateModel, Guid userId); + IResponseOutput DeleteWorkload(Guid id); + WorkloadDTO GetWorkloadDetailById(Guid id); + } +} diff --git a/IRaCIS.Core.Application.Contracts/Trial/WorkloadDistribution/DTO/WorkloadDistribution.cs b/IRaCIS.Core.Application.Contracts/Trial/WorkloadDistribution/DTO/WorkloadDistribution.cs new file mode 100644 index 0000000..a1f6bf6 --- /dev/null +++ b/IRaCIS.Core.Application.Contracts/Trial/WorkloadDistribution/DTO/WorkloadDistribution.cs @@ -0,0 +1,145 @@ +using IRaCIS.Core.Application.Contracts.RequestAndResponse; +using System; +using System.Collections.Generic; + +namespace IRaCIS.Application.ViewModels +{ + #region TP + public class WorkloadTPDTO + { + public Guid Id { get; set; } + public Guid SiteId { get; set; } + public string SiteName { get; set; } + public Guid SubjectId { get; set; } + public string SubjectCode { get; set; } + public Guid SubjectVisitId { get; set; } + public string VisitName { get; set; } + public decimal VisitNum { get; set; } + public Guid StudyId { get; set; } + public string StudyCode { get; set; } + public string TimepointCode { get; set; } + public Guid ReviewerId { get; set; } + public string ReviewerCode { get; set; } + public string ReviewerFirstName { get; set; } + public string ReviewerLastName { get; set; } + public string ReviewerChineseName { get; set; } + public int Status { get; set; } + public DateTime UpdateTime { get; set; } + } + #endregion + + #region Global + public class WorkloadGlobalDTO + { + public Guid Id { get; set; } + public Guid SiteId { get; set; } + public string SiteName { get; set; } + public Guid VisitId { get; set; } + public string VisitName { get; set; } + + public Guid TrialId { get; set; } + public Guid SubjectId { get; set; } + public string SubjectCode { get; set; } + public decimal VisitNum { get; set; } + + public string GlobalCode { get; set; } + public Guid ReviewerId { get; set; } + public string ReviewerCode { get; set; } + public string ReviewerFirstName { get; set; } + public string ReviewerLastName { get; set; } + public string ReviewerChineseName { get; set; } + public int Status { get; set; } + public DateTime UpdateTime { get; set; } + } + #endregion + + #region AD + public class WorkloadADDTO + { + public Guid Id { get; set; } + public Guid TrialId { get; set; } + public Guid SiteId { get; set; } + public string SiteName { get; set; } + public Guid SubjectId { get; set; } + public string SubjectCode { get; set; } + public string ADCode { get; set; } + public Guid ReviewerId { get; set; } + public string ReviewerCode { get; set; } + public string ReviewerFirstName { get; set; } + public string ReviewerLastName { get; set; } + public string ReviewerChineseName { get; set; } + public int Status { get; set; } + public DateTime UpdateTime { get; set; } + public Guid Global1Id { get; set; } + public Guid Global2Id { get; set; } + } + #endregion + + public class WorkloadDistributionQueryParam : PageInput + { + public Guid TrialId { get; set; } = Guid.Empty; + public Guid? SiteId { get; set; } = Guid.Empty; + public string SubjectCode { get; set; } = string.Empty; + public string WorkloadCode { get; set; } = string.Empty; + public string Reviewer { get; set; } = string.Empty; + public int? Status { get; set; } + public int? GroupId { get; set; } = 0; + } + + public class WorkloadTPInfo + { + public Guid Id { get; set; } + public Guid StudyId { get; set; } + } + public class WorkloadTPCommand + { + public List TpList { get; set; } = new List(); + public Guid ReviewerId { get; set; } + public string ReviewerName { get; set; } + } + + public class WorkloadGlobalInfo + { + public Guid Id { get; set; } + public Guid SubjectId { get; set; } + public decimal VisitNum { get; set; } + } + public class WorkloadGlobalCommand + { + public List GlobalList { get; set; } = new List(); + public Guid ReviewerId { get; set; } + public string ReviewerName { get; set; } + } + public class WorkloadAdCommand + { + public List IdList { get; set; } = new List(); + public Guid ReviewerId { get; set; } + public string ReviewerName { get; set; } + } + + //public class WorkloadDistributionUpdateCommand + //{ + // public Guid Id { get; set; } + // public Guid? ReviewerId { get; set; } + //} + + public class WorkloadDetailDTO + { + public Guid Id { get; set; } + public Guid WorkloadId { get; set; } + public string OptUserName { get; set; } + public DateTime OptTime { get; set; } + public string ReviewerFirstName { get; set; } + public string ReviewerLastName { get; set; } + public string ReviewerChineseName { get; set; } + public int Status { get; set; } + } + + //public class WorkloadDetailQueryParam + //{ + // public int WorkloadType { get; set; } //1-tp,2-global,3-ad + // public Guid WorkloadId { get; set; } + + //} + +} diff --git a/IRaCIS.Core.Application.Contracts/Trial/WorkloadDistribution/IWorkloadDistributionService.cs b/IRaCIS.Core.Application.Contracts/Trial/WorkloadDistribution/IWorkloadDistributionService.cs new file mode 100644 index 0000000..221b4ad --- /dev/null +++ b/IRaCIS.Core.Application.Contracts/Trial/WorkloadDistribution/IWorkloadDistributionService.cs @@ -0,0 +1,27 @@ +using System; +using System.Collections.Generic; +using IRaCIS.Application.ViewModels; +using IRaCIS.Core.Application.Contracts.RequestAndResponse; + +namespace IRaCIS.Core.Application.Contracts +{ + public interface IWorkloadDistributionService + { + PageOutput GetWorkloadTPList(WorkloadDistributionQueryParam param); + IResponseOutput DistributeTP(WorkloadTPCommand workloadTPCommand); + IResponseOutput UpdateDistributeTP(Guid tpId, Guid ReviewerId, Guid studyId); + + PageOutput GetWorkloadGlobalList(WorkloadDistributionQueryParam param); + IResponseOutput DistributeGlobal(WorkloadGlobalCommand workloadGlobalCommand); + IResponseOutput UpdateDistributeGlobal(Guid tpId, Guid ReviewerId,Guid subjectId, decimal visitNum); + + PageOutput GetWorkloadADList(WorkloadDistributionQueryParam param); + bool DistributeAD(WorkloadAdCommand workloadTPCommand); + bool UpdateDistributeAD(Guid tpId, Guid ReviewerId); + + IResponseOutput> GetWorkloadDetail(Guid WorkloadId); + + IResponseOutput UpdateGlobalStatus(Guid globalId); + + } +} diff --git a/IRaCIS.Core.Application.Contracts/_RequestAndResponse/Input/PageInput.cs b/IRaCIS.Core.Application.Contracts/_RequestAndResponse/Input/PageInput.cs new file mode 100644 index 0000000..3e5ce6c --- /dev/null +++ b/IRaCIS.Core.Application.Contracts/_RequestAndResponse/Input/PageInput.cs @@ -0,0 +1,13 @@ +namespace IRaCIS.Core.Application.Contracts.RequestAndResponse +{ + /// + /// 分页信息输入 + /// + public class PageInput + { + public int PageIndex { get; set; } = 1; + public int PageSize { set; get; } = 10; + public bool Asc { get; set; } = true; + public string SortField { get; set; } = ""; + } +} diff --git a/IRaCIS.Core.Application.Contracts/_RequestAndResponse/Output/IResponseOutput.cs b/IRaCIS.Core.Application.Contracts/_RequestAndResponse/Output/IResponseOutput.cs new file mode 100644 index 0000000..c3326e3 --- /dev/null +++ b/IRaCIS.Core.Application.Contracts/_RequestAndResponse/Output/IResponseOutput.cs @@ -0,0 +1,30 @@ +namespace IRaCIS.Core.Application.Contracts.RequestAndResponse +{ + /// + /// 响应数据输出接口 + /// + public interface IResponseOutput + { + /// + /// 是否成功 + /// + bool IsSuccess { get; } + + /// + /// 消息 + /// + string ErrorMessage { get; } + } + + /// + /// 响应数据输出泛型接口 + /// + /// + public interface IResponseOutput : IResponseOutput + { + /// + /// 返回数据 + /// + T Data { get; } + } +} diff --git a/IRaCIS.Core.Application.Contracts/_RequestAndResponse/Output/PageOutput.cs b/IRaCIS.Core.Application.Contracts/_RequestAndResponse/Output/PageOutput.cs new file mode 100644 index 0000000..bafb239 --- /dev/null +++ b/IRaCIS.Core.Application.Contracts/_RequestAndResponse/Output/PageOutput.cs @@ -0,0 +1,41 @@ +using System.Collections.Generic; + +namespace IRaCIS.Core.Application.Contracts.RequestAndResponse +{ + /// + /// 分页信息输出 泛型 + /// + public class PageOutput + { + /// + /// 当前页索引 + /// + public int PageIndex { get; set; } + + /// + /// 每页的记录条数 + /// + public int PageSize { get; set; } + + /// + /// 数据总数 + /// + public long TotalCount { get; set; } = 0; + + /// + /// 数据 + /// + public IList CurrentPageData { get; set; } + + public PageOutput(int pageIndex, int pageSize, long totalCount, IList data) + { + PageIndex = pageIndex; + PageSize = pageSize; + TotalCount = totalCount; + CurrentPageData = data; + } + public PageOutput() + { + } + } +} diff --git a/IRaCIS.Core.Application.Contracts/_RequestAndResponse/Output/ResponseOutput.cs b/IRaCIS.Core.Application.Contracts/_RequestAndResponse/Output/ResponseOutput.cs new file mode 100644 index 0000000..5b25808 --- /dev/null +++ b/IRaCIS.Core.Application.Contracts/_RequestAndResponse/Output/ResponseOutput.cs @@ -0,0 +1,133 @@ +using Newtonsoft.Json; + +namespace IRaCIS.Core.Application.Contracts.RequestAndResponse +{ + /// + /// 响应数据输出 泛型 + /// + public class ResponseOutput : IResponseOutput + { + /// + /// 是否成功标记 + /// + public bool IsSuccess { get; private set; } + + /// + /// 消息 + /// + public string ErrorMessage { get; private set; } + + /// + /// 数据 兼顾以前 Json序列化的时候返回属性名为“Result” + /// + [JsonProperty("Result")] + public T Data { get; private set; } + + /// + /// 成功 + /// + /// 数据 + /// 消息 + public ResponseOutput Ok(T data, string msg = "") + { + IsSuccess = true; + Data = data; + ErrorMessage = msg; + + return this; + } + + /// + /// 失败 + /// + /// 提示消息 + /// 数据 + /// + public ResponseOutput NotOk(string msg = "", T data = default) + { + IsSuccess = false; + ErrorMessage = msg; + Data = data; + return this; + } + } + + + + /// + /// 响应数据静态输出 为了代码简洁 不用每处都New + /// + public static class ResponseOutput + { + /// + /// 成功 -----适合查询 + /// + /// 数据 + /// 消息 + /// + public static IResponseOutput Ok(T data = default, string msg = "") + { + return new ResponseOutput().Ok(data, msg); + } + + /// + /// 成功 + /// + /// + public static IResponseOutput Ok() + { + return Ok(); + } + + /// + /// 失败 + /// + /// 消息 + /// 数据 + /// + public static IResponseOutput NotOk(string msg = "", T data = default) + { + return new ResponseOutput().NotOk(msg, data); + } + + /// + /// 失败 + /// + /// 消息 + /// + public static IResponseOutput NotOk(string msg = "") + { + return new ResponseOutput().NotOk(msg); + } + + /// + /// 根据布尔值返回结果 --适合删除 + /// + /// + /// + public static IResponseOutput Result(bool success) + { + return success ? Ok() : NotOk("Database operate failed"); + } + + /// + /// 根据布尔值返回结果 --适合添加和更新一起 + /// + /// + /// + public static IResponseOutput Result(bool success, T data = default) + { + return success ? Ok(data) : NotOk("Database operation failed"); + } + + /// + /// 根据布尔值返回结果 + /// + /// + /// + public static IResponseOutput Result(bool success) + { + return success ? Ok() : NotOk(); + } + } +} diff --git a/IRaCIS.Core.Application/AutoMapper/AutoMapperConfig.cs b/IRaCIS.Core.Application/AutoMapper/AutoMapperConfig.cs new file mode 100644 index 0000000..fcbc0f9 --- /dev/null +++ b/IRaCIS.Core.Application/AutoMapper/AutoMapperConfig.cs @@ -0,0 +1,32 @@ +using AutoMapper; + +namespace IRaCIS.Application.AutoMapper +{ + public class AutoMapperConfig + { + public static void Config() + { + //Mapper.Initialize(cfg => + //{ + // cfg.AddProfile(); + // cfg.AddProfile(new ViewModelToDomainMappingProfile()); + // cfg.AddProfile(new LogicChangeMappingProfile()); + // cfg.ForAllMaps((a, b) => b.ForAllMembers(opt => opt.Condition((src, dest, sourceMember) => sourceMember != null))); + //}); + } + + public static MapperConfiguration RegisterMappings() + { + //创建AutoMapperConfiguration, 提供静态方法Configure,一次加载所有层中Profile定义 + //MapperConfiguration实例可以静态存储在一个静态字段中,也可以存储在一个依赖注入容器中。 一旦创建,不能更改/修改。 + + return new MapperConfiguration(cfg => + { + cfg.AddProfile(); + cfg.AddProfile(new ViewModelToDomainMappingProfile()); + cfg.AddProfile(new LogicChangeMappingProfile()); + cfg.ForAllMaps((a, b) => b.ForAllMembers(opt => opt.Condition((src, dest, sourceMember) => sourceMember != null))); + }); + } + } +} diff --git a/IRaCIS.Core.Application/AutoMapper/DomainToViewModelMappingProfile.cs b/IRaCIS.Core.Application/AutoMapper/DomainToViewModelMappingProfile.cs new file mode 100644 index 0000000..6f489aa --- /dev/null +++ b/IRaCIS.Core.Application/AutoMapper/DomainToViewModelMappingProfile.cs @@ -0,0 +1,89 @@ +using AutoMapper; +using IRaCIS.Application.Interfaces; +using IRaCIS.Application.ViewModels; +using IRaCIS.Application.ViewModels.Pay; +using IRaCIS.Core.Domain; +using IRaCIS.Domain; +using IRaCIS.Domain.Models; + +namespace IRaCIS.Application.AutoMapper +{ + public class DomainToViewModelMappingProfile : Profile + { + public DomainToViewModelMappingProfile() + { + #region Reviewer + + CreateMap(); + CreateMap(); + + CreateMap(); + CreateMap(); + CreateMap(); + CreateMap(); + CreateMap(); + CreateMap(); + + CreateMap(); + + CreateMap(); + CreateMap(); + + CreateMap(); + + #endregion + + #region Management + + CreateMap(); + CreateMap(); + CreateMap(); + CreateMap(); + + CreateMap(); + + #endregion + + #region institution + + CreateMap(); + CreateMap(); + CreateMap(); + CreateMap(); + CreateMap(); + CreateMap(); + + #endregion + + #region WrokLoad + + CreateMap(); + + #endregion + + CreateMap(); + + CreateMap(); + + #region finacial + + CreateMap(); + CreateMap(); + CreateMap(); + CreateMap(); + CreateMap(); + + CreateMap(); + + + + #endregion + + #region image + + CreateMap(); + + #endregion + } + } +} diff --git a/IRaCIS.Core.Application/AutoMapper/LogicChangeMappingProfile.cs b/IRaCIS.Core.Application/AutoMapper/LogicChangeMappingProfile.cs new file mode 100644 index 0000000..033588a --- /dev/null +++ b/IRaCIS.Core.Application/AutoMapper/LogicChangeMappingProfile.cs @@ -0,0 +1,34 @@ +using IRaCIS.Application.ViewModels; +using IRaCIS.Domain.Models; +using AutoMapper; +using IRaCIS.Application.ViewModels.Pay; + +namespace IRaCIS.Application.AutoMapper +{ + public class LogicChangeMappingProfile : Profile + { + public LogicChangeMappingProfile() + { + + + //医生列表、项目显示列表模型转换 + CreateMap(); + + + CreateMap() + .ForMember(o => o.MessageTime, t => t.MapFrom(u => u.MessageTime.ToString())); + + + CreateMap() + .ForMember(o => o.InstitutionName, t => t.MapFrom(u => u.CROName)); + CreateMap() + .ForMember(o => o.InstitutionName, t => t.MapFrom(u => u.SponsorName)); + CreateMap() + .ForMember(o => o.InstitutionName, t => t.MapFrom(u => u.HospitalName)); + CreateMap() + .ForMember(o => o.InstitutionName, t => t.MapFrom(u => u.SiteName)); + + CreateMap(); + } + } +} \ No newline at end of file diff --git a/IRaCIS.Core.Application/AutoMapper/ViewModelToDomainMappingProfile.cs b/IRaCIS.Core.Application/AutoMapper/ViewModelToDomainMappingProfile.cs new file mode 100644 index 0000000..d9333e4 --- /dev/null +++ b/IRaCIS.Core.Application/AutoMapper/ViewModelToDomainMappingProfile.cs @@ -0,0 +1,141 @@ +using AutoMapper; +using IRaCIS.Application.Interfaces; +using IRaCIS.Application.ViewModels; +using IRaCIS.Application.ViewModels.Pay; +using IRaCIS.Core.Domain; +using IRaCIS.Domain; +using IRaCIS.Domain.Models; + +namespace IRaCIS.Application.AutoMapper +{ + public class ViewModelToDomainMappingProfile : Profile + { + public ViewModelToDomainMappingProfile() + { + + #region reviewer + + //基本信息 工作信息 添加时转换使用 + CreateMap(); + + //学习经历 添加时转换使用 + CreateMap(); + CreateMap(); + CreateMap(); + CreateMap(); + + //医生账户 + CreateMap(); + CreateMap(); + + CreateMap(); + + + CreateMap(); + + CreateMap(); + + #endregion + + + #region trial + + + //临床项目 + CreateMap(); + + #endregion + + + #region workLoad + + //工作量 + + + CreateMap(); + + #endregion + + + + CreateMap(); + + CreateMap(); + + CreateMap(); + + CreateMap(); + + + #region management + + CreateMap(); + + CreateMap(); + + CreateMap(); + + CreateMap(); + + //CreateMap(); + + #endregion + + #region institution + CreateMap(); + CreateMap(); + CreateMap(); + CreateMap(); + + + + //CreateMap(); + + //CreateMap(); + + //CreateMap(); + + + #endregion + + + + #region financial + CreateMap(); + CreateMap(); + + CreateMap(); + + CreateMap(); + + CreateMap(); + + CreateMap(); + CreateMap(); + + CreateMap(); + + + #endregion + + + + + #region image + + CreateMap(); + CreateMap(); + CreateMap(); + CreateMap(); + CreateMap(); + CreateMap(); + CreateMap(); + + #endregion + + + + + } + } +} \ No newline at end of file diff --git a/IRaCIS.Core.Application/Common/AttachmentService.cs b/IRaCIS.Core.Application/Common/AttachmentService.cs new file mode 100644 index 0000000..1fea56a --- /dev/null +++ b/IRaCIS.Core.Application/Common/AttachmentService.cs @@ -0,0 +1,126 @@ +using AutoMapper; +using AutoMapper.QueryableExtensions; +using IRaCIS.Application.Interfaces; +using IRaCIS.Application.ViewModels; +using IRaCIS.Core.Application.Contracts.RequestAndResponse; +using IRaCIS.Core.Domain.Interfaces; +using IRaCIS.Core.Domain.Models; +using System; +using System.Collections.Generic; +using System.Linq; + +namespace IRaCIS.Application.Services +{ + public class AttachmentService : IAttachmentService + { + private readonly IAttachmentRepository _doctorAttachmentRepository; + private readonly IMapper _mapper; + + public AttachmentService(IAttachmentRepository doctorAttachmentRepository, IMapper mapper) + { + _doctorAttachmentRepository = doctorAttachmentRepository; + _mapper = mapper; + } + + /// + /// 删除附件 + /// + /// + /// + public IResponseOutput DeleteAttachment(Guid attachmentId) + { + var success = _doctorAttachmentRepository.Delete(a => a.Id == attachmentId); + return ResponseOutput.Result(success); + } + + /// + /// 根据附件类型获取附件信息 + /// + /// + /// + /// + public IEnumerable GetAttachmentByType(Guid doctorId, string type) + { + return _doctorAttachmentRepository.Find(a => a.DoctorId == doctorId && a.Type.Equals(type)).ProjectTo(_mapper.ConfigurationProvider); + } + + public IEnumerable GetAttachmentByTypes(Guid doctorId, string[] types) + { + return _doctorAttachmentRepository.Find(a => a.DoctorId == doctorId && types.Contains(a.Type)).OrderBy(s => s.Type).ThenBy(m => m.CreateTime).ProjectTo(_mapper.ConfigurationProvider); + } + + public IEnumerable GetAttachments(Guid doctorId) + { + return _doctorAttachmentRepository.Find(a => a.DoctorId == doctorId).OrderBy(s => s.Type).ThenBy(m => m.CreateTime).ProjectTo(_mapper.ConfigurationProvider); + } + + public AttachmentDTO GetDetailById(Guid attachmentId) + { + var attachment = _doctorAttachmentRepository.FindSingleOrDefault(a => a.Id == attachmentId); + return _mapper.Map(attachment); + } + + + + /// + /// 保存多个附件 + /// + /// + /// + public IEnumerable SaveAttachmentRange(IEnumerable attachmentList) + { + var attachments = _mapper.Map>(attachmentList); + + foreach (var item in attachments) + { + if (item.Id != Guid.Empty) + { + _doctorAttachmentRepository.Delete(a => a.Id == item.Id); + } + } + + var result = _doctorAttachmentRepository.AddRange(attachments); + _doctorAttachmentRepository.SaveChanges(); + return _mapper.Map>(result); + } + + + + + public string GetDoctorOfficialCV(Guid doctorId) + { + var result = _doctorAttachmentRepository.FindSingleOrDefault(a => a.DoctorId == doctorId && + a.IsOfficial && a.Type.Equals("Resume")); + if (result != null) + { + return result.Path; + } + return string.Empty; + } + + public IResponseOutput SetOfficial(Guid doctorId, Guid attachmentId) + { + var resumeList = _doctorAttachmentRepository.Find(t => t.DoctorId == doctorId && t.Type == "Resume"); + foreach (var item in resumeList) + { + if (item.Id == attachmentId) item.IsOfficial = true; + else item.IsOfficial = false; + _doctorAttachmentRepository.Update(item); + } + + + //_doctorAttachmentRepository.Update(t => t.DoctorId == doctorId && t.Type == "Resume", entity => new Attachment() + //{ + // IsOfficial = false + //}); + + //var success1 = _doctorAttachmentRepository.Update(t => t.Id == attachmentId, attach => new Attachment() + //{ + // IsOfficial = true + //}); + return ResponseOutput.Result(_doctorAttachmentRepository.SaveChanges()); + + + } + } +} diff --git a/IRaCIS.Core.Application/Common/DictionaryService.cs b/IRaCIS.Core.Application/Common/DictionaryService.cs new file mode 100644 index 0000000..ed55b58 --- /dev/null +++ b/IRaCIS.Core.Application/Common/DictionaryService.cs @@ -0,0 +1,174 @@ +using AutoMapper; +using AutoMapper.QueryableExtensions; +using IRaCIS.Application.ExpressionExtend; +using IRaCIS.Application.Interfaces; +using IRaCIS.Application.ViewModels; +using IRaCIS.Core.Application.Contracts.RequestAndResponse; +using IRaCIS.Core.Domain.Interfaces; +using IRaCIS.Core.Domain.Models; +using IRaCIS.Infra.Data.ExpressionExtend; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Expressions; + +namespace IRaCIS.Application.Services +{ + public class DictionaryService : IDictionaryService + { + private readonly IDictionaryRepository _dicRepository; + private readonly IDoctorDictionaryRepository _doctorDictionaryRepository; + private readonly ITrialDictionaryRepository _trialDictionaryRepository; + private readonly IMapper _mapper; + + public DictionaryService(IDictionaryRepository sysDicRepository, IDoctorDictionaryRepository doctorDictionaryRepository, ITrialDictionaryRepository trialDictionaryRepository,IMapper mapper) + { + _dicRepository = sysDicRepository; + _doctorDictionaryRepository = doctorDictionaryRepository; + _trialDictionaryRepository = trialDictionaryRepository; + _mapper = mapper; + } + + /// 根据字典 Key 获取字典数据 + public DicResultDTO GetDictionaryResult(string[] searchArray) + { + var doctorViewList = _dicRepository.GetAll().ProjectTo(_mapper.ConfigurationProvider).OrderBy(t => t.KeyName) + .ThenBy(t => t.ShowOrder).ToList(); + + var projectDicResult = new DicResultDTO(); + foreach (var searchItem in searchArray) + { + var item = searchItem.Trim(); + var tempDic = new Dictionary(); + doctorViewList.Where(o => o.KeyName == item).ToList().ForEach(o => tempDic.Add(o.Id, o.Value)); + projectDicResult.DicList.Add(item, tempDic); + } + return projectDicResult; + } + + public DicResultDTO GetAllDictionary() + { + var list = _dicRepository.GetAll().ProjectTo(_mapper.ConfigurationProvider).OrderBy(t => t.KeyName) + .ThenBy(t => t.ShowOrder).ToList(); + + var types = list.Select(u => u.KeyName).Distinct(); + + var projectDicResult = new DicResultDTO(); + foreach (var type in types) + { + var tempDic = new Dictionary(); + list.Where(o => o.KeyName == type).ToList().ForEach(o => tempDic.Add(o.Id, o.Value)); + projectDicResult.DicList.Add(type, tempDic); + } + return projectDicResult; + } + + /// 根据Key,获取单个字典数组 + public PageOutput GetDicSelectList(DicQueryDTO dicSearchModel) + { + Expression> dictionaryLambda = x => true; + if (!string.IsNullOrWhiteSpace(dicSearchModel.KeyName.Trim())) + { + dictionaryLambda = dictionaryLambda.And(t => t.KeyName == dicSearchModel.KeyName.Trim()); + } + var dicQueryable = _dicRepository.GetAll().Where(dictionaryLambda).ProjectTo(_mapper.ConfigurationProvider); + var totalCount = dicQueryable.Count(); + + //处理排序字段 + var propName = dicSearchModel.SortField == string.Empty ? "KeyName" : dicSearchModel.SortField; + //处理升序和降序 + dicQueryable = dicSearchModel.Asc ? dicQueryable.OrderBy(propName) : dicQueryable.OrderByDescending(propName); + //分页 + dicQueryable = dicQueryable + .Skip((dicSearchModel.PageIndex - 1) * dicSearchModel.PageSize) + .Take(dicSearchModel.PageSize); + var list = dicQueryable.OrderBy(t => t.ShowOrder).ToList(); + return new PageOutput(dicSearchModel.PageIndex, dicSearchModel.PageSize, totalCount, list); + } + + /// 根据Type、Key 获取字典 树结构 + public List GetDicTree() + { + var keyNameTypeDistinctList = _dicRepository.Find(u => !(u.KeyName == "UserType" || u.KeyName == "InstitutionalType")).ProjectTo(_mapper.ConfigurationProvider).Distinct().ToList(); + var treeNodeList = new List(); + var group = keyNameTypeDistinctList.GroupBy(t => t.Type); + foreach (var groupItem in group) + { + var node = new DictionaryTreeNode() + { + Id = Guid.NewGuid(), + KeyName = groupItem.Key, + Type = groupItem.Key, + Children = keyNameTypeDistinctList.Where(t => t.Type == groupItem.Key).Select(t => + new DictionaryTreeNode() + { + Id = Guid.NewGuid(), + KeyName = t.KeyName, + Type = t.Type, + Children = new List() + }).ToList() + }; + treeNodeList.Add(node); + } + return treeNodeList; + } + + /// 添加或更新字典数据 + public IResponseOutput AddOrUpdateDictionary(DicViewModelDTO viewModel) + { + if (viewModel.Id == Guid.Empty) + { + var existItem = _dicRepository.FindSingleOrDefault(dic => dic.KeyName.Equals(viewModel.KeyName) && dic.Value.Equals(viewModel.Value)); + if (existItem != null) + { + return ResponseOutput.NotOk("新添加项不能与当前类别下面子项同名,请修改名称"); + } + var result = _dicRepository.Add(_mapper.Map(viewModel)); + var success = _dicRepository.SaveChanges(); + return ResponseOutput.Result(success); + } + else + { + var existItem = _dicRepository.FindSingleOrDefault(dic => dic.KeyName.Equals(viewModel.KeyName) && dic.Value.Equals(viewModel.Value)); + if (existItem != null && existItem.Id != viewModel.Id) + { + return ResponseOutput.NotOk("更新后的名称不能与该类别下子项同名,请修改名称"); + } + var updateItem = _dicRepository.GetAll().FirstOrDefault(t => t.Id == viewModel.Id); + _mapper.Map(viewModel, updateItem); + _dicRepository.Update(updateItem); + var success = _dicRepository.SaveChanges(); + return ResponseOutput.Result(success); + } + } + + /// 删除字典数据 + public IResponseOutput DeleteDictionary(Guid id) + { + if (_doctorDictionaryRepository.GetAll().Any(t => t.DictionaryId == id)) + { + return ResponseOutput.NotOk("医生简历表有数据关联此字典表项"); + } + + if (_trialDictionaryRepository.GetAll().Any(t => t.DictionaryId == id)) + { + return ResponseOutput.NotOk("项目表有数据关联此字典表项"); + } + + var success = _dicRepository.Delete(t => t.Id == id); + return ResponseOutput.Result(success); + } + + /// 获取所有字典数据 + public IEnumerable GetDicSelect() + { + return _dicRepository.GetAll().Select(t => t.KeyName).Distinct().ToList(); + } + + public DicViewModelDTO GetDetailById(Guid id) + { + var result = _dicRepository.FindSingleOrDefault(u => u.Id == id); + return _mapper.Map(result); + } + } +} diff --git a/IRaCIS.Core.Application/Common/FileService.cs b/IRaCIS.Core.Application/Common/FileService.cs new file mode 100644 index 0000000..b192cfd --- /dev/null +++ b/IRaCIS.Core.Application/Common/FileService.cs @@ -0,0 +1,211 @@ +using IRaCIS.Application.Interfaces; +using System; +using System.IO; +using System.Linq; +using System.Text; +using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Logging; +using IRaCIS.Core.Infrastructure; + +namespace IRaCIS.Application.Services +{ + public class FileService : IFileService + { + + private readonly IDoctorService _doctorService; + private readonly IAttachmentService _attachmentService; + private readonly IHostEnvironment _hostEnvironment; + private string defaultUploadFilePath = string.Empty; + private readonly ILogger _logger; + public FileService(IDoctorService doctorService, IAttachmentService attachmentService, + IHostEnvironment hostEnvironment, ILogger logger) + { + _doctorService = doctorService; + _attachmentService = attachmentService; + _hostEnvironment = hostEnvironment; + + defaultUploadFilePath = Directory.GetParent(_hostEnvironment.ContentRootPath).FullName; + _logger = logger; + } + + /// + /// 打包医生官方简历 + /// + /// + /// + public string CreateOfficialResumeZip(Guid[] doctorIds) + { + + //准备下载文件的临时路径 + var guidStr = Guid.NewGuid().ToString(); + + //string uploadFolderPath = HostingEnvironment.MapPath("/UploadFile/"); + string uploadFolderPath = Path.Combine(defaultUploadFilePath, "UploadFile"); + + var tempSavePath = Path.Combine(uploadFolderPath, "temp", guidStr); //待压缩的文件夹,将需要下载的文件拷贝到此文件夹 + if (!Directory.Exists(tempSavePath)) + { + Directory.CreateDirectory(tempSavePath); + } + + //找到服务器简历路径 循环拷贝简历到临时路径 + foreach (var doctorId in doctorIds) + { + var doctor = _doctorService.GetDoctorBasicInfo(doctorId); + var doctorName = doctor.FirstName + "_" + doctor.LastName; + + //找官方简历存在服务器的相对路径 + var sourceCvPath = _attachmentService.GetDoctorOfficialCV(doctorId); + if (!string.IsNullOrWhiteSpace(sourceCvPath)) + { + //服务器简历文件实际路径 + //var sourceCvFullPath = HostingEnvironment.MapPath(sourceCvPath); + var sourceCvPathTemp = sourceCvPath.Substring(1, sourceCvPath.Length-1);//.Replace('/','\\'); + string sourceCvFullPath = Path.Combine(defaultUploadFilePath, sourceCvPathTemp); + + var arr = sourceCvPath.Split('.'); + string extensionName = arr[arr.Length - 1]; //得到扩展名 + + //需要拷贝到的路径 + var doctorPath = Path.Combine(tempSavePath, doctor.Code.ToString() + "_" + doctorName + "." + extensionName); + + if (File.Exists(sourceCvFullPath)) + { + File.Copy(sourceCvFullPath, doctorPath, true); + } + } + } + + //创建ZIP + DateTime now = DateTime.Now; + StringBuilder sb = new StringBuilder(); + sb.Append(now.Year).Append(now.Month.ToString().PadLeft(2, '0')).Append(now.Day.ToString().PadLeft(2, '0')) + .Append(now.Hour.ToString().PadLeft(2, '0')).Append(now.Minute.ToString().PadLeft(2, '0')) + .Append(now.Second.ToString().PadLeft(2, '0')).Append(now.Millisecond.ToString().PadLeft(3, '0')); + + string targetZipPath = Path.Combine(uploadFolderPath, "CV_" + sb.ToString() + ".zip"); + ZipHelper.CreateZip(tempSavePath, targetZipPath); + + //返回Zip路径 + return Path.Combine("/UploadFile/", "CV_" + sb.ToString() + ".zip"); + } + + /// + /// 打包医生的所有附件 + /// + /// + /// + public string CreateDoctorsAllAttachmentZip(Guid[] doctorIds) + { + //准备下载文件的临时路径 + var guidStr = Guid.NewGuid().ToString(); + //string uploadFolderPath = HostingEnvironment.MapPath("/UploadFile/"); + string uploadFolderPath = Path.Combine(defaultUploadFilePath, "UploadFile"); + var tempSavePath = Path.Combine(uploadFolderPath, "temp", guidStr); //待压缩的文件夹,将需要下载的文件拷贝到此文件夹 + if (!Directory.Exists(tempSavePath)) + { + Directory.CreateDirectory(tempSavePath); + } + + + foreach (var doctorId in doctorIds) + { + //获取医生基本信息 + var doctor = _doctorService.GetDoctorBasicInfo(doctorId); + var doctorName = doctor.FirstName + "_" + doctor.LastName; + var doctorCode = doctor.Code; + + var doctorDestPath = Path.Combine(tempSavePath, doctorCode + "_" + doctorName); + if (!Directory.Exists(doctorDestPath)) + { + Directory.CreateDirectory(doctorDestPath); + } + + //服务器上传后的源路径 + string doctorFileSourcePath = Path.Combine(uploadFolderPath, doctorId.ToString()); + + if (Directory.Exists(doctorFileSourcePath)) + { + CopyDirectory(doctorFileSourcePath, doctorDestPath); + } + } + string target = Guid.NewGuid().ToString(); + string targetPath = Path.Combine(uploadFolderPath, target + ".zip"); + ZipHelper.CreateZip(tempSavePath, targetPath); + return Path.Combine("/UploadFile/", target + ".zip"); + } + + + public string CreateZipPackageByAttachment(Guid doctorId, Guid[] attachmentIds) + { + var doctor = _doctorService.GetDoctorBasicInfo(doctorId); + var doctorName = doctor.FirstName + "_" + doctor.LastName; + + Guid temp = Guid.NewGuid(); + //string root = HostingEnvironment.MapPath("/UploadFile/"); //文件根目录 + string root = Path.Combine(defaultUploadFilePath, "UploadFile"); + + var tempPath = Path.Combine(root, "temp", temp.ToString(), doctor.Code + doctorName); //待压缩的文件夹,将需要下载的文件拷贝到此文件夹 + var packagePath = Path.Combine(root, "temp", temp.ToString()); //打包目录 + if (!Directory.Exists(tempPath)) + { + Directory.CreateDirectory(tempPath); + } + var attachemnts = _attachmentService.GetAttachments(doctorId).Where(a => attachmentIds.Contains(a.Id)); + + foreach (var item in attachemnts) + { + var arr = item.Path.Trim().Split('/'); + var myPath = string.Empty; + var myFile = string.Empty; + //需要改进 + if (arr.Length > 0) + { + myFile = arr[arr.Length - 1]; + foreach (var arrItem in arr) + { + if (arrItem != string.Empty && !"UploadFile".Equals(arrItem)) + { + myPath += (arrItem + "/"); + } + } + myPath = myPath.TrimEnd('/'); + } + var sourcePath = Path.Combine(root, myPath); + + if (!string.IsNullOrWhiteSpace(sourcePath) && File.Exists(sourcePath)) + { + File.Copy(sourcePath, Path.Combine(tempPath, myFile), true); + } + } + string target = Guid.NewGuid().ToString(); + string targetPath = Path.Combine(root, target + ".zip"); + ZipHelper.CreateZip(packagePath, targetPath); + + return Path.Combine("/UploadFile/", target + ".zip"); + } + + private static void CopyDirectory(string srcPath, string destPath) + { + + DirectoryInfo dir = new DirectoryInfo(srcPath); + FileSystemInfo[] fileInfoArray = dir.GetFileSystemInfos(); //获取目录下(不包含子目录)的文件和子目录 + foreach (FileSystemInfo fileInfo in fileInfoArray) + { + if (fileInfo is DirectoryInfo) //判断是否文件夹 + { + if (!Directory.Exists(destPath + "\\" + fileInfo.Name)) + { + Directory.CreateDirectory(destPath + "\\" + fileInfo.Name); //目标目录下不存在此文件夹即创建子文件夹 + } + CopyDirectory(fileInfo.FullName, destPath + "\\" + fileInfo.Name); //递归调用复制子文件夹 + } + else + { + File.Copy(fileInfo.FullName, destPath + "\\" + fileInfo.Name, true); //不是文件夹即复制文件,true表示可以覆盖同名文件 + } + } + + } + } +} diff --git a/IRaCIS.Core.Application/Common/LogService.cs b/IRaCIS.Core.Application/Common/LogService.cs new file mode 100644 index 0000000..43410e7 --- /dev/null +++ b/IRaCIS.Core.Application/Common/LogService.cs @@ -0,0 +1,102 @@ +using AutoMapper; +using IRaCIS.Application.ExpressionExtend; +using IRaCIS.Application.Interfaces; +using IRaCIS.Application.ViewModels; +using IRaCIS.Core.Application.Contracts.RequestAndResponse; +using IRaCIS.Core.Domain.Interfaces; +using IRaCIS.Core.Domain.Models; +using IRaCIS.Core.Infrastructure; +using IRaCIS.Infra.Data.ExpressionExtend; +using Microsoft.AspNetCore.Http; +using System; +using System.Linq; +using System.Linq.Expressions; + +namespace IRaCIS.Application.Services +{ + public class LogService : ILogService + { + private readonly ISystemLogRepository _systemLogRepository; + private readonly IUserRepository _userRepository; + private readonly IMapper _mapper; + private readonly IHttpContextAccessor _context; + + public LogService(ISystemLogRepository systemLogRepository, IUserRepository userRepository, IMapper mapper, IHttpContextAccessor context) + { + _systemLogRepository = systemLogRepository; + _userRepository = userRepository; + _mapper = mapper; + _context = context; + } + public PageOutput GetLogList(QueryLogQueryDTO param) + { + Expression> logLambda = x => true; + DateTime bTime = new DateTime(param.BeginTime.Year, param.BeginTime.Month, param.BeginTime.Day, 0, 0, 1); + DateTime eTime = new DateTime(param.EndTime.Year, param.EndTime.Month, param.EndTime.Day, 23, 59, 59); + logLambda = logLambda.And(o => o.RequestTime >= bTime && o.RequestTime <= eTime); + if (!string.IsNullOrWhiteSpace(param.LogCategory)) + { + logLambda = logLambda.And(o => o.LogCategory == param.LogCategory); + } + if (!string.IsNullOrWhiteSpace(param.Keyword.Trim())) + { + logLambda = logLambda.And(o => o.Params.Contains(param.Keyword.Trim()) || o.Result.Contains(param.Keyword.Trim())); + } + var a = _systemLogRepository.Find(logLambda).ToList(); + var logQueryable = from log in _systemLogRepository.GetAll().Where(logLambda) + select new SystemLogDTO + { + Id = log.Id, + LogCategory = log.LogCategory, + ApiPath = log.ApiPath, + Params = log.Params, + Result = log.Result, + ElapsedMilliseconds = log.ElapsedMilliseconds, + RequestTime = log.RequestTime, + ClientIP = log.ClientIP, + Message = log.Message, + Status = log.Status, + OptUserId = log.OptUserId, + OptUserName = log.OptUserName + }; + var count = logQueryable.Count(); + var propName = string.Empty; + if (string.IsNullOrWhiteSpace(param.SortField)) + { + propName = "RequestTime"; + param.Asc = false; + } + else + { + propName = param.SortField; + } + logQueryable = param.Asc + ? logQueryable.OrderBy(propName) + : logQueryable.OrderByDescending(propName); + logQueryable = logQueryable + .Skip((param.PageIndex - 1) * param.PageSize) + .Take(param.PageSize); + var logList = logQueryable.ToList(); + + return new PageOutput(param.PageIndex, param.PageSize, count, logList); + } + + public IResponseOutput SaveLog2Db(SystemLogDTO input) + { + //string ua = _context.HttpContext.Request.Headers["User-Agent"]; + //var client = UAParser.Parser.GetDefault().Parse(ua); + //var device = client.Device.Family; + //device = device.ToLower() == "other" ? "" : device; + //input.Browser = client.UA.Family; + //input.Os = client.OS.Family; + //input.Device = device; + //input.BrowserInfo = ua; + + input.ClientIP = IPHelper.GetIP(_context?.HttpContext?.Request); + + _systemLogRepository.Add(_mapper.Map(input)); + var success = _systemLogRepository.SaveChanges(); + return ResponseOutput.Result(success); + } + } +} diff --git a/IRaCIS.Core.Application/Common/MailService.cs b/IRaCIS.Core.Application/Common/MailService.cs new file mode 100644 index 0000000..9186e47 --- /dev/null +++ b/IRaCIS.Core.Application/Common/MailService.cs @@ -0,0 +1,75 @@ +using IRaCIS.Core.Domain.Interfaces; +using IRaCIS.Core.Domain.Models; +using MailKit.Security; +using MimeKit; +using System; +using System.Threading.Tasks; + +namespace IRaCIS.Application.Services +{ + public interface IMailVerificationService + { + Task SendMail(Guid userId, string userName, string emailAddress, int verificationCode); + } + + public class MailVerificationService: IMailVerificationService + { + private readonly IVerificationCodeRepository _verificationCodeRepository; + + + public MailVerificationService(IVerificationCodeRepository verificationCodeRepository) + { + _verificationCodeRepository = verificationCodeRepository; + + } + + public async Task SendMail(Guid userId, string userName, string emailAddress, int verificationCode) + { + + + var messageToSend = new MimeMessage(); + //发件地址 + messageToSend.From.Add(new MailboxAddress("GRR", "iracis_grr@163.com")); + //收件地址 + messageToSend.To.Add(new MailboxAddress(userName, emailAddress)); + //主题 + messageToSend.Subject = "Reset PassWord (Verification Code)"; + + messageToSend.Body = new TextPart("plain") + { + Text = $@"Hey {userName},您正在通过邮箱重置密码,本次的验证码是:{verificationCode},3分钟内有效,如若不是本人操作,请忽略! + + -- GRR" + }; + using (var smtp = new MailKit.Net.Smtp.SmtpClient()) + { + smtp.MessageSent += (sender, args) => + { + // args.Response + var code = verificationCode.ToString(); + _verificationCodeRepository.Add(new VerificationCode() + { + CodeType = 0, + HasSend = true, + Code = code, + UserId = userId, + ExpirationTime = DateTime.Now.AddMinutes(3) + }); + _verificationCodeRepository.SaveChanges(); + + }; + + smtp.ServerCertificateValidationCallback = (s, c, h, e) => true; + + await smtp.ConnectAsync("smtp.163.com", 25, SecureSocketOptions.StartTls); + + await smtp.AuthenticateAsync("iracis_grr@163.com", "XLWVQKZAEKLDWOAH"); + + await smtp.SendAsync(messageToSend); + + await smtp.DisconnectAsync(true); + + } + } + } +} \ No newline at end of file diff --git a/IRaCIS.Core.Application/Common/MessageService.cs b/IRaCIS.Core.Application/Common/MessageService.cs new file mode 100644 index 0000000..91b21e4 --- /dev/null +++ b/IRaCIS.Core.Application/Common/MessageService.cs @@ -0,0 +1,56 @@ +using AutoMapper; +using IRaCIS.Application.Interfaces; +using IRaCIS.Application.ViewModels; +using IRaCIS.Core.Application.Contracts.RequestAndResponse; +using IRaCIS.Core.Domain.Interfaces; +using IRaCIS.Core.Domain.Models; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Expressions; + +namespace IRaCIS.Application.Services +{ + public class MessageService : IMessageService + { + private readonly IMessageRepository _sysMessageRepository; + private readonly IMapper _mapper; + + public MessageService(IMessageRepository sysMessageRepository,IMapper mapper) + { + _sysMessageRepository = sysMessageRepository; + _mapper = mapper; + } + + public IResponseOutput DeleteSysMessage(Guid messageId) + { + var success= _sysMessageRepository.Delete(m => m.Id == messageId); + return ResponseOutput.Result(success); + } + + public PageOutput GetMessageList(Guid doctorId, int pageSize, int pageIndex) + { + Expression> sysMessageLambda = x => x.ToDoctorId == doctorId; + var count = _sysMessageRepository.GetCount(sysMessageLambda); + var result = _sysMessageRepository.Find(pageSize, pageIndex, false, "Id", sysMessageLambda).ToList(); + + return new PageOutput(pageIndex, pageSize, count, _mapper.Map>(result)); + + } + + public int GetUnReadMessageCount(Guid doctorId) + { + return _sysMessageRepository.GetCount(m => m.ToDoctorId == doctorId && m.HasRead == false); + } + + public IResponseOutput MarkedAsRead(Guid messageId) + { + var success = _sysMessageRepository.Update(m => m.Id == messageId, u => new Message() + { + HasRead = true + }); + + return ResponseOutput.Result(success); + } + } +} \ No newline at end of file diff --git a/IRaCIS.Core.Application/Doctor/DoctorListQueryService.cs b/IRaCIS.Core.Application/Doctor/DoctorListQueryService.cs new file mode 100644 index 0000000..c5c47e3 --- /dev/null +++ b/IRaCIS.Core.Application/Doctor/DoctorListQueryService.cs @@ -0,0 +1,778 @@ +using AutoMapper; +using AutoMapper.QueryableExtensions; +using IRaCIS.Application.ExpressionExtend; +using IRaCIS.Application.Interfaces; +using IRaCIS.Application.ViewModels; +using IRaCIS.Core.Application.Contracts.RequestAndResponse; +using IRaCIS.Core.Domain.Interfaces; +using IRaCIS.Core.Domain.Models; +using IRaCIS.Core.Domain.Share; +using IRaCIS.Infra.Data.ExpressionExtend; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Dynamic.Core; +using System.Linq.Expressions; + + +namespace IRaCIS.Application.Services +{ + public class DoctorListQueryService : IDoctorListQueryService + { + private readonly IDoctorRepository _doctorRepository; + private readonly IDictionaryRepository _dictionaryRepository; + private readonly IHospitalRepository _hospitalRepository; + + private readonly IEnrollRepository _enrollRepository; + private readonly IEnrollDetailRepository _enrollDetailRepository; + private readonly IDoctorDictionaryRepository _doctorDictionaryRepository; + private readonly IUserRepository _userRepository; + private readonly IAttachmentRepository _attachmentRepository; + private readonly IUserDoctorRepository _userDoctorRepository; + private readonly ITrialRepository _trialRepository; + private readonly ITrialPaymentPriceRepository _TrialPaymentPrice; + private readonly IMapper _mapper; + + public DoctorListQueryService(IDoctorRepository doctorInfoRepository, + IDictionaryRepository dictionaryRepository, IHospitalRepository hospitalRepository, + IEnrollRepository intoGroupRepository, IEnrollDetailRepository intoGroupDetailRepository, + IDoctorDictionaryRepository doctorDictionaryRepository, IUserRepository userRepository, + IAttachmentRepository attachmentRepository, + IUserDoctorRepository userDoctorRepository, + ITrialRepository trialRepository, + ITrialPaymentPriceRepository trialPaymentPrice, + IMapper mapper + ) + { + _doctorRepository = doctorInfoRepository; + _dictionaryRepository = dictionaryRepository; + _hospitalRepository = hospitalRepository; + _TrialPaymentPrice = trialPaymentPrice; + + _enrollRepository = intoGroupRepository; + _enrollDetailRepository = intoGroupDetailRepository; + _doctorDictionaryRepository = doctorDictionaryRepository; + _userRepository = userRepository; + _attachmentRepository = attachmentRepository; + _userDoctorRepository = userDoctorRepository; + _trialRepository = trialRepository; + _mapper = mapper; + } + + /// + /// Reviewer列表分页查询 + /// + public PageOutput GetReviewerList(DoctorSearchDTO param, Guid reviewerId) + { + // 医生Lambda表达式树 条件拼接 + Expression> doctorLambda = default; + + //医生信息 + 医院信息 + 三个统计信息 + 医生表搜索条件过滤 + 中间表条件过滤 + IQueryable doctorQueryable = default; + + //多选记录条数-- 用于having过滤 + var realCount = param.ReadingTypeIdList.Count + param.TitleIdList.Count + + param.SubspecialityIdList.Count; + + var user = _userRepository.GetAll().First(t => t.Id == reviewerId); + + if (user.SuperAdmin || user.UserType.Contains(StaticData.DataAdmin) || user.UserType.Contains(StaticData.CROCoordinator)) + { + if (user.UserType.Contains(StaticData.CROCoordinator))//CRO协调者 + { + if (user.OrganizationName== "Parexel") + { + param.Nation = 0;//中国医生 + } + //else if()太美只能查看国外医生 + param.ContractorStatus = (int)ContractorStatus.Cooperation; + param.InformationConfirmed = (int)ReviewerInformationConfirmStatus.ConfirmPass; + } + doctorLambda = GetDoctorSearchLambda(param); + } + else + { + doctorLambda = GetDoctorSearchLambda(param); + + IQueryable userFilter = _userDoctorRepository.GetAll() + .Where(f => f.UserId == reviewerId).Select(k => k.DoctorId); + + doctorLambda = doctorLambda.And(t => + userFilter.Contains(t.Id)); + } + + //有多选信息过滤 + if (realCount > 0) + { + var doctorDictionaryFilterQueryable = GetDoctorOneToManyDictionaryFilterQueryable(param); + + doctorLambda = doctorLambda.And(t => doctorDictionaryFilterQueryable.Contains(t.Id)); + } + doctorQueryable = GetDoctorQueryable(doctorLambda); + + ////是否入组 过滤(统计字段) + if (param.EnrollStatus != null) + { + if (param.EnrollStatus == (int)ReviewerEnrollStatus.Yes) + { + doctorQueryable = doctorQueryable.Where(o => o.Reading == 0); + } + else + { + doctorQueryable = doctorQueryable.Where(o => o.Reading > 0); + } + } + + var propName = param.SortField == string.Empty ? "CreateTime" : param.SortField; + + doctorQueryable = param.Asc + ? doctorQueryable.OrderBy(propName).ThenBy(t=>t.Code) + : doctorQueryable.OrderByDescending(propName).ThenBy(t => t.Code); + + if (propName == "FirstName" || propName == "LastName") + { + doctorQueryable = param.Asc + ? doctorQueryable.OrderBy(t => t.LastName).ThenBy(t => t.FirstName) + : doctorQueryable.OrderByDescending(t => t.LastName).ThenBy(t => t.FirstName); + } + var count = doctorQueryable.Count(); + doctorQueryable = doctorQueryable + .Skip((param.PageIndex - 1) * param.PageSize) + .Take(param.PageSize); + var doctorList = doctorQueryable.ToList(); + + var doctorResumeIdList = _attachmentRepository.Find(u => u.Type == "Resume" && u.IsOfficial).Select(u => u.DoctorId).ToList(); + foreach (var item in doctorList) + { + if (doctorResumeIdList.Contains(item.Id)) + { + item.HasResume = true; + } + } + + DealDoctorDictionaryInfo(doctorList); + + return new PageOutput(param.PageIndex, + param.PageSize, count, doctorList); + } + + + + + + public PageOutput GetTrialDoctorList(EnrollGetQuery challengeQuery) + { + var costStatisticsQueryable = from enroll in _enrollRepository.GetAll().Where(t => t.TrialId == challengeQuery.TrialId) + join dociorc in _doctorRepository.GetAll() on enroll.DoctorId equals dociorc.Id + join price in _TrialPaymentPrice.GetAll() on enroll.TrialId equals price.TrialId + select new EnrollViewModel() + { + ChineseName = dociorc.ChineseName, + AdjustmentMultiple = enroll.AdjustmentMultiple, + FirstName = dociorc.FirstName, + LastName = dociorc.LastName, + DoctorId = dociorc.Id, + TrialId = challengeQuery.TrialId, + Id = enroll.Id, + Training = enroll.Training, + RefresherTraining = enroll.RefresherTraining, + Timepoint = enroll.Timepoint, + Timepoint48H = enroll.Timepoint48H, + Timepoint24H = enroll.Timepoint24H, + Adjudication = enroll.Adjudication, + Adjudication48H = enroll.Adjudication48H, + Adjudication24H = enroll.Adjudication24H, + Global = enroll.Global, + Code = dociorc.Code, + ReviewerCode = dociorc.ReviewerCode, + Downtime = enroll.Downtime, + }; + + + return new PageOutput(challengeQuery.PageIndex, + challengeQuery.PageSize, costStatisticsQueryable.Count(), + costStatisticsQueryable.Skip((challengeQuery.PageIndex - 1) * challengeQuery.PageSize).Take(challengeQuery.PageSize).ToList() + ); + + + + + + } + + + + public bool AddOrUpdateEnroll(EnrollCommand addOrUpdateModel) + { + + var trialDoctoritem = _enrollRepository.GetAll().FirstOrDefault(u => u.Id == addOrUpdateModel.Id); + if (trialDoctoritem == null)//insert + { + var trialExt = _mapper.Map(addOrUpdateModel); + _enrollRepository.Add(trialExt); + } + else//update + { + _enrollRepository.Update(_mapper.Map(addOrUpdateModel, trialDoctoritem)); + } + return _enrollRepository.SaveChanges(); + } + + + #region 入组查询相关 + /// + /// 获取可筛选筛选及已经筛选的医生列表 + /// + public PageOutput GetSelectionReviewerList( + ReviewerSelectionQueryDTO selectionQueryParam) + { + var trial = _trialRepository.FindSingleOrDefault(s=>s.Id== selectionQueryParam.TrialId); + selectionQueryParam.Nation = trial.AttendedReviewerType; + var dic = GetDictionary(); + //医生条件搜索Lambda拼接 + Expression> doctorLambda = GetDoctorSearchLambda(selectionQueryParam); ; + + //记录条数--having过滤 + var realCount = selectionQueryParam.ReadingTypeIdList.Count + selectionQueryParam.TitleIdList.Count + + selectionQueryParam.SubspecialityIdList.Count; + + IQueryable doctorQueryable = default; + + if (realCount != 0)//多选查询的 + { + var doctorDictionaryFilterQueryable = GetDoctorOneToManyDictionaryFilterQueryable(selectionQueryParam); + + doctorLambda = doctorLambda.And(t => doctorDictionaryFilterQueryable.Contains(t.Id)); + doctorQueryable = GetDoctorQueryable(doctorLambda); + } + else + { + doctorQueryable = GetDoctorQueryable(doctorLambda); + } + var propName = selectionQueryParam.SortField == "" ? "Code" : selectionQueryParam.SortField; + doctorQueryable = selectionQueryParam.Asc + ? DynamicQueryableExtensions.OrderBy(doctorQueryable, propName) + : DynamicQueryableExtensions.OrderBy(doctorQueryable, propName + " desc"); + if (propName == "FirstName" || propName == "LastName") + { + doctorQueryable = selectionQueryParam.Asc + ? doctorQueryable.OrderBy(t => t.LastName).ThenBy(t => t.FirstName) + : doctorQueryable.OrderByDescending(t => t.LastName).ThenBy(t => t.FirstName); + } + + if (selectionQueryParam.EnrollStatus != null) + { + if (selectionQueryParam.EnrollStatus == (int)ReviewerEnrollStatus.Yes) + { + doctorQueryable = doctorQueryable.Where(o => o.Reading == 0); + } + else + { + doctorQueryable = doctorQueryable.Where(o => o.Reading > 0); + } + } + var count = doctorQueryable.Count(); + doctorQueryable = doctorQueryable + .Skip((selectionQueryParam.PageIndex - 1) * selectionQueryParam.PageSize) + .Take(selectionQueryParam.PageSize); + var doctorViewList = doctorQueryable.ToList(); + + DealDoctorDictionaryInfo(doctorViewList); + var doctorList = _mapper.Map>(doctorViewList); + + //处理字典表信息连接、判断是否已申请时间 申请人 + doctorList = DealScreeningDoctorsConnectInfo(doctorList, dic, selectionQueryParam); + + return new PageOutput(selectionQueryParam.PageIndex, + selectionQueryParam.PageSize, count, doctorList); + + } + + /// + /// 获取提交CRO或者CRO审核的Reviewer列表 + /// + public PageOutput GetSubmissionOrApprovalReviewerList( + ReviewerSubmissionQueryDTO param) + { + //入组状态筛选条件 + var intoGroupSearchState = param.IntoGroupSearchState; + var trailId = param.TrialId; + + Expression> intoGroupDetailLambda = x => x.TrialId == trailId; + + Expression> intoGroupLambda = x => x.TrialId == trailId; + //提交CRO 以及下载简历列表 + if (intoGroupSearchState == 1) + { + + intoGroupLambda = intoGroupLambda.And(t => t.EnrollStatus >= + (int)EnrollStatus.HasApplyDownloadResume); + + intoGroupDetailLambda = intoGroupDetailLambda.And(t => t.EnrollStatus == + (int)EnrollStatus.HasCommittedToCRO); + } + + //CRO确认列表 状态为 已提交CRO + else if (intoGroupSearchState == 4) + { + intoGroupLambda = intoGroupLambda.And(t => t.EnrollStatus >= + (int)EnrollStatus.HasCommittedToCRO); + intoGroupDetailLambda = intoGroupDetailLambda.And(t => t.EnrollStatus == + (int)EnrollStatus.InviteIntoGroup); + } + + //医生表 表达式树条件 过滤 + var doctorQueryable = from doctorItem in _doctorRepository.Find() + //连接医院信息 左连接 + join hospitalItem in _hospitalRepository.GetAll() on doctorItem.HospitalId + equals hospitalItem.Id + into gt + from hospital in gt.DefaultIfEmpty() + join intoGroup in _enrollRepository.GetAll().Where(intoGroupLambda) + on doctorItem.Id equals intoGroup.DoctorId + select new ConfirmationReviewerDTO() + { + //医院信息 + City = hospital.City , + HospitalName = hospital.HospitalName , + Country = hospital.Country , + + //医生各种基本信息+单选外键 + Id = doctorItem.Id, + FirstName = doctorItem.FirstName, + LastName = doctorItem.LastName, + ChineseName = doctorItem.ChineseName, + Code = doctorItem.Code + }; + + var propName = param.SortField == "" ? "Code" : param.SortField; + doctorQueryable = param.Asc + ? DynamicQueryableExtensions.OrderBy(doctorQueryable, propName) + : DynamicQueryableExtensions.OrderBy(doctorQueryable, propName + " desc"); + if (propName == "FirstName" || propName == "LastName") + { + doctorQueryable = param.Asc + ? doctorQueryable.OrderBy(t => t.LastName).ThenBy(t => t.FirstName) + : doctorQueryable.OrderByDescending(t => t.LastName).ThenBy(t => t.FirstName); + } + + var count = doctorQueryable.Count(); + + doctorQueryable = doctorQueryable + .Skip((param.PageIndex - 1) * param.PageSize) + .Take(param.PageSize); + + var doctorViewList = doctorQueryable.ToList(); + + var doctorStateList = (from intoGroupDetail in _enrollDetailRepository.GetAll().Where(intoGroupDetailLambda) + join userItem in _userRepository.GetAll() on intoGroupDetail.CreateUserId equals userItem.Id into tt + from user in tt.DefaultIfEmpty() + select new DoctorStateModelDTO() + { + DoctorId = intoGroupDetail.DoctorId, + IntoGroupState = intoGroupDetail.EnrollStatus, + OptTime = intoGroupDetail.CreateTime, + OptUserName = user == null ? "" : user.UserName + }).ToList(); + + if (intoGroupSearchState == 1) + { + + foreach (var doctorIntoGroupOptViewModel in doctorViewList) + { + var opt = doctorStateList.FirstOrDefault(t => t.DoctorId == doctorIntoGroupOptViewModel.Id); + if (opt != null) + { + doctorIntoGroupOptViewModel.DoctorTrialState = (int)EnrollStatus.HasCommittedToCRO; + doctorIntoGroupOptViewModel.OptTime = opt.OptTime; + doctorIntoGroupOptViewModel.OptUserName = opt.OptUserName; + } + } + } + + //CRO确认列表 状态为 已提交CRO + else if (intoGroupSearchState == 4) + { + foreach (var doctorIntoGroupOptViewModel in doctorViewList) + { + var opt = doctorStateList.FirstOrDefault(t => t.DoctorId == doctorIntoGroupOptViewModel.Id); + if (opt != null) + { + doctorIntoGroupOptViewModel.DoctorTrialState = (int)EnrollStatus.InviteIntoGroup; + doctorIntoGroupOptViewModel.OptTime = opt.OptTime; + doctorIntoGroupOptViewModel.OptUserName = opt.OptUserName; + } + + } + } + + return new PageOutput(param.PageIndex, + param.PageSize, count, doctorViewList); + } + + /// + /// 获取项目入组待确认及已经确认或拒绝的Reviewer 列表 + /// + public PageOutput GetConfirmationReviewerList( + ReviewerConfirmationQueryDTO trialIdPageModel) + { + + Expression> intoGroupLambda = x => x.TrialId == trialIdPageModel.TrialId && x.EnrollStatus >= (int)EnrollStatus.InviteIntoGroup; + + var doctorQueryable = from doctor in _doctorRepository.Find() + //连接医院信息 左连接 + join hospitalItem in _hospitalRepository.GetAll() on doctor.HospitalId + equals hospitalItem.Id + into gt + from hospital in gt.DefaultIfEmpty() + join stateItem in _enrollRepository.Find(intoGroupLambda) on + doctor.Id equals stateItem.DoctorId + select new ConfirmationReviewerDTO() + { + //医院信息 + City = hospital.City, + HospitalName = hospital.HospitalName, + Country = hospital.Country, + + //医生各种基本信息+单选外键 + Id = doctor.Id, + FirstName = doctor.FirstName, + LastName = doctor.LastName, + ChineseName = doctor.ChineseName, + Code = doctor.Code, + + DoctorTrialState = (int)EnrollStatus.InviteIntoGroup + }; + var propName = trialIdPageModel.SortField == "" ? "Code" : trialIdPageModel.SortField; + doctorQueryable = trialIdPageModel.Asc + ? DynamicQueryableExtensions.OrderBy(doctorQueryable, propName) + : DynamicQueryableExtensions.OrderBy(doctorQueryable, propName + " desc"); + if (propName == "FirstName" || propName == "LastName") + { + doctorQueryable = trialIdPageModel.Asc + ? doctorQueryable.OrderBy(t => t.LastName).ThenBy(t => t.FirstName) + : doctorQueryable.OrderByDescending(t => t.LastName).ThenBy(t => t.FirstName); + } + var count = doctorQueryable.Count(); + doctorQueryable = doctorQueryable + .Skip((int)((trialIdPageModel.PageIndex - 1) * trialIdPageModel.PageSize)) + .Take((int)trialIdPageModel.PageSize); + var doctorList = doctorQueryable.ToList(); + + Expression> intoGroupDetailLambda = x => x.TrialId == trialIdPageModel.TrialId && x.EnrollStatus > (int)EnrollStatus.InviteIntoGroup; + + var doctorStateList = (from intoGroupDetail in _enrollDetailRepository.GetAll().Where(intoGroupDetailLambda) + join userItem in _userRepository.GetAll() on intoGroupDetail.CreateUserId equals userItem.Id into tt + from user in tt.DefaultIfEmpty() + select new DoctorStateModelDTO() + { + DoctorId = intoGroupDetail.DoctorId, + IntoGroupState = intoGroupDetail.EnrollStatus, + OptTime = intoGroupDetail.CreateTime, + OptUserName = user == null ? "" : user.UserName + }).ToList(); + + doctorList.ForEach(doctor => + { + var doctorState2 = doctorStateList.FirstOrDefault(t => t.DoctorId == doctor.Id && + t.IntoGroupState == + (int)EnrollStatus + .RefuseIntoGroup); + if (doctorState2 != null) + { + doctor.DoctorTrialState = (int)EnrollStatus.RefuseIntoGroup; + doctor.OptTime = doctorState2.OptTime; + doctor.OptUserName = doctorState2.OptUserName; + } + + var doctorState3 = doctorStateList.FirstOrDefault(t => t.DoctorId == doctor.Id && + t.IntoGroupState == + (int)EnrollStatus + .ConfirmIntoGroup); + if (doctorState3 != null) + { + doctor.DoctorTrialState = (int)EnrollStatus.ConfirmIntoGroup; + doctor.OptTime = doctorState3.OptTime; + doctor.OptUserName = doctorState3.OptUserName; + } + + }); + + return new PageOutput(trialIdPageModel.PageIndex, trialIdPageModel.PageSize, count, doctorList); + } + + /// + /// 处理是否已经筛选过 以及筛选时间 筛选人 + /// + private List DealScreeningDoctorsConnectInfo(List doctorList, List dic, ReviewerSelectionQueryDTO searchModel) + { + Expression> intoGroupDetailLambda = x => x.TrialId == searchModel.TrialId && x.EnrollStatus == + (int)EnrollStatus.HasApplyDownloadResume; + var doctorStateList = (from intoGroupDetail in _enrollDetailRepository.GetAll().Where(intoGroupDetailLambda) + join userItem in _userRepository.GetAll() on intoGroupDetail.CreateUserId equals userItem.Id into tt + from user in tt.DefaultIfEmpty() + select new DoctorStateModelDTO() + { + DoctorId = intoGroupDetail.DoctorId, + IntoGroupState = intoGroupDetail.EnrollStatus, + OptTime = intoGroupDetail.CreateTime, + OptUserName = user.UserName + }).ToList(); + // 处理关联字典表的逻辑 + doctorList.ForEach( + doctor => + { + //简历申请列表 --处理已经申请的 + var doctorState = doctorStateList.FirstOrDefault(t => t.DoctorId == doctor.Id && + t.IntoGroupState == + (int)EnrollStatus.HasApplyDownloadResume); + if (doctorState != null) + { + doctor.DoctorTrialState = (int)EnrollStatus.HasApplyDownloadResume; + doctor.OptTime = doctorState.OptTime; + doctor.OptUserName = doctorState.OptUserName; + } + }); + return doctorList; + + } + + #endregion + + /// + /// 连接医生关联字典表信息 + /// + private void DealDoctorDictionaryInfo(List doctorList) + { + var doctorHasSearchedIdList = doctorList.Select(t => t.Id).ToList(); + + var query = from doctorId in doctorHasSearchedIdList + join doctorDic in _doctorDictionaryRepository.GetAll() on doctorId equals doctorDic.DoctorId + join dic in _dictionaryRepository.GetAll() on doctorDic.DictionaryId equals dic.Id + select new + { + DoctorId = doctorId, + Id = dic.Id, + keyName = dic.KeyName, + Value = dic.Value, + ShowOrder = dic.ShowOrder + }; + + //获取多选信息列表 + var doctorMultipleInfoList = query.ToList(); + //字典表 后面做缓存 + var dictionaryList = GetDictionary(); + + doctorList.ForEach(doctor => + { + doctor.SubspecialityIds = doctorMultipleInfoList.Where(t => t.keyName == StaticData.Subspeciality && t.DoctorId == doctor.Id) + .OrderBy(t => t.ShowOrder).Select(t => t.Id).ToList(); + doctor.SubspecialityList = doctorMultipleInfoList.Where(t => t.keyName == StaticData.Subspeciality && t.DoctorId == doctor.Id) + .OrderBy(t => t.ShowOrder).Select(t => t.Value).ToList(); + + doctor.TitleIdList = doctorMultipleInfoList.Where(t => t.keyName == StaticData.Title && t.DoctorId == doctor.Id) + .OrderBy(t => t.ShowOrder).Select(t => t.Id).ToList(); + doctor.TitleList = doctorMultipleInfoList.Where(t => t.keyName == StaticData.Title && t.DoctorId == doctor.Id) + .OrderBy(t => t.ShowOrder).Select(t => t.Value).ToList(); + + doctor.ReadingTypeIds = doctorMultipleInfoList.Where(t => t.keyName == StaticData.ReadingType && t.DoctorId == doctor.Id) + .OrderBy(t => t.ShowOrder).Select(t => t.Id).ToList(); + doctor.ReadingTypeList = doctorMultipleInfoList.Where(t => t.keyName == StaticData.ReadingType && t.DoctorId == doctor.Id) + .OrderBy(t => t.ShowOrder).Select(t => t.Value).ToList(); + doctor.Department = doctor.DepartmentId == Guid.Empty + ? doctor.DepartmentOther ?? string.Empty + : dictionaryList.FirstOrDefault(o => o.Id == doctor.DepartmentId)?.Value ?? string.Empty; + + doctor.Speciality = doctor.SpecialityId == Guid.Empty + ? doctor.SpecialityOther ?? string.Empty + : dictionaryList.FirstOrDefault(o => o.Id == doctor.SpecialityId)?.Value ?? string.Empty; + + doctor.Rank = doctor.RankId == Guid.Empty + ? doctor.RankOther ?? string.Empty + : dictionaryList.FirstOrDefault(o => o.Id == doctor.RankId)?.Value ?? string.Empty; + + doctor.Position = doctor.PositionId == Guid.Empty + ? doctor.PositionOther ?? string.Empty + : dictionaryList.FirstOrDefault(o => o.Id == doctor.PositionId)?.Value ?? string.Empty; + }); + } + #region 获取医生列表Linq 语句 + private IQueryable GetDoctorOneToManyDictionaryFilterQueryable(DoctorSearchDTO doctorSearchModel) + { + //多选项 多选 组合查询 中间表过滤 + Expression> doctorDictionaryLambda = x => true; + var dicGuidList = new List(); + dicGuidList.AddRange(doctorSearchModel.ReadingTypeIdList); + dicGuidList.AddRange(doctorSearchModel.SubspecialityIdList); + dicGuidList.AddRange(doctorSearchModel.TitleIdList); + + if (dicGuidList.Count > 0) + { + doctorDictionaryLambda = doctorDictionaryLambda.And(u => dicGuidList.Contains(u.DictionaryId)); + } + var realCount = doctorSearchModel.ReadingTypeIdList.Count + doctorSearchModel.TitleIdList.Count + + doctorSearchModel.SubspecialityIdList.Count; + + var doctorDictionaryQueryable = from doctorDicItem in _doctorDictionaryRepository.GetAll().Where(doctorDictionaryLambda) + group doctorDicItem by doctorDicItem.DoctorId + into g + select new + { + DoctorId = g.Key, + Count = g.Count() + } + into zz + where zz.Count == realCount + select zz.DoctorId; + + return doctorDictionaryQueryable; + } + + private IQueryable GetDoctorQueryable(Expression> doctorLambda) + { + //医生表 表达式树条件 过滤 + var doctorQueryable = from doctorItem in _doctorRepository.Find(doctorLambda) + //连接医院信息 左连接 + join hospitalItem in _hospitalRepository.GetAll() on doctorItem.HospitalId + equals hospitalItem.Id + into gt + from hospital in gt.DefaultIfEmpty() + //获取统计信息--分组聚合 + join statisticsItem in ( + from intoGroupItem in _enrollRepository.GetAll() + group intoGroupItem by intoGroupItem.DoctorId + into g + select new + { + DoctorId = g.Key, + Submitted = g.Sum(t => + t.EnrollStatus == (int)EnrollStatus.HasCommittedToCRO ? 1 : 0), + Approved = g.Sum(t => + t.EnrollStatus == (int)EnrollStatus.InviteIntoGroup ? 1 : 0), + Reading = g.Sum(t => + t.EnrollStatus == (int)EnrollStatus.DoctorReading ? 1 : 0) + }) on doctorItem.Id equals statisticsItem.DoctorId + into gj + from sub in gj.DefaultIfEmpty() + select new DoctorDTO() + { + //医院信息 + City = hospital.City, + HospitalName = hospital.HospitalName, + Country = hospital.Country, + //医生各种基本信息+单选外键 + Id = doctorItem.Id, + FirstName = doctorItem.FirstName, + LastName = doctorItem.LastName, + ChineseName = doctorItem.ChineseName, + Code = doctorItem.Code, + Phone = doctorItem.Phone, + Introduction = doctorItem.Introduction, + EMail = doctorItem.EMail, + WeChat = doctorItem.WeChat, + DepartmentId = doctorItem.DepartmentId, + DepartmentOther = doctorItem.DepartmentOther, + SpecialityId = doctorItem.SpecialityId, + SpecialityOther = doctorItem.SpecialityOther, + RankId = doctorItem.RankId, + RankOther = doctorItem.RankOther, + PositionId = doctorItem.PositionId, + PositionOther = doctorItem.PositionOther, + HospitalId = doctorItem.HospitalId, + HospitalOther = doctorItem.HospitalOther, + ReadingTypeOther = doctorItem.ReadingTypeOther, + SubspecialityOther = doctorItem.SubspecialityOther, + + GCP = doctorItem.GCP, + GCPId = doctorItem.GCPId, + ResumePath = doctorItem.ResumePath, + ResumeStatus = doctorItem.ResumeStatus, + CooperateStatus = doctorItem.CooperateStatus, + CreateTime = doctorItem.CreateTime, + Reconfirmed = doctorItem.ReviewStatus == 1, + //统计信息 + Approved = sub.Approved, + Reading = sub.Reading, + Submitted = sub.Submitted + }; + return doctorQueryable; + } + + + #endregion + + #region 获取字典表、连接字典表 、表达式条件拼接 + + //获取字典表 + private List GetDictionary() + { + return //字典表 后面做缓存 + _dictionaryRepository.GetAll().ProjectTo(_mapper.ConfigurationProvider).OrderBy(t => t.KeyName) + .ThenBy(t => t.ShowOrder).ToList(); + } + + //医生条件查询拼接 + private Expression> GetDoctorSearchLambda(DoctorSearchDTO doctorSearchModel) + { + Expression> doctorLambda = x => true; + if (doctorSearchModel.DepartmentId != Guid.Empty && doctorSearchModel.DepartmentId != null) + { + doctorLambda = doctorLambda.And(o => o.DepartmentId == doctorSearchModel.DepartmentId); + } + + if (doctorSearchModel.SpecialityId != Guid.Empty && doctorSearchModel.SpecialityId != null) + { + doctorLambda = doctorLambda.And(o => o.SpecialityId == doctorSearchModel.SpecialityId); + } + + if (doctorSearchModel.HospitalId != Guid.Empty && doctorSearchModel.HospitalId != null) + { + doctorLambda = doctorLambda.And(o => o.HospitalId == doctorSearchModel.HospitalId); + } + + if (doctorSearchModel.PositionId != Guid.Empty && doctorSearchModel.PositionId != null) + { + doctorLambda = doctorLambda.And(o => o.PositionId == doctorSearchModel.PositionId); + } + + if (doctorSearchModel.RankId != Guid.Empty && doctorSearchModel.RankId != null) + { + doctorLambda = doctorLambda.And(o => o.RankId == doctorSearchModel.RankId); + } + + if (doctorSearchModel.ContractorStatus != null) + { + doctorLambda = doctorLambda.And(o => o.CooperateStatus == doctorSearchModel.ContractorStatus); + } + + if (doctorSearchModel.InformationConfirmed != null) + { + doctorLambda = doctorLambda.And(o => o.ResumeStatus == doctorSearchModel.InformationConfirmed); + } + if (doctorSearchModel.AcceptingNewTrial != null) + { + doctorLambda = doctorLambda.And(o => o.AcceptingNewTrial == doctorSearchModel.AcceptingNewTrial); + } + if (doctorSearchModel.ActivelyReading != null) + { + doctorLambda = doctorLambda.And(o => o.ActivelyReading == doctorSearchModel.ActivelyReading); + } + + if (!string.IsNullOrWhiteSpace(doctorSearchModel.Name)) + { + var doctorName = doctorSearchModel.Name.Trim(); + doctorLambda = doctorLambda.And(o => o.LastName.Contains(doctorName) + || o.FirstName.Contains(doctorName) + || o.ChineseName.Contains(doctorName)); + } + if (doctorSearchModel.Nation != null) //2全部 + { + doctorLambda = doctorLambda.And(o => o.Nation == doctorSearchModel.Nation); + } + + return doctorLambda; + } + #endregion + } +} + diff --git a/IRaCIS.Core.Application/Doctor/DoctorService.cs b/IRaCIS.Core.Application/Doctor/DoctorService.cs new file mode 100644 index 0000000..5458757 --- /dev/null +++ b/IRaCIS.Core.Application/Doctor/DoctorService.cs @@ -0,0 +1,490 @@ +using AutoMapper; +using AutoMapper.QueryableExtensions; +using IRaCIS.Application.Interfaces; +using IRaCIS.Application.ViewModels; +using IRaCIS.Core.Application.Contracts.RequestAndResponse; +using IRaCIS.Core.Domain.Interfaces; +using IRaCIS.Core.Domain.Models; +using IRaCIS.Core.Domain.Share; +using IRaCIS.Core.Infrastructure; +using Microsoft.EntityFrameworkCore; +using System; +using System.Collections.Generic; +using System.Linq; + + +namespace IRaCIS.Application.Services +{ + public class DoctorService : IDoctorService + { + private readonly IDoctorRepository _doctorRepository; + private readonly IDictionaryRepository _dictionaryRepository; + private readonly IHospitalRepository _hospitalRepository; + private readonly IMessageRepository _messageRepository; + private readonly IEnrollRepository _enrollRepository; + + private readonly IDoctorDictionaryRepository _doctorDictionaryRepository; + + private readonly IAttachmentRepository _attachmentRepository; + private readonly IUserDoctorRepository _userDoctorRepository; + private readonly ITrialRepository _trialRepository; + private readonly ITrialPaymentPriceRepository _trialExtRepository; + private readonly IMapper _mapper; + + public DoctorService(IDoctorRepository doctorInfoRepository, + IDictionaryRepository dictionaryRepository, IHospitalRepository hospitalRepository, + IMessageRepository sysMessageRepository, IEnrollRepository intoGroupRepository, + IDoctorDictionaryRepository doctorDictionaryRepository, + IAttachmentRepository attachmentRepository, + IUserDoctorRepository userDoctorRepository, + ITrialRepository trialRepository, + ITrialPaymentPriceRepository trialExtRepository,IMapper mapper) + { + _doctorRepository = doctorInfoRepository; + _dictionaryRepository = dictionaryRepository; + _hospitalRepository = hospitalRepository; + _messageRepository = sysMessageRepository; + _enrollRepository = intoGroupRepository; + + _doctorDictionaryRepository = doctorDictionaryRepository; + + _attachmentRepository = attachmentRepository; + _userDoctorRepository = userDoctorRepository; + _trialRepository = trialRepository; + _trialExtRepository = trialExtRepository; + _mapper = mapper; + } + + #region 医生基本信息--查询、新增、更新 + public IResponseOutput AddOrUpdateDoctorBasicInfo( + DoctorBasicInfoCommand basicInfoModel, Guid userId) + { + + if (basicInfoModel.Id == Guid.Empty|| basicInfoModel.Id==null) + { + var doctor = _mapper.Map(basicInfoModel); + var phone = doctor.Phone.Trim(); + //验证用户手机号 + if (_doctorRepository.GetAll().FirstOrDefault(t => t.Phone == phone) != null) + { + return ResponseOutput.NotOk("Current phone number is existed!", new DoctorBasicInfoCommand()); + } + + var email = doctor.EMail.Trim(); + if (_doctorRepository.GetAll().Any(t => t.EMail == email)) + { + return ResponseOutput.NotOk("Current email is existed!", new DoctorBasicInfoCommand()); + } + + var last = _doctorRepository.GetAll().OrderByDescending(c => c.Code).FirstOrDefault(); + if (last != null) + { + var num = 0; + if (int.TryParse(last.Code.Substring(2, 4), out num)) + { + doctor.Code = SystemConfig.CodePrefix + (++num).ToString().PadLeft(4, '0'); + } + else + { + return ResponseOutput.NotOk("Generated Code failed.", new DoctorBasicInfoCommand()); + } + } + else + { + doctor.Code = SystemConfig.CodePrefix + 1.ToString().PadLeft(4, '0'); + } + + doctor.Password = MD5Helper.Md5(doctor.Phone); + doctor.ResumeStatus = (int)ResumeStatus.Failed; + doctor.CooperateStatus = (int)ContractorStatus.Noncooperation; + doctor.ReviewStatus = 2; + + //插入中间表 + basicInfoModel.TitleIds.ForEach(titleId => doctor.DoctorDicList.Add(new DoctorDictionary() + { + DoctorId = doctor.Id, + KeyName = StaticData.Title, + DictionaryId = titleId + })); + + _doctorRepository.Add(doctor); + + _userDoctorRepository.Add(new UserDoctor() + { + DoctorId = doctor.Id, + UserId = userId + }); + var success = _doctorRepository.SaveChanges(); + return ResponseOutput.Result(success, _mapper.Map(doctor)); + + } + else + { + var updateModel = basicInfoModel; + + var phone = updateModel.Phone.Trim(); + if (_doctorRepository.FindSingleOrDefault(t => t.Phone == phone && t.Id != updateModel.Id) != null) + { + return ResponseOutput.NotOk("Current phone number is existed!", new DoctorBasicInfoCommand()); + } + var email = updateModel.EMail.Trim(); + if (_doctorRepository.GetAll().Any(t => t.EMail == email && t.Id != updateModel.Id)) + { + return ResponseOutput.NotOk("Current email is existed!", new DoctorBasicInfoCommand()); + } + + var doctor = _doctorRepository.FindSingleOrDefault(t => t.Id == updateModel.Id); + + if (doctor != null) + { + //删除中间表 Title对应的记录 + _doctorDictionaryRepository.Delete(t => t.DoctorId == updateModel.Id && t.KeyName == StaticData.Title); + + //重新插入新的 Title记录 + updateModel.TitleIds.ForEach(titleId => _doctorDictionaryRepository.Add(new DoctorDictionary() + { + DoctorId = updateModel.Id.Value, + KeyName = StaticData.Title, + DictionaryId = titleId + })); + + doctor.FirstName = updateModel.FirstName; + doctor.LastName = updateModel.LastName; + doctor.ChineseName = updateModel.ChineseName; + doctor.Sex = updateModel.Sex; + doctor.Phone = updateModel.Phone; + doctor.EMail = updateModel.EMail; + doctor.WeChat = updateModel.WeChat; + doctor.Introduction = updateModel.Introduction; + doctor.Nation = updateModel.Nation; + _doctorRepository.Update(doctor); + } + + var success = _doctorRepository.SaveChanges(); + + return ResponseOutput.Result(success, basicInfoModel); + + } + + } + + + + public DoctorBasicInfoDTO GetDoctorBasicInfo(Guid doctorId) + { + var dic = GetDictionary(); + + var doctorQueryable = _doctorRepository + .Find(t => t.Id == doctorId) + .Include(t => t.DoctorDicList) + .Select(doctor => new DoctorBasicInfoDTO() + { + Id = doctor.Id, + Code = doctor.Code, + ChineseName = doctor.ChineseName, + EMail = doctor.EMail, + FirstName = doctor.FirstName, + Introduction = doctor.Introduction, + LastName = doctor.LastName, + Phone = doctor.Phone, + Sex = doctor.Sex, + WeChat = doctor.WeChat, + Nation = doctor.Nation, + TitleIds = doctor.DoctorDicList + .Where(t => t.KeyName == StaticData.Title).Select(t => t.DictionaryId).ToList() + }); + + var doctorBasicInfo = doctorQueryable.FirstOrDefault(); + + if (doctorBasicInfo != null) + { + //连接具体名称 Title --MD Phd + + foreach (var dictionaryItem in dic) + { + if (doctorBasicInfo.TitleIds.Contains(dictionaryItem.Id)) + { + doctorBasicInfo.TitleList.AddRange(dic.Where(u => u.Id == dictionaryItem.Id) + .Select(h => h.Value)); + } + } + } + return doctorBasicInfo; + } + + #endregion + + #region Employment信息--查询和更新 + public EmploymentDTO GetEmploymentInfo(Guid doctorId) + { + var dic = GetDictionary(); + + var employmentQueryable = from doctorItem in _doctorRepository + .Find(t => t.Id == doctorId) + join hospitalItem in _hospitalRepository.GetAll() on doctorItem.HospitalId equals hospitalItem.Id into g + from hospital in g.DefaultIfEmpty() + select new EmploymentDTO() + { + //部门 + DepartmentId = doctorItem.DepartmentId, + DepartmentOther = doctorItem.DepartmentOther, + //医院 + HospitalId = doctorItem.HospitalId, + + PositionId = doctorItem.PositionId, + PositionOther = doctorItem.PositionOther, + RankId = doctorItem.RankId, + RankOther = doctorItem.RankOther, + + City = hospital.City, + Country = hospital.Country, + UniversityAffiliated = hospital.UniversityAffiliated, + HospitalName = hospital.HospitalName, + Province = hospital.Province + }; + + var employmentInfo = employmentQueryable.FirstOrDefault(); + + if (employmentInfo != null) + { + //医院信息设置 + if (employmentInfo.HospitalId == Guid.Empty) + { + employmentInfo.City = string.Empty; + employmentInfo.Country = string.Empty; + employmentInfo.UniversityAffiliated = string.Empty; + employmentInfo.HospitalName = string.Empty; + employmentInfo.Province = string.Empty; + } + employmentInfo.Department = employmentInfo.DepartmentId == Guid.Empty ? employmentInfo.DepartmentOther : dic.FirstOrDefault(o => o.Id == employmentInfo.DepartmentId)?.Value ?? ""; + + employmentInfo.Rank = employmentInfo.RankId == Guid.Empty ? employmentInfo.RankOther : dic.FirstOrDefault(o => o.Id == employmentInfo.RankId)?.Value ?? ""; + + employmentInfo.Position = employmentInfo.PositionId == Guid.Empty ? employmentInfo.PositionOther : dic.FirstOrDefault(o => o.Id == employmentInfo.PositionId)?.Value ?? ""; + } + return employmentInfo; + } + + public IResponseOutput UpdateDoctorEmploymentInfo(EmploymentCommand doctorWorkInfoModel) + { + var success = _doctorRepository.Update(d => d.Id == doctorWorkInfoModel.Id, u => new Doctor() + { + DepartmentId = doctorWorkInfoModel.DepartmentId, + DepartmentOther = doctorWorkInfoModel.DepartmentOther, + SpecialityId = doctorWorkInfoModel.DepartmentId, + SpecialityOther = doctorWorkInfoModel.DepartmentOther, + RankId = doctorWorkInfoModel.RankId, + RankOther = doctorWorkInfoModel.RankOther, + PositionId = doctorWorkInfoModel.PositionId, + PositionOther = doctorWorkInfoModel.PositionOther, + HospitalId = doctorWorkInfoModel.HospitalId, + UpdateTime = DateTime.Now + }); + return ResponseOutput.Result(success); + } + + #endregion + + #region 医生技能信息 查询和 更新 + public SpecialtyDTO GetDoctorSpecialty(Guid doctorId) + { + var dic = GetDictionary(); + var specialtyQueryable = _doctorRepository + .Find(t => t.Id == doctorId).Include(u => u.DoctorDicList) + .Select(specialty => new SpecialtyDTO() + { + Id = specialty.Id, + ReadingTypeOther = specialty.ReadingTypeOther, + SubspecialityOther = specialty.SubspecialityOther, + ReadingTypeIds = specialty.DoctorDicList.Where(t => t.KeyName == StaticData.ReadingType).Select(t => t.DictionaryId).ToList(), + SubspecialityIds = specialty.DoctorDicList.Where(t => t.KeyName == StaticData.Subspeciality).Select(t => t.DictionaryId).ToList(), + SpecialityId = specialty.SpecialityId, + SpecialityOther = specialty.SpecialityOther + }); + + var specialtyInfo = specialtyQueryable.FirstOrDefault(); + + if (specialtyInfo != null) + { + foreach (var dictionaryItem in dic) + { + if (specialtyInfo.ReadingTypeIds.Contains(dictionaryItem.Id)) + { + specialtyInfo.ReadingTypeList.AddRange(dic.Where(u => u.Id == dictionaryItem.Id) + .Select(h => h.Value)); + } + + if (specialtyInfo.SubspecialityIds.Contains(dictionaryItem.Id)) + { + specialtyInfo.SubspecialityList.AddRange(dic.Where(u => u.Id == dictionaryItem.Id) + .Select(h => h.Value)); + } + + } + + specialtyInfo.Speciality = dic.Where(u => u.Id == specialtyInfo.SpecialityId).Select(h => h.Value).FirstOrDefault(); + return specialtyInfo; + } + + return null; + } + + public IResponseOutput UpdateDoctorSpecialty(SpecialtyCommand specialtyUpdateModel) + { + var doctor = _doctorRepository.Find(t => t.Id == specialtyUpdateModel.Id).FirstOrDefault(); + + if (doctor != null) + { + //删除中间表 + _doctorDictionaryRepository.Delete(t => + t.DoctorId == specialtyUpdateModel.Id && t.KeyName == StaticData.Subspeciality); + _doctorDictionaryRepository.Delete(t => + t.DoctorId == specialtyUpdateModel.Id && t.KeyName == StaticData.ReadingType); + + //重新插入新的 + specialtyUpdateModel.ReadingTypeIds.ForEach(readingTypeId => _doctorDictionaryRepository.Add( + new DoctorDictionary() + { + DoctorId = specialtyUpdateModel.Id, + KeyName = StaticData.ReadingType, + DictionaryId = readingTypeId + })); + specialtyUpdateModel.SubspecialityIds.ForEach(subspecialityId => _doctorDictionaryRepository.Add( + new DoctorDictionary() + { + DoctorId = specialtyUpdateModel.Id, + KeyName = StaticData.Subspeciality, + DictionaryId = subspecialityId + })); + + + //更新字段 + //doctor.OtherSkills = specialtyUpdateModel.OtherSkills; + doctor.ReadingTypeOther = specialtyUpdateModel.ReadingTypeOther; + doctor.SubspecialityOther = specialtyUpdateModel.SubspecialityOther; + + doctor.SpecialityId = specialtyUpdateModel.SpecialityId; + doctor.SpecialityOther = specialtyUpdateModel.SpecialityOther; + + _doctorRepository.Update(doctor); + + var success= _doctorRepository.SaveChanges(); + return ResponseOutput.Result(success); + } + + return ResponseOutput.NotOk(); + } + #endregion + + #region 简历审核 + public IResponseOutput AuditResume(ResumeConfirmCommand auditResumeParam,Guid userId) + { + //判断 合作协议、正式简历 是否有。如果没有,显示提示信息,并且不能保存 + var attachmentList = _attachmentRepository.Find(u => u.DoctorId == auditResumeParam.Id) + .Select(u=>u.Type).ToList(); + if (auditResumeParam.ResumeStatus==1&&((!attachmentList.Contains("Resume")) || (!attachmentList.Contains("Consultant Agreement")))) + { + return ResponseOutput.NotOk("Must Upload Resume & Consultant Agreement"); + } + var success = _doctorRepository.Update(o => o.Id == auditResumeParam.Id, u => new Doctor() + { + CooperateStatus = auditResumeParam.CooperateStatus, + ResumeStatus = auditResumeParam.ResumeStatus, + AdminComment = auditResumeParam.AdminComment, + ReviewStatus = auditResumeParam.ReviewStatus, + AcceptingNewTrial = auditResumeParam.AcceptingNewTrial, + ActivelyReading = auditResumeParam.ActivelyReading, + AuditTime = DateTime.Now, + AuditUserId = userId + }); + + if (success) + { + if (!string.IsNullOrWhiteSpace(auditResumeParam.MessageContent)) + { + var message = new Message + { + FromUserId = userId, + ToDoctorId = auditResumeParam.Id, + Title = "简历审核反馈", + Content = auditResumeParam.MessageContent, + HasRead = false, + MessageTime = DateTime.Now + }; + _messageRepository.Add(message); + success = _messageRepository.SaveChanges(); + } + } + + return ResponseOutput.Result(success); + } + + public ResumeConfirmDTO GetDoctorAuditStatus(Guid doctorId) + { + var doctor = _doctorRepository.GetAll().ProjectTo(_mapper.ConfigurationProvider).FirstOrDefault(t => t.Id == doctorId); + return doctor; + } + + public DoctorEnrollInfoDTO GetDoctorEnrollInfo(Guid doctorId) + { + var doctorQueryable = + from doctor in _doctorRepository.Find(t => t.Id == doctorId) + join intoGroupItem in _enrollRepository.GetAll() on doctor.Id equals intoGroupItem.DoctorId into t + from intoGroupItem in t.DefaultIfEmpty() + group intoGroupItem by intoGroupItem.DoctorId + into g + select new DoctorEnrollInfoDTO + { + DoctorId = g.Key, + + Submitted = g.Sum(t => + t.EnrollStatus == (int)EnrollStatus.HasCommittedToCRO?1:0), + Approved = g.Sum(t => + t.EnrollStatus == (int)EnrollStatus.InviteIntoGroup?1:0), + Reading = g.Sum(t => + t.EnrollStatus == (int)EnrollStatus.DoctorReading?1:0) + }; + + return doctorQueryable.FirstOrDefault(); + } + public List GetDoctorSow(Guid doctorId) + { + var query = from enroll in _enrollRepository.Find(u => u.DoctorId == doctorId && u.EnrollStatus >= 10) + join trialExt in _trialExtRepository.GetAll() on enroll.TrialId equals trialExt.TrialId + join trial in _trialRepository.GetAll() on enroll.TrialId equals trial.Id + select new SowDTO + { + FileName = trialExt.SowName, + FilePath = trialExt.SowPath, + TrialCode = trial.Code, + CreateTime = trialExt.CreateTime + }; + return query.ToList().Where(u => !string.IsNullOrWhiteSpace(u.FileName)).ToList(); + } + public List GetDoctorAckSow(Guid doctorId) + { + var query = from enroll in _enrollRepository.Find(u => u.DoctorId == doctorId) + join attachment in _attachmentRepository.Find(u => u.DoctorId == doctorId) + on enroll.AttachmentId equals attachment.Id + join trial in _trialRepository.GetAll() on enroll.TrialId equals trial.Id + select new SowDTO + { + FileName = attachment.FileName, + FilePath = attachment.Path, + TrialCode = trial.Code, + CreateTime = attachment.CreateTime + }; + return query.ToList(); + } + + #endregion + + + private List GetDictionary() + { + return //字典表 后面做缓存 + _dictionaryRepository.GetAll().ProjectTo(_mapper.ConfigurationProvider).OrderBy(t => t.KeyName) + .ThenBy(t => t.ShowOrder).ToList(); + } + } +} diff --git a/IRaCIS.Core.Application/Doctor/EducationService.cs b/IRaCIS.Core.Application/Doctor/EducationService.cs new file mode 100644 index 0000000..e9c0a9b --- /dev/null +++ b/IRaCIS.Core.Application/Doctor/EducationService.cs @@ -0,0 +1,111 @@ +using AutoMapper; +using AutoMapper.QueryableExtensions; +using IRaCIS.Application.Interfaces; +using IRaCIS.Application.ViewModels; +using IRaCIS.Core.Application.Contracts.RequestAndResponse; +using IRaCIS.Core.Domain.Interfaces; +using IRaCIS.Core.Domain.Models; +using IRaCIS.Core.Domain.Share; +using System; +using System.Linq; + +namespace IRaCIS.Application.Services +{ + public class EducationService : IEducationService + { + private readonly IPostgraduateRepository _postgraduateRepository; + private readonly IMapper _mapper; + private readonly IEducationRepository _educationRepository; + + public EducationService(IEducationRepository doctorNormalEducationRepository, + IPostgraduateRepository doctorContinueLearningRepository, IMapper mapper) + { + _educationRepository = doctorNormalEducationRepository; + _postgraduateRepository = doctorContinueLearningRepository; + _mapper = mapper; + } + + public DoctorEducationExperienceDTO GetEducation(Guid doctorId) + { + var educationQueryable = _educationRepository.Find(o => o.DoctorId == doctorId).OrderBy(t => t.CreateTime).ProjectTo(_mapper.ConfigurationProvider); + var educationList = educationQueryable.ToList(); + var postgraduateList = _postgraduateRepository.Find(o => o.DoctorId == doctorId).OrderBy(t => t.CreateTime).ProjectTo(_mapper.ConfigurationProvider).ToList(); + + + var returnResult = new DoctorEducationExperienceDTO() + { + EducationList = educationList, + PostgraduateList = postgraduateList + }; + + return returnResult; + } + + public IResponseOutput AddOrUpdateEducationInfo(EducationCommand educationInfoViewModel) + { + if (educationInfoViewModel.Id == Guid.Empty || educationInfoViewModel.Id == null) + { + var doctorEducationInfo = _mapper.Map(educationInfoViewModel); + switch (educationInfoViewModel.Degree) + { + case StaticData.Bachelor: + doctorEducationInfo.ShowOrder = 1; + break; + case StaticData.Master: + doctorEducationInfo.ShowOrder = 2; + break; + case StaticData.Doctorate: + doctorEducationInfo.ShowOrder = 3; + break; + } + _educationRepository.Add(doctorEducationInfo); + var success = _educationRepository.SaveChanges(); + + return ResponseOutput.Result(success, doctorEducationInfo.Id.ToString()); + } + + else + { + _educationRepository.Update(_mapper.Map(educationInfoViewModel)); + var success = _educationRepository.SaveChanges(); + + return ResponseOutput.Result(success); + + } + } + + public IResponseOutput DeleteEducationInfo(Guid id) + { + var success = _educationRepository.Delete(o => o.Id == id); + + return ResponseOutput.Result(success); + } + + public IResponseOutput AddOrUpdatePostgraduateInfo(PostgraduateCommand postgraduateViewModel) + { + if (postgraduateViewModel.Id == Guid.Empty || postgraduateViewModel.Id == null) + { + var doctorContinueLearning = _mapper.Map(postgraduateViewModel); + _postgraduateRepository.Add(doctorContinueLearning); + var success= _postgraduateRepository.SaveChanges(); + + return ResponseOutput.Result(success,doctorContinueLearning.Id.ToString()); + } + else + { + _postgraduateRepository.Update(_mapper.Map(postgraduateViewModel)); + var success = _postgraduateRepository.SaveChanges(); + + return ResponseOutput.Result(success); + + } + } + + public IResponseOutput DeletePostgraduateInfo(Guid doctorId) + { + var success = _postgraduateRepository.Delete(o => o.Id == doctorId); + + return ResponseOutput.Result(success); + } + } +} \ No newline at end of file diff --git a/IRaCIS.Core.Application/Doctor/ResearchPublicationService.cs b/IRaCIS.Core.Application/Doctor/ResearchPublicationService.cs new file mode 100644 index 0000000..fa5e957 --- /dev/null +++ b/IRaCIS.Core.Application/Doctor/ResearchPublicationService.cs @@ -0,0 +1,61 @@ +using AutoMapper; +using AutoMapper.QueryableExtensions; +using IRaCIS.Application.Interfaces; +using IRaCIS.Application.ViewModels; +using IRaCIS.Core.Application.Contracts.RequestAndResponse; +using IRaCIS.Core.Domain.Interfaces; +using IRaCIS.Core.Domain.Models; +using System; +using System.Linq; + + +namespace IRaCIS.Application.Services +{ + public class ResearchPublicationService : IResearchPublicationService + { + private readonly IResearchPublicationRepository _researchPublicationRepository; + private readonly IMapper _mapper; + + public ResearchPublicationService(IResearchPublicationRepository scientificResearchRepository,IMapper mapper) + { + _researchPublicationRepository = scientificResearchRepository; + _mapper = mapper; + } + + public ResearchPublicationDTO GetResearchPublication(Guid doctorId) + { + var doctorScientificResearchInfo = _researchPublicationRepository.Find(o => o.DoctorId == doctorId) + .ProjectTo(_mapper.ConfigurationProvider).FirstOrDefault(); + + return doctorScientificResearchInfo; + } + + public IResponseOutput AddOrUpdateResearchPublication(ResearchPublicationDTO param) + { + if (param.Id == Guid.Empty|| param.Id == null) + { + var doctorScientificResearchInfo = + _mapper.Map(param); + _researchPublicationRepository.Add(doctorScientificResearchInfo); + var success = _researchPublicationRepository.SaveChanges(); + + return ResponseOutput.Result(success, doctorScientificResearchInfo.Id.ToString()); + + } + else + { + var success = _researchPublicationRepository.Update(o => o.Id == param.Id, + t => new ResearchPublication() + { + Publications = param.Publications, + AwardsHonors = param.AwardsHonors, + Research = param.Research, + Grants = param.Grants + }); + + return ResponseOutput.Result(success); + + } + } + } +} \ No newline at end of file diff --git a/IRaCIS.Core.Application/Doctor/TrialExperienceService.cs b/IRaCIS.Core.Application/Doctor/TrialExperienceService.cs new file mode 100644 index 0000000..11a8696 --- /dev/null +++ b/IRaCIS.Core.Application/Doctor/TrialExperienceService.cs @@ -0,0 +1,121 @@ +using AutoMapper; +using AutoMapper.QueryableExtensions; +using IRaCIS.Application.Interfaces; +using IRaCIS.Application.ViewModels; +using IRaCIS.Core.Application.Contracts.RequestAndResponse; +using IRaCIS.Core.Domain.Interfaces; +using IRaCIS.Core.Domain.Models; +using System; +using System.Collections.Generic; +using System.Linq; + +namespace IRaCIS.Application.Services +{ + public class TrialExperienceService : ITrialExperienceService + { + private readonly ITrialExperienceRepository _trialExperienceRepository; + private readonly IDoctorRepository _doctorRepository; + private readonly IAttachmentRepository _attachmentRepository; + private readonly IMapper _mapper; + + public TrialExperienceService(ITrialExperienceRepository trialExperienceRepository, IDoctorRepository doctorRepository, IAttachmentRepository attachmentRepository, IMapper mapper) + { + _trialExperienceRepository = trialExperienceRepository; + _doctorRepository = doctorRepository; + _attachmentRepository = attachmentRepository; + _mapper = mapper; + } + + public TrialExperienceViewModel GetTrialExperience(Guid doctorId) + { + var trialExperience = new TrialExperienceViewModel(); + + var doctor = _doctorRepository.Find(o => o.Id == doctorId) + .ProjectTo(_mapper.ConfigurationProvider).FirstOrDefault(); + + trialExperience.ClinicalTrialExperienceList = + GetTrialExperienceList(doctorId); + + if (doctor != null) + { + trialExperience.GCP = doctor.GCP; + trialExperience.Id = doctor.Id; + trialExperience.OtherClinicalExperience = doctor.OtherClinicalExperience ?? ""; + var attachment = _attachmentRepository.GetAll().FirstOrDefault(t => t.Id == doctor.GCPId); + if (attachment != null) + { + trialExperience.ExpiryDateStr = attachment.ExpiryDate == null ? "" : attachment.ExpiryDate?.ToString("yyyy-MM-dd HH:mm"); + + trialExperience.Path = attachment.Path; + trialExperience.Type = attachment.Type; + trialExperience.FileName = attachment.FileName; + trialExperience.GCPId = attachment.Id; + } + + } + + return trialExperience; + } + + private List GetTrialExperienceList(Guid doctorId) + { + var doctorClinicalTrialExperienceList = _trialExperienceRepository.Find(o => o.DoctorId == doctorId).OrderBy(t => t.CreateTime) + .ProjectTo(_mapper.ConfigurationProvider).ToList(); + + return doctorClinicalTrialExperienceList; + } + + public IResponseOutput AddOrUpdateTrialExperience(TrialExperienceCommand trialExperienceViewModel) + { + if (trialExperienceViewModel.Id == Guid.Empty|| trialExperienceViewModel.Id == null) + { + var trialExperience = + _mapper.Map(trialExperienceViewModel); + _trialExperienceRepository.Add(trialExperience); + + var success = _trialExperienceRepository.SaveChanges(); + return ResponseOutput.Result(success, trialExperience.Id); + } + else + { + _trialExperienceRepository.Update(_mapper.Map(trialExperienceViewModel)); + var success = _trialExperienceRepository.SaveChanges(); + return ResponseOutput.Result(success, trialExperienceViewModel.Id); + } + } + + public IResponseOutput DeleteTrialExperience(Guid doctorId) + { + var success = _trialExperienceRepository.Delete(o => o.Id == doctorId); + return ResponseOutput.Result(success); + } + + public IResponseOutput UpdateGcpExperience(GCPExperienceCommand updateGCPExperienceParam) + { + //_attachmentRepository.Delete(t => t.DoctorId == updateGCPExperienceParam.Id && t.Type == StaticData.GCP); + + var successs = _doctorRepository.Update(o => o.Id == updateGCPExperienceParam.Id, u => new Doctor() + { + GCP = updateGCPExperienceParam.GCP, + GCPId = updateGCPExperienceParam.GCPId + }); + + + + return ResponseOutput.Result(successs, updateGCPExperienceParam.GCPId.ToString()); + + } + + /// 更新其他经验 + public IResponseOutput UpdateOtherExperience(Guid doctorId, string otherClinicalExperience) + { + var success = _doctorRepository.Update(o => o.Id == doctorId, u => new Doctor() + { + OtherClinicalExperience = otherClinicalExperience ?? string.Empty + }); + + return ResponseOutput.Result(success); + } + + } +} \ No newline at end of file diff --git a/IRaCIS.Core.Application/Doctor/VacationService.cs b/IRaCIS.Core.Application/Doctor/VacationService.cs new file mode 100644 index 0000000..e678052 --- /dev/null +++ b/IRaCIS.Core.Application/Doctor/VacationService.cs @@ -0,0 +1,83 @@ +using AutoMapper; +using AutoMapper.QueryableExtensions; +using IRaCIS.Application.Interfaces; +using IRaCIS.Application.ViewModels; +using IRaCIS.Core.Application.Contracts.RequestAndResponse; +using System; +using System.Linq; +using IRaCIS.Core.Domain.Interfaces; +using IRaCIS.Core.Domain.Models; + +namespace IRaCIS.Application.Services +{ + + public class VacationService : IVacationService + { + private readonly IVacationRepository _vacationRepository; + private readonly IMapper _mapper; + + public VacationService(IVacationRepository vacationRepository,IMapper mapper) + { + _vacationRepository = vacationRepository; + _mapper = mapper; + } + public IResponseOutput AddOrUpdateVacation(VacationCommand param) + { + if (param.Id == Guid.Empty|| param.Id ==null) + { + var result = _vacationRepository.Add(_mapper.Map(param)); + + var success = _vacationRepository.SaveChanges(); + + return ResponseOutput.Result(success, result.Id); + + } + else + { + var success = _vacationRepository.Update(u => u.Id == param.Id, + h => new Vacation + { + StartDate = param.StartDate, + EndDate = param.EndDate + }); + + return ResponseOutput.Result(success); + + } + + } + + public IResponseOutput DeleteVacation(Guid holidayId) + { + var success = _vacationRepository.Delete(u => u.Id == holidayId); + + return ResponseOutput.Result(success); + + } + + public PageOutput GetVacationList(Guid doctorId, int pageIndex, int pageSize) + { + var result = _vacationRepository.Find(u => u.DoctorId == doctorId).ProjectTo(_mapper.ConfigurationProvider) + .OrderBy(o => o.StartDate).Skip((pageIndex - 1) * pageSize).Take(pageSize).ToList(); + + var data = new PageOutput() + { + PageIndex = pageIndex, + PageSize = pageSize, + CurrentPageData = result, + TotalCount = _vacationRepository.GetCount(u => u.DoctorId == doctorId) + }; + + return data; + + } + + public IResponseOutput OnVacation(Guid doctorId) + { + var count = _vacationRepository.GetCount(u => u.DoctorId == doctorId && u.EndDate >= DateTime.Now && u.StartDate <= DateTime.Now); + + return ResponseOutput.Result(count > 0); + } + + } +} diff --git a/IRaCIS.Core.Application/Financial/CalculateService.cs b/IRaCIS.Core.Application/Financial/CalculateService.cs new file mode 100644 index 0000000..8358e7a --- /dev/null +++ b/IRaCIS.Core.Application/Financial/CalculateService.cs @@ -0,0 +1,738 @@ +using AutoMapper; +using AutoMapper.QueryableExtensions; +using IRaCIS.Application.Interfaces; +using IRaCIS.Application.ViewModels; +using IRaCIS.Application.ViewModels.Pay; +using IRaCIS.Core.Application.Contracts.RequestAndResponse; +using IRaCIS.Core.Domain.Share; +using IRaCIS.Infra.Data.ExpressionExtend; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Expressions; +using IRaCIS.Core.Domain.Interfaces; +using IRaCIS.Core.Domain.Models; + +namespace IRaCIS.Application.Services +{ + public class CalculateService : ICalculateService + { + private readonly IPaymentRepository _paymentRepository; + private readonly ITrialPaymentPriceRepository _trialPaymentRepository; + private readonly IReviewerPayInfoRepository _doctorPayInfoRepository; + private readonly ITrialRepository _trialRepository; + private readonly IDoctorRepository _doctorRepository; + private readonly IWorkloadRepository _doctorWorkloadRepository; + private readonly IRankPriceRepository _rankPriceRepository; + private readonly IPaymentDetailRepository _paymentDetailRepository; + private readonly IVolumeRewardService _volumeRewardPriceService; + private readonly IExchangeRateRepository _exchangeRateRepository; + private readonly IPaymentAdjustmentRepository _payAdjustmentRepository; + private readonly IEnrollRepository _enrollRepository; + private readonly IMapper _mapper; + + public CalculateService(IPaymentRepository paymentRepository, ITrialPaymentPriceRepository trialPaymentPriceRepository, + IReviewerPayInfoRepository reviewerPayInfoRepository, + ITrialRepository trialRepository, + IDoctorRepository doctorRepository, + IWorkloadRepository workloadRepository, + IRankPriceRepository rankPriceRepository, + IPaymentDetailRepository paymentDetailRepository, + IVolumeRewardService volumeRewardService, + IExchangeRateRepository exchangeRateRepository, + IEnrollRepository enrollRepository, + IPaymentAdjustmentRepository paymentAdjustmentRepository, IMapper mapper) + { + _paymentRepository = paymentRepository; + _trialPaymentRepository = trialPaymentPriceRepository; + _doctorPayInfoRepository = reviewerPayInfoRepository; + _trialRepository = trialRepository; + _enrollRepository= enrollRepository; + _doctorRepository = doctorRepository; + _doctorWorkloadRepository = workloadRepository; + _rankPriceRepository = rankPriceRepository; + _paymentDetailRepository = paymentDetailRepository; + _volumeRewardPriceService = volumeRewardService; + _exchangeRateRepository = exchangeRateRepository; + _payAdjustmentRepository = paymentAdjustmentRepository; + _mapper = mapper; + } + + /// + /// 获取某个月下的某些医生最终确认的工作量,用于计算月度费用 + /// + private List GetFinalConfirmedWorkloadAndPayPriceList(CalculateDoctorAndMonthDTO calculateFeeParam) + { + Expression> workloadLambda = x => true; + + DateTime bTime = new DateTime(calculateFeeParam.CalculateMonth.Year, calculateFeeParam.CalculateMonth.Month, 1); + var eTime = bTime.AddMonths(1); + workloadLambda = workloadLambda.And(t => + t.WorkTime >= bTime && t.WorkTime < eTime); + + workloadLambda = workloadLambda.And(t => calculateFeeParam.NeedCalculateReviewers.Contains(t.DoctorId) && t.DataFrom == (int)WorkLoadFromStatus.FinalConfirm); + var workLoadQueryable = from doctor in _doctorRepository.GetAll() + join workLoad in _doctorWorkloadRepository.GetAll().Where(workloadLambda) on + doctor.Id equals workLoad.DoctorId + join trial in _trialRepository.GetAll() on workLoad.TrialId equals trial.Id + join trialPay in _trialPaymentRepository.GetAll() on trial.Id equals trialPay.TrialId + into temp + from trialPay in temp.DefaultIfEmpty() + join doctorPayInfo in _doctorPayInfoRepository.GetAll() on doctor.Id equals doctorPayInfo.DoctorId + join rankPrice in _rankPriceRepository.GetAll() on doctorPayInfo.RankId equals rankPrice.Id + select new CalculatePaymentDTO() + { + Id = workLoad.Id, + DoctorId = workLoad.DoctorId, + WorkTime = workLoad.WorkTime, + DataFrom = workLoad.DataFrom, + TrialId = workLoad.TrialId, + TrialCode = trial.Code, + + Timepoint = workLoad.Timepoint, + TimepointIn24H = workLoad.TimepointIn24H, + TimepointIn48H = workLoad.TimepointIn48H, + Global = workLoad.Global, + Adjudication = workLoad.Adjudication, + AdjudicationIn24H = workLoad.AdjudicationIn24H, + AdjudicationIn48H = workLoad.AdjudicationIn48H, + Training = workLoad.Training, + RefresherTraining = workLoad.RefresherTraining, + Downtime = workLoad.Downtime, + + TrialAdditional = trialPay.TrialAdditional, + PersonalAdditional = doctorPayInfo.Additional, + AdjustmentMultiple = trialPay.AdjustmentMultiple, + + TimepointPrice = rankPrice.Timepoint, + TimepointIn24HPrice = rankPrice.TimepointIn24H, + TimepointIn48HPrice = rankPrice.TimepointIn48H, + AdjudicationPrice = rankPrice.Adjudication, + AdjudicationIn24HPrice = rankPrice.AdjudicationIn24H, + AdjudicationIn48HPrice = rankPrice.AdjudicationIn48H, + DowntimePrice = rankPrice.Downtime, + GlobalPrice = rankPrice.Global, + TrainingPrice = rankPrice.Training, + RefresherTrainingPrice = rankPrice.RefresherTraining + }; + + return workLoadQueryable.ToList(); + } + + /// + /// 计算月度费用,并调用AddOrUpdateMonthlyPayment和AddOrUpdateMonthlyPaymentDetail方法, + /// 将费用计算的月度数据及详情保存 + /// + + public IResponseOutput CalculateMonthlyPayment(CalculateDoctorAndMonthDTO param, string token) + { + var yearMonth = param.CalculateMonth.ToString("yyyy-MM"); + var rate = _exchangeRateRepository.FindSingleOrDefault(u => u.YearMonth == yearMonth); + + decimal exchangeRate = rate?.Rate ?? 0; + + var workLoadAndPayPriceList = GetFinalConfirmedWorkloadAndPayPriceList(param); + var volumeRewardPriceList = _volumeRewardPriceService.GetVolumeRewardPriceList(); + + #region 奖励数据校验 + for (int i = 0; i < volumeRewardPriceList.Count; i++) + { + if (i == 0 && volumeRewardPriceList[i].Min != 0) + { + return ResponseOutput.NotOk("Volume reward data error."); + } + if (i > 0) + { + if (volumeRewardPriceList[i - 1].Max + 1 != volumeRewardPriceList[i].Min) + return ResponseOutput.NotOk("Volume reward data error."); + } + } + + + #endregion + + + List paymentList = new List(); + List reviewerPaymentUSDList = new List(); + + // 获取所有医生费用 一次从数据库里面全部取出来 + + var allDoctorList = workLoadAndPayPriceList.Where(x => param.NeedCalculateReviewers.Contains(x.DoctorId)).ToList(); + var allDoctorIds = allDoctorList.Select(x => x.DoctorId).Distinct().ToList(); + var listTrialId = allDoctorList.Select(x => x.TrialId).Distinct().ToList(); + + var trialDoctorlist = (from enroll in _enrollRepository.GetAll().Where(x => listTrialId.Contains(x.TrialId) || allDoctorIds.Contains(x.DoctorId)) + join price in _trialPaymentRepository.GetAll() on enroll.TrialId equals price.TrialId + select new DoctorPrice() + { + IsNewTrial = price.IsNewTrial, + AdjustmentMultiple = enroll.AdjustmentMultiple, + TrialId = enroll.TrialId, + DoctorId = enroll.DoctorId, + Training = enroll.Training, + Adjudication = enroll.Adjudication, + Adjudication24H = enroll.Adjudication24H, + Adjudication48H = enroll.Adjudication48H, + Downtime = enroll.Downtime, + Global = enroll.Global, + RefresherTraining = enroll.RefresherTraining, + Timepoint = enroll.Timepoint, + Timepoint24H = enroll.Timepoint24H, + Timepoint48H = enroll.Timepoint48H, + }).ToList(); + + + + foreach (var doctor in param.NeedCalculateReviewers) + { + if (_paymentRepository.GetAll().Any(u => u.DoctorId == doctor && u.YearMonth == yearMonth && u.IsLock)) + { + break; + } + List paymentDetailList = new List(); + decimal totalNormal = 0; + + //计算单个医生费用统,并且插入到统计表 + var doctorWorkloadAndPayPriceList = workLoadAndPayPriceList.Where(u => u.DoctorId == doctor).ToList(); + + //阅片数量 计算奖励费用 + int readCount = 0; + + int codeOrder = 0; + + //这里需要改 + + foreach (var item in doctorWorkloadAndPayPriceList) + { + var doctordata = trialDoctorlist.Where(x => x.IsNewTrial ?? false && x.Training == item.Training && x.DoctorId == item.DoctorId).FirstOrDefault(); + + if (doctordata != null) + { + item.Training = doctordata.Training ?? 0; + item.Adjudication = doctordata.Adjudication ?? 0; + item.AdjudicationIn24H = doctordata.Adjudication24H ?? 0; + item.AdjudicationIn48H = doctordata.Adjudication48H ?? 0; + item.Downtime = doctordata.Downtime ?? 0; + item.Global = doctordata.Global ?? 0; + item.RefresherTraining = doctordata.RefresherTraining ?? 0; + item.Timepoint = doctordata.Timepoint ?? 0; + item.TimepointIn24H = doctordata.Timepoint24H ?? 0; + item.TimepointIn48H = doctordata.Timepoint48H ?? 0; + item.PersonalAdditional = 0; + } + ++codeOrder; + readCount += (item.Timepoint + item.TimepointIn24H + item.TimepointIn48H + + item.Adjudication + item.AdjudicationIn24H + item.AdjudicationIn48H); + decimal trainingTotal = item.Training * item.TrainingPrice; + decimal refresherTrainingTotal = item.RefresherTraining * item.RefresherTrainingPrice; + decimal downtimeTotal = item.Downtime * item.DowntimePrice; + //规则定义 global 的价格是Tp和个人附加的一半 + decimal globalTotal = item.Global * (item.TimepointPrice / 2 + item.PersonalAdditional / 2); + + //项目如果没有添加附加数据 默认为0 + decimal timePointTotal = item.Timepoint * (item.TimepointPrice * item.AdjustmentMultiple + item.PersonalAdditional + (item.TrialAdditional == null ? 0 : (decimal)item.TrialAdditional)); + + decimal timePointIn24HTotal = item.TimepointIn24H * (item.TimepointIn24HPrice * item.AdjustmentMultiple + item.PersonalAdditional); + decimal timePointIn48HTotal = item.TimepointIn48H * (item.TimepointIn48HPrice * item.AdjustmentMultiple + item.PersonalAdditional); + decimal adjudicationTotal = item.Adjudication * (item.AdjudicationPrice * item.AdjustmentMultiple + item.PersonalAdditional + (item.TrialAdditional == null ? 0 : (decimal)item.TrialAdditional)); + decimal adjudicationIn24HTotal = item.AdjudicationIn24H * (item.AdjudicationIn24HPrice * item.AdjustmentMultiple + item.PersonalAdditional); + decimal adjudicationIn48HTotal = item.AdjudicationIn48H * (item.AdjudicationIn48HPrice * item.AdjustmentMultiple + item.PersonalAdditional); + + totalNormal += (trainingTotal + refresherTrainingTotal + downtimeTotal + globalTotal + timePointTotal + timePointIn24HTotal + + timePointIn48HTotal + adjudicationTotal + adjudicationIn24HTotal + adjudicationIn48HTotal); + + #region 统计明细信息 + + paymentDetailList.Add(new PaymentDetailCommand + { + TrialCode = item.TrialCode, + PaymentType = "Training", + Count = item.Training, + BasePrice = item.TrainingPrice, + PersonalAdditional = 0, + TrialAdditional = 0, + PaymentId = Guid.Empty, + DoctorId = item.DoctorId, + TrialId = item.TrialId, + ShowTypeOrder = 1, + ShowCodeOrder = codeOrder, + ExchangeRate = exchangeRate, + YearMonth = yearMonth, + PaymentUSD = item.Training * item.TrainingPrice, + PaymentCNY = item.Training * item.TrainingPrice * exchangeRate + }); + paymentDetailList.Add(new PaymentDetailCommand + { + TrialCode = item.TrialCode, + PaymentType = "Refresher Training", + Count = item.RefresherTraining, + BasePrice = item.RefresherTrainingPrice, + PersonalAdditional = 0, + TrialAdditional = 0, + PaymentId = Guid.Empty, + DoctorId = item.DoctorId, + TrialId = item.TrialId, + ShowTypeOrder = 2, + ShowCodeOrder = codeOrder, + ExchangeRate = exchangeRate, + YearMonth = yearMonth, + PaymentUSD = item.RefresherTraining * item.RefresherTrainingPrice, + PaymentCNY = item.RefresherTraining * item.RefresherTrainingPrice * exchangeRate + }); + paymentDetailList.Add(new PaymentDetailCommand + { + TrialCode = item.TrialCode, + PaymentType = "Downtime", + Count = item.Downtime, + BasePrice = item.DowntimePrice, + PersonalAdditional = 0, + TrialAdditional = 0, + PaymentId = Guid.Empty, + DoctorId = item.DoctorId, + TrialId = item.TrialId, + ShowTypeOrder = 3, + ShowCodeOrder = codeOrder, + ExchangeRate = exchangeRate, + YearMonth = yearMonth, + PaymentUSD = item.Downtime * item.DowntimePrice, + PaymentCNY = item.Downtime * item.DowntimePrice * exchangeRate + }); + + paymentDetailList.Add(new PaymentDetailCommand + { + TrialCode = item.TrialCode, + PaymentType = "Timepoint Regular", + Count = item.Timepoint, + BasePrice = item.TimepointPrice, + PersonalAdditional = doctordata != null ? 0 : item.PersonalAdditional, + TrialAdditional = doctordata != null ? 0 : item.TimepointPrice * (item.AdjustmentMultiple - 1) + (item.TrialAdditional == null ? 0 : (decimal)item.TrialAdditional), + PaymentId = Guid.Empty, + DoctorId = item.DoctorId, + TrialId = item.TrialId, + ShowTypeOrder = 4, + ShowCodeOrder = codeOrder, + ExchangeRate = exchangeRate, + YearMonth = yearMonth, + PaymentUSD = item.Timepoint * (item.TimepointPrice * item.AdjustmentMultiple + item.PersonalAdditional + (item.TrialAdditional == null ? 0 : (decimal)item.TrialAdditional)), + PaymentCNY = item.Timepoint * (item.TimepointPrice * item.AdjustmentMultiple + item.PersonalAdditional + (item.TrialAdditional == null ? 0 : (decimal)item.TrialAdditional)) * exchangeRate + }); + + paymentDetailList.Add(new PaymentDetailCommand + { + TrialCode = item.TrialCode, + PaymentType = "Timepoint 48-Hour", + Count = item.TimepointIn48H, + BasePrice = item.TimepointIn48HPrice, + PersonalAdditional = doctordata != null ? 0 : item.PersonalAdditional, + TrialAdditional = doctordata != null ? 0 : item.TimepointIn48HPrice * (item.AdjustmentMultiple - 1) + 0,//48小时不加项目附加 + PaymentId = Guid.Empty, + DoctorId = item.DoctorId, + TrialId = item.TrialId, + ShowTypeOrder = 5, + ShowCodeOrder = codeOrder, + ExchangeRate = exchangeRate, + YearMonth = yearMonth, + PaymentUSD = item.TimepointIn48H * (item.TimepointIn48HPrice * item.AdjustmentMultiple + 0 + item.PersonalAdditional), + PaymentCNY = item.TimepointIn48H * (item.TimepointIn48HPrice * item.AdjustmentMultiple + 0 + item.PersonalAdditional) * exchangeRate + }); + paymentDetailList.Add(new PaymentDetailCommand + { + TrialCode = item.TrialCode, + PaymentType = "Timepoint 24-Hour", + Count = item.TimepointIn24H, + BasePrice = item.TimepointIn24HPrice, + PersonalAdditional = doctordata != null ? 0 : item.PersonalAdditional, + TrialAdditional = doctordata != null ? 0 : item.TimepointIn24HPrice * (item.AdjustmentMultiple - 1) + 0, + PaymentId = Guid.Empty, + DoctorId = item.DoctorId, + TrialId = item.TrialId, + ShowTypeOrder = 6, + ShowCodeOrder = codeOrder, + ExchangeRate = exchangeRate, + YearMonth = yearMonth, + PaymentUSD = item.TimepointIn24H * (item.TimepointIn24HPrice * item.AdjustmentMultiple + 0 + item.PersonalAdditional), + PaymentCNY = item.TimepointIn24H * (item.TimepointIn24HPrice * item.AdjustmentMultiple + 0 + item.PersonalAdditional) * exchangeRate + }); + paymentDetailList.Add(new PaymentDetailCommand + { + TrialCode = item.TrialCode, + PaymentType = "Adjudication Regular", + Count = item.Adjudication, + BasePrice = item.AdjudicationPrice, + PersonalAdditional = doctordata != null ? 0 : item.PersonalAdditional, + TrialAdditional = doctordata != null ? 0 : item.AdjudicationPrice * (item.AdjustmentMultiple - 1) + (item.TrialAdditional == null ? 0 : (decimal)item.TrialAdditional), + PaymentId = Guid.Empty, + DoctorId = item.DoctorId, + TrialId = item.TrialId, + ShowTypeOrder = 7, + ShowCodeOrder = codeOrder, + ExchangeRate = exchangeRate, + YearMonth = yearMonth, + PaymentUSD = item.Adjudication * (item.AdjudicationPrice * item.AdjustmentMultiple + item.PersonalAdditional + (item.TrialAdditional == null ? 0 : (decimal)item.TrialAdditional)), + PaymentCNY = item.Adjudication * (item.AdjudicationPrice * item.AdjustmentMultiple + item.PersonalAdditional + (item.TrialAdditional == null ? 0 : (decimal)item.TrialAdditional)) * exchangeRate + }); + + paymentDetailList.Add(new PaymentDetailCommand + { + TrialCode = item.TrialCode, + PaymentType = "Adjudication 48-Hour", + Count = item.AdjudicationIn48H, + BasePrice = item.AdjudicationIn48HPrice, + PersonalAdditional = doctordata != null ? 0 : item.PersonalAdditional, + TrialAdditional = doctordata != null ? 0 : item.AdjudicationIn48HPrice * (item.AdjustmentMultiple - 1) + 0, + PaymentId = Guid.Empty, + DoctorId = item.DoctorId, + TrialId = item.TrialId, + ShowTypeOrder = 8, + ShowCodeOrder = codeOrder, + ExchangeRate = exchangeRate, + YearMonth = yearMonth, + PaymentUSD = item.AdjudicationIn48H * (item.AdjudicationIn48HPrice * item.AdjustmentMultiple + item.PersonalAdditional + 0), + PaymentCNY = item.AdjudicationIn48H * (item.AdjudicationIn48HPrice * item.AdjustmentMultiple + item.PersonalAdditional + 0) * exchangeRate + }); + paymentDetailList.Add(new PaymentDetailCommand + { + TrialCode = item.TrialCode, + PaymentType = "Adjudication 24-Hour", + Count = item.AdjudicationIn24H, + BasePrice = item.AdjudicationIn24HPrice, + PersonalAdditional = doctordata != null ? 0 : item.PersonalAdditional, + TrialAdditional = doctordata != null ? 0 : item.AdjudicationIn24HPrice * (item.AdjustmentMultiple - 1) + 0, + PaymentId = Guid.Empty, + DoctorId = item.DoctorId, + TrialId = item.TrialId, + ShowTypeOrder = 9, + ShowCodeOrder = codeOrder, + ExchangeRate = exchangeRate, + YearMonth = yearMonth, + PaymentUSD = item.AdjudicationIn24H * (item.AdjudicationIn24HPrice * item.AdjustmentMultiple + 0 + item.PersonalAdditional), + PaymentCNY = item.AdjudicationIn24H * (item.AdjudicationIn24HPrice * item.AdjustmentMultiple + 0 + item.PersonalAdditional) * exchangeRate + }); + paymentDetailList.Add(new PaymentDetailCommand + { + TrialCode = item.TrialCode, + PaymentType = "Global", + Count = item.Global, + BasePrice = item.TimepointPrice / 2,//item.GlobalPrice, + PersonalAdditional = doctordata != null ? 0 : item.PersonalAdditional / 2, + TrialAdditional = 0, + PaymentId = Guid.Empty, + DoctorId = item.DoctorId, + TrialId = item.TrialId, + ShowTypeOrder = 10, + ShowCodeOrder = codeOrder, + ExchangeRate = exchangeRate, + YearMonth = yearMonth, + PaymentUSD = item.Global * (item.TimepointPrice / 2 + item.PersonalAdditional / 2), + PaymentCNY = item.Global * (item.TimepointPrice / 2 + item.PersonalAdditional / 2) * exchangeRate + }); + #endregion + } + + int typeOrder = 0; + if (readCount > 0) + { + paymentDetailList.Add(new PaymentDetailCommand + { + TrialCode = "Volume Reward", + PaymentType = "Total TP & AD", + Count = readCount, + BasePrice = 0, + PersonalAdditional = 0, + TrialAdditional = 0, + PaymentId = Guid.Empty, + DoctorId = doctor, + TrialId = Guid.Empty, + ShowTypeOrder = typeOrder, + ShowCodeOrder = (++codeOrder), + ExchangeRate = exchangeRate, + YearMonth = yearMonth, + PaymentUSD = 0, + PaymentCNY = 0 + }); + + foreach (var awardItem in volumeRewardPriceList) + { + ++typeOrder; + if ((readCount - awardItem.Min + 1) < 0) + { + break; + } + if (awardItem.Min == 0) + { + paymentDetailList.Add(new PaymentDetailCommand + { + TrialCode = "Volume Reward", + PaymentType = awardItem.Min + "-" + awardItem.Max, + Count = readCount >= awardItem.Max ? + (awardItem.Max - awardItem.Min) : (readCount - awardItem.Min), + BasePrice = awardItem.Price, + PersonalAdditional = 0, + TrialAdditional = 0, + PaymentId = Guid.Empty,//result.Data, + DoctorId = doctor, + TrialId = Guid.Empty, + ShowTypeOrder = typeOrder, + ShowCodeOrder = (++codeOrder), + ExchangeRate = exchangeRate, + YearMonth = yearMonth, + PaymentUSD = (readCount >= awardItem.Max ? + (awardItem.Max - awardItem.Min) : (readCount - awardItem.Min)) * awardItem.Price, + PaymentCNY = (readCount >= awardItem.Max ? + (awardItem.Max - awardItem.Min) : (readCount - awardItem.Min)) * awardItem.Price * exchangeRate + }); + } + else + { + paymentDetailList.Add(new PaymentDetailCommand + { + TrialCode = "Volume Reward", + PaymentType = awardItem.Min + "-" + awardItem.Max, + Count = readCount >= awardItem.Max ? + (awardItem.Max - awardItem.Min + 1) : (readCount - awardItem.Min + 1), + BasePrice = awardItem.Price, + PersonalAdditional = 0, + TrialAdditional = 0, + PaymentId = Guid.Empty, + DoctorId = doctor, + TrialId = Guid.Empty, + ShowTypeOrder = typeOrder, + ShowCodeOrder = (++codeOrder), + ExchangeRate = exchangeRate, + YearMonth = yearMonth, + PaymentUSD = (readCount >= awardItem.Max ? + (awardItem.Max - awardItem.Min + 1) : (readCount - awardItem.Min + 1)) * awardItem.Price, + PaymentCNY = (readCount >= awardItem.Max ? + (awardItem.Max - awardItem.Min + 1) : (readCount - awardItem.Min + 1)) * awardItem.Price * exchangeRate + }); + } + } + + } + decimal award = 0; + volumeRewardPriceList = volumeRewardPriceList.OrderBy(u => u.Min).ToList(); + + var levelTemp = -1; //用来计算属于哪一个挡位 + foreach (var awarPriceitem in volumeRewardPriceList) + { + if (awarPriceitem.Min == 0) + { + if (readCount > awarPriceitem.Max) + { + ++levelTemp; + award += (awarPriceitem.Max - awarPriceitem.Min) * awarPriceitem.Price; + } + if (awarPriceitem.Min < readCount && readCount < awarPriceitem.Max) + { + ++levelTemp; + award += (readCount - awarPriceitem.Min) * awarPriceitem.Price; + break; ; + } + } + else + { + if (readCount > awarPriceitem.Max) + { + ++levelTemp; + award += (awarPriceitem.Max - awarPriceitem.Min + 1) * awarPriceitem.Price; + } + if (awarPriceitem.Min < readCount && readCount < awarPriceitem.Max) + { + ++levelTemp; + award += (readCount - awarPriceitem.Min + 1) * awarPriceitem.Price; + break; ; + } + } + } + decimal totalUSD = award + totalNormal;//总费用 + + var result = AddOrUpdateMonthlyPayment(new PaymentCommand + { + DoctorId = doctor, + Year = param.CalculateMonth.Year, + Month = param.CalculateMonth.Month, + PaymentUSD = totalUSD, + CalculateUser = token, + CalculateTime = DateTime.Now, + ExchangeRate = exchangeRate, + PaymentCNY = exchangeRate * totalUSD, + }); + + + reviewerPaymentUSDList.Add(new ReviewerPaymentUSD { DoctorId = doctor, PaymentUSD = totalUSD, RecordId = result.Data }); + foreach (var detail in paymentDetailList) + { + //var data = trialDoctorlist.FirstOrDefault(x => x.DoctorId == detail.DoctorId && x.TrialId == detail.TrialId && x.IsNewTrial == true && (x.AdjustmentMultiple??0) != 0); + //if (data != null) + //{ + // detail.BasePrice = data.AdjustmentMultiple??0; + // detail.PersonalAdditional = 0; + // detail.TrialAdditional = 0; + //} + + detail.PaymentId = result.Data; + } + AddOrUpdateMonthlyPaymentDetail(paymentDetailList, result.Data); + + UpdatePaymentAdjustment(doctor, yearMonth); + } + return ResponseOutput.Ok(reviewerPaymentUSDList); + } + + + + + // 重新计算调整费用 + + private void UpdatePaymentAdjustment(Guid reviewerId,string yearMonth) + { + var adjustList = _payAdjustmentRepository.GetAll().Where(u => u.YearMonth == yearMonth && + !u.IsLock&&u.ReviewerId==reviewerId).ToList(); + + + var needUpdatePayment = adjustList.GroupBy(t => t.ReviewerId).Select(g => new + { + ReviewerId = g.Key, + AdjustCNY = g.Sum(t => t.AdjustmentCNY), + AdjustUSD = g.Sum(t => t.AdjustmentUSD) + }); + + foreach (var reviewer in needUpdatePayment) + { + _paymentRepository.Update(u => u.YearMonth == yearMonth && + !u.IsLock && u.DoctorId == reviewer.ReviewerId, t => new Payment() + { + AdjustmentUSD = reviewer.AdjustUSD, + AdjustmentCNY = reviewer.AdjustCNY + + }); + } + } + + /// + /// 保存费用计算的月度数据 + /// + private IResponseOutput AddOrUpdateMonthlyPayment(PaymentCommand addOrUpdateModel) + { + var success = false; + var paymentModel = _paymentRepository.GetAll().FirstOrDefault(t => + t.DoctorId == addOrUpdateModel.DoctorId && t.YearMonth == addOrUpdateModel.YearMonth); + + + + //var taxCNY = GetTax(addOrUpdateModel.PaymentCNY); + //var actuallyPaidCNY = addOrUpdateModel.PaymentCNY - taxCNY; + //var bankTransferCNY = addOrUpdateModel.PaymentCNY - taxCNY; + + if (paymentModel == null) + { + var payment = _mapper.Map(addOrUpdateModel); + + //payment.BankTransferCNY = bankTransferCNY; + //payment.TaxCNY= taxCNY; + //payment.BankTransferCNY = bankTransferCNY; + payment.YearMonthDate = DateTime.Parse(payment.YearMonth); + + payment = _paymentRepository.Add(payment); + success = _paymentRepository.SaveChanges(); + return ResponseOutput.Result(success, payment.Id); + } + else + { + // 如果是 当月计算的工作量费用 和 调整费用都为0,则删除该行记录 + if (addOrUpdateModel.PaymentUSD == 0 && paymentModel.AdjustmentUSD == 0) + { + success = _paymentRepository.Delete(u => u.Id == paymentModel.Id); + //_paymentDetailRepository.Delete(u=>u.PaymentId==paymentModel.Id); + } + else + { + success = _paymentRepository.Update(t => t.Id == paymentModel.Id, u => new Payment() + { + PaymentUSD = addOrUpdateModel.PaymentUSD, + CalculateTime = addOrUpdateModel.CalculateTime, + CalculateUser = addOrUpdateModel.CalculateUser, + //TaxCNY = taxCNY, + //ActuallyPaidCNY = actuallyPaidCNY, + //BankTransferCNY = bankTransferCNY, + PaymentCNY = addOrUpdateModel.PaymentCNY, + ExchangeRate = addOrUpdateModel.ExchangeRate + }); + } + + return ResponseOutput.Result(success, paymentModel.Id); + } + + } + + + + + /// + /// 保存费用计算的月度详情 + /// + private bool AddOrUpdateMonthlyPaymentDetail(List addOrUpdateList, Guid paymentId) + { + //var paymentDetailIds = addOrUpdateList.Select(t => t.PaymentId).ToList(); + _paymentDetailRepository.Delete(t => t.PaymentId == paymentId); + _paymentDetailRepository.AddRange(_mapper.Map>(addOrUpdateList)); + return _paymentDetailRepository.SaveChanges(); + } + + /// + /// 锁定某个月下的某些医生,医生费用结算后调用锁定 + /// + public IResponseOutput UpdateLockStatus(List reviewerIds, string yearMonth, bool isLock) + { + var paymentLockSuccess = _paymentRepository.Update(u => reviewerIds.Contains(u.DoctorId) && u.YearMonth == yearMonth, t => new Payment + { + IsLock = isLock + }); + + var adjustmentLockSuccess = _payAdjustmentRepository.Update( + t => t.YearMonth == yearMonth && reviewerIds.Contains(t.ReviewerId), u => + new PaymentAdjustment() + { + IsLock = true + }); + _doctorWorkloadRepository.Update(u => reviewerIds.Contains(u.DoctorId) && u.YearMonth == yearMonth, + t => new Workload { IsLock = true }); + + return ResponseOutput.Result(paymentLockSuccess || adjustmentLockSuccess); + } + + /// + /// 获取待计算费用的Reviewer对应的月份列表 + /// + public List GetNeedCalculateReviewerList(Guid reviewerId, string yearMonth) + { + Expression> calculateLambda = u => !u.IsLock; + if (reviewerId != Guid.Empty) + { + calculateLambda = calculateLambda.And(u => u.DoctorId == reviewerId); + } + if (!string.IsNullOrWhiteSpace(yearMonth)) + { + calculateLambda = calculateLambda.And(u => u.YearMonth == yearMonth); + } + return _paymentRepository.Find(calculateLambda).ProjectTo(_mapper.ConfigurationProvider).ToList(); + } + + /// + /// 查询Reviewer某个月的费用是否被锁定 + /// + public bool IsLock(Guid reviewerId, string yearMonth) + { + return _paymentRepository.GetAll().Any(u => u.DoctorId == reviewerId && u.YearMonth == yearMonth && u.IsLock); + } + + //public bool ResetMonthlyPayment(Guid reviewerId, Guid trialId, string yearMonth) + //{ + // var payment = _paymentRepository.FindSingleOrDefault(u => u.DoctorId == reviewerId && u.YearMonth == yearMonth); + // payment.PaymentCNY = 0; + // payment.PaymentUSD = 0; + // _paymentRepository.Update(payment); + // _paymentDetailRepository.Delete(u=>u.DoctorId==reviewerId && u.TrialId==trial) + //} + } +} diff --git a/IRaCIS.Core.Application/Financial/ExchangeRateService.cs b/IRaCIS.Core.Application/Financial/ExchangeRateService.cs new file mode 100644 index 0000000..62c6f40 --- /dev/null +++ b/IRaCIS.Core.Application/Financial/ExchangeRateService.cs @@ -0,0 +1,115 @@ +using AutoMapper; +using AutoMapper.QueryableExtensions; +using IRaCIS.Application.ExpressionExtend; +using IRaCIS.Application.Interfaces; +using IRaCIS.Application.ViewModels; +using IRaCIS.Core.Application.Contracts.RequestAndResponse; +using IRaCIS.Core.Domain.Share; +using IRaCIS.Infra.Data.ExpressionExtend; +using System; +using System.Linq; +using System.Linq.Expressions; +using IRaCIS.Core.Domain.Interfaces; +using IRaCIS.Core.Domain.Models; + +namespace IRaCIS.Application.Services +{ + public class ExchangeRateService : IExchangeRateService + { + private readonly IExchangeRateRepository _exchangeRateRepository; + private readonly IMapper _mapper; + private readonly IPaymentRepository _paymentRepository; + + public ExchangeRateService(IExchangeRateRepository exchangeRateRepository, IMapper mapper,IPaymentRepository paymentRepository) + { + _exchangeRateRepository = exchangeRateRepository; + _mapper = mapper; + _paymentRepository = paymentRepository; + } + public IResponseOutput AddOrUpdateExchangeRate(ExchangeRateCommand model) + { + if (model.Id == Guid.Empty||model.Id==null) + { + var existItem = _exchangeRateRepository.FindSingleOrDefault(u => u.YearMonth == model.YearMonth); + if (existItem != null) + { + return ResponseOutput.NotOk("Same month's exchange rate is already exist."); + } + var rate = _mapper.Map(model); + rate = _exchangeRateRepository.Add(rate); + if (_exchangeRateRepository.SaveChanges()) + { + return ResponseOutput.Ok(rate.Id.ToString()); + } + else + { + return ResponseOutput.NotOk(); + } + + } + else + { + var success = _exchangeRateRepository.Update(t => t.Id == model.Id, u => new ExchangeRate() + { + //YearMonth = model.YearMonth, + Rate = model.Rate, + UpdateTime = DateTime.Now + }); + return ResponseOutput.Result(success, success ? string.Empty : StaticData.UpdateFailed); + } + } + + public IResponseOutput DeleteExchangeRate(Guid id) + { + var monthInfo = _exchangeRateRepository.GetAll().FirstOrDefault(t => t.Id == id); + + if (_paymentRepository.GetAll().Any(t => t.YearMonth == monthInfo.YearMonth)) + { + return ResponseOutput.NotOk("The exchange rate has been used in monthly payment"); + } + + + var success = _exchangeRateRepository.Delete(t => t.Id == id); + + return ResponseOutput.Result(success, success ? string.Empty : StaticData.DeleteFailed); ; + } + + public decimal GetExchangeRateByMonth(string month) + { + //var rate = _exchangeRateRepository.FindSingleOrDefault(u => u.YearMonth.Equals(month)); + //if (rate == null) + //{ + // return 0; + //} + //return rate.Rate; + + var rate = _exchangeRateRepository.GetAll().FirstOrDefault(t => t.YearMonth == month); + if (rate == null) + { + return 0; + } + return rate.Rate; + } + + public PageOutput GetExchangeRateList(ExchangeRateQueryDTO queryParam) + { + + Expression> exchangeRateLambda = x => true; + if (queryParam.SearchMonth != null) + { + var yearMonth = queryParam.SearchMonth?.ToString("yyyy-MM"); + exchangeRateLambda = exchangeRateLambda.And(o => o.YearMonth == yearMonth); + } + var exchangeRateQueryable = _exchangeRateRepository.GetAll().Where(exchangeRateLambda).ProjectTo(_mapper.ConfigurationProvider); + + exchangeRateQueryable = exchangeRateQueryable.OrderByDescending("YearMonth"); + int count = exchangeRateQueryable.Count(); + exchangeRateQueryable = exchangeRateQueryable.Skip((queryParam.PageIndex - 1) * queryParam.PageSize) + .Take(queryParam.PageSize); + var list = exchangeRateQueryable.ToList(); + + return new PageOutput(queryParam.PageIndex, queryParam.PageSize, count, list); + + } + } +} diff --git a/IRaCIS.Core.Application/Financial/FinancialService.cs b/IRaCIS.Core.Application/Financial/FinancialService.cs new file mode 100644 index 0000000..d4d0ff2 --- /dev/null +++ b/IRaCIS.Core.Application/Financial/FinancialService.cs @@ -0,0 +1,1286 @@ +using AutoMapper; +using AutoMapper.QueryableExtensions; +using IRaCIS.Application.ExpressionExtend; +using IRaCIS.Application.Interfaces; +using IRaCIS.Application.ViewModels; +using IRaCIS.Application.ViewModels.Pay; +using IRaCIS.Core.Application.Contracts.RequestAndResponse; +using IRaCIS.Core.Domain.Share; +using IRaCIS.Infra.Data.ExpressionExtend; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Expressions; +using IRaCIS.Core.Domain.Interfaces; +using IRaCIS.Core.Domain.Models; + +namespace IRaCIS.Application.Services +{ + public class FinancialService : IPaymentService + { + private readonly IPaymentRepository _paymentRepository; + private readonly IReviewerPayInfoRepository _doctorPayInfoRepository; + private readonly ITrialRepository _trialRepository; + private readonly IDoctorRepository _doctorRepository; + private readonly IRankPriceRepository _rankPriceRepository; + private readonly IPaymentDetailRepository _paymentDetailRepository; + private readonly ICRORepository _croRepository; + private readonly IWorkloadRepository _workloadRepository; + private readonly ITrialRevenuesPriceRepository _trialRevenuePriceRepository; + private readonly IPaymentAdjustmentRepository _payAdjustmentRepository; + private readonly IEnrollRepository _enrollRepository; + private readonly ITrialPaymentPriceRepository _TrialPaymentPriceRepository; + private readonly IMapper _mapper; + + + public FinancialService(IPaymentRepository costStatisticsRepository, + IReviewerPayInfoRepository doctorPayInfoRepository, + ITrialRepository trialRepository, + IDoctorRepository doctorRepository, + IRankPriceRepository rankPriceRepository, + IPaymentDetailRepository costStatisticsDetailRepository, + ICRORepository croCompanyRepository, + IWorkloadRepository workloadRepository, + ITrialRevenuesPriceRepository trialCostRepository, + IEnrollRepository enrollRepository, + ITrialPaymentPriceRepository trialPaymentPriceRepository, + IPaymentAdjustmentRepository costAdjustmentRepository, IMapper mapper + ) + { + _TrialPaymentPriceRepository = trialPaymentPriceRepository; + _enrollRepository = enrollRepository; + _paymentRepository = costStatisticsRepository; + _doctorPayInfoRepository = doctorPayInfoRepository; + _trialRepository = trialRepository; + _doctorRepository = doctorRepository; + _rankPriceRepository = rankPriceRepository; + _paymentDetailRepository = costStatisticsDetailRepository; + _croRepository = croCompanyRepository; + _workloadRepository = workloadRepository; + _trialRevenuePriceRepository = trialCostRepository; + _payAdjustmentRepository = costAdjustmentRepository; + _mapper = mapper; + } + + /// + /// Financials /MonthlyPayment 列表查询接口 + /// + public PageOutput GetMonthlyPaymentList(MonthlyPaymentQueryDTO queryParam) + { + //var year = queryParam.StatisticsDate.Year; + //var month = queryParam.StatisticsDate.Month; + //var searchBeginDateTime = queryParam.StatisticsDate; + //Expression> workloadLambda = t => t.DataFrom == (int)WorkLoadFromStatus.FinalConfirm; + //workloadLambda = workloadLambda.And(t => + // t.WorkTime >= queryParam.StatisticsDate && t.WorkTime <= queryParam.StatisticsDate); + //var rate = _exchangeRateRepository.FindSingleOrDefault(u => u.YearMonth == yearMonth); + //var exchangeRate = rate == null ? 0 : rate.Rate; + + var yearMonth = queryParam.StatisticsDate.ToString("yyyy-MM"); + + Expression> doctorLambda = x => true; + if (!string.IsNullOrWhiteSpace(queryParam.KeyWord)) + { + var reviewer = queryParam.KeyWord.Trim(); + doctorLambda = doctorLambda.And(u => u.ChineseName.Contains(reviewer) + || u.FirstName.Contains(reviewer) + || u.LastName.Contains(reviewer) + || u.Code.Contains(reviewer)); + } + + if (queryParam.Nation != null) + { + doctorLambda = doctorLambda.And(u => u.Nation == queryParam.Nation); + } + + var costStatisticsQueryable = + + from monthlyPayment in _paymentRepository.GetAll().Where(t => t.YearMonth == yearMonth) + join payInfo in _doctorPayInfoRepository.GetAll() on monthlyPayment.DoctorId equals payInfo.DoctorId + into cc + from payInfo in cc.DefaultIfEmpty() + join doctor in _doctorRepository.GetAll().Where(doctorLambda) on monthlyPayment.DoctorId equals doctor.Id + join rankPrice in _rankPriceRepository.GetAll() on payInfo.RankId equals rankPrice.Id into dd + from rankPriceItem in dd.DefaultIfEmpty() + select new PaymentViewModel() + { + Id = monthlyPayment.Id, + DoctorId = monthlyPayment.DoctorId, + YearMonth = monthlyPayment.YearMonth, + PaymentUSD = monthlyPayment.PaymentUSD, + CalculateTime = monthlyPayment.CalculateTime, + CalculateUser = monthlyPayment.CalculateUser, + IsLock = monthlyPayment.IsLock, + ExchangeRate = monthlyPayment.ExchangeRate, + PaymentCNY = monthlyPayment.PaymentCNY, + AdjustPaymentCNY = monthlyPayment.AdjustmentCNY, + AdjustPaymentUSD = monthlyPayment.AdjustmentUSD, + + TotalPaymentCNY = monthlyPayment.AdjustmentCNY + monthlyPayment.PaymentCNY, + TotalPaymentUSD = monthlyPayment.AdjustmentUSD + monthlyPayment.PaymentUSD, + + + Code = doctor.Code, + FirstName = doctor.FirstName, + LastName = doctor.LastName, + ChineseName = doctor.ChineseName, + Phone = doctor.Phone, + DoctorNameInBank = payInfo.DoctorNameInBank, + RankName = rankPriceItem.RankName, + IDCard = payInfo.IDCard, + BankCardNumber = payInfo.BankCardNumber, + BankName = payInfo.BankName + }; + + var propName = string.IsNullOrWhiteSpace(queryParam.SortField) ? "Code" : queryParam.SortField; + costStatisticsQueryable = queryParam.Asc ? costStatisticsQueryable.OrderBy(propName).ThenBy(u => u.Code) + : costStatisticsQueryable.OrderByDescending(propName).ThenBy(u => u.Code); + var count = costStatisticsQueryable.Count(); + costStatisticsQueryable = costStatisticsQueryable.Skip((queryParam.PageIndex - 1) * queryParam.PageSize).Take(queryParam.PageSize); + var costStatisticsList = costStatisticsQueryable.ToList(); + + + #region 增加调整费用总计字段之前 + //var doctorIds = costStatisticsList.Select(t => t.DoctorId).ToList(); + + //var adjList = _payAdjustmentRepository.GetAll() + // .Where(t => t.YearMonth == yearMonth && doctorIds.Contains(t.ReviewerId)) + // .GroupBy(t => t.ReviewerId).Select(g => new + // { + // ReviewerId = g.Key, + // AdjustPaymentCNY = g.Sum(t => t.AdjustPaymentCNY), + // AdjustPaymentUSD = g.Sum(t => t.AdjustPaymentUSD) + // }).ToList(); + + //costStatisticsList.ForEach(t => + //{ + // var tempAdj = adjList.FirstOrDefault(u => u.ReviewerId == t.DoctorId); + // if (tempAdj != null) + // { + // t.AdjustPaymentUSD = tempAdj.AdjustPaymentUSD; + // t.AdjustPaymentCNY = tempAdj.AdjustPaymentCNY; + + // } + //}); + + + #endregion + + return new PageOutput(queryParam.PageIndex, queryParam.PageSize, count, costStatisticsList); + } + + /// + /// Financials / MonthlyPaymentDetail 详情查询接口 + /// + public PayDetailDTO GetMonthlyPaymentDetailList(Guid paymentId, Guid reviewerId, DateTime yearMonth) + { + var returnModel = new PayDetailDTO(); + var yearMonthStr = yearMonth.ToString("yyyy-MM"); + + List detailList = new List(); + //有详细表的数据 先查出来 + if (paymentId != Guid.Empty) + { + + //from enroll in _enrollRepository.Where(t => t.TrialId == challengeQuery.TrialId) + //join dociorc in _doctorRepository.Where() on enroll.DoctorId equals dociorc.Id + //join price in _TrialPaymentPriceRepository.Where() on enroll.TrialId equals price.TrialId + + + //select new EnrollViewModel() + //{ + // ChineseName = dociorc.ChineseName, + // AdjustmentMultiple = enroll.AdjustmentMultiple, + // FirstName = dociorc.FirstName, + // LastName = dociorc.LastName, + // DoctorId = dociorc.Id, + // TrialId = challengeQuery.TrialId + + //}; + //detailList = _paymentDetailRepository.AsQueryable() + // .Where(t => t.PaymentId == paymentId) + // .OrderBy(t => t.ShowCodeOrder).ThenBy(t => t.ShowTypeOrder).ProjectTo(_mapper.ConfigurationProvider).ToList(); + + + detailList =(from pay in _paymentDetailRepository.GetAll().Where(t => t.PaymentId == paymentId) + join enroll in _enrollRepository.GetAll() on new { pay.DoctorId, pay.TrialId } equals new { enroll.DoctorId, enroll.TrialId } + join price in _TrialPaymentPriceRepository.GetAll() on pay.TrialId equals price.TrialId + orderby pay.ShowCodeOrder + orderby pay.ShowTypeOrder + select new PaymentDetailDTO() + { + Id = pay.Id, + ShowCodeOrder = pay.ShowCodeOrder, + ShowTypeOrder = pay.ShowTypeOrder, + PaymentUSD = pay.PaymentUSD, + BasePrice = pay.BasePrice, + PersonalAdditional = pay.PersonalAdditional, + TrialAdditional = pay.TrialAdditional, + TrialCode = pay.TrialCode, + PaymentCNY = pay.PaymentCNY, + DoctorId = pay.DoctorId, + ExchangeRate = pay.ExchangeRate, + IsNewTrial = price.IsNewTrial, + NewPersonalAdditional = enroll.AdjustmentMultiple, + + }).ToList(); + + } + //费用调整 + //_payAdjustmentRepository.Where(t => t.YearMonth == yearMonthStr && t.ReviewerId == reviewerId) + var adjList = + (from costAdjustment in _payAdjustmentRepository.GetAll().Where(t => t.YearMonth == yearMonthStr && t.ReviewerId == paymentId) + join enroll in _enrollRepository.GetAll()on new { costAdjustment.ReviewerId, costAdjustment.TrialId } equals new { ReviewerId = enroll.DoctorId, enroll.TrialId } + join price in _TrialPaymentPriceRepository.GetAll() on costAdjustment.TrialId equals price.TrialId + + + select new PaymentDetailDTO() + { + Id = costAdjustment.Id, + TrialCode = "Adjustment", + PaymentCNY = costAdjustment.AdjustmentCNY, + PaymentUSD = costAdjustment.AdjustmentUSD, + DoctorId = costAdjustment.ReviewerId, + ExchangeRate = costAdjustment.ExchangeRate, + AdjustmentView = new AdjustmentDTO() + { + AdjustPaymentUSD = costAdjustment.AdjustmentUSD, + AdjustPaymentCNY = costAdjustment.AdjustmentCNY, + Note = costAdjustment.Note + }, + IsNewTrial = price.IsNewTrial, + NewPersonalAdditional = enroll.AdjustmentMultiple, + + }).ToList(); + + + + + detailList.AddRange(adjList); + + detailList.ForEach(x => + { + x.PersonalAdditional = x.IsNewTrial == true && x.NewPersonalAdditional != null ? 0 : x.PersonalAdditional; + x.TrialAdditional = x.IsNewTrial == true && x.NewPersonalAdditional != null ? 0 : x.TrialAdditional; + x.BasePrice = x.IsNewTrial == true && x.NewPersonalAdditional != null ? x.NewPersonalAdditional.Value : x.BasePrice; + + }); + + returnModel.DetailList = detailList; + + + + var doctorId = returnModel.DetailList.FirstOrDefault()?.DoctorId; + var query = from doctor in _doctorRepository.GetAll() + .Where(t => t.Id == doctorId) + join payInfo in _doctorPayInfoRepository.GetAll() on doctor.Id equals payInfo.DoctorId + join rank in _rankPriceRepository.GetAll() on payInfo.RankId equals rank.Id + select new DoctorPayInfo() + { + Code = doctor.ReviewerCode, + ChineseName = doctor.ChineseName, + FirstName = doctor.FirstName, + LastName = doctor.LastName, + Phone = doctor.Phone, + DoctorId = doctor.Id, + PayTitle = rank.RankName, + YearMonth = yearMonthStr + }; + + returnModel.DoctorInfo = query.FirstOrDefault(); + + return returnModel; + } + + + public List GetReviewersMonthlyPaymentDetail(List manyReviewers) + { + List result = new List(); + + manyReviewers.ForEach(t => result.Add(GetMonthlyPaymentDetailList(t.PaymentId, t.ReviewerId, t.YearMonth))); + + return result; + + } + + + /// + /// Financials / Payment History 列表查询接口 + /// + public PageOutput GetPaymentHistoryList(PaymentQueryDTO queryParam) + { + Expression> doctorLambda = x => true; + if (!string.IsNullOrWhiteSpace(queryParam.Reviewer)) + { + var reviewer = queryParam.Reviewer.Trim(); + doctorLambda = doctorLambda.And(u => u.ChineseName.Contains(reviewer) + || u.FirstName.Contains(reviewer) + || u.LastName.Contains(reviewer) + || u.Code.Contains(reviewer)); + } + if (queryParam.Nation != null) + { + doctorLambda = doctorLambda.And(u => u.Nation == queryParam.Nation); + } + + Expression> paymentLambda = x => x.IsLock && x.YearMonthDate >= queryParam.BeginMonth && x.YearMonthDate <= queryParam.EndMonth; + + #region 在 payment表加 调整总计前 + + //var paymentQueryable = _paymentRepository.GetAll().Where(paymentLambda) + // .Select( + // t => new + // { + // ReviewerId = t.DoctorId, + // t.YearMonth, + // t.PaymentUSD, + // t.PaymentCNY, + // t.AdjustPaymentCNY, + // t.AdjustPaymentUSD + // }); + + //Expression> payAdjustmentLambda = x => x.IsLock && x.AdjustedYearMonth >= param.BeginMonth && x.AdjustedYearMonth <= param.EndMonth; + + //var adjQueryable = _payAdjustmentRepository.GetAll() + // .Where(payAdjustmentLambda) + // .GroupBy(t => new { t.ReviewerId, t.YearMonth }).Select(g => new + // { + // g.Key.ReviewerId, + // g.Key.YearMonth, + // PaymentUSD = 0, + // PaymentCNY = 0, + // AdjustPaymentCNY = g.Sum(t => t.AdjustPaymentCNY), + // AdjustPaymentUSD = g.Sum(t => t.AdjustPaymentUSD) + // }); + + //var query = from pay in (from paymentCost in paymentQueryable + // join adjCost in adjQueryable on new { paymentCost.YearMonth, paymentCost.ReviewerId } equals new { adjCost.YearMonth, adjCost.ReviewerId } into a + // from adjCost in a.DefaultIfEmpty() + // select new + // { + // paymentCost.ReviewerId, + // paymentCost.PaymentUSD, + // paymentCost.PaymentCNY, + // AdjustmentCNY = adjCost == null ? 0 : adjCost.AdjustPaymentCNY, + // AdjustmentUSD = adjCost == null ? 0 : adjCost.AdjustPaymentUSD + // } + // ).Union( + // from adjCost in adjQueryable + // join paymentCost in paymentQueryable on new { adjCost.YearMonth, adjCost.ReviewerId } equals new { paymentCost.YearMonth, paymentCost.ReviewerId } into a + // from paymentCost in a.DefaultIfEmpty() + // select new + // { + // ReviewerId = adjCost.ReviewerId, + // PaymentUSD = paymentCost == null ? 0 : paymentCost.PaymentUSD, + // PaymentCNY = paymentCost == null ? 0 : paymentCost.PaymentCNY, + // AdjustmentCNY = adjCost.AdjustPaymentCNY, + // AdjustmentUSD = adjCost.AdjustPaymentUSD + // } + // ) + + #endregion + + var query = from monthlyPay in _paymentRepository.GetAll().Where(paymentLambda) + .GroupBy(t => t.DoctorId).Select(g => new + { + ReviewerId = g.Key, + PaymentUSD = g.Sum(u => u.PaymentUSD), + PaymentCNY = g.Sum(u => u.PaymentCNY), + AdjustmentCNY = g.Sum(u => u.AdjustmentCNY), + AdjustmentUSD = g.Sum(u => u.AdjustmentCNY) + }) + join doctor in _doctorRepository.Find(doctorLambda) on monthlyPay.ReviewerId equals doctor.Id + select new MonthlyPaymentDTO + { + ReviewerId = doctor.Id, + ChineseName = doctor.ChineseName, + FirstName = doctor.FirstName, + LastName = doctor.LastName, + ReviewerCode = doctor.Code, + PaymentUSD = monthlyPay.PaymentUSD, + PaymentCNY = monthlyPay.PaymentCNY, + AdjustmentCNY = monthlyPay.AdjustmentCNY, + AdjustmentUSD = monthlyPay.AdjustmentUSD, + TotalCNY = monthlyPay.AdjustmentCNY + monthlyPay.PaymentCNY, + TotalUSD = monthlyPay.AdjustmentUSD + monthlyPay.PaymentUSD + }; + var propName = queryParam.SortField == string.Empty ? "ReviewerCode" : queryParam.SortField; + query = queryParam.Asc ? query.OrderBy(propName).ThenBy(u => u.ReviewerCode) : query.OrderByDescending(propName).ThenBy(u => u.ReviewerCode); + if (propName == "FirstName" || propName == "LastName") + { + query = queryParam.Asc ? query.OrderBy(t => t.LastName).ThenBy(t => t.FirstName) + : query.OrderByDescending(t => t.LastName).ThenBy(t => t.FirstName); + } + var count = query.Count(); + query = query.Skip((queryParam.PageIndex - 1) * queryParam.PageSize).Take(queryParam.PageSize); + var list = query.ToList(); + return new PageOutput(queryParam.PageIndex, queryParam.PageSize, count, list); + + } + + /// + /// Financials / Payment History 详情接口 + /// + public List GetPaymentHistoryDetailList(VolumeQueryDTO param) + { + var beginDate = new DateTime(param.BeginMonth.Year, param.BeginMonth.Month, 1); + var endDate = new DateTime(param.EndMonth.Year, param.EndMonth.Month, 1); + + Expression> monthlyPayLambda = x => x.IsLock && x.DoctorId == param.ReviewerId && x.YearMonthDate >= beginDate && x.YearMonthDate <= endDate; + + var query = + from monthlyPayment in _paymentRepository.Find(monthlyPayLambda) + + select new VolumeStatisticsDTO + { + StatisticsId = monthlyPayment.Id, + Month = monthlyPayment.YearMonth, + ExchangeRate = monthlyPayment.ExchangeRate, + PaymentUSD = monthlyPayment.PaymentUSD, + PaymentCNY = monthlyPayment.PaymentCNY, + AdjustmentCNY = monthlyPayment.AdjustmentCNY, + AdjustmentUSD = monthlyPayment.AdjustmentUSD, + VolumeReward = 0 + }; + + var payDetailList = query.OrderBy(t => t.Month).ToList(); + + List statisticsIdList = payDetailList.Select(t => t.StatisticsId).ToList(); + + var monthlyPayDetailList = _paymentDetailRepository.Find(u => + statisticsIdList.Contains(u.PaymentId)).Select(t => new + { + PaymentId = t.PaymentId, + t.PaymentUSD, + t.TrialCode, + t.PaymentCNY, + t.YearMonth + }).ToList(); + + payDetailList.ForEach(t => + { + t.VolumeReward = monthlyPayDetailList + .Where(u => u.PaymentId == t.StatisticsId && u.TrialCode == "Volume Reward") + .Sum(k => k.PaymentUSD); + + t.TrialPaymentList = monthlyPayDetailList + .Where(u => u.PaymentId == t.StatisticsId && u.TrialCode != "Volume Reward" && u.YearMonth == t.Month) + .GroupBy(u => u.TrialCode).Select(g => new TrialPaymentDTO + { + TrialPayment = g.Sum(k => k.PaymentUSD), + TrialCode = g.Key + }).ToList(); + }); + + + #region 改表之前 + + //var tempVolume = _costStatisticsDetailRepository.Find(u => + // statisticsIdList.Contains(u.PaymentId)).ToList(); + + //foreach (var item in payDetailList) + //{ + // var temp = tempVolume.Where(u => u.PaymentId == item.StatisticsId && u.TrialCode == "Volume Reward"); + // var Volume = 0.0; + // foreach (var t in temp) + // { + // Volume += (t.BasePrice * t.Count); + // } + // item.VolumeReward = Volume; + + // var trialCodes = tempVolume.Where(u => u.PaymentId == item.StatisticsId + // && u.TrialCode != "Volume Reward").GroupBy(u => u.TrialCode).Select(u => u.Key).Distinct(); + + // foreach (var trial in trialCodes) + // { + // var trialFee = 0.0; + // var aa = tempVolume.Where(u => u.PaymentId == item.StatisticsId && u.TrialCode == trial + // ).ToList(); + + // foreach (var a in aa) + // { + // trialFee += (a.Count * (a.BasePrice + a.PersonalAdditional + a.TrialAdditional)); + // } + // item.TrialFeeList.Add(new TrialFeeViewModel + // { + // TrialCode = trial, + // TrialFee = trialFee + // }); + // } + + //} + + #endregion + + return payDetailList; + } + + /// + /// Financials / Revenues 列表查询接口 + /// + public PageOutput GetRevenuesList(StatisticsQueryDTO queryParam) + { + var bDate = new DateTime(queryParam.BeginDate.Year, queryParam.BeginDate.Month, 1); + var eDate = new DateTime(queryParam.EndDate.Year, queryParam.EndDate.Month, 1); + Expression> workloadLambda = x => x.DataFrom == (int)WorkLoadFromStatus.FinalConfirm; + workloadLambda = workloadLambda.And(x => x.WorkTime >= bDate && x.WorkTime <= eDate); + + Expression> trialLambda = x => true; + if (Guid.Empty != queryParam.CroId && queryParam.CroId != null) + { + trialLambda = trialLambda.And(u => u.CROId == queryParam.CroId); + } + if (!string.IsNullOrWhiteSpace(queryParam.TrialCode)) + { + var trialCode = queryParam.TrialCode.Trim(); + trialLambda = trialLambda.And(u => u.Code.Contains(trialCode)); + } + + if (queryParam.AttendedReviewerType != null) + { + trialLambda = trialLambda.And(u => u.AttendedReviewerType == queryParam.AttendedReviewerType); + } + + Expression> doctorLambda = x => true; + + if (!string.IsNullOrWhiteSpace(queryParam.Reviewer)) + { + var reviewer = queryParam.Reviewer.Trim(); + doctorLambda = doctorLambda.And(u => u.ChineseName.Contains(reviewer) + || u.FirstName.Contains(reviewer) + || u.LastName.Contains(reviewer) + || u.Code.Contains(reviewer)); + } + if (queryParam.Nation != null) + { + doctorLambda = doctorLambda.And(u => u.Nation == queryParam.Nation); + } + + List incomeList = new List(); + IQueryable query = default; + var propName = string.Empty; + var count = 0; + + #region 按照详细维度 ReviewId TrialId + + if (queryParam.StatType == 0) + { + query = from workLoad in _workloadRepository.GetAll().Where(workloadLambda) + join doctor in _doctorRepository.Find(doctorLambda) + on workLoad.DoctorId equals doctor.Id + join trial in _trialRepository.Find(trialLambda) + on workLoad.TrialId equals trial.Id + join cro in _croRepository.GetAll() on trial.CROId equals cro.Id into ttt + from croItem in ttt.DefaultIfEmpty() + join trialCost in _trialRevenuePriceRepository.GetAll() on workLoad.TrialId equals trialCost.TrialId into c + from trialCost in c.DefaultIfEmpty() + select new RevenuesDTO + { + + TrialId = workLoad.TrialId, + Cro = croItem.CROName, + ReviewerCode = doctor.Code, + ChineseName = doctor.ChineseName, + FirstName = doctor.FirstName, + LastName = doctor.LastName, + + Indication = trial.Indication, + TrialCode = trial.Code, + Expedited = trial.Expedited, + CroId = trial.CROId, + + Downtime = workLoad.Downtime * trialCost.Downtime, + Training = workLoad.Training * trialCost.Training, + Timepoint = workLoad.Timepoint * trialCost.Timepoint, + TimepointIn24H = workLoad.TimepointIn24H * trialCost.TimepointIn24H, + TimepointIn48H = workLoad.TimepointIn48H * trialCost.TimepointIn48H, + Global = workLoad.Global * trialCost.Global, + Adjudication = workLoad.Adjudication * trialCost.Adjudication, + AdjudicationIn24H = + workLoad.AdjudicationIn24H * trialCost.AdjudicationIn24H, + AdjudicationIn48H = workLoad.AdjudicationIn48H * trialCost.AdjudicationIn48H, + + YearMonth = workLoad.YearMonth, + + Total = (workLoad.Downtime * trialCost.Downtime + + workLoad.Training * trialCost.Training + + workLoad.Timepoint * trialCost.Timepoint + + workLoad.TimepointIn24H * trialCost.TimepointIn24H + + workLoad.TimepointIn48H * trialCost.TimepointIn48H + + workLoad.Global * trialCost.Global + + workLoad.Adjudication * trialCost.Adjudication + + workLoad.AdjudicationIn24H * trialCost.AdjudicationIn24H + + workLoad.AdjudicationIn48H * trialCost.AdjudicationIn48H + + workLoad.RefresherTraining * trialCost.RefresherTraining + ) + + }; + + //处理排序字段 + propName = queryParam.SortField == "" ? "ReviewerCode" : queryParam.SortField; + + } + //按照项目维度 + if (queryParam.StatType == 1) + { + + var workloadQuery = from workLoad in _workloadRepository.GetAll().Where(workloadLambda) + + group workLoad by workLoad.TrialId + into gWorkLoad + select new + { + TrialId = gWorkLoad.Key, + Downtime = gWorkLoad.Sum(t => t.Downtime), + Training = gWorkLoad.Sum(t => t.Training), + Timepoint = gWorkLoad.Sum(t => t.Timepoint), + TimepointIn24H = gWorkLoad.Sum(t => t.TimepointIn24H), + TimepointIn48H = gWorkLoad.Sum(t => t.TimepointIn48H), + Global = gWorkLoad.Sum(t => t.Global), + Adjudication = gWorkLoad.Sum(t => t.Adjudication), + AdjudicationIn24H = gWorkLoad.Sum(t => t.AdjudicationIn24H), + AdjudicationIn48H = gWorkLoad.Sum(t => t.AdjudicationIn48H), + RefresherTraining = gWorkLoad.Sum(t => t.RefresherTraining), + }; + + query = from workLoad in workloadQuery + join trialCost in _trialRevenuePriceRepository.GetAll() on workLoad.TrialId equals trialCost.TrialId + into c + from trialCost in c.DefaultIfEmpty() + join trial in _trialRepository.Find(trialLambda) on workLoad.TrialId equals trial.Id + join cro in _croRepository.GetAll() on trial.CROId equals cro.Id into ttt + from croItem in ttt.DefaultIfEmpty() + select new RevenuesDTO + { + + TrialId = trial.Id, + Indication = trial.Indication, + TrialCode = trial.Code, + Expedited = trial.Expedited, + CroId = trial.CROId, + Cro = croItem.CROName, + Training = workLoad.Training * trialCost.Training, + Timepoint = workLoad.Timepoint * trialCost.Timepoint, + TimepointIn24H = workLoad.TimepointIn24H * trialCost.TimepointIn24H, + TimepointIn48H = workLoad.TimepointIn48H * trialCost.TimepointIn48H, + Adjudication = workLoad.Adjudication * trialCost.Adjudication, + AdjudicationIn24H = workLoad.AdjudicationIn24H * trialCost.AdjudicationIn24H, + AdjudicationIn48H = workLoad.AdjudicationIn48H * trialCost.AdjudicationIn48H, + Global = workLoad.Global * trialCost.Global, + Downtime = workLoad.Downtime * trialCost.Downtime, + + Total = (workLoad.Downtime * trialCost.Downtime + + workLoad.Training * trialCost.Training + + workLoad.Timepoint * trialCost.Timepoint + + workLoad.TimepointIn24H * trialCost.TimepointIn24H + + workLoad.TimepointIn48H * trialCost.TimepointIn48H + + workLoad.Global * trialCost.Global + + workLoad.Adjudication * trialCost.Adjudication + + workLoad.AdjudicationIn24H * trialCost.AdjudicationIn24H + + workLoad.AdjudicationIn48H * trialCost.AdjudicationIn48H + + workLoad.RefresherTraining * trialCost.RefresherTraining + ) + }; + + //处理排序字段 + propName = queryParam.SortField == "" ? "TrialCode" : queryParam.SortField; + + } + + //按照人的维度 + if (queryParam.StatType == 2) + { + var workloadQuery = from workLoad in _workloadRepository.GetAll().Where(workloadLambda) + join doctor in _doctorRepository.Find(doctorLambda) + on workLoad.DoctorId equals doctor.Id + join trial in _trialRepository.Find(trialLambda) on workLoad.TrialId equals trial.Id + join trialCost in _trialRevenuePriceRepository.GetAll() on workLoad.TrialId equals trialCost.TrialId into c + from trialCost in c.DefaultIfEmpty() + + select new + { + DoctorId = workLoad.DoctorId, + Downtime = workLoad.Downtime * trialCost.Downtime, + Training = workLoad.Training * trialCost.Training, + Timepoint = workLoad.Timepoint * trialCost.Timepoint, + TimepointIn24H = workLoad.TimepointIn24H * trialCost.TimepointIn24H, + TimepointIn48H = workLoad.TimepointIn48H * trialCost.TimepointIn48H, + Global = workLoad.Global * trialCost.Global, + Adjudication = workLoad.Adjudication * trialCost.Adjudication, + AdjudicationIn24H = + workLoad.AdjudicationIn24H * trialCost.AdjudicationIn24H, + AdjudicationIn48H = workLoad.AdjudicationIn48H * trialCost.AdjudicationIn48H, + RefresherTraining = workLoad.RefresherTraining * trialCost.RefresherTraining, + ReviewerCode = doctor.Code, + ChineseName = doctor.ChineseName, + FirstName = doctor.FirstName, + LastName = doctor.LastName, + + }; + + + query = workloadQuery.GroupBy(t => new { t.DoctorId, t.ReviewerCode, t.ChineseName, t.FirstName, t.LastName }).Select(gWorkLoad => new RevenuesDTO + { + ReviewerCode = gWorkLoad.Key.ReviewerCode, + ChineseName = gWorkLoad.Key.ChineseName, + FirstName = gWorkLoad.Key.FirstName, + LastName = gWorkLoad.Key.LastName, + + Downtime = gWorkLoad.Sum(t => t.Downtime), + Training = gWorkLoad.Sum(t => t.Training), + Timepoint = gWorkLoad.Sum(t => t.Timepoint), + TimepointIn24H = gWorkLoad.Sum(t => t.TimepointIn24H), + TimepointIn48H = gWorkLoad.Sum(t => t.TimepointIn48H), + Global = gWorkLoad.Sum(t => t.Global), + Adjudication = gWorkLoad.Sum(t => t.Adjudication), + AdjudicationIn24H = gWorkLoad.Sum(t => t.AdjudicationIn24H), + AdjudicationIn48H = gWorkLoad.Sum(t => t.AdjudicationIn48H), + + Total = gWorkLoad.Sum(t => t.Downtime) + + gWorkLoad.Sum(t => t.Training) + + gWorkLoad.Sum(t => t.Timepoint) + + gWorkLoad.Sum(t => t.TimepointIn24H) + + gWorkLoad.Sum(t => t.TimepointIn48H) + + gWorkLoad.Sum(t => t.Global) + + gWorkLoad.Sum(t => t.Adjudication) + + gWorkLoad.Sum(t => t.AdjudicationIn24H) + + gWorkLoad.Sum(t => t.AdjudicationIn48H) + + gWorkLoad.Sum(t => t.RefresherTraining) + + }); + + propName = queryParam.SortField == string.Empty ? "ReviewerCode" : queryParam.SortField; + + + } + + //按照月份维度 + if (queryParam.StatType == 3) + { + var workloadQuery = from workLoad in _workloadRepository.GetAll().Where(workloadLambda) + join trial in _trialRepository.Find(trialLambda) + on workLoad.TrialId equals trial.Id + join doctor in _doctorRepository.Find(doctorLambda) + on workLoad.DoctorId equals doctor.Id + join trialCost in _trialRevenuePriceRepository.GetAll() on workLoad.TrialId equals trialCost.TrialId into c + from trialCost in c.DefaultIfEmpty() + + select new + { + workLoad.YearMonth, + Downtime = workLoad.Downtime * trialCost.Downtime, + Training = workLoad.Training * trialCost.Training, + Timepoint = workLoad.Timepoint * trialCost.Timepoint, + TimepointIn24H = workLoad.TimepointIn24H * trialCost.TimepointIn24H, + TimepointIn48H = workLoad.TimepointIn48H * trialCost.TimepointIn48H, + Global = workLoad.Global * trialCost.Global, + Adjudication = workLoad.Adjudication * trialCost.Adjudication, + AdjudicationIn24H = + workLoad.AdjudicationIn24H * trialCost.AdjudicationIn24H, + AdjudicationIn48H = workLoad.AdjudicationIn48H * trialCost.AdjudicationIn48H, + RefresherTraining = workLoad.RefresherTraining * trialCost.RefresherTraining, + + }; + + query = workloadQuery.GroupBy(t => t.YearMonth).Select(gWorkLoad => new RevenuesDTO + { + + YearMonth = gWorkLoad.Key, + Downtime = gWorkLoad.Sum(t => t.Downtime), + Training = gWorkLoad.Sum(t => t.Training), + Timepoint = gWorkLoad.Sum(t => t.Timepoint), + TimepointIn24H = gWorkLoad.Sum(t => t.TimepointIn24H), + TimepointIn48H = gWorkLoad.Sum(t => t.TimepointIn48H), + Global = gWorkLoad.Sum(t => t.Global), + Adjudication = gWorkLoad.Sum(t => t.Adjudication), + AdjudicationIn24H = gWorkLoad.Sum(t => t.AdjudicationIn24H), + AdjudicationIn48H = gWorkLoad.Sum(t => t.AdjudicationIn48H), + Total = gWorkLoad.Sum(t => t.Downtime) + + gWorkLoad.Sum(t => t.Training) + + gWorkLoad.Sum(t => t.Timepoint) + + gWorkLoad.Sum(t => t.TimepointIn24H) + + gWorkLoad.Sum(t => t.TimepointIn48H) + + gWorkLoad.Sum(t => t.Global) + + gWorkLoad.Sum(t => t.Adjudication) + + gWorkLoad.Sum(t => t.AdjudicationIn24H) + + gWorkLoad.Sum(t => t.AdjudicationIn48H) + + gWorkLoad.Sum(t => t.RefresherTraining) + + }); + propName = queryParam.SortField == string.Empty ? "YearMonth" : queryParam.SortField; + } + + + #endregion + //if (propName == "FirstName" || propName == "LastName") + //{ + // query = param.Asc + // ? query.OrderBy(t => t.LastName).ThenBy(t => t.FirstName) + // : query.OrderByDescending(t => t.LastName).ThenBy(t => t.FirstName); + //} + + //非详细 只用单字段排序 + if (queryParam.StatType != 0) + { + query = queryParam.Asc ? query.OrderBy(propName) : query.OrderByDescending(propName); + } + //详情 多字段排序 + if (queryParam.StatType == 0) + { + query = queryParam.Asc ? query.OrderBy(propName).ThenBy(t => t.TrialId).ThenBy(t => t.YearMonth).ThenBy(t => t.ReviewerCode) : + query.OrderByDescending(propName).ThenBy(t => t.TrialId).ThenBy(t => t.YearMonth).ThenBy(t => t.ReviewerCode) + ; + } + + + count = query.Count(); + query = query.Skip((queryParam.PageIndex - 1) * queryParam.PageSize).Take(queryParam.PageSize); + + incomeList = query.ToList(); + + #region 处理缺失项目价格 按照医生 或者月份维度 + + if (queryParam.StatType == 2 || queryParam.StatType == 3) + { + var hasIncomePriceTrialIds = _trialRevenuePriceRepository.GetAll().Select(t => t.TrialId).ToList(); + + workloadLambda = workloadLambda.And(t => !hasIncomePriceTrialIds.Contains(t.TrialId)); + var doctorMissingTrialCodesQuery = (from workLoad in _workloadRepository.GetAll().Where(workloadLambda) + join trial in _trialRepository.GetAll() on workLoad.TrialId equals trial.Id + select new + { + DoctorId = workLoad.DoctorId, + Month = workLoad.YearMonth, + TrialCode = trial.Code + }).Distinct(); + + var doctorMissingTrialCodes = (doctorMissingTrialCodesQuery.ToList().GroupBy(t => t.DoctorId).Select(g => new + { + DoctorId = g.Key, + TrialCodes = g.Select(u => u.TrialCode).Distinct().ToList() + })).ToList(); + + var monthMissingTrialCode = (doctorMissingTrialCodesQuery.ToList().GroupBy(t => t.Month).Select(g => new + { + Month = g.Key, + TrialCodes = g.Select(u => u.TrialCode).Distinct().ToList() + })).ToList(); + + incomeList.ForEach(income => + { + var doctor = doctorMissingTrialCodes.FirstOrDefault(t => t.DoctorId == income.Id); + var month = monthMissingTrialCode.FirstOrDefault(t => t.Month == income.YearMonth); + + if (queryParam.StatType == 2) + { + income.MissingTrialCodes = doctor == null ? new List() : doctor.TrialCodes; + } + else + { + income.MissingTrialCodes = month == null ? new List() : month.TrialCodes; + } + }); + } + + if (queryParam.StatType == 0 || queryParam.StatType == 1) + { + incomeList.ForEach(income => + { + List temp = new List(); + + + + if (Math.Abs(income.Total) < 0.001m) + { + temp.Add(income.TrialCode); + income.MissingTrialCodes = temp; + } + + }); + } + #endregion + + return new PageOutput(queryParam.PageIndex, queryParam.PageSize, count, incomeList); + + } + + /// + /// Financials / Analysis 项目维度分析接口 + /// + public List GetTrialAnalysisList(TrialAnalysisQueryDTO param) + { + var bDate = new DateTime(param.BeginDate.Year, param.BeginDate.Month, 1); + var eDate = new DateTime(param.EndDate.Year, param.EndDate.Month, 1); + + Expression> workloadLambda = x => x.DataFrom == (int)WorkLoadFromStatus.FinalConfirm; + + Expression> trialLambda = x => true; + if (Guid.Empty != param.CroId && param.CroId != null) + { + trialLambda = trialLambda.And(u => u.CROId == param.CroId); + } + if (!string.IsNullOrWhiteSpace(param.TrialCode)) + { + var trialCode = param.TrialCode.Trim(); + trialLambda = trialLambda.And(u => u.Code.Contains(trialCode)); + } + if (param.AttendedReviewerType != null) + { + trialLambda = trialLambda.And(u => u.AttendedReviewerType == param.AttendedReviewerType); + } + + var lockedPaymentIdAndYearMonth = _paymentRepository.GetAll().Where(t => t.IsLock && t.YearMonthDate >= bDate && t.YearMonthDate <= eDate).Select(t => new { PaymentId = t.Id, t.YearMonth, t.DoctorId }); + + var costStatisticsIds = lockedPaymentIdAndYearMonth.Select(t => t.PaymentId).ToList(); + + var lockedDoctorIdAndYearMonthQueryable = lockedPaymentIdAndYearMonth.Select(t => new { t.YearMonth, t.DoctorId }); + + + ////工作量过滤查询 锁定得月份 + //workloadLambda = workloadLambda.And(x => lockedDoctorIdAndYearMonthQueryable.Contains()); + + var trialPayQuery = from costStatisticsDetail in _paymentDetailRepository.GetAll() + .Where(t => costStatisticsIds.Contains(t.PaymentId) && t.TrialCode != "Volume Reward") + group costStatisticsDetail by costStatisticsDetail.TrialId + into g + select new + { + TrialId = g.Key, + PaymentUSD = g.Sum(t => t.PaymentUSD) + }; + + + var workloadQuery = from workLoad in _workloadRepository.GetAll().Where(workloadLambda) + join lockedDoctorAndMonth in lockedDoctorIdAndYearMonthQueryable on new { workLoad.DoctorId, YearMonth = workLoad.YearMonth } equals new { lockedDoctorAndMonth.DoctorId, lockedDoctorAndMonth.YearMonth } + group workLoad by workLoad.TrialId + + into gWorkLoad + select new + { + TrialId = gWorkLoad.Key, + Downtime = gWorkLoad.Sum(t => t.Downtime), + Training = gWorkLoad.Sum(t => t.Training), + Timepoint = gWorkLoad.Sum(t => t.Timepoint), + TimepointIn24H = gWorkLoad.Sum(t => t.TimepointIn24H), + TimepointIn48H = gWorkLoad.Sum(t => t.TimepointIn48H), + Global = gWorkLoad.Sum(t => t.Global), + Adjudication = gWorkLoad.Sum(t => t.Adjudication), + AdjudicationIn24H = gWorkLoad.Sum(t => t.AdjudicationIn24H), + AdjudicationIn48H = gWorkLoad.Sum(t => t.AdjudicationIn48H) + + }; + + var workloadIncomeQuery = from workLoad in workloadQuery + join trialCost in _trialRevenuePriceRepository.GetAll() on workLoad.TrialId equals trialCost.TrialId + into c + from trialCost in c.DefaultIfEmpty() + join trial in _trialRepository.Find(trialLambda) on workLoad.TrialId equals trial.Id into t + from trial in t.DefaultIfEmpty() + join cro in _croRepository.GetAll() on trial.CROId equals cro.Id into ttt + from croItem in ttt.DefaultIfEmpty() + select new TrialAnalysisDTO + { + TrialId = trial.Id, + Indication = trial.Indication, + TrialCode = trial.Code, + Expedited = trial.Expedited, + Cro = croItem == null ? "" : croItem.CROName, + + Type = "Trial", + + RevenusUSD = (workLoad.Downtime * trialCost.Downtime) + + (workLoad.Training * trialCost.Training) + + (workLoad.Timepoint * trialCost.Timepoint) + + (workLoad.TimepointIn24H * trialCost.TimepointIn24H) + + (workLoad.TimepointIn48H * trialCost.TimepointIn48H) + + (workLoad.Adjudication * trialCost.Adjudication) + + (workLoad.AdjudicationIn24H * trialCost.AdjudicationIn24H) + + (workLoad.AdjudicationIn48H * trialCost.AdjudicationIn48H) + + (workLoad.Global * trialCost.Global), + + }; + + + var trialPayList = trialPayQuery.OrderBy(t => t.PaymentUSD).ToList(); + var workloadIncomeList = workloadIncomeQuery.ToList(); + var returnList = workloadIncomeList; + returnList.ForEach(t => + { + var pay = trialPayList.FirstOrDefault(u => u.TrialId == t.TrialId); + t.PaymentUSD = pay == null ? 0 : pay.PaymentUSD; + }); + + if ((Guid.Empty == param.CroId || null == param.CroId) && string.IsNullOrWhiteSpace(param.TrialCode)) + { + var volumeReward = _paymentDetailRepository.GetAll() + .Where(t => costStatisticsIds.Contains(t.PaymentId) && t.TrialCode == "Volume Reward") + .Sum(t => (decimal?)t.PaymentUSD) ?? 0; + + var adjustment = _payAdjustmentRepository.GetAll() + .Where(t => t.YearMonthDate >= param.BeginDate + && t.YearMonthDate <= param.EndDate && t.IsLock) + .Sum(u => (decimal?)u.AdjustmentUSD) ?? 0; + + returnList.Add(new TrialAnalysisDTO() + { + Type = "Volume Reward", + RevenusUSD = 0, + PaymentUSD = volumeReward + }); + returnList.Add(new TrialAnalysisDTO() + { + Type = "Adjustment", + RevenusUSD = 0, + PaymentUSD = adjustment + }); + } + return returnList; + } + + /// + /// Financials / Analysis 医生维度分析接口 + /// + public List GetReviewerAnalysisList(AnalysisQueryDTO param) + { + var beginDate = new DateTime(param.BeginDate.Year, param.BeginDate.Month, 1); + var endDate = new DateTime(param.EndDate.Year, param.EndDate.Month, 1); + + Expression> workloadLambda = x => x.DataFrom == (int)WorkLoadFromStatus.FinalConfirm; + + Expression> doctorLambda = x => true; + if (!string.IsNullOrWhiteSpace(param.Reviewer)) + { + var reviewer = param.Reviewer.Trim(); + doctorLambda = doctorLambda.And(u => u.ChineseName.Contains(reviewer) + || u.FirstName.Contains(reviewer) + || u.LastName.Contains(reviewer) + || u.Code.Contains(reviewer)); + } + if (param.Nation != null) + { + doctorLambda = doctorLambda.And(u => u.Nation == param.Nation); + } + + var lockedPaymentIdAndYearMonth = _paymentRepository.GetAll().Where(t => t.IsLock && t.YearMonthDate >= param.BeginDate && t.YearMonthDate <= param.EndDate).Select(t => new { PaymentId = t.Id, t.YearMonth, t.DoctorId }); + + var lockedDoctorIdAndYearMonthQueryable = lockedPaymentIdAndYearMonth.Select(t => new { t.YearMonth, t.DoctorId }); + + + + Expression> monthlyPayLambda = x => x.IsLock && x.YearMonthDate >= beginDate && x.YearMonthDate <= endDate; + var payQuery = + from monthlyPayment in _paymentRepository.Find(monthlyPayLambda) + .GroupBy(t => t.DoctorId).Select(g => new + { + ReviewerId = g.Key, + PaymentUSD = g.Sum(u => u.PaymentUSD), + PaymentCNY = g.Sum(u => u.PaymentCNY), + AdjustmentCNY = g.Sum(u => u.AdjustmentCNY), + AdjustmentUSD = g.Sum(u => u.AdjustmentUSD) + }) + join doctor in _doctorRepository.Find(doctorLambda) on monthlyPayment.ReviewerId equals doctor.Id + select new MonthlyPaymentDTO + { + ReviewerId = doctor.Id, + ChineseName = doctor.ChineseName, + FirstName = doctor.FirstName, + LastName = doctor.LastName, + ReviewerCode = doctor.Code, + PaymentUSD = monthlyPayment.PaymentUSD, + PaymentCNY = monthlyPayment.PaymentCNY, + AdjustmentCNY = monthlyPayment.AdjustmentCNY, + AdjustmentUSD = monthlyPayment.AdjustmentUSD, + TotalUSD = monthlyPayment.AdjustmentUSD + monthlyPayment.PaymentUSD, + TotalCNY = monthlyPayment.AdjustmentCNY + monthlyPayment.PaymentCNY, + }; + + //获取工作量收入 workloadLambda 已经加入过滤 payment锁定月份 + + ////工作量过滤查询 锁定得月份 + + var workloadIncomeQuery = from workLoad in _workloadRepository.GetAll().Where(workloadLambda) + join doctor in _doctorRepository.Find(doctorLambda) + on workLoad.DoctorId equals doctor.Id + join lockedDoctorAndMonth in lockedDoctorIdAndYearMonthQueryable on new { workLoad.DoctorId, workLoad.YearMonth } equals new { lockedDoctorAndMonth.DoctorId, lockedDoctorAndMonth.YearMonth } + join trialCost in _trialRevenuePriceRepository.GetAll() on workLoad.TrialId equals trialCost.TrialId into c + from trialCost in c.DefaultIfEmpty() + + select new + { + DoctorId = workLoad.DoctorId, + Downtime = workLoad.Downtime * trialCost.Downtime, + Training = workLoad.Training * trialCost.Training, + Timepoint = workLoad.Timepoint * trialCost.Timepoint, + TimepointIn24H = workLoad.TimepointIn24H * trialCost.TimepointIn24H, + TimepointIn48H = workLoad.TimepointIn48H * trialCost.TimepointIn48H, + Global = workLoad.Global * trialCost.Global, + Adjudication = workLoad.Adjudication * trialCost.Adjudication, + AdjudicationIn24H = workLoad.AdjudicationIn24H * trialCost.AdjudicationIn24H, + AdjudicationIn48H = workLoad.AdjudicationIn48H * trialCost.AdjudicationIn48H + + + }; + + //工作量收入按照人分组统计 + var workloadIncomeList = workloadIncomeQuery.GroupBy(t => t.DoctorId).Select(gWorkLoad => new + { + + DoctorId = gWorkLoad.Key, + //TrialId = Guid.Empty, + Downtime = gWorkLoad.Sum(t => t.Downtime), + Training = gWorkLoad.Sum(t => t.Training), + Timepoint = gWorkLoad.Sum(t => t.Timepoint), + TimepointIn24H = gWorkLoad.Sum(t => t.TimepointIn24H), + TimepointIn48H = gWorkLoad.Sum(t => t.TimepointIn48H), + Global = gWorkLoad.Sum(t => t.Global), + Adjudication = gWorkLoad.Sum(t => t.Adjudication), + AdjudicationIn24H = gWorkLoad.Sum(t => t.AdjudicationIn24H), + AdjudicationIn48H = gWorkLoad.Sum(t => t.AdjudicationIn48H), + }).ToList(); + var workloadPayList = payQuery.ToList(); + //var workloadIncomeList = workloadIncomeQuery.ToList(); + + var returnList = new List(); + + #region 处理找到缺失的项目 + + //有项目价格的trial Id 集合 + var hasIncomePriceTrialIds = _trialRevenuePriceRepository.GetAll().Select(t => t.TrialId).ToList(); + + workloadLambda = workloadLambda.And(t => !hasIncomePriceTrialIds.Contains(t.TrialId)); + var doctorMissingTrialCodesQuery = (from workLoad in _workloadRepository.GetAll().Where(workloadLambda) + join trial in _trialRepository.GetAll() on workLoad.TrialId equals trial.Id + select new + { + DoctorId = workLoad.DoctorId, + TrialCode = trial.Code + }).Distinct(); + + var doctorMissingTrialCodes = (doctorMissingTrialCodesQuery.ToList().GroupBy(t => t.DoctorId).Select(g => new + { + DoctorId = g.Key, + TrialCodes = g.Select(u => u.TrialCode).ToList() + })).ToList(); + + + #endregion + + workloadPayList.ForEach(pay => + { + var doctor = workloadIncomeList.FirstOrDefault(t => t.DoctorId == pay.ReviewerId); + + var doctorMissingCode = doctorMissingTrialCodes.FirstOrDefault(t => t.DoctorId == pay.ReviewerId); + + returnList.Add(new ReviewerAnalysisDTO() + { + ReviewerId = pay.ReviewerId, + ChineseName = pay.ChineseName, + FirstName = pay.FirstName, + LastName = pay.LastName, + ReviewerCode = pay.ReviewerCode, + PaymentUSD = pay.PaymentUSD + pay.AdjustmentUSD, + + //付费表的医生数量肯定事全的 工作量的不一定全 (只有调整) + RevenusUSD = doctor != null + ? doctor.Adjudication + doctor.AdjudicationIn24H + doctor.AdjudicationIn48H + doctor.Global + + doctor.Downtime + doctor.Training + + doctor.Timepoint + doctor.TimepointIn24H + doctor.TimepointIn48H + : 0, + MissingTrialCodes = doctorMissingCode != null ? doctorMissingCode.TrialCodes : new List() + }); + }); + return returnList.OrderBy(t => t.ReviewerCode).ToList(); + } + + public List GetLaborPaymentList(List paymentIds) + { + var query = from payment in _paymentRepository.GetAll().Where(t => paymentIds.Contains(t.Id)) + join reviewer in _doctorRepository.GetAll() on payment.DoctorId equals reviewer.Id + join payInfo in _doctorPayInfoRepository.GetAll() on payment.DoctorId equals payInfo.DoctorId + select new LaborPayment() + { + + ChineseName = reviewer.ChineseName, + FirstName = reviewer.FirstName, + LastName = reviewer.LastName, + ResidentId = payInfo.IDCard, + PaymentCNY = payment.PaymentCNY + payment.AdjustmentCNY, + YearMonth = payment.YearMonth, + Phone = reviewer.Phone, + AccountNumber = payInfo.BankCardNumber, + Bank = payInfo.BankName + + //TaxCNY = payment.TaxCNY, + //ActuallyPaidCNY = payment.ActuallyPaidCNY, + //BankTransferCNY = payment.BankTransferCNY, + }; + var result = query.ToList(); + + result.ForEach(t => + { + t.TaxCNY =GetTax2(t.PaymentCNY); + + t.ActuallyPaidCNY = t.PaymentCNY - t.TaxCNY; + t.BankTransferCNY = t.PaymentCNY - t.TaxCNY; + }); + + return result; + + } + + + //会计报税方式和计算方式不同 导致 超过2w的人 扣钱多了 + private decimal GetTax(decimal paymentCNY) + { + if (paymentCNY >= 0 && paymentCNY <= 800) + { + return 0; + } + + else if (paymentCNY >= 800 && paymentCNY <= 4000) + { + return (paymentCNY - 800) * 0.2m; + } + else if (paymentCNY > 4000 && paymentCNY <= 20000) + { + return paymentCNY * 0.8m * 0.2m; + } + else if (paymentCNY > 20000 && paymentCNY <= 50000) + { + return (paymentCNY * 0.3m) - 2000; + } + else + { + return paymentCNY * 0.4m - 7000; + } + } + + private decimal GetTax2(decimal paymentCNY) + { + if (paymentCNY >= 0 && paymentCNY <= 800) + { + return 0; + } + + var calculateTaxPart = paymentCNY <= 4000 ? paymentCNY - 800 : paymentCNY * (1 - 0.2m); + + + if (calculateTaxPart <= 20000) + { + return calculateTaxPart * 0.2m; + } + + else if (calculateTaxPart > 20000 && calculateTaxPart <= 50000) + { + return calculateTaxPart * 0.3m - 2000; + } + + else + { + return calculateTaxPart * 0.4m - 7000; + } + + + } + } +} \ No newline at end of file diff --git a/IRaCIS.Core.Application/Financial/PaymentAdjustmentService.cs b/IRaCIS.Core.Application/Financial/PaymentAdjustmentService.cs new file mode 100644 index 0000000..67b96e8 --- /dev/null +++ b/IRaCIS.Core.Application/Financial/PaymentAdjustmentService.cs @@ -0,0 +1,303 @@ +using AutoMapper; +using AutoMapper.QueryableExtensions; +using IRaCIS.Application.ExpressionExtend; +using IRaCIS.Application.Interfaces; +using IRaCIS.Application.ViewModels.Pay; +using IRaCIS.Core.Application.Contracts.RequestAndResponse; +using IRaCIS.Core.Domain.Share; +using IRaCIS.Infra.Data.ExpressionExtend; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Expressions; +using IRaCIS.Core.Domain.Interfaces; +using IRaCIS.Core.Domain.Models; + +namespace IRaCIS.Application.Services.Pay +{ + public class PaymentAdjustmentService : IPaymentAdjustmentService + { + private readonly IPaymentAdjustmentRepository _payAdjustmentRepository; + private readonly IDoctorRepository _doctorRepository; + private readonly IExchangeRateRepository _exchangeRateRepository; + private readonly IPaymentRepository _paymentRepository; + private readonly IMapper _mapper; + + public PaymentAdjustmentService(IPaymentAdjustmentRepository costAdjustmentRepository, IDoctorRepository doctorRepository, + IExchangeRateRepository exchangeRateRepository, IPaymentRepository paymentRepository, IMapper mapper) + { + _payAdjustmentRepository = costAdjustmentRepository; + _doctorRepository = doctorRepository; + _exchangeRateRepository = exchangeRateRepository; + _paymentRepository = paymentRepository; + _mapper = mapper; + } + + public IResponseOutput AddOrUpdatePaymentAdjustment(PaymentAdjustmentCommand addOrUpdateModel, Guid optUseId) + { + + var yearMonthDate = new DateTime(addOrUpdateModel.YearMonth.Year, addOrUpdateModel.YearMonth.Month, 1); + var yearMonth = addOrUpdateModel.YearMonth.ToString("yyyy-MM"); + + var payment = _paymentRepository.FindSingleOrDefault(u => u.DoctorId == addOrUpdateModel.ReviewerId + && u.YearMonth == yearMonth); + + //判断付费表中是否有记录 + if (payment == null) + { + //没有 添加仅有的调整费用记录 + payment = new Payment + { + DoctorId = addOrUpdateModel.ReviewerId, + YearMonth = yearMonth, + YearMonthDate = yearMonthDate, + PaymentCNY = 0, + PaymentUSD = 0, + AdjustmentCNY = 0, + AdjustmentUSD = 0 + }; + _paymentRepository.Add(payment); + _paymentRepository.SaveChanges(); + } + else + { + if (payment.IsLock) + { + return ResponseOutput.NotOk("Doctor payment has confirmed lock"); + } + } + + var exchangeRate = _exchangeRateRepository.GetAll().FirstOrDefault(t => t.YearMonth == yearMonth); + if (addOrUpdateModel.Id == Guid.Empty || addOrUpdateModel.Id == null) + { + var costAdjustment = _mapper.Map(addOrUpdateModel); + + //视图模型和领域模型没对应 重新赋值 + costAdjustment.ExchangeRate = exchangeRate?.Rate ?? 0; + costAdjustment.AdjustmentCNY = addOrUpdateModel.AdjustPaymentUSD * (exchangeRate?.Rate ?? 0) ; + costAdjustment.AdjustmentUSD = addOrUpdateModel.AdjustPaymentUSD; + + _payAdjustmentRepository.Add(costAdjustment); + + //添加的时候,每个月调整汇总费用 需要加上本次调整的费用 + payment.AdjustmentCNY += costAdjustment.AdjustmentCNY; + payment.AdjustmentUSD += costAdjustment.AdjustmentUSD; + + _paymentRepository.Update(payment); + + if (_payAdjustmentRepository.SaveChanges()) + { + return ResponseOutput.Ok(costAdjustment.Id.ToString()); + } + else + { + return ResponseOutput.NotOk(StaticData.AddFailed); + } + } + else + { + // 更新的时候,先查出来,更新前的调整费用数据 + var paymentAdjust = _payAdjustmentRepository.FindSingleOrDefault(t => t.Id == addOrUpdateModel.Id); + + + _mapper.Map(addOrUpdateModel, paymentAdjust); + + paymentAdjust.ExchangeRate = exchangeRate?.Rate ?? 0; + paymentAdjust.AdjustmentUSD = addOrUpdateModel.AdjustPaymentUSD; + paymentAdjust.AdjustmentCNY = addOrUpdateModel.AdjustPaymentUSD * (exchangeRate?.Rate ?? 0); + + _payAdjustmentRepository.Update(paymentAdjust); + var success = _payAdjustmentRepository.SaveChanges(); + + if (success) + { + + var adjustmentList = _payAdjustmentRepository.Find(u=> u.ReviewerId == addOrUpdateModel.ReviewerId && u.YearMonth == yearMonth).ToList(); + + payment.AdjustmentCNY = adjustmentList.Sum(t => t.AdjustmentCNY); + payment.AdjustmentUSD = adjustmentList.Sum(t => t.AdjustmentUSD); + + + _paymentRepository.Update(payment); + + _paymentRepository.SaveChanges(); + } + + //查询得到历史汇总 + + + + return ResponseOutput.Result(success, success ? string.Empty : StaticData.UpdateFailed); + + #region 逻辑存在错误 问题待查 + + //// 更新的时候,先查出来,更新前的调整费用数据 + //var paymentAdjust = _payAdjustmentRepository.FindSingleOrDefault(t => t.Id == addOrUpdateModel.Id); + + ////减去数据库本条记录的值 + //payment.AdjustmentCNY = -paymentAdjust.AdjustmentCNY; + //payment.AdjustmentUSD = -paymentAdjust.AdjustmentUSD; + + //_mapper.Map(addOrUpdateModel, paymentAdjust); + + //paymentAdjust.ExchangeRate = exchangeRate?.Rate ?? 0; + //paymentAdjust.AdjustmentUSD = addOrUpdateModel.AdjustPaymentUSD; + //paymentAdjust.AdjustmentCNY = addOrUpdateModel.AdjustPaymentUSD * (exchangeRate?.Rate ?? 0); + + //_payAdjustmentRepository.Update(paymentAdjust); + + ////查询得到历史汇总 + //var adjustment = _payAdjustmentRepository.Find(u => u.ReviewerId == addOrUpdateModel.ReviewerId && u.YearMonth == yearMonth) + // .GroupBy(u => new { u.ReviewerId, u.YearMonth }).Select(g => new + // { + // AdjustCNY = g.Sum(t => t.AdjustmentCNY), + // AdjustUSD = g.Sum(t => t.AdjustmentUSD) + // }).FirstOrDefault(); + + ////最终的值 等于历史汇总 减去更新前的加上当前更新的值 + //payment.AdjustmentCNY += (adjustment.AdjustCNY + paymentAdjust.AdjustmentCNY); + //payment.AdjustmentUSD += (adjustment.AdjustUSD + paymentAdjust.AdjustmentUSD); + + //_paymentRepository.Update(payment); + + //var success = _payAdjustmentRepository.SaveChanges(); + //return ResponseOutput.Result(success, success ? string.Empty : StaticData.UpdateFailed); + + #endregion + + + + } + } + + public IResponseOutput DeleteCostAdjustment(Guid id) + { + var adjustPayment = _payAdjustmentRepository.FindSingleOrDefault(u => u.Id == id); + + var monthPay = _paymentRepository.GetAll().FirstOrDefault(t => + t.DoctorId == adjustPayment.ReviewerId && t.YearMonth == adjustPayment.YearMonth); + + _payAdjustmentRepository.Delete(new PaymentAdjustment() { Id = id }); + + var success = _payAdjustmentRepository.SaveChanges(); + + if (success) + { + + var adjustmentList= _payAdjustmentRepository.Find(u => + u.ReviewerId == adjustPayment.ReviewerId && u.YearMonth == adjustPayment.YearMonth).ToList(); + + monthPay.AdjustmentCNY = adjustmentList.Sum(t=>t.AdjustmentCNY); + monthPay.AdjustmentUSD = adjustmentList.Sum(t=>t.AdjustmentUSD); + + + + _paymentRepository.Update(monthPay); + + _paymentRepository.SaveChanges(); + } + + + + return ResponseOutput.Result(success); + } + + public PageOutput GetPaymentAdjustmentList(PaymentAdjustmentQueryDTO queryParam) + { + + var beginYearMonth = queryParam.BeginMonth.AddDays(1 - queryParam.BeginMonth.Day); + var endYearMonth = queryParam.EndMonth.AddDays(1 - queryParam.EndMonth.Day).AddMonths(1).AddDays(-1); + + Expression> trialLambda = x => true; + var trialCode = queryParam.TrialCode.Trim(); + if (!string.IsNullOrWhiteSpace(trialCode)) + { + trialLambda = trialLambda.And(u => u.Code.Contains(trialCode)); + } + + Expression> doctorLambda = x => true; + var reviewer = queryParam.Reviewer.Trim(); + if (!string.IsNullOrWhiteSpace(reviewer)) + { + doctorLambda = doctorLambda.And(u => u.ChineseName.Contains(reviewer) + || u.FirstName.Contains(reviewer) + || u.LastName.Contains(reviewer) + || u.Code.Contains(reviewer)); + } + var costAdjustmentQueryable = from costAdjustment in _payAdjustmentRepository.GetAll() + .Where(t => t.YearMonthDate >= beginYearMonth && t.YearMonthDate <= endYearMonth) + join doctor in _doctorRepository.GetAll().Where(doctorLambda) + on costAdjustment.ReviewerId equals doctor.Id + + select new PaymentAdjustmentDetailDTO() + { + AdjustPaymentCNY = costAdjustment.AdjustmentCNY, + AdjustPaymentUSD = costAdjustment.AdjustmentUSD, + IsLock = costAdjustment.IsLock, + Id = costAdjustment.Id, + YearMonth = costAdjustment.YearMonth, + YearMonthDate = costAdjustment.YearMonthDate, + Note = costAdjustment.Note, + ReviewerId = costAdjustment.ReviewerId, + ReviewerCode = doctor.Code, + FirstName = doctor.FirstName, + LastName = doctor.LastName, + ChineseName = doctor.ChineseName + }; + + var propName = string.IsNullOrWhiteSpace(queryParam.SortField) ? "YearMonthDate" : queryParam.SortField; + + costAdjustmentQueryable = queryParam.Asc ? costAdjustmentQueryable.OrderBy(propName) : costAdjustmentQueryable.OrderByDescending(propName); + + var count = costAdjustmentQueryable.Count(); + costAdjustmentQueryable = costAdjustmentQueryable.Skip((queryParam.PageIndex - 1) * queryParam.PageSize) + .Take(queryParam.PageSize); + var list = costAdjustmentQueryable.ToList(); + + return new PageOutput(queryParam.PageIndex, queryParam.PageSize, count, list); + } + + public List GetReviewerSelectList() + { + return _doctorRepository.GetAll().Where(t => t.CooperateStatus == (int)ContractorStatus.Cooperation && t.ResumeStatus == (int)ResumeStatus.Pass).ProjectTo(_mapper.ConfigurationProvider).ToList(); + } + + public void CalculateCNY(string yearMonth, decimal rate) + { + + //如果是double 不会保留两位小数 + _payAdjustmentRepository.Update(u => u.YearMonth == yearMonth && + !u.IsLock, t => new PaymentAdjustment + { + AdjustmentCNY = t.AdjustmentUSD * rate, + ExchangeRate = rate, + UpdateTime = DateTime.Now + }); + + var adjustList = _payAdjustmentRepository.GetAll().Where(u => u.YearMonth == yearMonth && + !u.IsLock).ToList(); + + + + var needUpdatePayment= adjustList.GroupBy(t => t.ReviewerId).Select(g => new + { + ReviewerId = g.Key, + AdjustCNY = g.Sum(t => t.AdjustmentCNY), + AdjustUSD = g.Sum(t => t.AdjustmentUSD) + }); + + foreach (var reviewer in needUpdatePayment) + { + _paymentRepository.Update(u => u.YearMonth == yearMonth && + !u.IsLock && u.DoctorId == reviewer.ReviewerId, t => new Payment() + { + AdjustmentUSD = reviewer.AdjustUSD, + AdjustmentCNY = reviewer.AdjustCNY + + }); + } + + + } + } +} \ No newline at end of file diff --git a/IRaCIS.Core.Application/Financial/RankPriceService.cs b/IRaCIS.Core.Application/Financial/RankPriceService.cs new file mode 100644 index 0000000..a5c71ff --- /dev/null +++ b/IRaCIS.Core.Application/Financial/RankPriceService.cs @@ -0,0 +1,109 @@ +using AutoMapper; +using AutoMapper.QueryableExtensions; +using IRaCIS.Application.ExpressionExtend; +using IRaCIS.Application.Interfaces; +using IRaCIS.Application.ViewModels; +using IRaCIS.Core.Application.Contracts.RequestAndResponse; +using IRaCIS.Core.Domain.Share; +using System; +using System.Collections.Generic; +using System.Linq; +using IRaCIS.Core.Domain.Interfaces; +using IRaCIS.Core.Domain.Models; + +namespace IRaCIS.Application.Services.Pay +{ + public class RankPriceService : IRankPriceService + { + private readonly IRankPriceRepository _rankPriceRepository; + private readonly IReviewerPayInfoRepository _reviewerPayInfoRepository; + private readonly IMapper _mapper; + + public RankPriceService(IRankPriceRepository rankPriceRepository, IReviewerPayInfoRepository reviewerPayInfoRepository,IMapper mapper) + { + _rankPriceRepository = rankPriceRepository; + _reviewerPayInfoRepository = reviewerPayInfoRepository; + _mapper = mapper; + } + + + public IResponseOutput AddOrUpdateRankPrice(RankPriceCommand addOrUpdateModel, Guid userId) + { + if (addOrUpdateModel.Id == Guid.Empty|| addOrUpdateModel.Id ==null) + { + var rankPrice = _mapper.Map(addOrUpdateModel); + rankPrice = _rankPriceRepository.Add(rankPrice); + if (_rankPriceRepository.SaveChanges()) + { + return ResponseOutput.Ok(rankPrice.Id.ToString()); + } + else + { + return ResponseOutput.NotOk(); + } + + } + else + { + var success = _rankPriceRepository.Update(t => t.Id == addOrUpdateModel.Id, u => new RankPrice() + { + UpdateUserId = userId, + UpdateTime = DateTime.Now, + RefresherTraining=addOrUpdateModel.RefresherTraining, + RankName = addOrUpdateModel.RankName, + Timepoint = addOrUpdateModel.Timepoint, + TimepointIn24H = addOrUpdateModel.TimepointIn24H, + TimepointIn48H = addOrUpdateModel.TimepointIn48H, + Adjudication = addOrUpdateModel.Adjudication, + AdjudicationIn24H = addOrUpdateModel.AdjudicationIn24H, + AdjudicationIn48H = addOrUpdateModel.AdjudicationIn48H, + Global = addOrUpdateModel.Global, + Training = addOrUpdateModel.Training, + Downtime = addOrUpdateModel.Downtime + + }); + + + return ResponseOutput.Result(success, success ? "" : StaticData.UpdateFailed); + } + } + + public IResponseOutput DeleteRankPrice(Guid id) + { + + if (_reviewerPayInfoRepository.GetAll().Any(t => t.RankId == id)) + { + return ResponseOutput.NotOk("This title has been used by reviewer payment information"); + } + + var success = _rankPriceRepository.Delete(t => t.Id == id); + + return ResponseOutput.Result(success, success ? string.Empty : StaticData.DeleteFailed); + } + + public PageOutput GetRankPriceList(RankPriceQueryDTO queryParam) + { + var rankPriceQueryable = _rankPriceRepository.GetAll().ProjectTo(_mapper.ConfigurationProvider); + + //var propName = string.IsNullOrWhiteSpace(queryParam.SortField) ? "RankName" : queryParam.SortField; + //rankPriceQueryable = queryParam.Asc ? rankPriceQueryable.OrderBy(propName) : rankPriceQueryable.OrderByDescending(propName); + + rankPriceQueryable = rankPriceQueryable.OrderBy("ShowOrder"); + var count = rankPriceQueryable.Count(); + rankPriceQueryable = rankPriceQueryable.Skip((queryParam.PageIndex - 1) * queryParam.PageSize) + .Take(queryParam.PageSize); + var list = rankPriceQueryable.ToList(); + + return new PageOutput(queryParam.PageIndex, queryParam.PageSize, count, list); + } + + + public List GetRankDic() + { + var rankQueryable = _rankPriceRepository.GetAll().ProjectTo(_mapper.ConfigurationProvider); + return rankQueryable.ToList(); + + } + + } +} \ No newline at end of file diff --git a/IRaCIS.Core.Application/Financial/ReviewerPayInfoService.cs b/IRaCIS.Core.Application/Financial/ReviewerPayInfoService.cs new file mode 100644 index 0000000..2a9805d --- /dev/null +++ b/IRaCIS.Core.Application/Financial/ReviewerPayInfoService.cs @@ -0,0 +1,151 @@ +using AutoMapper; +using IRaCIS.Application.ExpressionExtend; +using IRaCIS.Application.Interfaces; +using IRaCIS.Application.ViewModels; +using IRaCIS.Core.Application.Contracts.RequestAndResponse; +using IRaCIS.Infra.Data.ExpressionExtend; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Expressions; +using IRaCIS.Core.Domain.Interfaces; +using IRaCIS.Core.Domain.Models; + +namespace IRaCIS.Application.Services.Pay +{ + public class ReviewerPayInfoService : IReviewerPayInfoService + { + private readonly IReviewerPayInfoRepository _doctorPayInfoRepository; + private readonly IDoctorRepository _doctorRepository; + private readonly IRankPriceRepository _rankPriceRepository; + private readonly IHospitalRepository _hospitalRepository; + private readonly IMapper _mapper; + + public ReviewerPayInfoService(IDoctorRepository doctorRepository, IReviewerPayInfoRepository doctorPayInfoRepository, + IRankPriceRepository rankPriceRepository, IHospitalRepository hospitalRepository, IMapper mapper) + { + _doctorPayInfoRepository = doctorPayInfoRepository; + _doctorRepository = doctorRepository; + _rankPriceRepository = rankPriceRepository; + _hospitalRepository = hospitalRepository; + _mapper = mapper; + } + public IResponseOutput AddOrUpdateReviewerPayInfo(ReviewerPayInfoCommand addOrUpdateModel, Guid userId) + { + var success = false; + var doctorPayInfoExistedItem = _doctorPayInfoRepository.FindSingleOrDefault(u => u.DoctorId == addOrUpdateModel.DoctorId); + if (doctorPayInfoExistedItem == null)//insert + { + var doctorPayInfo = _mapper.Map(addOrUpdateModel); + //doctorPayInfo.CreateTime = DateTime.Now; + //doctorPayInfo.CreateUserId = userId; + _doctorPayInfoRepository.Add(doctorPayInfo); + + } + else//update + { + _doctorPayInfoRepository.Update(_mapper.Map(addOrUpdateModel, doctorPayInfoExistedItem)); + + } + success = _doctorPayInfoRepository.SaveChanges(); + return ResponseOutput.Result(success); + } + + public PageOutput GetDoctorPayInfoList(DoctorPaymentInfoQueryDTO queryParam) + { + Expression> doctorLambda = x => true; + if (queryParam.HospitalId != Guid.Empty && queryParam.HospitalId != null) + { + doctorLambda = doctorLambda.And(o => o.HospitalId == queryParam.HospitalId); + } + + if (!string.IsNullOrEmpty(queryParam.SearchName)) + { + var searchKeyword = queryParam.SearchName.Trim(); + doctorLambda = doctorLambda.And(u => u.ChineseName.Contains(searchKeyword) + || u.FirstName.Contains(searchKeyword) || u.LastName.Contains(searchKeyword)); + } + + var doctorQueryable = from doctor in _doctorRepository.GetAll().Where(doctorLambda) + join hospitalItem in _hospitalRepository.GetAll() on doctor.HospitalId + equals hospitalItem.Id + into gt + from hospital in gt.DefaultIfEmpty() + join trialPayInfo in _doctorPayInfoRepository.Find() + on doctor.Id equals trialPayInfo.DoctorId into payInfo + from doctorPayInfo in payInfo.DefaultIfEmpty() + join rankPrice in _rankPriceRepository.Find() + on doctorPayInfo.RankId equals rankPrice.Id into rankPriceInfo + from rankPrice in rankPriceInfo.DefaultIfEmpty() + select new DoctorPayInfoQueryListDTO + { + //Id = doctorPayInfo.Id, + DoctorId = doctor.Id, + Code = doctor.Code, + LastName = doctor.LastName, + FirstName = doctor.FirstName, + ChineseName = doctor.ChineseName, + Phone = doctor.Phone, + DoctorNameInBank = doctorPayInfo.DoctorNameInBank, + IDCard = doctorPayInfo.IDCard, + BankCardNumber = doctorPayInfo.BankCardNumber, + BankName = doctorPayInfo.BankName, + RankId = doctorPayInfo.RankId, + RankName = rankPrice.RankName, + Additional = doctorPayInfo.Additional, + Hospital = hospital.HospitalName, + CreateTime = doctor.CreateTime + }; + var count = doctorQueryable.Count(); + var propName = string.IsNullOrWhiteSpace(queryParam.SortField) ? "Code" : queryParam.SortField; + doctorQueryable = queryParam.Asc ? doctorQueryable.OrderBy(propName) : doctorQueryable.OrderByDescending(propName); + doctorQueryable = doctorQueryable.Skip((queryParam.PageIndex - 1) * queryParam.PageSize) + .Take(queryParam.PageSize); + + var trialList = doctorQueryable.ToList(); + return new PageOutput(queryParam.PageIndex, queryParam.PageSize, count, trialList); + + } + + public DoctorPayInfoQueryListDTO GetReviewerPayInfo(Guid doctorId) + { + var doctorQueryable = from doctor in _doctorRepository.Find(u => u.Id == doctorId) + join trialPayInfo in _doctorPayInfoRepository.Find() + on doctor.Id equals trialPayInfo.DoctorId into payInfo + from doctorPayInfo in payInfo.DefaultIfEmpty() + join rankPrice in _rankPriceRepository.Find() + on doctorPayInfo.RankId equals rankPrice.Id into rankPriceInfo + from rankPrice in rankPriceInfo.DefaultIfEmpty() + select new DoctorPayInfoQueryListDTO + { + //Id = doctorPayInfo.Id, + DoctorId = doctor.Id, + Code = doctor.Code, + LastName = doctor.LastName, + FirstName = doctor.FirstName, + ChineseName = doctor.ChineseName, + Phone = doctor.Phone, + DoctorNameInBank = doctorPayInfo.DoctorNameInBank, + IDCard = doctorPayInfo.IDCard, + BankCardNumber = doctorPayInfo.BankCardNumber, + BankName = doctorPayInfo.BankName, + RankId = doctorPayInfo.RankId, + RankName = rankPrice.RankName, + Additional = doctorPayInfo.Additional, + CreateTime = doctor.CreateTime + }; + + return doctorQueryable.FirstOrDefault(); + } + + /// + /// 根据rankId 获取ReviewerId,用于当Rank的单价信息改变时,触发费用计算 + /// + /// + /// + public List GetReviewerIdByRankId(Guid rankId) + { + return _doctorPayInfoRepository.Find(u => u.RankId == rankId).Select(u => u.DoctorId).ToList(); + } + } +} diff --git a/IRaCIS.Core.Application/Financial/TrialPaymentPriceService.cs b/IRaCIS.Core.Application/Financial/TrialPaymentPriceService.cs new file mode 100644 index 0000000..51a73ed --- /dev/null +++ b/IRaCIS.Core.Application/Financial/TrialPaymentPriceService.cs @@ -0,0 +1,119 @@ +using AutoMapper; +using AutoMapper.QueryableExtensions; +using IRaCIS.Application.ExpressionExtend; +using IRaCIS.Application.Interfaces; +using IRaCIS.Application.ViewModels; +using IRaCIS.Core.Application.Contracts.RequestAndResponse; +using IRaCIS.Core.Domain.Interfaces; +using IRaCIS.Core.Domain.Models; +using IRaCIS.Infra.Data.ExpressionExtend; +using System; +using System.Linq; +using System.Linq.Dynamic.Core; +using System.Linq.Expressions; + +namespace IRaCIS.Application.Services.Pay +{ + public class TrialPaymentPriceService : ITrialPaymentPriceService + { + private readonly ITrialPaymentPriceRepository _trialExtRepository; + private readonly ICRORepository _croRepository; + private readonly IMapper _mapper; + private readonly ITrialRepository _trialRepository; + public TrialPaymentPriceService(ITrialRepository trialRepository, ITrialPaymentPriceRepository trialExtRepository, + ICRORepository croCompanyRepository, IMapper mapper) + { + _trialExtRepository = trialExtRepository; + _croRepository = croCompanyRepository; + _mapper = mapper; + _trialRepository = trialRepository; + } + + /// + /// 添加或更新项目支付价格信息 + /// + public IResponseOutput AddOrUpdateTrialPaymentPrice(TrialPaymentPriceCommand addOrUpdateModel, Guid userId) + { + + var trialExistedItem = _trialExtRepository.FindSingleOrDefault(u => u.TrialId == addOrUpdateModel.TrialId); + if (trialExistedItem == null)//insert + { + var trialExt = _mapper.Map(addOrUpdateModel); + + _trialExtRepository.Add(trialExt); + + } + else//update + { + _trialExtRepository.Update(_mapper.Map(addOrUpdateModel, trialExistedItem)); + + } + var success = _trialExtRepository.SaveChanges(); + return ResponseOutput.Result(success); + } + + public IResponseOutput UploadTrialSOW(Guid userId, TrialSOWPathDTO trialSowPath) + { + var trialPaymentPrice= _trialExtRepository.GetAll().FirstOrDefault(u => u.TrialId == trialSowPath.TrialId); + + if (trialPaymentPrice == null)//添加 + { + _trialExtRepository.Add(_mapper.Map(trialSowPath)); + } + else//更新 + { + _trialExtRepository.Update(_mapper.Map(trialSowPath, trialPaymentPrice)); + } + + var success = _trialExtRepository.SaveChanges(); + + return ResponseOutput.Result(success); + } + + public IResponseOutput DeleteTrialSOW(Guid userId, DeleteSowPathDTO trialSowPath) + { + var success = _trialExtRepository.Update(u => u.TrialId == trialSowPath.TrialId, s => new TrialPaymentPrice + { + SowPath = "", + SowName = "", + UpdateTime = DateTime.Now, + UpdateUserId = userId + }); + + return ResponseOutput.Result(success); + } + + /// + /// 获取项目支付价格信息列表 + /// + public PageOutput GetTrialPaymentPriceList(TrialPaymentPriceQueryDTO queryParam) + { + var trialQueryable2 = _trialExtRepository.GetAll(); + + if (queryParam.CroId != null) + { + trialQueryable2 = trialQueryable2.Where(o => o.Trial.CROId == queryParam.CroId); + } + + if (!string.IsNullOrEmpty(queryParam.KeyWord)) + { + trialQueryable2 = trialQueryable2.Where(o => o.Trial.Indication.Contains(queryParam.KeyWord)); + } + + var data= trialQueryable2.ProjectTo(_mapper.ConfigurationProvider); + + var list = data.Skip((queryParam.PageIndex - 1) * queryParam.PageSize).Take(queryParam.PageSize).ToList(); + return new PageOutput(queryParam.PageIndex, + queryParam.PageSize, data.Count(), + list + ); + + + } + + + + + + } +} diff --git a/IRaCIS.Core.Application/Financial/TrialRevenuesPriceService.cs b/IRaCIS.Core.Application/Financial/TrialRevenuesPriceService.cs new file mode 100644 index 0000000..ea4fb18 --- /dev/null +++ b/IRaCIS.Core.Application/Financial/TrialRevenuesPriceService.cs @@ -0,0 +1,155 @@ +using AutoMapper; +using IRaCIS.Application.ExpressionExtend; +using IRaCIS.Application.Interfaces; +using IRaCIS.Application.ViewModels; +using IRaCIS.Core.Application.Contracts.RequestAndResponse; +using IRaCIS.Infra.Data.ExpressionExtend; +using System; +using System.Linq; +using System.Linq.Expressions; +using IRaCIS.Core.Domain.Interfaces; +using IRaCIS.Core.Domain.Models; + +namespace IRaCIS.Application.Services +{ + public class TrialRevenuesPriceService : ITrialRevenuesPriceService + { + private readonly ITrialRepository _trialRepository; + private readonly ITrialRevenuesPriceRepository _trialRevenuesPriceRepository; + private readonly ICRORepository _croRepository; + private readonly IDictionaryRepository _dictionaryRepository; + private readonly ITrialRevenuesPriceVerificationRepository _trialRevenuesPriceVerificationRepository; + private readonly IMapper _mapper; + + public TrialRevenuesPriceService(ITrialRepository trialRepository, ITrialRevenuesPriceRepository trialCostRepository, ICRORepository croCompanyRepository, IDictionaryRepository dictionaryRepository, ITrialRevenuesPriceVerificationRepository trialRevenuesPriceVerificationRepository, IMapper mapper) + { + _trialRepository = trialRepository; + _trialRevenuesPriceRepository = trialCostRepository; + _croRepository = croCompanyRepository; + _dictionaryRepository = dictionaryRepository; + _trialRevenuesPriceVerificationRepository = trialRevenuesPriceVerificationRepository; + _mapper = mapper; + } + public IResponseOutput AddOrUpdateTrialRevenuesPrice(TrialRevenuesPriceDTO model) + { + var count = model.Timepoint + + model.TimepointIn24H + + model.TimepointIn48H + + model.Adjudication + + model.AdjudicationIn24H + + model.AdjudicationIn48H + + model.Downtime + + model.Global + + model.Training; + + if (count <= 0) + { + return ResponseOutput.NotOk("Please add meaningful data"); + } + var trialExistedItem = _trialRevenuesPriceRepository.FindSingleOrDefault(u => u.TrialId == model.TrialId); + if (trialExistedItem == null)//insert + { + var trialCost = _mapper.Map(model); + _trialRevenuesPriceRepository.Add(trialCost); + var success = _trialRevenuesPriceRepository.SaveChanges(); + return ResponseOutput.Result(success, trialCost.Id.ToString()); + } + else//update + { + var trialRevenuesPrice = _trialRevenuesPriceRepository.GetAll() + .FirstOrDefault(u => u.TrialId == model.TrialId); + + _trialRevenuesPriceRepository.Update(_mapper.Map(model, trialRevenuesPrice)); + + // 完善价格的 将对应的列设置为true 变更为有价格了 + + var aaa = _trialRevenuesPriceVerificationRepository.Update(t => t.TrialId == model.TrialId, u => new TrialRevenuesPriceVerification() + { + //有价格 则设置为true 否则 该列不变 + Timepoint = model.Timepoint > 0 || u.Timepoint, + TimepointIn24H = model.TimepointIn24H > 0 || u.TimepointIn24H, + TimepointIn48H = model.TimepointIn48H > 0 || u.TimepointIn48H, + Adjudication = model.Adjudication > 0 || u.Adjudication, + AdjudicationIn24H = + model.AdjudicationIn24H > 0 || u.AdjudicationIn24H, + AdjudicationIn48H = + model.AdjudicationIn48H > 0 || u.AdjudicationIn48H, + Global = model.Global > 0 || u.Global, + Downtime = model.Downtime > 0 || u.Downtime, + Training = model.Training > 0 || u.Training, + RefresherTraining = model.RefresherTraining > 0 || u.RefresherTraining, + }); + + //删除所有有价格的记录 为true 表示有价格或者不需要价格 缺价格的为false + _trialRevenuesPriceVerificationRepository.Delete(t => t.TrialId == model.TrialId && + t.Timepoint&& + t.TimepointIn24H&& + t.TimepointIn48H && + t.Adjudication && + t.AdjudicationIn24H && + t.AdjudicationIn48H && + t.Global && + t.Training &&t.RefresherTraining); + + + + var success = _trialRevenuesPriceRepository.SaveChanges(); + return ResponseOutput.Result(success); + } + } + + public bool DeleteTrialCost(Guid id) + { + return _trialRevenuesPriceRepository.Delete(u => u.Id == id); + } + + public PageOutput GetTrialRevenuesPriceList(TrialRevenuesPriceQueryDTO queryParam) + { + Expression> trialLambda = x => true; + if (queryParam.CroId != Guid.Empty && queryParam.CroId != null) + { + trialLambda = trialLambda.And(o => o.CROId == queryParam.CroId); + } + var trialQueryable = from trial in _trialRepository.Find(u => u.Code.Contains(queryParam.KeyWord) + || u.Indication.Contains(queryParam.KeyWord)).Where(trialLambda) + join cro in _croRepository.GetAll() on trial.CROId equals cro.Id into CRO + from croInfo in CRO.DefaultIfEmpty() + join dic in _dictionaryRepository.GetAll() on trial.ReviewModeId equals dic.Id into dict + from dic in dict.DefaultIfEmpty() + join trialCost in _trialRevenuesPriceRepository.GetAll() + on trial.Id equals trialCost.TrialId into trialInfo + from trialCostItem in trialInfo.DefaultIfEmpty() + select new TrialRevenuesPriceDetialDTO + { + Id = trialCostItem == null ? Guid.Empty : trialCostItem.Id, + TrialId = trial.Id, + TrialCode = trial.Code, + Indication = trial.Indication, + Cro = croInfo == null ? string.Empty : croInfo.CROName, + ReviewMode = dic == null ? string.Empty : dic.Value, + Timepoint = trialCostItem == null ? 0 : trialCostItem.Timepoint, + TimepointIn24H = trialCostItem == null ? 0 : trialCostItem.TimepointIn24H, + TimepointIn48H = trialCostItem == null ? 0 : trialCostItem.TimepointIn48H, + Adjudication = trialCostItem == null ? 0 : trialCostItem.Adjudication, + AdjudicationIn24H = trialCostItem == null ? 0 : trialCostItem.AdjudicationIn24H, + AdjudicationIn48H = trialCostItem == null ? 0 : trialCostItem.AdjudicationIn48H, + Downtime = trialCostItem == null ? 0 : trialCostItem.Downtime, + Global = trialCostItem == null ? 0 : trialCostItem.Global, + Training = trialCostItem == null ? 0 : trialCostItem.Training, + RefresherTraining= trialCostItem == null ? 0 : trialCostItem.RefresherTraining, + Expedited = trial.Expedited + + }; + var count = trialQueryable.Count(); + var propName = string.IsNullOrWhiteSpace(queryParam.SortField) ? "TrialCode" : queryParam.SortField; + trialQueryable = queryParam.Asc ? trialQueryable.OrderBy(propName) : trialQueryable.OrderByDescending(propName); + trialQueryable = trialQueryable.Skip((queryParam.PageIndex - 1) * queryParam.PageSize) + .Take(queryParam.PageSize); + + var trialList = trialQueryable.ToList(); + return new PageOutput(queryParam.PageIndex, queryParam.PageSize, count, trialList); + } + + + } +} diff --git a/IRaCIS.Core.Application/Financial/VolumeRewardService.cs b/IRaCIS.Core.Application/Financial/VolumeRewardService.cs new file mode 100644 index 0000000..921bcf4 --- /dev/null +++ b/IRaCIS.Core.Application/Financial/VolumeRewardService.cs @@ -0,0 +1,65 @@ +using AutoMapper; +using AutoMapper.QueryableExtensions; +using IRaCIS.Application.ExpressionExtend; +using IRaCIS.Application.Interfaces; +using IRaCIS.Core.Application.Contracts.RequestAndResponse; +using IRaCIS.Core.Domain.Share; +using System; +using System.Collections.Generic; +using System.Linq; +using IRaCIS.Core.Domain.Interfaces; +using IRaCIS.Core.Domain.Models; + +namespace IRaCIS.Application.Services.Pay +{ + public class VolumeRewardService : IVolumeRewardService + { + private readonly IVolumeRewardRepository _volumeRewardRepository; + private readonly IMapper _mapper; + + public VolumeRewardService(IVolumeRewardRepository volumeRewardRepository,IMapper mapper) + { + _volumeRewardRepository = volumeRewardRepository; + _mapper = mapper; + } + /// + /// 批量添加或更新奖励费用单价 + /// + public IResponseOutput AddOrUpdateVolumeRewardPriceList(IEnumerable addOrUpdateModel, Guid userId) + { + _volumeRewardRepository.Delete(t => t.Id != Guid.Empty); + var temp = _mapper.Map>(addOrUpdateModel); + foreach (var item in temp) + { + item.CreateUserId = userId; + item.CreateTime = DateTime.Now; + } + _volumeRewardRepository.AddRange(temp); + var success = _volumeRewardRepository.SaveChanges(); + + return ResponseOutput.Result(success, success ? string.Empty : StaticData.UpdateFailed); + } + + /// + /// 获取所有奖励单价列表-用于计算时,一次性获取所有 + /// + public List GetVolumeRewardPriceList() + { + return _volumeRewardRepository.GetAll().ProjectTo(_mapper.ConfigurationProvider).OrderBy(t => t.Min).ToList(); + } + + /// + /// 分页获取奖励单价列表 + /// + public PageOutput GetVolumeRewardPriceList(AwardPriceQueryDTO queryParam) + { + var awardPriceQueryable = _volumeRewardRepository.GetAll().ProjectTo(_mapper.ConfigurationProvider); + awardPriceQueryable = awardPriceQueryable.OrderBy("Min"); + var count = awardPriceQueryable.Count(); + awardPriceQueryable = awardPriceQueryable.Skip((queryParam.PageIndex - 1) * queryParam.PageSize) + .Take(queryParam.PageSize); + var list = awardPriceQueryable.ToList(); + return new PageOutput(queryParam.PageIndex, queryParam.PageSize, count, list); + } + } +} \ No newline at end of file diff --git a/IRaCIS.Core.Application/IRaCIS.Core.Application.csproj b/IRaCIS.Core.Application/IRaCIS.Core.Application.csproj new file mode 100644 index 0000000..12c2f17 --- /dev/null +++ b/IRaCIS.Core.Application/IRaCIS.Core.Application.csproj @@ -0,0 +1,51 @@ + + + + netcoreapp3.1 + + + + ..\bin + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/IRaCIS.Core.Application/Institution/CROService.cs b/IRaCIS.Core.Application/Institution/CROService.cs new file mode 100644 index 0000000..83b3da4 --- /dev/null +++ b/IRaCIS.Core.Application/Institution/CROService.cs @@ -0,0 +1,117 @@ +using AutoMapper; +using AutoMapper.QueryableExtensions; +using IRaCIS.Application.ExpressionExtend; +using IRaCIS.Application.Interfaces; +using IRaCIS.Application.ViewModels; +using IRaCIS.Core.Application.Contracts.RequestAndResponse; +using IRaCIS.Core.Domain.Interfaces; +using IRaCIS.Core.Domain.Models; +using IRaCIS.Core.Domain.Share; +using IRaCIS.Infra.Data.ExpressionExtend; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Expressions; + +namespace IRaCIS.Application.Services +{ + public class CroService : ICroService + { + private readonly ICRORepository _croRepository; + private readonly ITrialRepository _trialRepository; + private readonly IUserRepository _userRepository; + private readonly IMapper _mapper; + + public CroService(ICRORepository croCompanyRepository, ITrialRepository trialRepository, IUserRepository userRepository,IMapper mapper) + { + _croRepository = croCompanyRepository; + _trialRepository = trialRepository; + _userRepository = userRepository; + _mapper = mapper; + } + + /// 分页获取CRO列表 + public PageOutput GetCroList(CROCompanyQueryDTO croCompanySearchModel) + { + Expression> croLambda = x => true; + if (!string.IsNullOrWhiteSpace(croCompanySearchModel.CROName.Trim())) + { + croLambda = croLambda.And(t => t.CROName.Contains(croCompanySearchModel.CROName.Trim())); + } + var croQueryable = _croRepository.Find(croLambda).ProjectTo(_mapper.ConfigurationProvider); + var count = croQueryable.Count(); + + var propName = string.IsNullOrWhiteSpace(croCompanySearchModel.SortField) ? "Id" : croCompanySearchModel.SortField; + + croQueryable = croCompanySearchModel.Asc ? croQueryable.OrderBy(propName) : croQueryable.OrderByDescending(propName); + + croQueryable = croQueryable + .Skip(((croCompanySearchModel.PageIndex - 1) * croCompanySearchModel.PageSize)) + .Take(croCompanySearchModel.PageSize); + + var croList = croQueryable.ToList(); + return new PageOutput(croCompanySearchModel.PageIndex, + croCompanySearchModel.PageSize, count, croList); + } + + /// 根据CRO 名称查询所有CRO 列表 + public IEnumerable GetCroSearchList() + { + var croQueryable = _croRepository.GetAll().ProjectTo(_mapper.ConfigurationProvider); + return croQueryable.ToList(); + } + + + + /// 添加CRO信息 + public IResponseOutput AddOrUpdateCro(CROCompanyDTO addCroCompanyViewModel, Guid userId) + { + if (addCroCompanyViewModel.Id == Guid.Empty||addCroCompanyViewModel.Id==null) + { + if (_croRepository.FindSingleOrDefault(t => t.CROName == addCroCompanyViewModel.CROName) != null) + { + return ResponseOutput.NotOk("Name repetition. "); + } + var temp = _mapper.Map(addCroCompanyViewModel); + + var cro = _croRepository.Add(temp); + var success = _croRepository.SaveChanges(); + + return ResponseOutput.Result(success, cro.Id.ToString()); + } + else + { + var updateCroCompanyViewModel = addCroCompanyViewModel; + if (_croRepository.FindSingleOrDefault(t => t.CROName == updateCroCompanyViewModel.CROName && t.Id != updateCroCompanyViewModel.Id) != null) + { + return ResponseOutput.NotOk("Name repetition. "); + } + var success = _croRepository.Update(t => t.Id == updateCroCompanyViewModel.Id, u => new CRO() + { + CROName = updateCroCompanyViewModel.CROName, + CROCode = updateCroCompanyViewModel.CROCode, + UpdateTime = DateTime.Now, + UpdateUserId = userId + }); + return ResponseOutput.Result(success, success ? string.Empty : StaticData.AddFailed); + } + + } + + /// 删除CRO信息 + public IResponseOutput DeleteCro(Guid cROCompanyId) + { + if (_trialRepository.Find().Any(t => t.CROId == cROCompanyId)) + { + return ResponseOutput.NotOk("存在该CRO的项目,暂时无法删除。"); + } + if (_userRepository.Find().Any(t => t.OrganizationId == cROCompanyId)) + { + return ResponseOutput.NotOk("该CRO下存在用户,暂时无法删除。"); + } + var success = _croRepository.Delete(t => t.Id == cROCompanyId); + + return ResponseOutput.Result(success, success ? string.Empty : StaticData.DeleteFailed); + } + } +} \ No newline at end of file diff --git a/IRaCIS.Core.Application/Institution/HospitalService.cs b/IRaCIS.Core.Application/Institution/HospitalService.cs new file mode 100644 index 0000000..68cba2b --- /dev/null +++ b/IRaCIS.Core.Application/Institution/HospitalService.cs @@ -0,0 +1,126 @@ +using AutoMapper; +using AutoMapper.QueryableExtensions; +using IRaCIS.Application.ExpressionExtend; +using IRaCIS.Application.Interfaces; +using IRaCIS.Application.ViewModels; +using IRaCIS.Core.Application.Contracts.RequestAndResponse; +using IRaCIS.Core.Domain.Interfaces; +using IRaCIS.Core.Domain.Models; +using IRaCIS.Core.Domain.Share; +using IRaCIS.Infra.Data.ExpressionExtend; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Expressions; + +namespace IRaCIS.Application.Services +{ + public class HospitalService : IHospitalService + { + private readonly IHospitalRepository _hospitalRepository; + private readonly IDoctorRepository _doctorRepository; + private readonly IUserRepository _userRepository; + private readonly IMapper _mapper; + + public HospitalService(IHospitalRepository hospitalRepository, IDoctorRepository doctorRepository, + IUserRepository userRepository, IMapper mapper) + { + _hospitalRepository = hospitalRepository; + _doctorRepository = doctorRepository; + _userRepository = userRepository; + _mapper = mapper; + } + + /// 获取所有医院列表 + public IEnumerable GetHospitalList() + { + return _hospitalRepository.GetAll().ProjectTo(_mapper.ConfigurationProvider); + } + + /// 添加医院 + public IResponseOutput AddOrUpdateHospital(HospitalCommand addViewModel) + { + if (addViewModel.Id == Guid.Empty || addViewModel.Id == null) + { + if (_hospitalRepository.GetAll().FirstOrDefault(t => t.HospitalName == addViewModel.HospitalName) != null) + { + return ResponseOutput.NotOk("Same hospital name already exist."); + } + var hospital = _hospitalRepository.Add(_mapper.Map(addViewModel)); + var success = _hospitalRepository.SaveChanges(); + + return ResponseOutput.Result(success, hospital.Id.ToString()); + } + else + { + var updateViewModel = addViewModel; + if (_hospitalRepository.FindSingleOrDefault(t => t.HospitalName == updateViewModel.HospitalName && t.Id != updateViewModel.Id) != null) + { + return ResponseOutput.NotOk("Same hospital name already exist."); + } + var success = _hospitalRepository.Update(t => t.Id == updateViewModel.Id, u => new Hospital() + { + City = updateViewModel.City, + Country = updateViewModel.Country, + HospitalName = updateViewModel.HospitalName, + Province = updateViewModel.Province, + UniversityAffiliated = updateViewModel.UniversityAffiliated + }); + + return ResponseOutput.Result(success, success ? string.Empty : StaticData.UpdateFailed); + } + } + + + + /// 删除医院信息 + public IResponseOutput DeleteHospital(Guid hospitalId) + { + if (_doctorRepository.GetAll().FirstOrDefault(t => t.Id == hospitalId) != null) + { + return ResponseOutput.NotOk("医生信息表已关联此医院"); + } + if (_userRepository.Find().Any(t => t.OrganizationId == hospitalId)) + { + return ResponseOutput.NotOk("该医院下存在用户,暂时无法删除。"); + } + + var success = _hospitalRepository.Delete(t => t.Id == hospitalId); + + return ResponseOutput.Result(success, success ? string.Empty : StaticData.DeleteFailed); + } + + /// 分页获取医院列表 + public PageOutput GetHospitalPageList(HospitalQueryDTO hospitalSearchModel) + { + Expression> hospitalLambda = x => true; + + if (hospitalSearchModel.HospitalName.Trim() != string.Empty) + { + hospitalLambda = hospitalLambda.And(t => t.HospitalName.Contains(hospitalSearchModel.HospitalName.Trim())); + } + if (hospitalSearchModel.City.Trim() != string.Empty) + { + hospitalLambda = hospitalLambda.And(t => t.City.Contains(hospitalSearchModel.City.Trim())); + } + if (hospitalSearchModel.Province.Trim() != string.Empty) + { + hospitalLambda = hospitalLambda.And(t => t.Province.Contains(hospitalSearchModel.Province.Trim())); + } + + var hospitalQueryable = + _hospitalRepository.GetAll().Where(hospitalLambda).ProjectTo(_mapper.ConfigurationProvider); + var count = hospitalQueryable.Count(); + var propName = string.IsNullOrWhiteSpace(hospitalSearchModel.SortField) ? "HospitalName" : hospitalSearchModel.SortField; + hospitalQueryable = hospitalSearchModel.Asc + ? hospitalQueryable.OrderBy(propName) + : hospitalQueryable.OrderByDescending(propName); + + hospitalQueryable = hospitalQueryable + .Skip((hospitalSearchModel.PageIndex - 1) * hospitalSearchModel.PageSize) + .Take(hospitalSearchModel.PageSize); + var userList = hospitalQueryable.ToList(); + return new PageOutput(hospitalSearchModel.PageIndex, hospitalSearchModel.PageSize, count, userList); + } + } +} \ No newline at end of file diff --git a/IRaCIS.Core.Application/Institution/SiteService.cs b/IRaCIS.Core.Application/Institution/SiteService.cs new file mode 100644 index 0000000..4e4fbde --- /dev/null +++ b/IRaCIS.Core.Application/Institution/SiteService.cs @@ -0,0 +1,173 @@ +using AutoMapper; +using AutoMapper.QueryableExtensions; +using IRaCIS.Application.ExpressionExtend; +using IRaCIS.Application.Interfaces; +using IRaCIS.Application.ViewModels; +using IRaCIS.Core.Application.Contracts.RequestAndResponse; +using IRaCIS.Core.Domain.Interfaces; +using IRaCIS.Core.Domain.Models; +using IRaCIS.Core.Domain.Share; +using IRaCIS.Infra.Data.ExpressionExtend; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Expressions; + +namespace IRaCIS.Application.Services +{ + public class SiteService : ISiteService + { + private readonly ISiteRepository _siteRepository; + private readonly IHospitalRepository _hospitalRepository; + private readonly IMapper _mapper; + private readonly IUserTrialRepository _userTrialRepository; + private readonly IUserRepository _userRepository; + + public SiteService(ISiteRepository researchCenterRepository, + IHospitalRepository hospitalRepository, IMapper mapper, + IUserTrialRepository userTrialRepository, + IUserRepository userRepository) + { + _siteRepository = researchCenterRepository; + _hospitalRepository = hospitalRepository; + _mapper = mapper; + _userTrialRepository = userTrialRepository; + _userRepository = userRepository; + } + + /// 分页获取研究中心列表 + public PageOutput GetSiteList(SiteQueryParam searchModel) + { + Expression> researchCenterLambda = x => true; + + if (!string.IsNullOrWhiteSpace(searchModel.SiteName.Trim())) + { + researchCenterLambda = researchCenterLambda.And(t => t.SiteName.Contains(searchModel.SiteName.Trim())); + } + + IQueryable siteQueryable = default; + if (searchModel.UserId == Guid.Empty) //查询所有Site + { + siteQueryable = from site in _siteRepository.GetAll().Where(researchCenterLambda) + join hospital in _hospitalRepository.GetAll() on site.HospitalId equals hospital.Id into h + from centerHospital in h.DefaultIfEmpty() + select new SiteSelectDTO() + { + Id = site.Id, + SiteName = site.SiteName, + City = site.City, + Country = site.Country, + SiteCode = site.SiteCode, + HospitalId = site.HospitalId, + DirectorName = site.DirectorName, + DirectorPhone = site.DirectorPhone, + ContactName = site.ContactName, + ContactPhone = site.ContactPhone, + HospitalName = centerHospital.HospitalName + }; + + //researchCenterQueryable = _researchCenterRepository.GetAll().Where(researchCenterLambda).ProjectTo(); + } + else //查询该用户没有是否选中改研究中心 ) + { + siteQueryable = + from site in _siteRepository.GetAll().Where(researchCenterLambda) + join userResearchCenter in _userTrialRepository + .Find(t => t.UserId == searchModel.UserId) on site.Id equals userResearchCenter + .SiteId into t + from userResearch in t.DefaultIfEmpty() + join hospital in _hospitalRepository.GetAll() on site.HospitalId equals hospital.Id into h + from centerHospital in h.DefaultIfEmpty() + select new SiteSelectDTO() + { + Id = site.Id, + SiteName = site.SiteName, + SiteCode = site.SiteCode, + IsSelect = userResearch == null ? false : true, + HospitalId = site.HospitalId, + HospitalName = centerHospital.HospitalName + }; + } + var count = siteQueryable.Count(); + + //处理排序字段 + var propName = string.IsNullOrWhiteSpace(searchModel.SortField) ? "SiteName" : searchModel.SortField; + //处理升序和降序 + siteQueryable = searchModel.Asc + ? siteQueryable.OrderBy(propName) + : siteQueryable.OrderByDescending(propName); + + //分页 + siteQueryable = siteQueryable + .Skip((searchModel.PageIndex - 1) * searchModel.PageSize) + .Take(searchModel.PageSize); + var researchCenterList = siteQueryable.ToList(); + return new PageOutput(searchModel.PageIndex, searchModel.PageSize, count, researchCenterList); + } + + public IEnumerable GetSiteList() + { + return _siteRepository.GetAll().ProjectTo(_mapper.ConfigurationProvider); + } + + + /// 添加研究中心 + public IResponseOutput AddOrUpdateSite(SiteCommand site, Guid userId) + { + if (site.Id == Guid.Empty || site.Id == null) + { + if (_siteRepository.GetAll().FirstOrDefault(t => t.SiteName == site.SiteName) != null) + { + return ResponseOutput.NotOk("Please specify another center name"); + } + var temp = _mapper.Map(site); + + var saveMode = _siteRepository.Add(temp); + var success = _siteRepository.SaveChanges(); + + return ResponseOutput.Result(success, saveMode.Id.ToString()); + } + else + { + var updateModel = site; + bool exist = _siteRepository.IsExist(u => u.SiteName == updateModel.SiteName && u.Id != updateModel.Id); + if (exist) + { + return ResponseOutput.NotOk("已存在同名的中心名称"); + } + + var success = _siteRepository.Update(u => u.Id == updateModel.Id, s => new Site + { + SiteCode = updateModel.SiteCode, + SiteName = updateModel.SiteName, + City = updateModel.City, + Country = updateModel.Country, + HospitalId = updateModel.HospitalId, + DirectorName = updateModel.DirectorName, + DirectorPhone = updateModel.DirectorPhone, + ContactName = updateModel.ContactName, + ContactPhone = updateModel.ContactPhone, + UpdateUserId = userId, + UpdateTime = DateTime.Now + }); + + return ResponseOutput.Result(success, success ? string.Empty : StaticData.UpdateFailed); + } + } + + /// 删除研究中心 + public IResponseOutput DeleteSite(Guid siteId) + { + if (_userRepository.Find().Any(t => t.OrganizationId == siteId)) + { + return ResponseOutput.NotOk("该Site下存在用户,暂时无法删除。"); + } + if (_userTrialRepository.Find().Any(t => t.SiteId == siteId)) + { + return ResponseOutput.NotOk("有项目在该Site下,暂时无法删除。"); + } + var success = _siteRepository.Delete(t => t.Id == siteId); + return ResponseOutput.Result(success); + } + } +} \ No newline at end of file diff --git a/IRaCIS.Core.Application/Institution/SponsorService.cs b/IRaCIS.Core.Application/Institution/SponsorService.cs new file mode 100644 index 0000000..64b776c --- /dev/null +++ b/IRaCIS.Core.Application/Institution/SponsorService.cs @@ -0,0 +1,118 @@ +using AutoMapper; +using AutoMapper.QueryableExtensions; +using IRaCIS.Application.ExpressionExtend; +using IRaCIS.Application.Interfaces; +using IRaCIS.Application.ViewModels; +using IRaCIS.Core.Application.Contracts.RequestAndResponse; +using IRaCIS.Core.Domain.Interfaces; +using IRaCIS.Core.Domain.Models; +using IRaCIS.Infra.Data.ExpressionExtend; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Expressions; + +namespace IRaCIS.Application.Services +{ + public class SponsorService : ISponsorService + { + private readonly ISponsorRepository _sponsorRepository; + private readonly ITrialRepository _trialRepository; + private readonly IMapper _mapper; + private readonly IUserRepository _userRepository; + + public SponsorService(ISponsorRepository sponsorRepository, ITrialRepository trialRepository, IUserRepository userRepository, IMapper mapper) + { + _sponsorRepository = sponsorRepository; + _trialRepository = trialRepository; + _userRepository = userRepository; + _mapper = mapper; + } + + /// 分页获取申办方列表 + public PageOutput GetSponsorList(SponsorQueryDTO sponsorSearchModel) + { + Expression> sponsorLambda = x => true; + if (!string.IsNullOrWhiteSpace(sponsorSearchModel.SponsorName)) + { + sponsorLambda = sponsorLambda.And(t => t.SponsorName.Contains(sponsorSearchModel.SponsorName.Trim())); + } + var sponsorQueryable = _sponsorRepository.GetAll().Where(sponsorLambda).ProjectTo(_mapper.ConfigurationProvider); + var count = sponsorQueryable.Count(); + + //处理排序字段 + var propName = string.IsNullOrWhiteSpace(sponsorSearchModel.SortField) ? "Id" : sponsorSearchModel.SortField; + //处理升序和降序 + sponsorQueryable = sponsorSearchModel.Asc + ? sponsorQueryable.OrderBy(propName) + : sponsorQueryable.OrderByDescending(propName); + + //分页 + sponsorQueryable = sponsorQueryable + .Skip(((sponsorSearchModel.PageIndex - 1) * sponsorSearchModel.PageSize)) + .Take(sponsorSearchModel.PageSize); + //数据库查询 + var sponsorList = sponsorQueryable.ToList(); + return new PageOutput(sponsorSearchModel.PageIndex, + sponsorSearchModel.PageSize, count, sponsorList); + } + + /// 分页获取申办方列表 + public IEnumerable GetSponsorSearchList() + { + //Expression> sponsorLambda = x => true; + //if (!string.IsNullOrWhiteSpace(sponsorSearchModel.SponsorName)) + //{ + // sponsorLambda = sponsorLambda.And(t => t.SponsorName.Contains(sponsorSearchModel.SponsorName.Trim())); + //} + var sponsorQueryable = _sponsorRepository.GetAll().ProjectTo(_mapper.ConfigurationProvider); + return sponsorQueryable.ToList(); + } + + /// 添加申办方 + public IResponseOutput AddOrUpdateSponsor(SponsorCommand addSponsorViewModel) + { + if (addSponsorViewModel.Id==Guid.Empty|| addSponsorViewModel.Id == null) + { + if (_sponsorRepository.FindSingleOrDefault(t => t.SponsorName == addSponsorViewModel.SponsorName) != null) + { + return ResponseOutput.NotOk("Name repetition. "); + } + var sponsor = _sponsorRepository.Add(_mapper.Map(addSponsorViewModel)); + var success = _sponsorRepository.SaveChanges(); + return ResponseOutput.Result(success, sponsor.Id.ToString()); + } + else + { + var updateSponsorViewModel = addSponsorViewModel; + + if (_sponsorRepository.FindSingleOrDefault(t => t.SponsorName == updateSponsorViewModel.SponsorName && t.Id != updateSponsorViewModel.Id) != null) + { + return ResponseOutput.NotOk("Name repetition. "); + } + var success = _sponsorRepository.Update(t => t.Id == updateSponsorViewModel.Id, u => new Sponsor() + { + SponsorName = updateSponsorViewModel.SponsorName + }); + + return ResponseOutput.Result(success); + } + + } + + /// 删除申办方 + public IResponseOutput DeleteSponsor(Guid sponsorId) + { + if (_trialRepository.GetAll().Any(t => t.CROId == sponsorId)) + { + return ResponseOutput.NotOk("在项目表中已关联此项"); + } + if (_userRepository.Find().Any(t => t.OrganizationId == sponsorId)) + { + return ResponseOutput.NotOk("该申办方下存在用户,暂时无法删除。"); + } + var success = _sponsorRepository.Delete(t => t.Id == sponsorId); + return ResponseOutput.Result(success); + } + } +} \ No newline at end of file diff --git a/IRaCIS.Core.Application/Management/InstitutionService.cs b/IRaCIS.Core.Application/Management/InstitutionService.cs new file mode 100644 index 0000000..4a67a6f --- /dev/null +++ b/IRaCIS.Core.Application/Management/InstitutionService.cs @@ -0,0 +1,67 @@ +using AutoMapper; +using AutoMapper.QueryableExtensions; +using IRaCIS.Application.Interfaces; +using IRaCIS.Application.ViewModels; +using IRaCIS.Core.Domain.Interfaces; +using System; +using System.Collections.Generic; + +namespace IRaCIS.Application.Services +{ + public class InstitutionService: IInstitutionService + { + private readonly IDictionaryRepository _dictionaryRepository; + private readonly ICRORepository _croRepository; + private readonly ISponsorRepository _sponsorRepository; + private readonly IHospitalRepository _hospitalRepository; + private readonly ISiteRepository _siteRepository; + private readonly IMapper _mapper; + + public InstitutionService(IDictionaryRepository dictionaryRepository, + ICRORepository crOCompanyRepository, + ISponsorRepository sponsorRepository, + IHospitalRepository hospitalRepository, + ISiteRepository researchCenterRepository,IMapper mapper) + { + _dictionaryRepository = dictionaryRepository; + _croRepository = crOCompanyRepository; + _sponsorRepository = sponsorRepository; + _hospitalRepository = hospitalRepository; + _siteRepository = researchCenterRepository; + _mapper = mapper; + } + public IEnumerable GetInstitutionSelectionByTypeId(Guid typeId) + { + List result = new List(); + //bool isSuccess = false; + + if (typeId != Guid.Empty) + { + var dicItem = _dictionaryRepository.FindSingleOrDefault(u => u.Id == typeId); + + if (dicItem.Type.Contains("CRO")) + { + result.AddRange(_croRepository.GetAll().ProjectTo(_mapper.ConfigurationProvider)); + //isSuccess = true; + } + if (dicItem.Type.Contains("Sponsor")) + { + result.AddRange(_sponsorRepository.GetAll().ProjectTo(_mapper.ConfigurationProvider)); + //isSuccess = true; + } + if (dicItem.Type.Contains("Hospital")) + { + result.AddRange(_hospitalRepository.GetAll().ProjectTo(_mapper.ConfigurationProvider)); + //isSuccess = true; + } + if (dicItem.Type.Contains("Site")) + { + result.AddRange(_siteRepository.GetAll().ProjectTo(_mapper.ConfigurationProvider)); + //isSuccess = true; + } + } + + return result; + } + } +} diff --git a/IRaCIS.Core.Application/Management/MenuService.cs b/IRaCIS.Core.Application/Management/MenuService.cs new file mode 100644 index 0000000..2c2f33f --- /dev/null +++ b/IRaCIS.Core.Application/Management/MenuService.cs @@ -0,0 +1,317 @@ +using AutoMapper; +using AutoMapper.QueryableExtensions; +using IRaCIS.Application.Interfaces; +using IRaCIS.Application.ViewModels; +using IRaCIS.Core.Application.Contracts.RequestAndResponse; +using IRaCIS.Core.Domain.Interfaces; +using IRaCIS.Core.Domain.Models; +using System; +using System.Collections.Generic; +using System.Linq; + +namespace IRaCIS.Application.Services +{ + public class MenuService : IMenuService + { + private readonly IMenuFunctionRepository _menuFunctionRepository; + private readonly IRoleMenuFunctionRepository _roleMenuFunctionRepository; + private readonly IMapper _mapper; + + public MenuService(IMenuFunctionRepository menuRepository, IRoleMenuFunctionRepository roleMenuRepository, IMapper mapper) + { + _menuFunctionRepository = menuRepository; + _roleMenuFunctionRepository = roleMenuRepository; + _mapper = mapper; + } + + #region byzhouhang 递归 + + /// + /// 根据父节点ID递归生成树 + /// + /// + /// + /// + public List GetTreeList(Guid parentId, List allMenuList) + { + //树节点集合 每个节点包含一个菜单项 和一个子菜单集合 + List treeList = new List(); + + // 根据父菜单节点获取子菜单节点 并且进行排序 + List menuList = allMenuList.Where(x => x.ParentId == parentId).OrderBy(t => t.ShowOrder).ToList(); + + foreach (var menuItem in menuList) + { + MenuTreeNode treeItem = new MenuTreeNode() + { + Id = menuItem.Id, + ParentId = menuItem.ParentId, + RouteName = menuItem.RouteName, + MenuName = menuItem.MenuName, + Path = menuItem.Path, + Hidden = menuItem.Hidden, + Component = menuItem.Component, + FunctionName = menuItem.FunctionName, + IsFunction = menuItem.IsFunction, + MetaActiveMenu = menuItem.MetaActiveMenu, + MetaBreadcrumb = menuItem.MetaBreadcrumb, + MetaIcon = menuItem.MetaIcon, + MetaTitle = menuItem.MetaTitle, + Redirect = menuItem.Redirect, + ShowOrder = menuItem.ShowOrder, + Note = menuItem.Note, + Status = menuItem.Status, + Children = GetTreeList(menuItem.Id, allMenuList) + }; + + treeList.Add(treeItem); + } + return treeList; + } + + + ///// + ///// 递归获取某父节点下所有的子节点 + ///// + ///// + ///// + ///// + //private List GetMenuIds(Guid parentId, List allMenuList) + //{ + // var menuIdList = new List(); + + // // 根据单节点获取子节点 并且进行排序 + // List menuList = allMenuList.Where(x => x.ParentId == parentId).OrderBy(t => t.ShowOrder).ToList(); + + // foreach (var menuItem in menuList) + // { + // menuIdList.Add(menuItem.Id); + + // menuIdList.AddRange(GetMenuIds(menuItem.Id, allMenuList)); + // } + + // return menuIdList; + //} + + #endregion + + ////获取菜单树 没有被禁用的 + //public List GetTreeNotDisabled() + //{ + // var allMenuList = _menuFunctionRepository.GetAll().Where(t => t.Status == 1).ProjectTo(_mapper.ConfigurationProvider).ToList(); + + // return GetTreeList(Guid.Empty, allMenuList); + //} + + //所有的菜单树 包括禁用的 + public List GetTreeAll() + { + var allMenuList = _menuFunctionRepository.GetAll().ProjectTo(_mapper.ConfigurationProvider).ToList(); + + return GetTreeList(Guid.Empty, allMenuList); + } + + public List GetMenuFunctionIsSelectByRoleId(Guid roleId) + { + var menuFuncQuery = from function in _menuFunctionRepository.Find(u => !u.IsFunction) + join roleMenuFunctionItem in _roleMenuFunctionRepository.GetAll() + .Where(t => t.RoleId == roleId) + on function.Id equals roleMenuFunctionItem.MenuFunctionId into t + from roleFunction in t.DefaultIfEmpty() + select new MenuTreeNodeSelect() + { + IsSelect = roleFunction != null, + ShowOrder = function.ShowOrder, + MenuName = function.MenuName, + Note = function.Note, + FunctionName = function.FunctionName, + ParentId = function.ParentId, + Id = function.Id, + }; + var list = menuFuncQuery.ToList(); + return GetSelectTreeList(Guid.Empty, list); + } + + public List GetFunctionIsSelectByRoleId(Guid roleId, Guid parentId) + { + var menuFuncQuery = from function in _menuFunctionRepository.Find(u => u.IsFunction && + u.ParentId == parentId) + join roleMenuFunctionItem in _roleMenuFunctionRepository.GetAll() + .Where(t => t.RoleId == roleId) + on function.Id equals roleMenuFunctionItem.MenuFunctionId into t + from roleFunction in t.DefaultIfEmpty() + select new MenuTreeNodeSelect() + { + IsSelect = roleFunction != null, + ShowOrder = function.ShowOrder, + MenuName = function.MenuName, + Note = function.Note, + FunctionName = function.FunctionName, + ParentId = function.ParentId, + Id = function.Id, + }; + return menuFuncQuery.ToList(); + //return GetSelectTreeList(Guid.Empty, list); + } + + private List GetTreeList(Guid parentId, List allMenuList) + { + List TreeList = new List(); + List menuList = allMenuList.Where(x => x.ParentId == parentId).OrderBy(t => t.ShowOrder).ToList(); + + foreach (var menuItem in menuList) + { + MenuTreeNode treeItem = new MenuTreeNode() + { + Id = menuItem.Id, + ParentId = menuItem.ParentId, + RouteName = menuItem.RouteName, + MenuName = menuItem.MenuName, + Path = menuItem.Path, + Hidden = menuItem.Hidden, + Component = menuItem.Component, + FunctionName = menuItem.FunctionName, + IsFunction = menuItem.IsFunction, + MetaActiveMenu = menuItem.MetaActiveMenu, + MetaBreadcrumb = menuItem.MetaBreadcrumb, + MetaIcon = menuItem.MetaIcon, + MetaTitle = menuItem.MetaTitle, + Redirect = menuItem.Redirect, + ShowOrder = menuItem.ShowOrder, + Note = menuItem.Note, + Status = menuItem.Status, + Children = GetTreeList(menuItem.Id, allMenuList) + }; + + TreeList.Add(treeItem); + } + return TreeList; + } + + + private List GetSelectTreeList(Guid parentId, List allMenuList) + { + List TreeList = new List(); + List menuList = allMenuList.Where(x => x.ParentId == parentId).OrderBy(t => t.ShowOrder).ToList(); + + foreach (var menuItem in menuList) + { + MenuTreeNodeSelect treeItem = new MenuTreeNodeSelect() + { + Id = menuItem.Id, + ParentId = menuItem.ParentId, + RouteName = menuItem.RouteName, + MenuName = menuItem.MenuName, + Note = menuItem.Note, + IsSelect = menuItem.IsSelect, + ShowOrder = menuItem.ShowOrder, + Children = GetSelectTreeList(menuItem.Id, allMenuList) + }; + + TreeList.Add(treeItem); + } + return TreeList; + } + + /// + /// 添加菜单 + /// + /// + /// + /// + public IResponseOutput AddOrUpdateMenu(MenuFunctionCommand menuAddOrUpdateModel, Guid userId) + { + if (menuAddOrUpdateModel.Id == null || menuAddOrUpdateModel.Id == Guid.Empty) + { + bool exist = _menuFunctionRepository.IsExist(u => u.ParentId == menuAddOrUpdateModel.ParentId && u.MenuName == menuAddOrUpdateModel.MenuName); + if (exist) + { + return ResponseOutput.NotOk("该父节点已经存在同名的节点"); + } + + if (!string.IsNullOrWhiteSpace(menuAddOrUpdateModel.FunctionName)) + { + menuAddOrUpdateModel.IsFunction = true; + } + + var result = _menuFunctionRepository.Add(_mapper.Map(menuAddOrUpdateModel)); + + if (_menuFunctionRepository.SaveChanges()) + { + return ResponseOutput.Ok(result.Id.ToString()); + } + return ResponseOutput.NotOk(); + } + else + { + var menuUpdateModel = menuAddOrUpdateModel; + bool exist = _menuFunctionRepository.IsExist(u => u.ParentId == menuUpdateModel.ParentId && + u.MenuName == menuUpdateModel.MenuName && u.Id != menuUpdateModel.Id); + if (exist) + { + return ResponseOutput.NotOk("该父节点已经存在同名的节点"); + } + var updateModel = _mapper.Map(menuUpdateModel); + + if (!string.IsNullOrWhiteSpace(updateModel.FunctionName)) + { + updateModel.IsFunction = true; + } + _menuFunctionRepository.Update(updateModel); + + var success = _menuFunctionRepository.SaveChanges(); + return ResponseOutput.Result(success); + } + } + + /// + /// 删除菜单 + /// + /// + /// + public IResponseOutput DeleteMenuFunction(Guid menuId) + { + var success = _menuFunctionRepository.Delete(u => u.Id == menuId || u.ParentId == menuId); + return ResponseOutput.Result(success); + } + + public IResponseOutput UpdateRoleMenuSelect(Guid roleId, List menuIds) + { + var deleteSuccess = + _roleMenuFunctionRepository.Delete(t => t.RoleId == roleId && !t.IsFunction); + foreach (var item in menuIds) + { + _roleMenuFunctionRepository.Add(new RoleMenuFunction() + { + MenuFunctionId = item, + RoleId = roleId, + IsFunction = false + }); + } + var addSuccess = _roleMenuFunctionRepository.SaveChanges(); + + return ResponseOutput.Result(deleteSuccess || addSuccess); + } + + public IResponseOutput UpdateRoleFunctionSelect(FunctionSelectDTO function) + { + var success = false; + if (function.IsSelect) + { + _roleMenuFunctionRepository.Add(new RoleMenuFunction() + { + MenuFunctionId = function.FunctionId, + RoleId = function.RoleId, + IsFunction = true + }); + success = _roleMenuFunctionRepository.SaveChanges(); + } + else + { + success = _roleMenuFunctionRepository.Delete(u => u.MenuFunctionId == function.FunctionId && function.RoleId == u.RoleId); + } + + return ResponseOutput.Result(success); + } + } +} diff --git a/IRaCIS.Core.Application/Management/RoleService.cs b/IRaCIS.Core.Application/Management/RoleService.cs new file mode 100644 index 0000000..b8619d2 --- /dev/null +++ b/IRaCIS.Core.Application/Management/RoleService.cs @@ -0,0 +1,154 @@ +using AutoMapper; +using AutoMapper.QueryableExtensions; +using IRaCIS.Application.Interfaces; +using IRaCIS.Application.ViewModels; +using IRaCIS.Core.Application.Contracts.RequestAndResponse; +using IRaCIS.Core.Domain.Interfaces; +using IRaCIS.Core.Domain.Models; +using System; +using System.Linq; + +namespace IRaCIS.Application.Services +{ + public class RoleService : IRoleService + { + private readonly IRoleRepository _roleRepository; + private readonly IUserRoleRepository _userRoleRepository; + private readonly IMapper _mapper; + public RoleService(IRoleRepository roleRepository, + IUserRoleRepository userRoleRepository, IMapper mapper + ) + { + _roleRepository = roleRepository; + _userRoleRepository = userRoleRepository; + _mapper = mapper; + } + + public IResponseOutput AddOrUpdateRole(RoleCommand role, Guid userId) + { + if (role.Id == Guid.Empty|| role.Id ==null) + { + var exist = _roleRepository.GetAll().FirstOrDefault(u => u.RoleName == role.RoleName); + if (exist != null) + { + return ResponseOutput.NotOk("Same role name is existed"); + } + var result = _roleRepository.Add(_mapper.Map(role)); + + return ResponseOutput.Result(_roleRepository.SaveChanges()); + + } + else + { + var exist = _roleRepository.GetAll().FirstOrDefault(u => u.RoleName == role.RoleName && u.Id != role.Id); + if (exist != null) + { + return ResponseOutput.NotOk("Same role name is existed"); + } + var success = _roleRepository.Update(t => t.Id == role.Id, u => new Role() + { + UpdateTime = DateTime.Now, + UpdateUserId = userId, + RoleName = role.RoleName, + PrivilegeLevel = role.PrivilegeLevel, + RoleDescription = role.RoleDescription + }); + + return ResponseOutput.Result(success); + } + } + + //public IResponseOutput CopyRole(Guid sourceRoleId, RoleAddOrUpdateModel role) + //{ + // var exist = _roleRepository.GetAll().FirstOrDefault(u => u.RoleName == role.RoleName); + // if (exist != null) + // { + // return new IResponseOutput { IsSuccess = false, ErrorMessage = "Role Name is existed", Result = Guid.Empty }; + // } + // var result = _roleRepository.Add(_mapper.Map(role)); + + // var roleMenu = _roleMenuRepository.Find(u => u.RoleId == sourceRoleId); + // //var roleFunction = _roleFunctionRepository.Find(u => u.RoleId == sourceRoleId); + + + // if (_roleRepository.SaveChanges()) + // { + // foreach (var item in roleMenu) + // { + // item.Id = Guid.Empty; + // item.RoleId = result.Id; + // _roleMenuRepository.Add(item); + // }; + // _roleMenuRepository.SaveChanges(); + + // //foreach (var roleFunctionItem in roleFunction) + // //{ + // // roleFunctionItem.Id = Guid.Empty; + // // roleFunctionItem.RoleId = result.Id; + // // _roleFunctionRepository.Add(roleFunctionItem); + // //}; + // //_roleFunctionRepository.SaveChanges(); + + // return new IResponseOutput { IsSuccess = true, Result = result.Id }; + // } + // return new IResponseOutput { IsSuccess = false, ErrorMessage = ConstClass.AddFailed, Result = Guid.Empty }; + //} + + public IResponseOutput DeleteRole(Guid roleId) + { + //删除角色,需要判断该角色是否被使用 + var exist = _userRoleRepository.GetAll().FirstOrDefault(u => u.RoleId == roleId); + if (exist != null) + return ResponseOutput.NotOk("This role is used,can not delete."); + + var result = _roleRepository.Delete(u => u.Id == roleId); + return ResponseOutput.Result(result); + } + + + public PageOutput GetRoleListByPage(int pageIndex, int pageSize) + { + var count = _roleRepository.GetCount(); + var data = _roleRepository.Find(pageSize, pageIndex, true, u => u.RoleName).ProjectTo(_mapper.ConfigurationProvider).ToList(); + return new PageOutput(pageIndex, pageSize, count, data); + } + + public PageOutput GetRoleListByPage(Guid userId, int pageIndex, int pageSize) + { + var query = from role in _roleRepository.GetAll() + join userRoleItem in _userRoleRepository.GetAll().Where(t => t.UserId == userId) on role.Id equals userRoleItem.RoleId into t + from userRole in t.DefaultIfEmpty() + select new UserSelectRoleDTO() + { + Id = role.Id, + IsSelect = userRole == null ? false : true, + RoleDescription = role.RoleDescription, + RoleName = role.RoleName + }; + var count = _roleRepository.GetCount(); + var data = query.ToList(); + return new PageOutput(pageIndex, pageSize, count, data); + } + + public IResponseOutput UpdateUserRole(Guid userId, Guid roleId, bool isSelect) + { + var success = false; + if (isSelect) + { + _userRoleRepository.Add(new UserRole() + { + RoleId = roleId, + UserId = userId + }); + success = _userRoleRepository.SaveChanges(); + } + else + { + success = _userRoleRepository.Delete(t => t.UserId == userId && t.RoleId == roleId); + } + + return ResponseOutput.Result(success); + + } + } +} diff --git a/IRaCIS.Core.Application/Management/UserService.cs b/IRaCIS.Core.Application/Management/UserService.cs new file mode 100644 index 0000000..96d6453 --- /dev/null +++ b/IRaCIS.Core.Application/Management/UserService.cs @@ -0,0 +1,880 @@ +using AutoMapper; +using AutoMapper.QueryableExtensions; +using IRaCIS.Application.ExpressionExtend; +using IRaCIS.Application.Interfaces; +using IRaCIS.Application.ViewModels; +using IRaCIS.Core.Application.Contracts.RequestAndResponse; +using IRaCIS.Core.Domain.Interfaces; +using IRaCIS.Core.Domain.Models; +using IRaCIS.Core.Domain.Share; +using IRaCIS.Core.Infrastructure; +using IRaCIS.Infra.Data.ExpressionExtend; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Expressions; +using System.Text.RegularExpressions; +using System.Threading.Tasks; +using IRaCIS.Core.Domain.Share.AuthUser; + +namespace IRaCIS.Application.Services +{ + + public class UserService : IUserService + { + private readonly IUserRepository _userRepository; + private readonly IUserRoleRepository _userRoleRepository; + private readonly IRoleMenuFunctionRepository _roleMenuRepository; + private readonly IRoleRepository _roleRepository; + private readonly IMenuFunctionRepository _menuRepository; + private readonly IDictionaryRepository _dictionaryRepository; + private readonly IMailVerificationService _mailVerificationService; + private readonly IVerificationCodeRepository _verificationCodeRepository; + private readonly IDoctorRepository _doctorRepository; + private readonly IUserInfo _userInfo; + private readonly IMapper _mapper; + + public UserService(IUserRepository userRepository, + IUserRoleRepository userRoleRepository, + IRoleMenuFunctionRepository roleMenuRepository, + IRoleRepository roleRepository, + IMenuFunctionRepository menuRepository, + IDictionaryRepository dictionaryRepository, + IMailVerificationService mailVerificationService, + IVerificationCodeRepository verificationCodeRepository, + IDoctorRepository doctorRepository, + IUserInfo userInfo, + IMapper mapper) + { + _userRepository = userRepository; + _userRoleRepository = userRoleRepository; + _roleMenuRepository = roleMenuRepository; + _roleRepository = roleRepository; + _menuRepository = menuRepository; + _dictionaryRepository = dictionaryRepository; + _mailVerificationService = mailVerificationService; + _verificationCodeRepository = verificationCodeRepository; + _doctorRepository = doctorRepository; + _userInfo = userInfo; + _mapper = mapper; + } + + public async Task SendVerificationCode(string emailOrPhone, int verificationType, bool isReviewer = false) + { + if (string.IsNullOrEmpty(emailOrPhone)) + { + return ResponseOutput.NotOk(verificationType == 0 ? "Please input email" : "Please input Phone"); + + } + //防止输入前后有空格 + var emailOrPhoneStr = emailOrPhone.Trim(); + + //检查手机或者邮箱是否有效 + if (!Regex.IsMatch(emailOrPhoneStr, @"/^1[34578]\d{9}$/") && !Regex.IsMatch(emailOrPhoneStr, @"^[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+(\.[a-zA-Z0-9_-]+)+$")) + { + + return ResponseOutput.NotOk(verificationType == 0 + ? "Please input a legal email" + : "Please input a legal phone"); + + } + + //医生登录 + if (isReviewer) + { + var exist = _doctorRepository.GetAll().Any(t => t.EMail == emailOrPhoneStr || t.Phone == emailOrPhoneStr); + + if (!exist) + { + return ResponseOutput.NotOk(verificationType == 0 + ? "No user has this email" + : "No user has this phone"); + + } + + var user = _doctorRepository.GetAll().First(t => t.EMail == emailOrPhoneStr || t.Phone == emailOrPhoneStr); + //邮箱 + if (verificationType == 0) + { + //验证码 6位 + int verificationCode = new Random().Next(100000, 1000000); + + await _mailVerificationService.SendMail(user.Id, user.ChineseName, emailOrPhoneStr, + verificationCode); + } + //手机短信 + else + { + + } + + } + else//管理用户登录 + { + //查找改邮箱或者手机的用户 + var exist = _userRepository.GetAll().Any(t => t.EMail == emailOrPhoneStr || t.Phone == emailOrPhoneStr); + + if (!exist) + { + return ResponseOutput.NotOk(verificationType == 0 + ? "No user has this email" + : "No user has this phone"); + + } + var user = _userRepository.GetAll().First(t => t.EMail == emailOrPhoneStr || t.Phone == emailOrPhoneStr); + //邮箱 + if (verificationType == 0) + { + //验证码 6位 + int verificationCode = new Random().Next(100000, 1000000); + + await _mailVerificationService.SendMail(user.Id, user.RealName, emailOrPhoneStr, + verificationCode); + } + //手机短信 + else + { + + } + } + + + + + return ResponseOutput.Ok(); + } + + public IResponseOutput SetNewPassword(string emailOrPhone, int verificationType, + string verificationCode, string newPwd, bool isReviewer) + { + if (isReviewer) + { + var emailOrPhoneStr = emailOrPhone.Trim(); + var verificationCodeStr = verificationCode.Trim(); + var user = _doctorRepository.GetAll().First(t => t.EMail == emailOrPhoneStr || t.Phone == emailOrPhoneStr); + + var verificationRecord = _verificationCodeRepository + .GetAll().FirstOrDefault(t => t.UserId == user.Id && t.Code == verificationCodeStr && t.CodeType == verificationType); + + //检查数据库是否存在该验证码 + if (verificationRecord == null) + { + + return ResponseOutput.NotOk("Verification code error"); + + } + else + { + //检查验证码是否失效 + if (verificationRecord.ExpirationTime < DateTime.Now) + { + return ResponseOutput.NotOk("Verification code time has expired"); + + } + else //验证码正确 并且 没有超时 + { + //更新密码 + var success = _doctorRepository.Update(t => t.Id == user.Id, u => new Doctor() + { + Password = newPwd + }); + + //删除验证码历史记录 + _verificationCodeRepository.Delete(t => t.UserId == user.Id && t.CodeType == verificationType); + + return ResponseOutput.Result(success, "database update failed"); + + } + } + } + else + { + var emailOrPhoneStr = emailOrPhone.Trim(); + var verificationCodeStr = verificationCode.Trim(); + + var user = _userRepository.GetAll().First(t => t.EMail == emailOrPhoneStr || t.Phone == emailOrPhoneStr); + + + var verificationRecord = _verificationCodeRepository + .GetAll().FirstOrDefault(t => t.UserId == user.Id && t.Code == verificationCodeStr && t.CodeType == verificationType); + + //检查数据库是否存在该验证码 + if (verificationRecord == null) + { + + return ResponseOutput.NotOk("Verification code error"); + + } + else + { + //检查验证码是否失效 + if (verificationRecord.ExpirationTime < DateTime.Now) + { + return ResponseOutput.NotOk("Verification code time has expired"); + + } + else //验证码正确 并且 没有超时 + { + //更新密码 + //var pwd = MD5Helper.Md5(newPwd); + //var count = _doctorRepository.Update().Where(t => t.Id == doctor.Id).Set(d => d.Password == pwd).ExecuteAffrows(); + + var success = _userRepository.Update(t => t.Id == user.Id, u => new User() + { + Password = newPwd + }); + + //删除验证码历史记录 + _verificationCodeRepository.Delete(t => t.UserId == user.Id && t.CodeType == verificationType); + + return ResponseOutput.Result(success, "database update failed"); + + } + } + } + + } + + public IResponseOutput Login(string userName, string password) + { + var name = userName.Trim(); + var passwordMd5 = password.Trim(); + + var user = _userRepository.GetAll().FirstOrDefault(u => u.UserName == name && u.Password == passwordMd5); + + if (user != null) + { + if (user.Status == 0) + { + return ResponseOutput.NotOk("用户已被禁用!", new LoginReturnDTO()); + } + + var userLoginReturnModel = new LoginReturnDTO(); + userLoginReturnModel.BasicInfo = new UserBasicInfo() + { + Id = user.Id, + UserName = user.UserName, + RealName = user.RealName, + Sex = user.Sex + }; + + if (user.SuperAdmin) + { + userLoginReturnModel.BasicInfo.IsAdmin = true; + userLoginReturnModel.MenuTree = GetAdminMenuTree().FirstOrDefault()?.Childrens; + userLoginReturnModel.FuncDictionary = DealFunction(GetAdminFunctionTree().FirstOrDefault()?.Childrens); + } + else + { + var menuTree = GetUserMenuTreeNew(userLoginReturnModel.BasicInfo.Id) + .FirstOrDefault()?.Childrens; + userLoginReturnModel.MenuTree = menuTree ?? new List(); + userLoginReturnModel.FuncDictionary = DealFunction(GetUserFuncTreeNew(userLoginReturnModel.BasicInfo.Id)?.First().Childrens); + } + return ResponseOutput.Ok(userLoginReturnModel); + } + + + //此处下面 代码 为了支持医生也能登录 而且前端不加选择到底是管理用户 还是医生用户 + + var doctor = _doctorRepository.GetAll().FirstOrDefault(u => u.Phone == name && u.Password == passwordMd5); + + if (doctor != null) + { + var userLoginReturnModel = new LoginReturnDTO(); + userLoginReturnModel.BasicInfo = new UserBasicInfo() + { + Id = doctor.Id, + UserName = doctor.LastName + " / " + doctor.FirstName, + RealName = doctor.ChineseName, + Sex = doctor.Sex, + IsReviewer = true, + ReviewerCode = doctor.Code + }; + + var menuTree = GetUserMenuTreeNew(userLoginReturnModel.BasicInfo.Id, true) + .FirstOrDefault()?.Childrens; + + userLoginReturnModel.MenuTree = menuTree ?? new List(); + userLoginReturnModel.FuncDictionary = DealFunction(GetUserFuncTreeNew(userLoginReturnModel.BasicInfo.Id, true)?.FirstOrDefault()?.Childrens); + return ResponseOutput.Ok(userLoginReturnModel); + } + + return ResponseOutput.NotOk("Please check the user name or password.", new LoginReturnDTO()); + } + + + public IResponseOutput VerifySignature(string userName, string password) + { + var name = userName.Trim(); + var passwordMd5 = password.Trim(); + + var user = _userRepository.GetAll().FirstOrDefault(u => u.UserName == name && u.Password == passwordMd5); + + if (user != null) + { + if (user.Status == 0) + { + return ResponseOutput.NotOk("用户已被禁用!", false); + } + + return ResponseOutput.Ok(true); + } + return ResponseOutput.NotOk("Password error!", false); + } + + public Dictionary> DealFunction(List functionTreeNodes) + { + Dictionary> returnDictionary = new Dictionary>(); + functionTreeNodes?.ForEach(t => + { + List functionNames = new List(); + returnDictionary.Add(t.RouteName, Test(t.Childrens, functionNames)); + }); + + return returnDictionary; + } + + public List Test(List functionTreeNodes, List functionNames) + { + functionTreeNodes?.ForEach(t => + { + if (!string.IsNullOrEmpty(t.FunctionName)) + { + functionNames.Add(t.FunctionName); + } + else + { + Test(t.Childrens, functionNames); + } + }); + + return functionNames; + } + + + /// + /// 管理员获取菜单树 + /// + /// + public List GetAdminMenuTree() + { + var allMenuList = _menuRepository.GetAll().Where(t => t.Status == 1 && t.IsFunction == false && t.SuperAdmin).Select(menu => new MenuFuncTreeNodeView() + { + Id = menu.Id, + ParentId = menu.ParentId, + component = menu.Component, + meta = new Meta + { + MetaActiveMenu = menu.MetaActiveMenu, + MetaBreadcrumb = menu.MetaBreadcrumb, + MetaIcon = menu.MetaIcon, + MetaTitle = menu.MetaTitle, + }, + + hidden = menu.Hidden, + redirect = menu.Redirect, + routeName = menu.RouteName, + path = menu.Path, + ShowOrder = menu.ShowOrder + + }).ToList(); + + return GetMenuTree(Guid.Empty, allMenuList); + } + + public List GetUserMenuTreeNew(Guid userId, bool isReviewer = false) + { + if (!isReviewer) + { + var allMenuList = (from menuId in (from userRole in _userRoleRepository.GetAll() + .Where(t => t.UserId == userId) + join roleMenu in _roleMenuRepository.GetAll() on userRole.RoleId equals roleMenu.RoleId + select roleMenu.MenuFunctionId).Distinct() + join menu in _menuRepository.GetAll().Where(t => t.IsFunction == false) on menuId equals menu.Id + select new MenuFuncTreeNodeView() + { + Id = menu.Id, + ParentId = menu.ParentId, + component = menu.Component, + hidden = menu.Hidden, + redirect = menu.Redirect, + routeName = menu.RouteName, + path = menu.Path, + ShowOrder = menu.ShowOrder, + meta = new Meta + { + MetaActiveMenu = menu.MetaActiveMenu, + MetaBreadcrumb = menu.MetaBreadcrumb, + MetaIcon = menu.MetaIcon, + MetaTitle = menu.MetaTitle, + }, + }).Distinct().ToList(); + + return GetMenuTree(Guid.Empty, allMenuList); + } + else + { + //内置角色Id 不允许删除 + var roleId = Guid.Parse("4062ECFF-C6D4-4C22-2CAF-08D85F6F9A95"); + + var allMenuList = (from roleMenu in _roleMenuRepository.GetAll().Where(t => t.RoleId == roleId) + join menu in _menuRepository.GetAll().Where(t => t.IsFunction == false) on roleMenu.MenuFunctionId equals menu.Id + select new MenuFuncTreeNodeView() + { + Id = menu.Id, + ParentId = menu.ParentId, + component = menu.Component, + hidden = menu.Hidden, + redirect = menu.Redirect, + routeName = menu.RouteName, + path = menu.Path, + ShowOrder = menu.ShowOrder, + meta = new Meta + { + MetaActiveMenu = menu.MetaActiveMenu, + MetaBreadcrumb = menu.MetaBreadcrumb, + MetaIcon = menu.MetaIcon, + MetaTitle = menu.MetaTitle, + }, + }).Distinct().ToList(); + return GetMenuTree(Guid.Empty, allMenuList); + } + } + + public List GetMenuTree(Guid parentId, List allMenuList) + { + //树节点集合 每个节点包含一个菜单项 和一个子菜单集合 + List treeList = new List(); + + // 根据父菜单节点获取子菜单节点 并且进行排序 + List menuList = allMenuList.Where(x => x.ParentId == parentId).OrderBy(t => t.ShowOrder).ToList(); + + foreach (var menuItem in menuList) + { + MenuFuncTreeNodeView treeItem = new MenuFuncTreeNodeView() + { + Id = menuItem.Id, + + component = menuItem.component, + hidden = menuItem.hidden, + routeName = menuItem.routeName, + path = menuItem.path, + ParentId = menuItem.ParentId, + ShowOrder = menuItem.ShowOrder, + redirect = menuItem.redirect, + meta = new Meta + { + MetaActiveMenu = menuItem.meta.MetaActiveMenu, + MetaBreadcrumb = menuItem.meta.MetaBreadcrumb, + MetaIcon = menuItem.meta.MetaIcon, + MetaTitle = menuItem.meta.MetaTitle, + }, + + Childrens = GetMenuTree(menuItem.Id, allMenuList) + }; + + treeList.Add(treeItem); + } + return treeList; + } + + public List GetFuncTree(Guid parentId, List allFuncList) + { + //树节点集合 每个节点包含一个菜单项 和一个子菜单集合 + List treeList = new List(); + + // 根据父菜单节点获取子菜单节点 并且进行排序 + List menuList = allFuncList.Where(x => x.ParentId == parentId).OrderBy(t => t.ShowOrder).ToList(); + + foreach (var menuItem in menuList) + { + FunctionTreeNodeDTO treeItem = new FunctionTreeNodeDTO() + { + Id = menuItem.Id, + FunctionName = menuItem.FunctionName, + RouteName = menuItem.RouteName, + ParentId = menuItem.ParentId, + ShowOrder = menuItem.ShowOrder, + + Childrens = GetFuncTree(menuItem.Id, allFuncList) + }; + + treeList.Add(treeItem); + } + return treeList; + } + + public List GetAdminFunctionTree() + { + var allFuncList = _menuRepository.GetAll().Where(t => t.Status == 1).Select(menu => new FunctionTreeNodeDTO() + { + Id = menu.Id, + ParentId = menu.ParentId, + FunctionName = menu.FunctionName, + RouteName = menu.RouteName, + ShowOrder = menu.ShowOrder + + }).ToList(); + + + //var root = _menuRepository.GetAll().Where(t => t.Status == 1 && t.RouteName == "Root").Select(menu => + // new FunctionTreeNodeView() + // { + // Id = menu.Id, + // ParentId = menu.ParentId, + // FunctionName = menu.FunctionName, + // RouteName = menu.RouteName, + // ShowOrder = menu.ShowOrder + + // }).First(); + //allFuncList.Add(root); + + return GetFuncTree(Guid.Empty, allFuncList); + } + public List GetUserFuncTreeNew(Guid userId, bool isReviewer = false) + { + if (!isReviewer) + { + var allFuncList = (from menuId in (from userRole in _userRoleRepository.GetAll() + .Where(t => t.UserId == userId) + join roleMenu in _roleMenuRepository.GetAll() on userRole.RoleId equals roleMenu.RoleId + select roleMenu.MenuFunctionId).Distinct() + join menu in _menuRepository.GetAll() on menuId equals menu.Id + select new FunctionTreeNodeDTO() + { + Id = menu.Id, + ParentId = menu.ParentId, + RouteName = menu.RouteName, + FunctionName = menu.FunctionName, + ShowOrder = menu.ShowOrder + + }).Distinct().ToList(); + return GetFuncTree(Guid.Empty, allFuncList); + } + else + { + //内置角色Id 不允许删除 + var roleId = Guid.Parse("4062ECFF-C6D4-4C22-2CAF-08D85F6F9A95"); + + var allFuncList = (from menuId in _roleMenuRepository.GetAll().Where(t => t.RoleId == roleId) + .Select(t => t.MenuFunctionId) + join menu in _menuRepository.GetAll() on menuId equals menu.Id + select new FunctionTreeNodeDTO() + { + Id = menu.Id, + ParentId = menu.ParentId, + RouteName = menu.RouteName, + FunctionName = menu.FunctionName, + ShowOrder = menu.ShowOrder + + }).Distinct().ToList(); + + return GetFuncTree(Guid.Empty, allFuncList); + } + } + + public IEnumerable GetAllUser() + { + return _userRepository.GetAll().ProjectTo(_mapper.ConfigurationProvider).ToList(); + } + + private Expression> GetUserSearchLambda(UserListQueryDTO userQueryModel) + { + Expression> userLambda = x => x.SuperAdmin == false; + if (!string.IsNullOrWhiteSpace(userQueryModel.UserName)) + { + userLambda = userLambda.And(t => t.UserName.Contains(userQueryModel.UserName.Trim())); + } + if (!string.IsNullOrWhiteSpace(userQueryModel.Phone)) + { + userLambda = userLambda.And(t => t.Phone.Contains(userQueryModel.Phone.Trim())); + } + if (!string.IsNullOrWhiteSpace(userQueryModel.OrganizationName)) + { + userLambda = userLambda.And(t => t.OrganizationName.Contains(userQueryModel.OrganizationName.Trim())); + } + if (Guid.Empty != userQueryModel.UserType && userQueryModel.UserType != null) + { + userLambda = userLambda.And(t => t.UserTypeId == userQueryModel.UserType); + } + + if (userQueryModel.UserState != null) + { + switch (userQueryModel.UserState) + { + case 1: + userLambda = userLambda.And(t => t.Status == 1);//可用 + break; + case 0: + userLambda = userLambda.And(t => t.Status == 0);//禁用 + break; + default: + break; + } + } + + return userLambda; + } + + + /// 获取用户列表 + public PageOutput GetUserList(UserListQueryDTO param) + { + + var userLambda = GetUserSearchLambda(param); + IQueryable userQueryable = default; + userQueryable = from user in _userRepository.GetAll().Where(userLambda) + join dicItem in _dictionaryRepository.GetAll() on user.UserTypeId equals dicItem.Id into d + from userType in d.DefaultIfEmpty() + select new UserListDTO() + { + Id = user.Id, + Password = user.Password, + RealName = user.RealName, + Sex = user.Sex, + UserName = user.UserName, + Status = user.Status, + Phone = user.Phone, + EMail = user.EMail, + UserTypeId = userType == null ? Guid.Empty : userType.Id, + UserType = userType == null ? string.Empty : userType.Value, + OrganizationName = user.OrganizationName, + Code = user.Code, + }; + var count = userQueryable.Count(); + var propName = param.SortField == string.Empty ? "UserName" : param.SortField; + userQueryable = param.Asc ? userQueryable.OrderBy(propName) : userQueryable.OrderByDescending(propName); + userQueryable = userQueryable.Skip((param.PageIndex - 1) * param.PageSize).Take(param.PageSize); + var userList = userQueryable.ToList(); + + var userIds = userList.Select(t => t.Id).ToList(); + + + var userRoleList = (from userRole in _userRoleRepository.GetAll().Where(t => userIds.Contains(t.UserId)) + join role in _roleRepository.GetAll() on userRole.RoleId equals role.Id + select new UserIdRoleName + { + RoleName = role.RoleName, + RoleDescription = role.RoleDescription, + UserId = userRole.UserId + }).ToList().GroupBy(t => t.UserId).Select(u => + new UserIdRoleNameList + { + UserId = u.Key, + RoleList = u.Select(t => + new RoleDTO() + { + RoleName = t.RoleName, + RoleDescription = t.RoleDescription + }) + }); + + + + userList.ForEach(t => + { + var temp = userRoleList.FirstOrDefault(u => u.UserId == t.Id); + if (temp != null) + { + t.RoleNameList = temp.RoleList; + } + }); + return new PageOutput(param.PageIndex, param.PageSize, count, userList); + } + + public UserDetailDTO GetUserById(Guid id) + { + + var temp = _userRepository.GetAll().ProjectTo(_mapper.ConfigurationProvider).FirstOrDefault(t => t.Id == id); + var dicItem = _dictionaryRepository.FindSingleOrDefault(u => u.Id == temp.UserTypeId); + temp.UserTypeName = dicItem == null ? string.Empty : dicItem.Value; + return temp; + } + + + public IResponseOutput AddUser(UserCommand userAddModel, Guid userId) + { + if (_userRepository.GetAll().Any(t => t.UserName == userAddModel.UserName || t.EMail == userAddModel.EMail)) + { + return ResponseOutput.NotOk("User name or email already exist.", new UserAddedReturnDTO()); + } + + var saveItem = _mapper.Map(userAddModel); + + #region 处理code + var last = _userRepository.GetAll().OrderByDescending(c => c.Code).FirstOrDefault(); + if (last != null) + { + var num = 0; + if (int.TryParse(last.Code.Substring(1, 4), out num)) + { + saveItem.Code = SystemConfig.UserCodePrefix + (++num).ToString().PadLeft(4, '0'); + } + else + { + return ResponseOutput.NotOk("Generated Code failed.", new UserAddedReturnDTO()); + + } + } + else + { + saveItem.Code = SystemConfig.UserCodePrefix + 1.ToString().PadLeft(4, '0'); + } + + if (userAddModel.OrganizationName.ToUpper().Contains(StaticData.MainCompany)) + { + saveItem.IsZhiZhun = true; + } + else + { + saveItem.IsZhiZhun = false; + } + + #endregion + + saveItem.Password = MD5Helper.Md5(StaticData.DefaultPassword); + saveItem.CreateUserId = Guid.Empty; + + _userRepository.Add(saveItem); + var success = _userRepository.SaveChanges(); + + return ResponseOutput.Result(success, new UserAddedReturnDTO { Id = saveItem.Id, Code = saveItem.Code }); + + } + + + public IResponseOutput UpdateUser(UserCommand model, Guid userId) + { + var userType = _dictionaryRepository.FindSingleOrDefault(u => u.Id == model.UserTypeId); + if (userType == null) + { + return ResponseOutput.NotOk("selected wrong user type."); + + } + // 判断当前用户名是否已经存在 + if (_userRepository.GetAll().Any(t => (t.UserName == model.UserName && t.Id != model.Id) || (t.EMail == model.EMail && t.Id != model.Id) + )) + { + return ResponseOutput.NotOk("User name or enmail already exist."); + + } + if (model.OrganizationName.ToUpper().Contains(StaticData.MainCompany)) + { + model.IsZhiZhun = true; + } + else + { + model.IsZhiZhun = false; + } + + + #region 方式一 直接更新需要的字段 字段多 很麻烦 容易掉 + + //var success = _userRepository.Update(t => t.Id == model.Id, u => new User() + //{ + // Status = model.Status, + // UpdateTime = DateTime.Now, + // UpdateUserId = userId, + // RealName = model.RealName, + // UserName = model.UserName, + // Phone = model.Phone, + // EMail = model.EMail, + // Sex = model.Sex, + // UserTypeId = model.UserTypeId, + // UserType = model.UserType, + // OrganizationId = model.OrganizationId, + // OrganizationName = model.OrganizationName, + // OrganizationType = model.OrganizationType, + // OrganizationTypeId = model.OrganizationTypeId, + // DepartmentName = model.DepartmentName, + // PositionName = model.PositionName, + // IsZhiZhun = model.IsZhiZhun + //}); + + #endregion + + var user = _userRepository.GetAll().First(t => t.Id == model.Id); + + _mapper.Map(model, user); + _userRepository.Update(user); + var success = _userRepository.SaveChanges(); + + return ResponseOutput.Result(success); + + } + + public IResponseOutput UpdateUserState(Guid userId, int state) + { + var success = _userRepository.Update(u => u.Id == userId, t => new User + { + Status = state + }); + return ResponseOutput.Result(success); + } + + public IResponseOutput ResetPassword(Guid userId) + { + var success = _userRepository.Update(t => t.Id == userId, u => new User() + { + Password = MD5Helper.Md5(StaticData.DefaultPassword) + }); + + return ResponseOutput.Result(success); + } + + public IResponseOutput ModifyPassword(EditPasswordCommand editPwModel) + { + if (_userRepository.GetAll().FirstOrDefault(t => t.Id == _userInfo.Id && t.Password == editPwModel.OldPassWord) != null) + { + var success = _userRepository.Update(t => t.Id == _userInfo.Id, u => new User() + { + Password = editPwModel.NewPassWord + }); + + return ResponseOutput.Result(success); + } + + if (_doctorRepository.GetAll().Any(t => t.Id == _userInfo.Id && t.Password == editPwModel.OldPassWord)) + { + var success = _doctorRepository.Update(t => t.Id == _userInfo.Id, u => new Doctor() + { + Password = editPwModel.NewPassWord + }); + + return ResponseOutput.Result(success); + } + + return ResponseOutput.NotOk("Old password is wrong."); + + } + + public List GetUserRolesById(Guid userId) + { + var query = from userRole in _userRoleRepository.Find(u => u.UserId == userId) + join role in _roleRepository.GetAll() on userRole.RoleId equals role.Id into t + from userRoleItem in t.DefaultIfEmpty() + select userRoleItem.RoleName; + return query.ToList(); + } + + public int GetUserRoleMaxPrivilegeLevel(Guid userId) + { + var user = _userRepository.FindSingleOrDefault(u => u.Id == userId); + if (user.SuperAdmin) + { + return 9999; + } + var query = from userRole in _userRoleRepository.Find(u => u.UserId == userId) + join role in _roleRepository.GetAll() on userRole.RoleId equals role.Id into t + from userRoleItem in t.DefaultIfEmpty() + select userRoleItem.PrivilegeLevel; + var list = query.ToList(); + if (list.Count == 0) + { + return 0; + } + return list.Max(); + } + } +} diff --git a/IRaCIS.Core.Application/Report/GlobalService.cs b/IRaCIS.Core.Application/Report/GlobalService.cs new file mode 100644 index 0000000..470813c --- /dev/null +++ b/IRaCIS.Core.Application/Report/GlobalService.cs @@ -0,0 +1,196 @@ +using IRaCIS.Core.Application.Contracts; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Dynamic.Core; +using AutoMapper; +using IRaCIS.Application.ViewModels; +using IRaCIS.Core.Domain.Interfaces; +using IRaCIS.Core.Domain.Models; + +namespace IRaCIS.Core.Application +{ + public class GlobalService : IGlobalService + { + private readonly IGlobalRSRepository _globalRsRepository; + private readonly IGlobalResultRepository _globalResultRepository; + private readonly IRSRepository _rsRepository; + private readonly IVisitStageRepository _visitStageRepository; + private readonly IMapper _mapper; + private readonly ISubjectVisitRepository _subjectVisitRepository; + private readonly IWorkloadADRepository _workloadAdRepository; + private readonly IWorkloadGlobalRepository _workloadGlobalRepository; + private readonly ITrialRepository _trialRepository; + private readonly ISubjectRepository _subjectRepository; + + public GlobalService(IGlobalRSRepository globalRsRepository, IGlobalResultRepository globalResultRepository, + IRSRepository rsRepository, IVisitStageRepository visitStageRepository, IMapper mapper, ISubjectVisitRepository subjectVisitRepository, IWorkloadADRepository workloadAdRepository, + IWorkloadGlobalRepository workloadGlobalRepository, ITrialRepository trialRepository, ISubjectRepository subjectRepository) + { + _globalRsRepository = globalRsRepository; + _globalResultRepository = globalResultRepository; + _rsRepository = rsRepository; + _visitStageRepository = visitStageRepository; + _mapper = mapper; + _subjectVisitRepository = subjectVisitRepository; + _workloadAdRepository = workloadAdRepository; + _workloadGlobalRepository = workloadGlobalRepository; + _trialRepository = trialRepository; + _subjectRepository = subjectRepository; + } + + + public IEnumerable GetHistoryVisitRsList(Guid trialId, Guid subjectId, decimal visitNum, Guid globalId, string globalCode) + { + + var tpGroup = 'T' + globalCode.Trim().Substring(globalCode.Trim().Length - 2); + + + var query = from rs in _rsRepository.GetAll() + .Where(t => t.SubjectGuid == subjectId && t.TrialGuid == trialId && t.RSTESTCD == "OVRLRESP" && t.VISITNUM <= visitNum && t.TpCode.Contains(tpGroup)) + + join globalRs in _globalRsRepository.GetAll().Where(t => t.GlobalId == globalId) on new { rs.TpCode, VisitNum = rs.VISITNUM } equals new { globalRs.TpCode, globalRs.VisitNum } into cc + from globalRs in cc.DefaultIfEmpty() + + join visitStage in _visitStageRepository.GetAll().Where(t => t.TrialId == trialId) on rs.VISITNUM equals visitStage.VisitNum + select new HistoryVisitRSDTO + { + StudyId = rs.StudyGuid, + StudyCode = rs.STUDYID, + VisitNum = visitStage.VisitNum, + VisitName = visitStage.VisitName, + OverallResponse = rs.RSORRES, + TpCode = rs.TpCode, + GlobalRSSelect = new GlobalRSSelectView() + { + Agree = globalRs.Agree, + NewRS = globalRs.NewRS, + Note = globalRs.Note + } + }; + + var visitRsList = query.OrderBy(t => t.VisitNum).ToList(); + + return visitRsList; + + } + + public PreviousGlobalReadsView GetHistoryGlobalRsList(Guid trialId, Guid subjectId, decimal visitNum, + Guid globalId) + { + //subjectCode = subjectCode.Trim(); + + var query = from globalResult in _globalResultRepository.GetAll() + .Where(t => t.SubjectId == subjectId && t.VisitNum < visitNum) + join visitStage in _visitStageRepository.GetAll().Where(t => t.TrialId == trialId) on globalResult.VisitNum equals visitStage.VisitNum + select new HistoryGlobalRsDTO + { + VisitNum = visitStage.VisitNum, + VisitName = visitStage.VisitName, + OverallResponse = globalResult.Result + }; + + var subjectNote = _globalResultRepository.GetAll().FirstOrDefault(t => t.GlobalId == globalId)?.SubjectNote; + + return new PreviousGlobalReadsView() + { + PreviousGlobalReadsList = query.ToList(), + SubjectNote = subjectNote + }; + + } + + public bool AddGlobalReport(GlobalTaskReportCommand globalTaskReportCommand) + { + //删除上一次保存得记录 + _globalResultRepository.Delete(t => t.GlobalId == globalTaskReportCommand.GlobalId); + _globalRsRepository.Delete(t => t.GlobalId == globalTaskReportCommand.GlobalId); + + + var globalRsList = _mapper.Map>(globalTaskReportCommand.GlobalRSReportList); + + _globalRsRepository.AddRange(globalRsList); + + var first = globalRsList.OrderByDescending(t => t.VisitNum).First(); + + var globalResult = new GlobalResult() + { + VisitNum = first.VisitNum, + SubjectCode = globalTaskReportCommand.SubjectCode, + SubjectNote = globalTaskReportCommand.SubjectNote, + SubjectId = globalTaskReportCommand.SubjectId, + + GlobalId = first.GlobalId, + Result = first.NewRS + }; + + _globalResultRepository.Add(globalResult); + + return _globalResultRepository.SaveChanges(); + + } + + //public string GetCommentsForSubject(Guid globalId) + //{ + // return _globalResultRepository.GetAll().FirstOrDefault(t => t.GlobalId == globalId)?.SubjectNote; + //} + + public AdReportDTO GetAdReport(Guid adId) + { + var adReport = new AdReportDTO(); + var ad = _workloadAdRepository.GetAll().First(t => t.Id == adId); + var globalId1 = ad.Global1Id; + var globalId2 = ad.Global2Id; + + var query = from global in _workloadGlobalRepository.GetAll().Where(t => t.Id == globalId1 || t.Id == globalId2) + join trial in _trialRepository.GetAll().Where(t => t.Id == ad.TrialId) on global.TrialId equals trial.Id + join subject in _subjectRepository.GetAll() on global.SubjectId equals subject.Id + select new WorkloadReadingDTO + { + Id = global.Id, + WorkloadId = global.Id, + WorkloadType = 1, + Status = global.Status, + UpdateTime = global.UpdateTime, + TrialId = global.TrialId, + SubjectId = global.SubjectId, + SubjectCode = subject.Code, + //VisitNum = visit.VisitNum, + //VisitName = visit.VisitName, + VisitNum = global.VisitNum, + VisitName = global.VisitName, + + Expedited = trial.Expedited, + TrialCode = trial.Code, + TrialIndication = trial.Indication, + WorkloadCode = global.GlobalCode + }; + + var globalList = query.ToList(); + + var global1 = globalList.First(t => t.Id == globalId1); + var global2 = globalList.First(t => t.Id == globalId2); + + adReport.Global1VisitRS = GetHistoryVisitRsList(global1.TrialId, global1.SubjectId, + global1.VisitNum, global1.Id, global1.WorkloadCode); + + adReport.Global2VisitRS = GetHistoryVisitRsList(global2.TrialId, global2.SubjectId + ,global2.VisitNum, global2.Id, global2.WorkloadCode); + + adReport.Global1 = GetHistoryGlobalRsList(global1.TrialId, global1.SubjectId, global1.VisitNum, global1.Id); + adReport.Global2 = GetHistoryGlobalRsList(global2.TrialId, global2.SubjectId, global2.VisitNum, global2.Id); + + adReport.ADInfo = ad; + + return adReport; + + } + + public bool AddAdjudicationReport(ADReportCommand adReportCommand) + { + return _workloadAdRepository.Update(t => t.Id == adReportCommand.AdId, + u => new WorkloadAD() + {AdNote = adReportCommand.ADNote, SelectGlobalId = adReportCommand.SelectGlobalId}); + } + } +} \ No newline at end of file diff --git a/IRaCIS.Core.Application/Report/ReportService.cs b/IRaCIS.Core.Application/Report/ReportService.cs new file mode 100644 index 0000000..152115c --- /dev/null +++ b/IRaCIS.Core.Application/Report/ReportService.cs @@ -0,0 +1,616 @@ +using AutoMapper; +using IRaCIS.Application.ExpressionExtend; +using IRaCIS.Core.Application.Contracts; +using IRaCIS.Core.Domain.Interfaces; +using IRaCIS.Core.Domain.Models; +using System; +using System.Collections.Generic; +using System.Linq.Dynamic.Core; +using System.Linq; +using IRaCIS.Core.Domain.Share.AuthUser; +using IRaCIS.Core.Domain.Share; +using Microsoft.EntityFrameworkCore.Internal; + +namespace IRaCIS.Core.Application +{ + public class ReportService : IReportService + { + private readonly ITURepository _tURepository; + private readonly ITRRepository _tRRepository; + private readonly IRSRepository _rSRepository; + private readonly IReportRepository _reportRepository; + private readonly IVisitStageRepository _visitStageRepository; + private readonly ISubjectVisitRepository _subjectVisitRepository; + private readonly IWorkloadTPRepository _workloadTPRepository; + private readonly IWorkloadGlobalRepository _workloadGlobalRepository; + private readonly IMapper _mapper; + private readonly IUserInfo _userInfo; + + private string linkGroupId; + public ReportService(ITURepository tURepository, ITRRepository tRRepository, + IRSRepository rSRepository, IReportRepository reportRepository, + IWorkloadTPRepository workloadTPRepository, + IVisitStageRepository visitStageRepository, + ISubjectVisitRepository subjectVisitRepository, + IWorkloadGlobalRepository workloadGlobalRepository, + IMapper mapper, IUserInfo userInfo) + { + _tURepository = tURepository; + _tRRepository = tRRepository; + _rSRepository = rSRepository; + _reportRepository = reportRepository; + _workloadTPRepository = workloadTPRepository; + _visitStageRepository = visitStageRepository; + _subjectVisitRepository = subjectVisitRepository; + _workloadGlobalRepository = workloadGlobalRepository; + _mapper = mapper; + _userInfo = userInfo; + } + public bool AddLesion(List lesionList, ReportDTO report) + { + TU lastTu = _tURepository.GetAll().OrderByDescending("TUSEQ").FirstOrDefault(); + int tuSeq = 101; + if (lastTu != null) { tuSeq = lastTu.TUSEQ + 1; } + TR lastTr = _tRRepository.GetAll().OrderByDescending("TRSEQ").FirstOrDefault(); + int trSeq = 1; + if (lastTr != null) { trSeq = lastTr.TRSEQ + 1; } + + foreach (var lesion in lesionList) + { + var linkId = lesion.TULNKID; + if (string.IsNullOrWhiteSpace(lesion.TULNKID)) + { + linkId = (lesion.TUORRES == "TARGET") ? "T" + tuSeq.ToString() : "NT" + tuSeq.ToString(); + } + _tURepository.Add(new TU + { + STUDYID = lesion.STUDYID, + LesionType = lesion.LesionType, + USUBJID = lesion.USUBJID, + TUSEQ = tuSeq, + TULNKID = linkId, + + TUTESTCD = lesion.TUTESTCD, + TUTEST = lesion.TUTEST, + TUORRES = lesion.TUORRES, + TUSTRESC = lesion.TUSTRESC, + + TULOC = lesion.TULOC, + LocDescription = lesion.LocDescription, + TULAT = lesion.TULAT, + TUDIR = lesion.TUDIR, + TUPORTOT = lesion.TUPORTOT, + TUMETHOD = lesion.TUMETHOD, + TUEVAL = lesion.TUEVAL, + + VISIT = lesion.VISIT, + VISITNUM = lesion.VISITNUM, + VISITDY = lesion.VISITDY, + + TUREFID = lesion.TUREFID, + TUACPTFL = lesion.TUACPTFL, + TUEVALID = _userInfo.ReviewerCode,//lesion.TUEVALID, + TUGRPID = string.Empty, + TUDY = lesion.TUDY,// 检查日 + EPOCH = lesion.EPOCH, + TUDTC = lesion.TUDTC, + TUNAM = lesion.TUNAM, + TUSPID = lesion.TUSPID, + TpCode = report.TpCode + }); + _tRRepository.Add(new TR + { + STUDYID = lesion.STUDYID, + + USUBJID = lesion.USUBJID, + TRSEQ = trSeq, + TRLNKID = linkId, + TRGRPID = lesion.TRGRPID, + TRLNKGRP = linkGroupId, + + TRTESTCD = lesion.TRTESTCD, + TRTEST = lesion.TRTEST, + TRORRES = lesion.TRORRES, + TRORRESU = lesion.TRORRESU, + + TRNAM = lesion.TUNAM, + TRMETHOD = lesion.TUMETHOD, + TREVAL = lesion.TUEVAL, + TREVALID = _userInfo.ReviewerCode,//lesion.TUEVALID, + TRACPTFL = lesion.TUACPTFL, + CoveredLesion = true, + Note = lesion.Note, + + VISITNUM = lesion.VISITNUM, + VISIT = lesion.VISIT, + VISITDY = lesion.VISITDY, + EPOCH = lesion.EPOCH, + TRDTC = lesion.TRDTC, + TRDY = lesion.TRDY, + TpCode = report.TpCode + }); + tuSeq++; + trSeq++; + } + + return _rSRepository.SaveChanges(); + } + + private IList GetBLLesion(string trialCode, string SubjectCode, string tpcodeGroup) + { + int[] t = { 1, 2, 3 }; + var query = from tu in _tURepository.Find(u => t.Contains(u.LesionType) + && u.STUDYID == trialCode && u.USUBJID == SubjectCode && u.TpCode.Contains(tpcodeGroup) /*u.TUEVALID==_userInfo.ReviewerCode*/) + join tr in _tRRepository.Find(u => u.VISITNUM == 1 && u.STUDYID == trialCode + && u.USUBJID == SubjectCode && u.TREVALID == _userInfo.ReviewerCode) + on tu.TULNKID equals tr.TRLNKID into temp + from tr in temp.DefaultIfEmpty() + select new LesionInformation + { + TUId = tu.Id, + LesionType = tu.LesionType, + TULNKID = tu.TULNKID, + TUSEQ = tu.TUSEQ, + TULOC = tu.TULOC, + LocDescription = tu.LocDescription, + TULAT = tu.TULAT, + TUDIR = tu.TUDIR, + TUPORTOT = tu.TUPORTOT, + TRORRES = tr.TRORRES, + VISITNUM = tu.VISITNUM, + Note = tr.Note + }; + return query.ToList(); + } + + public BaseLineReportDTO GetBaseLineReport(string trialCode, string subjectCode, string tpCode) + { + var tpcodeGroup = tpCode.Substring(tpCode.Length - 3, 3); + var report = _reportRepository.FindSingleOrDefault(u => u.TrialCode == trialCode && u.SubjectCode == subjectCode && u.VisitNum == 1); ; + + BaseLineReportDTO result = new BaseLineReportDTO + { + LesionInformation = GetBLLesion(trialCode, subjectCode, tpcodeGroup).Where(u => u.VISITNUM == 1).ToList(), + ReportResult = _mapper.Map(report) + }; + return result; + } + public VisitLesionInfo GetVisitLesion(string trialCode, string subjectCode, decimal visitNum, string tpCode) + { + var tpcodeGroup = tpCode.Substring(tpCode.Length - 3, 3); + VisitLesionInfo visitLesionInfo = new VisitLesionInfo(); + var blLesionList = GetBLLesion(trialCode, subjectCode, tpcodeGroup); + int[] t = { 1, 2, 3 }; + var query = from tu in _tURepository.Find(u => u.STUDYID == trialCode && u.USUBJID == subjectCode && u.TpCode.Contains(tpcodeGroup) /*u.TUEVALID == _userInfo.ReviewerCode*/) + join tr in _tRRepository.Find(u => u.VISITNUM == visitNum && u.STUDYID == trialCode && u.USUBJID == subjectCode && u.TpCode.Contains(tpcodeGroup)) + on tu.TULNKID equals tr.TRLNKID into temp + from tr in temp.DefaultIfEmpty() + select new LesionInformation + { + TUId = tu.Id, + TUSEQ = tu.TUSEQ, + TULOC = tu.TULOC, + LesionType = tu.LesionType, + TULNKID = tu.TULNKID, + LocDescription = tu.LocDescription, + TULAT = tu.TULAT, + TUDIR = tu.TUDIR, + TUPORTOT = tu.TUPORTOT, + TRORRESU = tr.TRORRESU, + TRORRES = tr.TRORRES, + Note = tr.Note, + CoveredLesion = tr.CoveredLesion, + VISITNUM = tr.VISITNUM + }; + var list = query.ToList(); + var currentVisitLesion = list.Where(u => t.Contains(u.LesionType) && u.VISITNUM == visitNum).ToList(); + foreach (var item in blLesionList) + { + var temp = _mapper.Map(item); + temp.CurrentLesion = currentVisitLesion.Where(u => u.STUDYID == item.STUDYID + && u.USUBJID == item.USUBJID && u.TUEVAL == item.TUEVAL + && u.TULNKID == item.TULNKID).FirstOrDefault() ?? new LesionInformation(); + visitLesionInfo.BLLesionList.Add(temp); + } + + List blIdList = blLesionList.Select(u => u.TUId).ToList(); + List visitIdList = currentVisitLesion.Where(u => t.Contains(u.LesionType)).Select(u => u.TUId).ToList(); + var visitLesion = visitIdList.Except(blIdList); + + foreach (var item in visitLesion) + { + VisitLesion tempLesion = new VisitLesion(); + tempLesion.CurrentLesion = currentVisitLesion.Where(u => u.TUId == item).FirstOrDefault() ?? new LesionInformation(); + tempLesion.LesionType = tempLesion.CurrentLesion.LesionType; + tempLesion.TUSEQ = tempLesion.CurrentLesion.TUSEQ; + visitLesionInfo.BLLesionList.Add(tempLesion); + } + // 以往新病灶,病灶类型为5,且访视编号小于当前访视,且不是基线 + var previousLesion = list.Where(u => u.VISITNUM < visitNum && u.VISITNUM != 1 && u.LesionType == 5).ToList(); + foreach (var item in previousLesion) + { + var temp = _mapper.Map(item); + temp.CurrentLesion = currentVisitLesion.Where(u => u.TULNKID==item.TULNKID && u.STUDYID == item.STUDYID && u.USUBJID == item.USUBJID && u.TUEVAL == item.TUEVAL).FirstOrDefault() ?? new LesionInformation(); + visitLesionInfo.PreviousNewLesionList.Add(temp); + } + + visitLesionInfo.EquivocalNewLesionList = list.Where(u => u.VISITNUM <= visitNum && u.LesionType == 4).ToList(); + visitLesionInfo.UnequivocalNewLesionList = list.Where(u => u.VISITNUM == visitNum && u.LesionType == 5).ToList(); + + var report = _reportRepository.FindSingleOrDefault(u => u.TrialCode == trialCode && u.SubjectCode == subjectCode && u.VisitNum == visitNum); ; + visitLesionInfo.ReportResult = _mapper.Map(report); + + var rs = _rSRepository.Find(u => u.STUDYID == trialCode && u.USUBJID == subjectCode + && u.RSEVALID == _userInfo.ReviewerCode && u.VISITNUM == visitNum); + + var target = rs.FirstOrDefault(u => u.RSTESTCD == "TRGRESP"); + var non_target = rs.FirstOrDefault(u => u.RSTESTCD == "NTRGRESP"); + var overall = rs.FirstOrDefault(u => u.RSTESTCD == "OVRLRESP"); + + visitLesionInfo.Efficacy = new EfficacyAssessment + { + + TargetLesion = target?.RSORRES, + TargetLesionNote = target?.Note, + Non_targetLesion = non_target?.RSORRES, + Non_targetLesionNote = non_target?.Note, + OverallAssessment = overall?.RSORRES, + OverallAssessmentNote = overall?.Note + }; + + var preRS = _rSRepository.Find(u => u.STUDYID == trialCode && u.USUBJID == subjectCode + && u.VISITNUM < visitNum && u.RSTESTCD == "OVRLRESP" + && u.RSEVAL == _userInfo.ReviewerCode /*&& u.VISITNUM == visitNum*/) + .Select(u => new PreviousOverallAssessment + { + VisitName = u.VISIT, + OverallAssessment = u.RSORRES + }).ToList(); + visitLesionInfo.PreviousOverallAssessment = preRS; + + var targetList = _tRRepository.Find(u => (!string.IsNullOrWhiteSpace(u.TRLNKID)) && (!u.TRLNKID.Contains("N")) && u.STUDYID == trialCode && + u.USUBJID == subjectCode && u.TpCode.Contains(tpcodeGroup) && u.VISITNUM < visitNum).ToList(); + + var q = from ttt in targetList + group ttt by ttt.VISIT into s + select new MinVisit + { + MinSum = s.Sum(p => p.TRORRES_Double), + MinVistName = s.Key + }; + var tempList = q.ToList(); + MinVisit min = new MinVisit(); + if (tempList.Count>0) + { + min = tempList.FirstOrDefault(); + } + foreach (var item in tempList) + { + if (min.MinSum > item.MinSum) + { + min = item; + } + } + visitLesionInfo.MinVisitInfo = min; + + return visitLesionInfo; + } + + public bool SubmiteReport(Guid tpId) + { + // 提交报告 同时查询VisitStage(项目访视计划,看是否需要添加全局) + + var query = from workloadTp in _workloadTPRepository.GetAll().Where(u => u.Id == tpId) + join subjectVisit in _subjectVisitRepository.GetAll() + on workloadTp.SubjectVisitId equals subjectVisit.Id + join visitStage in _visitStageRepository.GetAll() + on new { workloadTp.TrialId, subjectVisit.VisitNum } equals new { visitStage.TrialId, visitStage.VisitNum } + select new + { + WorkloadTp = workloadTp, + VisitNum = subjectVisit.VisitNum, + VisitName = subjectVisit.VisitName, + NeedGlobal = visitStage.NeedGlobal + }; + var workload = query.ToList().FirstOrDefault(); + if (workload != null) + { + if (workload.NeedGlobal)// 需要产生全局 + { + var group = workload.WorkloadTp.TimepointCode.Substring(workload.WorkloadTp.TimepointCode.Length - 2, 2); + _workloadGlobalRepository.Add(new WorkloadGlobal + { + GlobalCode = workload.WorkloadTp.TimepointCode + "G" + group, + ReviewerId = Guid.Empty, + SiteId = workload.WorkloadTp.SiteId, + Status = -1, + SubjectId = workload.WorkloadTp.SubjectId, + TrialId = workload.WorkloadTp.TrialId, + VisitId = workload.WorkloadTp.SubjectVisitId, + VisitNum = workload.VisitNum, + VisitName = workload.VisitName, + UpdateTime = DateTime.Now + }); + } + } + return _workloadTPRepository.Update(u => u.Id == tpId, s => new WorkloadTP + { + Status = (int)WorkloadStatus.ReviewFinish + }); + } + + /// + /// 保存基线期报告(病灶及测量数据,扩展报告的信息) + /// + /// + /// + public bool SaveBLReport(BaseLineReportCommand baseLineReportCommand) + { + if (baseLineReportCommand.LesionInformation.Count < 1) return false; + + var addedLesion = baseLineReportCommand.LesionInformation[0]; + + //删除已经有的数据 + _tURepository.Delete(u => u.VISITNUM == addedLesion.VISITNUM && u.USUBJID == addedLesion.USUBJID && u.TUEVALID == _userInfo.ReviewerCode); + _tRRepository.Delete(u => u.VISITNUM == addedLesion.VISITNUM && u.USUBJID == addedLesion.USUBJID && u.TREVALID == _userInfo.ReviewerCode); + _reportRepository.Delete(u => u.TPId == baseLineReportCommand.ReportResult.TPId); + + _workloadTPRepository.Update(u => u.Id == baseLineReportCommand.ReportResult.TPId, s => new WorkloadTP + { + Status = (int)WorkloadStatus.Reading + }); + + //序号按照每个项目、每个受试者、每个评估者,一条记录 + TU lastTu = _tURepository.Find(u => u.STUDYID == addedLesion.STUDYID && u.USUBJID == addedLesion.USUBJID + && u.TUEVAL == addedLesion.TUEVAL).OrderByDescending("TUSEQ").FirstOrDefault(); + int tuSeq = 101; + if (lastTu != null) { tuSeq = lastTu.TUSEQ; } + TR lastTr = _tRRepository.GetAll().OrderByDescending("TRSEQ").FirstOrDefault(); + int trSeq = 1; + if (lastTr != null) { trSeq = lastTr.TRSEQ; } + + linkGroupId = Guid.NewGuid().ToString(); + foreach (var lesion in baseLineReportCommand.LesionInformation) + { + var linkId = lesion.TULNKID; + if (string.IsNullOrWhiteSpace(lesion.TULNKID)) + { + linkId = (lesion.TUORRES == "TARGET") ? "T" + tuSeq.ToString() : "NT" + tuSeq.ToString(); + } + _tURepository.Add(new TU + { + STUDYID = lesion.STUDYID, + LesionType = lesion.LesionType, + USUBJID = lesion.USUBJID, + TUSEQ = tuSeq, + TULNKID = linkId, + + TUTESTCD = lesion.TUTESTCD, + TUTEST = lesion.TUTEST, + TUORRES = lesion.TUORRES, + TUSTRESC = lesion.TUSTRESC, + + TULOC = lesion.TULOC, + LocDescription = lesion.LocDescription, + TULAT = lesion.TULAT, + TUDIR = lesion.TUDIR, + TUPORTOT = lesion.TUPORTOT, + TUMETHOD = lesion.TUMETHOD, + TUEVAL = lesion.TUEVAL, + VISIT = lesion.VISIT, + VISITNUM = lesion.VISITNUM, + VISITDY = lesion.VISITDY, + + TUREFID = lesion.TUREFID, + TUACPTFL = lesion.TUACPTFL, + TUEVALID = _userInfo.ReviewerCode,//lesion.TUEVALID, + TUGRPID = string.Empty, + TUDY = lesion.TUDY,// 检查日 + EPOCH = lesion.EPOCH, + TUDTC = lesion.TUDTC, + TUNAM = lesion.TUNAM, + TUSPID = lesion.TUSPID, + + TpCode = baseLineReportCommand.ReportResult.TpCode + }); + _tRRepository.Add(new TR + { + STUDYID = lesion.STUDYID, + + USUBJID = lesion.USUBJID, + TRSEQ = trSeq, + TRLNKID = linkId, + TRGRPID = lesion.TRGRPID, + TRLNKGRP = linkGroupId, + + TRTESTCD = lesion.TRTESTCD, + TRTEST = lesion.TRTEST, + TRORRES = lesion.TRORRES, + TRORRESU = lesion.TRORRESU, + + TRNAM = lesion.TUNAM, + TRMETHOD = lesion.TUMETHOD, + TREVAL = lesion.TUEVAL, + TREVALID = _userInfo.ReviewerCode,//lesion.TUEVALID, + TRACPTFL = lesion.TUACPTFL, + + Note = lesion.Note, + + VISITNUM = lesion.VISITNUM, + VISIT = lesion.VISIT, + VISITDY = lesion.VISITDY, + EPOCH = lesion.EPOCH, + TRDTC = lesion.TRDTC, + TRDY = lesion.TRDY, + TpCode = baseLineReportCommand.ReportResult.TpCode + }); + tuSeq++; + trSeq++; + } + + _tRRepository.Add(new TR + { + STUDYID = addedLesion.STUDYID, + + USUBJID = addedLesion.USUBJID, + TRSEQ = trSeq, + TRLNKID = string.Empty, + TRGRPID = addedLesion.TRGRPID, + TRLNKGRP = linkGroupId, + + TRTESTCD = addedLesion.TRTESTCD, + TRTEST = "Sum of Diameter", + TRORRES = baseLineReportCommand.SumOfDiameter, + TRORRESU = "mm",//addedLesion.TRORRESU, + + TRNAM = addedLesion.TUNAM, + TRMETHOD = addedLesion.TUMETHOD, + TREVAL = addedLesion.TUEVAL, + TREVALID = _userInfo.ReviewerCode,//addedLesion.TUEVALID, + TRACPTFL = addedLesion.TUACPTFL, + + Note = string.Empty, + + VISITNUM = addedLesion.VISITNUM, + VISIT = addedLesion.VISIT, + VISITDY = addedLesion.VISITDY, + EPOCH = addedLesion.EPOCH, + TRDTC = addedLesion.TRDTC, + TRDY = addedLesion.TRDY, + TpCode = baseLineReportCommand.ReportResult.TpCode + }); + trSeq++; + _tRRepository.Add(new TR + { + STUDYID = addedLesion.STUDYID, + + USUBJID = addedLesion.USUBJID, + TRSEQ = trSeq, + TRLNKID = string.Empty, + TRGRPID = addedLesion.TRGRPID, + TRLNKGRP = linkGroupId, + + TRTESTCD = addedLesion.TRTESTCD, + TRTEST = "Sum Diameters of Non Lymph Node Tumors", + TRORRES = baseLineReportCommand.SumDiameterOfNonLymphNode, + TRORRESU = "mm",//addedLesion.TRORRESU, + + TRNAM = addedLesion.TUNAM, + TRMETHOD = addedLesion.TUMETHOD, + TREVAL = addedLesion.TUEVAL, + TREVALID = _userInfo.ReviewerCode,//addedLesion.TUEVALID, + TRACPTFL = addedLesion.TUACPTFL, + + Note = string.Empty, + + VISITNUM = addedLesion.VISITNUM, + VISIT = addedLesion.VISIT, + VISITDY = addedLesion.VISITDY, + EPOCH = addedLesion.EPOCH, + TRDTC = addedLesion.TRDTC, + TRDY = addedLesion.TRDY, + TpCode = baseLineReportCommand.ReportResult.TpCode + }); + trSeq++; + _reportRepository.Add(_mapper.Map(baseLineReportCommand.ReportResult)); + + return _reportRepository.SaveChanges(); + } + + public bool SaveVisitReport(VisitReportCommand visitReportCommand) + { + linkGroupId = Guid.NewGuid().ToString(); + var visitNum = visitReportCommand.ReportResult.VisitNum; + var subjectId = visitReportCommand.ReportResult.SubjectCode; + + //删除已经有的数据 + _tURepository.Delete(u => u.VISITNUM == visitNum && u.USUBJID == subjectId && u.TUEVALID == _userInfo.ReviewerCode); + _tRRepository.Delete(u => u.VISITNUM == visitNum && u.USUBJID == subjectId && u.TREVALID == _userInfo.ReviewerCode); + _reportRepository.Delete(u => u.TPId == visitReportCommand.ReportResult.TPId); + _rSRepository.Delete(u => u.VISITNUM == visitNum && u.RSEVALID == _userInfo.ReviewerCode); + + var report = visitReportCommand.ReportResult; + + _workloadTPRepository.Update(u => u.Id == report.TPId, s => new WorkloadTP + { + Status = (int)WorkloadStatus.Reading + }); + if (visitReportCommand.LesionInformation.Count > 0) + { + AddLesion(visitReportCommand.LesionInformation, report); + } + + TR lastTr = _tRRepository.GetAll().OrderByDescending("TRSEQ").FirstOrDefault(); + int trSeq = 1; + if (lastTr != null) { trSeq = lastTr.TRSEQ + 1; } + + foreach (var lesion in visitReportCommand.TRList) + { + _tRRepository.Add(new TR + { + STUDYID = lesion.STUDYID, + + USUBJID = lesion.USUBJID, + TRSEQ = trSeq, + TRLNKID = lesion.TRLNKID, + TRGRPID = lesion.TRGRPID, + TRLNKGRP = linkGroupId, + + TRTESTCD = lesion.TRTESTCD, + TRTEST = lesion.TRTEST, + TRORRES = lesion.TRORRES, + TRORRESU = lesion.TRORRESU, + + TRNAM = lesion.TRNAM, + TRMETHOD = lesion.TRMETHOD, + TREVAL = lesion.TREVAL, + TREVALID = _userInfo.ReviewerCode,// lesion.TREVALID, + TRACPTFL = lesion.TRACPTFL, + + Note = lesion.Note, + CoveredLesion = lesion.CoveredLesion, + VISITNUM = lesion.VISITNUM, + VISIT = lesion.VISIT, + VISITDY = lesion.VISITDY, + EPOCH = lesion.EPOCH, + TRDTC = lesion.TRDTC, + TRDY = lesion.TRDY, + TpCode = visitReportCommand.ReportResult.TpCode + }); + trSeq++; + } + foreach (var rs in visitReportCommand.RSList) + { + _rSRepository.Add(new RS + { + STUDYID = rs.STUDYID, + USUBJID = rs.USUBJID, + RSSEQ = 0,// + RSLNKGRP = linkGroupId, + RSTESTCD = rs.RSTESTCD, + RSTEST = rs.RSTEST, + RSCAT = rs.RSCAT, + RSORRES = rs.RSORRES, + RSSTRESC = rs.RSSTRESC, + RSSTAT = rs.RSSTAT, + RSREASND = rs.RSCAT, + RSEVAL = rs.RSEVAL, + RSEVALID = _userInfo.ReviewerCode,// + VISITNUM = rs.VISITNUM, + VISIT = rs.VISIT, + RSDTC = rs.RSDTC, + RSDY = rs.RSDY, + TpCode = visitReportCommand.ReportResult.TpCode, + StudyGuid = rs.StudyGuid, + TrialGuid = rs.TrialGuid, + SubjectGuid = rs.SubjectGuid, + Note = rs.Note + }); + } + + _reportRepository.Add(_mapper.Map(visitReportCommand.ReportResult)); + + return _rSRepository.SaveChanges(); + } + } +} diff --git a/IRaCIS.Core.Application/StatisticsService.cs b/IRaCIS.Core.Application/StatisticsService.cs new file mode 100644 index 0000000..503bd1f --- /dev/null +++ b/IRaCIS.Core.Application/StatisticsService.cs @@ -0,0 +1,734 @@ +using IRaCIS.Application.ExpressionExtend; +using IRaCIS.Application.Interfaces; +using IRaCIS.Application.ViewModels; +using IRaCIS.Core.Application.Contracts.RequestAndResponse; +using IRaCIS.Core.Domain.Interfaces; +using IRaCIS.Core.Domain.Models; +using IRaCIS.Core.Domain.Share; +using IRaCIS.Infra.Data.ExpressionExtend; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Expressions; + +namespace IRaCIS.Application.Services +{ + public class StatisticsService : IStatisticsService + { + private readonly IDoctorRepository _doctorRepository; + private readonly ITrialRepository _trialRepository; + private readonly IEnrollRepository _enrollRepository; + private readonly IWorkloadRepository _workloadRepository; + private readonly ICRORepository _croCompanyRepository; + private readonly IDictionaryRepository _dictionaryRepository; + private readonly IHospitalRepository _hospitalRepository; + private readonly IEnrollDetailRepository _enrollDetailRepository; + private readonly IUserRepository _userRepository; + private readonly IUserTrialRepository _userTrialRepository; + + public StatisticsService(IDoctorRepository doctorRepository, ITrialRepository trialRepository, + IEnrollRepository intoGroupRepository, IWorkloadRepository workloadRepository, + ICRORepository croCompanyRepository, + IDictionaryRepository dictionaryRepository, + IHospitalRepository hospitalRepository, + IEnrollDetailRepository enrollDetailRepository, IUserRepository userRepository, + IUserTrialRepository userTrialRepository) + { + _doctorRepository = doctorRepository; + _trialRepository = trialRepository; + _enrollRepository = intoGroupRepository; + _workloadRepository = workloadRepository; + _croCompanyRepository = croCompanyRepository; + _dictionaryRepository = dictionaryRepository; + _hospitalRepository = hospitalRepository; + _enrollDetailRepository = enrollDetailRepository; + _userRepository = userRepository; + _userTrialRepository = userTrialRepository; + } + + public PageOutput GetWorkloadByTrialAndReviewer(StatisticsWorkloadQueryParam param, + Guid userId) + { + var currentUser = _userRepository.FindSingleOrDefault(u => u.Id == userId); + + var bDate = new DateTime(param.BeginDate.Year, param.BeginDate.Month, param.BeginDate.Day); + var eDate = new DateTime(param.EndDate.Year, param.EndDate.Month, param.EndDate.Day); + eDate = eDate.AddDays(1); + Expression> workloadLambda = x => x.DataFrom == (int)WorkLoadFromStatus.FinalConfirm; + workloadLambda = workloadLambda.And(x => x.WorkTime >= bDate && x.WorkTime < eDate); + + Expression> trialLambda = x => true; + if (currentUser.SuperAdmin) //超级管理员按照条件查询所有 + { + if (Guid.Empty != param.CroId && param.CroId != null) + { + trialLambda = trialLambda.And(u => u.CROId == param.CroId); + } + } + else if (currentUser.UserType.Contains("CROCoordinator")) //协调者看CRO下面的 + { + trialLambda = trialLambda.And(u => u.CROId == currentUser.OrganizationId); + } + else //不管是精鼎的pm还是我们的pm 还是运维人员 只能看到自己参与项目的统计 + { + List trialIdList = _userTrialRepository.Find(u => u.UserId == userId&&u.SiteId==Guid.Empty).Select(u => u.TrialId).ToList(); + trialLambda = trialLambda.And(u => trialIdList.Contains(u.Id)); + } + if (!string.IsNullOrWhiteSpace(param.TrialCode)) + { + trialLambda = trialLambda.And(u => u.Code.Contains(param.TrialCode.Trim())); + } + + Expression> doctorLambda = x => true; + if (!string.IsNullOrWhiteSpace(param.Reviewer)) + { + + var reviewer = param.Reviewer.Trim(); + doctorLambda = doctorLambda.And(u => u.ChineseName.Contains(reviewer) + || u.FirstName.Contains(reviewer) + || u.LastName.Contains(reviewer) + || u.Code.Contains(reviewer) + ); + + } + if (Guid.Empty != param.HospitalId && param.HospitalId != null) + { + doctorLambda = doctorLambda.And(u => u.HospitalId == param.HospitalId); + } + + var workloadQuery = from workLoad in _workloadRepository.GetAll().Where(workloadLambda) + join trial in _trialRepository.Find(trialLambda) + on workLoad.TrialId equals trial.Id + join doctor in _doctorRepository.Find(doctorLambda) + on workLoad.DoctorId equals doctor.Id + group workLoad by new { workLoad.DoctorId, workLoad.TrialId } + into gWorkLoad + + select new + { + DoctorId = gWorkLoad.Key.DoctorId, + TrialId = gWorkLoad.Key.TrialId, + Downtime = gWorkLoad.Sum(t => t.Downtime), + Training = gWorkLoad.Sum(t => t.Training), + Timepoint = gWorkLoad.Sum(t => t.Timepoint), + TimepointIn24H = gWorkLoad.Sum(t => t.TimepointIn24H), + TimepointIn48H = gWorkLoad.Sum(t => t.TimepointIn48H), + Global = gWorkLoad.Sum(t => t.Global), + Adjudication = gWorkLoad.Sum(t => t.Adjudication), + AdjudicationIn24H = gWorkLoad.Sum(t => t.AdjudicationIn24H), + AdjudicationIn48H = gWorkLoad.Sum(t => t.AdjudicationIn48H), + RefresherTraining= gWorkLoad.Sum(t => t.RefresherTraining), + + }; + var query = from w in workloadQuery + join trial in _trialRepository.Find(trialLambda) on w.TrialId equals trial.Id into t + from trialItem in t.DefaultIfEmpty() + join doctor in _doctorRepository.Find(doctorLambda) on w.DoctorId equals doctor.Id into tt + from doctorItem in tt.DefaultIfEmpty() + join cro in _croCompanyRepository.GetAll() on trialItem.CROId equals cro.Id into ttt + from croItem in ttt.DefaultIfEmpty() + select new WorkloadByTrialAndReviewerDTO + { + Id = Guid.NewGuid(), + TrialId = trialItem.Id, + Indication = trialItem.Indication, + TrialCode = trialItem.Code, + CroId = trialItem.CROId, + Cro = croItem.CROName, + ReviewerCode = doctorItem.Code, + ChineseName = doctorItem.ChineseName, + FirstName = doctorItem.FirstName, + LastName = doctorItem.LastName, + Training = w.Training, + Timepoint = w.Timepoint, + TimepointIn24H = w.TimepointIn24H, + TimepointIn48H = w.TimepointIn48H, + Adjudication = w.Adjudication, + AdjudicationIn24H = w.AdjudicationIn24H, + AdjudicationIn48H = w.AdjudicationIn48H, + Global = w.Global, + Downtime = w.Downtime, + RefresherTraining=w.RefresherTraining, + + PersonalTotal = w.Timepoint + w.TimepointIn24H + w.TimepointIn48H + w.Adjudication + w.AdjudicationIn24H + + w.AdjudicationIn48H + w.Global + }; + + var propName = param.SortField == "" ? "ReviewerCode" : param.SortField; + query = param.Asc + ? query.OrderBy(propName).ThenBy(t=>t.TrialCode).ThenBy(u=>u.ReviewerCode) + : query.OrderByDescending(propName).ThenBy(t => t.TrialCode).ThenBy(u => u.ReviewerCode); + if (propName == "FirstName" || propName == "LastName") + { + query = param.Asc + ? query.OrderBy(t => t.LastName).ThenBy(t => t.FirstName) + : query.OrderByDescending(t => t.LastName).ThenBy(t => t.FirstName); + } + var count = query.Count(); + + query = query + .Skip((param.PageIndex - 1) * param.PageSize) + .Take(param.PageSize); + var doctorViewList = query.ToList(); + + return new PageOutput(param.PageIndex, param.PageSize, count, doctorViewList); + } + public PageOutput GetEnrollStatByReviewer(EnrollStatByReviewerQueryDTO param) + { + var bDate = new DateTime(param.BeginDate.Year, param.BeginDate.Month, 1); + var eDate = new DateTime(param.EndDate.Year, param.EndDate.Month, 1); + eDate = eDate.AddMonths(1); + + Expression> enrollLambda = x => true; + enrollLambda = enrollLambda.And(x => x.EnrollTime >= bDate && x.EnrollTime < eDate); + + Expression> hospitalLambda = x => true; + if (Guid.Empty != param.HospitalId&& param.HospitalId!=null) + { + hospitalLambda = hospitalLambda.And(u => u.Id == param.HospitalId); + } + + Expression> doctorLambda = x => true; + if (!string.IsNullOrWhiteSpace(param.Reviewer)) + { + + var reviewer = param.Reviewer.Trim(); + doctorLambda = doctorLambda.And(u => u.ChineseName.Contains(reviewer) + || u.FirstName.Contains(reviewer) + || u.LastName.Contains(reviewer) + || u.Code.Contains(reviewer) + ); + } + + var enrollQueryable = + from enroll in _enrollRepository.Find(enrollLambda) + group enroll by new { enroll.DoctorId } + into g + select new + { + DoctorId = g.Key.DoctorId, + Submitted = g.Sum(t => + t.EnrollStatus == (int)EnrollStatus.HasCommittedToCRO?1:0), + Approved = g.Sum(t => + t.EnrollStatus == (int)EnrollStatus.InviteIntoGroup?1:0), + Reading = g.Sum(t => + t.EnrollStatus == (int)EnrollStatus.DoctorReading?1:0), + Finished = g.Sum(t => + t.EnrollStatus >= (int)EnrollStatus.End?1:0), + }; + + + var query = from w in enrollQueryable + + join doctor in _doctorRepository.Find(doctorLambda) on w.DoctorId equals doctor.Id + join hospital in _hospitalRepository.Find(hospitalLambda) on doctor.HospitalId equals hospital.Id + select new EnrollStatByReviewerDTO + { + Id = Guid.NewGuid(), + Hospital = hospital.HospitalName, + ReviewerCode = doctor.Code, + ChineseName = doctor.ChineseName, + FirstName = doctor.FirstName, + LastName = doctor.LastName, + Pending = w.Submitted, + Approved = w.Approved, + Reading = w.Reading, + Finished = w.Finished, + + Total = w.Submitted+ w.Approved+ w.Reading+ w.Finished + }; + + if (param.SortField != "EntryRate") + { + var propName = param.SortField == "" ? "ReviewerCode" : param.SortField; + query = param.Asc + ? query.OrderBy(propName).ThenBy(u => u.ReviewerCode) + : query.OrderByDescending(propName).ThenBy(u => u.ReviewerCode); + if (propName == "FirstName" || propName == "LastName") + { + query = param.Asc + ? query.OrderBy(t => t.LastName).ThenBy(t => t.FirstName) + : query.OrderByDescending(t => t.LastName).ThenBy(t => t.FirstName); + } + } + + + var count = query.Count(); + query = query + .Skip((param.PageIndex - 1) * param.PageSize) + .Take(param.PageSize); + var list = query.ToList(); + + if (param.SortField == "EntryRate") + { + list = param.Asc + ? list.OrderBy(t => t.EntryRate).ToList() + : list.OrderByDescending(t => t.EntryRate).ToList(); + } + + return new PageOutput(param.PageIndex, param.PageSize, count, list); + } + + public PageOutput GetEnrollStatByTrial(EnrollStatByTrialQueryDTO param) + { + + #region 筛选条件 + + Expression> trialLambda = x => true; + + if (param.Expedited != null) + { + trialLambda = trialLambda.And(o => o.Expedited == param.Expedited); + } + + if (!string.IsNullOrEmpty(param.TrialCode)) + { + var code = param.TrialCode.Trim(); + trialLambda = trialLambda.And(o => o.Code.Contains(code)); + } + + if (!string.IsNullOrWhiteSpace(param.Indication)) + { + var indication = param.Indication.Trim(); + trialLambda = trialLambda.And(o => o.Indication.Contains(indication)); + } + + if (param.CROId != Guid.Empty&& param.CROId != null) + { + trialLambda = trialLambda.And(o => o.CROId == param.CROId); + } + + + if (param.BeginDate != null && param.EndDate != null) + { + var bDate = new DateTime(param.BeginDate.Value.Year, param.BeginDate.Value.Month, param.BeginDate.Value.Day); + var eDate = new DateTime(param.EndDate.Value.Year, param.EndDate.Value.Month, param.BeginDate.Value.Day); + eDate = eDate.AddMonths(1); + + trialLambda = trialLambda.And(o => o.CreateTime>=bDate&&o.CreateTime t.EnrollStatus >= (int)EnrollStatus.ConfirmIntoGroup).GroupBy(t => t.TrialId).Select(g => new + { + TrialId = g.Key, + EnrollCount = g.Count() + }); + + var trialQuery = from trial in _trialRepository.GetAll().Where(trialLambda) + join cro in _croCompanyRepository.GetAll() on trial.CROId equals cro.Id into t + from cro in t.DefaultIfEmpty() + + join trialEnroll in trialEnrollStatQuery on trial.Id equals trialEnroll.TrialId + select new EnrollStatByTrialDTO + { + TrialId= trial.Id, + Cro = cro != null ? cro.CROName : "", + Expedited = trial.Expedited, + Indication = trial.Indication, + TrialCode = trial.Code, + EnrollCount= trialEnroll.EnrollCount, + CreateTime = trial.CreateTime + }; + + var propName = param.SortField == "" ? "TrialCode" : param.SortField; + trialQuery = param.Asc + ? trialQuery.OrderBy(propName) + : trialQuery.OrderByDescending(propName); + + var count = trialQuery.Count(); + + trialQuery = trialQuery + .Skip((param.PageIndex - 1) * param.PageSize) + .Take(param.PageSize); + + var trialList = trialQuery.ToList(); + + var trialIds = trialList.Select(t => t.TrialId).ToList(); + + var enrollReviewerQuery = from enroll in _enrollRepository.GetAll() + .Where(t => t.EnrollStatus >= (int)EnrollStatus.ConfirmIntoGroup&& trialIds.Contains(t.TrialId)) + join reviewer in _doctorRepository.GetAll() on enroll.DoctorId equals reviewer.Id + + select new + { + TrialId = enroll.TrialId, + NameCN = reviewer.ChineseName, + Name = reviewer.LastName + " / " + reviewer.FirstName + }; + var enrollReviewerByTrialList = enrollReviewerQuery.ToList().GroupBy(t => t.TrialId).Select(g => new + { + TrialId = g.Key, + ReviewerNameCNList = g.Select(t => t.NameCN).ToList(), + ReviewerNameList = g.Select(t => t.Name).ToList() + }).ToList(); + + + trialList.ForEach(t => + { + var trialDoctors = enrollReviewerByTrialList.FirstOrDefault(u => u.TrialId == t.TrialId); + + if (trialDoctors != null) + { + t.ReviewerNameCNList = trialDoctors.ReviewerNameCNList; + t.ReviewerNameList = trialDoctors.ReviewerNameList; + } + }); + + + return new PageOutput(param.PageIndex, param.PageSize, count, trialList); + + } + + + #region Dashboard 数据统计 + public ReadingDataDTO GetReadingDataByType() + { + int tp = 0; int ad = 0; int g = 0; + var finalConfirmWorkload = _workloadRepository.Find(u => u.DataFrom == (int)WorkLoadFromStatus.FinalConfirm).ToList(); + foreach (var item in finalConfirmWorkload) + { + tp += (item.Timepoint + item.TimepointIn24H + item.TimepointIn48H); + ad += (item.Adjudication + item.AdjudicationIn24H + item.AdjudicationIn48H); + g += item.Global; + } + return new ReadingDataDTO + { + Timepoint = tp, + Adjudication = ad, + Global = g + }; + } + + public List GetReadingDataByMonth(int monthCount) + { + DateTime now = DateTime.Now.AddMonths(-1); + DateTime eTime = new DateTime(now.Year, now.Month, 20); + + DateTime now6 = now.AddMonths(-1 * (monthCount - 1)); + DateTime bTime = new DateTime(now.AddMonths(-(monthCount - 1)).Year, + now.AddMonths(-(monthCount - 1)).Month, 1, 0, 0, 0, 0); + + var query = from workload in _workloadRepository + .Find(u => u.DataFrom == (int)WorkLoadFromStatus.FinalConfirm && + u.WorkTime >= bTime && u.WorkTime < eTime) + group workload by workload.YearMonth + into gWorkLoad + select new ReadingDataMonthDTO + { + Month = gWorkLoad.Key, + Timepoint = gWorkLoad.Sum(t => t.Timepoint) + gWorkLoad.Sum(t => t.TimepointIn24H) + + gWorkLoad.Sum(t => t.TimepointIn48H), + Adjudication = gWorkLoad.Sum(t => t.Adjudication) + gWorkLoad.Sum(t => t.AdjudicationIn24H) + + gWorkLoad.Sum(t => t.AdjudicationIn48H), + Global = gWorkLoad.Sum(t => t.Global) + }; + var workloadList = query.OrderByDescending(u => u.Month).ToList(); + List result = new List(); + + for (int i = 0; i < monthCount; i++) + { + var tempTime = now.AddMonths(-1 * i); + var existedItem = workloadList.Find(u => u.Month == + (tempTime.Year + "-" + tempTime.Month.ToString().PadLeft(2, '0'))); + if (existedItem != null) + { + result.Add(new ReadingDataMonthDTO + { + Month = existedItem.Month, + Timepoint = existedItem.Timepoint, + Adjudication = existedItem.Adjudication, + Global = existedItem.Global + }); + } + else + { + result.Add(new ReadingDataMonthDTO + { + Month = tempTime.Year + "-" + tempTime.Month.ToString().PadLeft(2, '0'), + Timepoint = 0, + Adjudication = 0, + Global = 0 + }); + } + } + return result; + } + + public List GetReadingDataRank(int topCount) + { + var query = from workload in _workloadRepository + .Find(u => u.DataFrom == (int)WorkLoadFromStatus.FinalConfirm) + group workload by workload.DoctorId + into gWorkLoad + + select new ReadingDataRankDTO + { + TotalReadingCount = gWorkLoad.Sum(t => t.Timepoint) + gWorkLoad.Sum(t => t.TimepointIn24H) + + gWorkLoad.Sum(t => t.TimepointIn48H) + gWorkLoad.Sum(t => t.Adjudication) + gWorkLoad.Sum(t => t.AdjudicationIn24H) + + gWorkLoad.Sum(t => t.AdjudicationIn48H) + gWorkLoad.Sum(t => t.Global), + ReviewerId = gWorkLoad.Key, + Timepoint = gWorkLoad.Sum(t => t.Timepoint) + gWorkLoad.Sum(t => t.TimepointIn24H) + + gWorkLoad.Sum(t => t.TimepointIn48H), + Adjudication = gWorkLoad.Sum(t => t.Adjudication) + gWorkLoad.Sum(t => t.AdjudicationIn24H) + + gWorkLoad.Sum(t => t.AdjudicationIn48H), + Global = gWorkLoad.Sum(t => t.Global) + }; + var workloadList = query.OrderByDescending(u => u.TotalReadingCount).Take(topCount).ToList(); + var reviewerList = from w in workloadList + join doctor in _doctorRepository.Find() on w.ReviewerId equals doctor.Id into tt + from doctorItem in tt.DefaultIfEmpty() + select new ReadingDataRankDTO + { + TotalReadingCount = w.TotalReadingCount, + ReviewerId = w.ReviewerId, + Timepoint = w.Timepoint, + Adjudication = w.Adjudication, + Global = w.Global, + ReviewerCode = doctorItem == null ? string.Empty : doctorItem.Code, + FirstName = doctorItem == null ? string.Empty : doctorItem.FirstName, + LastName = doctorItem == null ? string.Empty : doctorItem.LastName, + ChineseName = doctorItem == null ? string.Empty : doctorItem.ChineseName + }; + return reviewerList.ToList(); + } + + + public List GetReviewersByRank() + { + var query = from q in (from reviewer in _doctorRepository.GetAll() + //.Find(u => u.ReviewStatus == 1 && u.CooperateStatus == 1) + group reviewer by reviewer.RankId + into gReviewer + select new + { + RankId = gReviewer.Key, + ReviewerCount = gReviewer.Count() + }) + + join dic in _dictionaryRepository.Find() on q.RankId equals dic.Id into tt + from dicItem in tt.DefaultIfEmpty() + select new RankReviewersDTO + { + RankId = q.RankId, + ReviewerCount = q.ReviewerCount, + RankName = dicItem == null ? "Other" : dicItem.Value + }; + + var rankList = query.ToList(); + var staffList = rankList.Where(u => u.RankName == "Staff" || u.RankName == "Other"); + int staffCount = 0; + foreach (var item in staffList) + { + staffCount += item.ReviewerCount; + } + rankList.RemoveAll(u => u.RankName == "Staff" || u.RankName == "Other"); + + rankList.Add(new RankReviewersDTO { RankId = Guid.NewGuid(), RankName = "Staff", ReviewerCount = staffCount }); + + return rankList; + } + + public List GetEnrollDataByQuarter(int type, int count) + { + //等于0按照月份 否则按照季度 + if (type != 0) + { + var quarterCount = count; + var year = DateTime.Now.AddMonths(-(quarterCount - 1) * 3 - DateTime.Now.Month % 3 + 1).Year; + var month = DateTime.Now.AddMonths(-(quarterCount - 1) * 3 - DateTime.Now.Month % 3 + 1).Month; + + var beginMonth = new DateTime(year, month, 1); + + var endMonth = DateTime.Now; + var querySql = from enrollDetail in _enrollDetailRepository.GetAll().Where(t => + t.CreateTime > beginMonth && t.CreateTime < endMonth && + t.EnrollStatus == (int)EnrollStatus.ConfirmIntoGroup) + select new + { + + OptTime = enrollDetail.CreateTime, + Year = enrollDetail.CreateTime.Year, + Month = enrollDetail.CreateTime.Month, + }; + + var result = querySql.GroupBy(t => new { t.Year, t.Month }).Select(s => new EnrollDataDTO + { + Year = s.Key.Year, + Month = s.Key.Month, + EnrollCount = s.Count() + }).ToList(); + + + #region 填充数据 + + List returnList = new List(); + for (int i = 0; i < DateTime.Now.Month % 3 + (quarterCount - 1) * 3; i++) + { + var tempTime = DateTime.Now.AddMonths(-1 * i); + var existedItem = result.FirstOrDefault(u => u.YearMonth == tempTime.ToString("yyyy-MM")); + if (existedItem != null) + { + returnList.Add(new EnrollDataDTO + { + Month = existedItem.Month, + Year = existedItem.Year, + EnrollCount = existedItem.EnrollCount + }); + } + else + { + returnList.Add(new EnrollDataDTO + { + Month = tempTime.Month, + Year = tempTime.Year, + EnrollCount = 0 + }); + } + } + + #endregion + + var returnResult = returnList.GroupBy(t => t.QuarterStr).Select(u => new EnrollQuartDataDTO() + { + ViewStr = u.Key, + EnrollCount = u.Sum(t => t.EnrollCount) + }).ToList(); + + return returnResult; + } + else + { + var year = DateTime.Now.AddMonths(-(count - 1)).Year; + var month = DateTime.Now.AddMonths(-(count - 1)).Month; + + var beginMonth = new DateTime(year, month, 1); + + var endMonth = DateTime.Now; + var querySql = from enrollDetail in _enrollDetailRepository.GetAll().Where(t => + t.CreateTime > beginMonth && t.CreateTime < endMonth && + t.EnrollStatus == (int)EnrollStatus.ConfirmIntoGroup) + select new + { + + OptTime = enrollDetail.CreateTime, + Year = enrollDetail.CreateTime.Year, + Month = enrollDetail.CreateTime.Month, + }; + + var result = querySql.GroupBy(t => new { t.Year, t.Month }).Select(s => new EnrollDataDTO + { + Year = s.Key.Year, + Month = s.Key.Month, + EnrollCount = s.Count() + }).ToList(); + + #region 填充数据 + + List returnList = new List(); + for (int i = 0; i < count; i++) + { + var tempTime = DateTime.Now.AddMonths(-1 * i); + var existedItem = result.FirstOrDefault(u => u.YearMonth == tempTime.ToString("yyyy-MM")); + if (existedItem != null) + { + returnList.Add(new EnrollDataDTO + { + Month = existedItem.Month, + Year = existedItem.Year, + EnrollCount = existedItem.EnrollCount + }); + } + else + { + returnList.Add(new EnrollDataDTO + { + Month = tempTime.Month, + Year = tempTime.Year, + EnrollCount = 0 + }); + } + } + + #endregion + + var returnResult = returnList.GroupBy(t => t.YearMonth).Select(u => new EnrollQuartDataDTO() + { + ViewStr = u.Key, + EnrollCount = u.Sum(t => t.EnrollCount) + }).ToList(); + + return returnResult; + } + + } + + public List GetTrialCountRank(int topCount) + { + var queryList = (from enrollDetail in _enrollDetailRepository.GetAll().Where(t => + t.EnrollStatus == (int)EnrollStatus.ConfirmIntoGroup) + group enrollDetail by enrollDetail.DoctorId + into g + select new + { + ReviewerId = g.Key, + TrialCount = g.Count() + }).OrderByDescending(u => u.TrialCount).Take(topCount).ToList(); + + var trialDataRank = from stat in queryList + join doctor in _doctorRepository.GetAll() on stat.ReviewerId equals doctor.Id + select new TrialDataRankDTO() + { + TrialCount = stat.TrialCount, + ChineseName = doctor.ChineseName, + FirstName = doctor.FirstName, + LastName = doctor.LastName, + ReviewerId = doctor.Id, + ReviewerCode = doctor.Code + }; + return trialDataRank.ToList(); + + } + + public List GetLatestWorkLoadList(int searchCount) + { + var workloadList = _workloadRepository.GetAll() + .Where(t => t.DataFrom == (int)WorkLoadFromStatus.FinalConfirm && + (t.Adjudication + t.AdjudicationIn24H + t.AdjudicationIn48H) > 0 && + (t.Timepoint + t.TimepointIn24H + t.TimepointIn48H) > 0) + .OrderByDescending(t => t.CreateTime).Take(searchCount).ToList(); + + + var reviewerList = from w in workloadList + join doctor in _doctorRepository.Find() on w.DoctorId equals doctor.Id into tt + from doctorItem in tt.DefaultIfEmpty() + join trial in _trialRepository.GetAll() on w.TrialId equals trial.Id into cc + from trialItem in cc.DefaultIfEmpty() + select new LatestWorkLoadDTO + { + + ReviewerId = w.DoctorId, + Timepoint = w.Timepoint + w.TimepointIn48H + w.TimepointIn24H, + Adjudication = w.Adjudication + w.AdjudicationIn48H + w.AdjudicationIn24H, + Global = w.Global, + ReviewerCode = doctorItem == null ? string.Empty : doctorItem.Code, + FirstName = doctorItem == null ? string.Empty : doctorItem.FirstName, + LastName = doctorItem == null ? string.Empty : doctorItem.LastName, + ChineseName = doctorItem == null ? string.Empty : doctorItem.ChineseName, + + TrialCode = trialItem == null ? string.Empty : trialItem.Code + }; + return reviewerList.ToList(); + + + } + + + + #endregion + + } +} diff --git a/IRaCIS.Core.Application/Trial/Enrollment/TrialEnrollmentService.cs b/IRaCIS.Core.Application/Trial/Enrollment/TrialEnrollmentService.cs new file mode 100644 index 0000000..41774f3 --- /dev/null +++ b/IRaCIS.Core.Application/Trial/Enrollment/TrialEnrollmentService.cs @@ -0,0 +1,237 @@ +using IRaCIS.Application.Interfaces; +using IRaCIS.Core.Application.Contracts.RequestAndResponse; +using IRaCIS.Core.Domain.Interfaces; +using IRaCIS.Core.Domain.Models; +using IRaCIS.Core.Domain.Share; +using System; +using System.Linq; + +namespace IRaCIS.Application.Services +{ + public class TrialEnrollmentService: ITrialEnrollmentService + { + private readonly ITrialRepository _trialRepository; + private readonly ITrialDetailRepository _trialDetailRepository; + private readonly IEnrollRepository _enrollRepository; + private readonly IEnrollDetailRepository _enrollDetailRepository; + public TrialEnrollmentService(ITrialRepository clinicalTrialProjectRepository, + ITrialDetailRepository clinicalProjectDetailRepository, + IEnrollRepository intoGroupRepository, + IEnrollDetailRepository intoGroupDetailRepository) + { + _trialRepository = clinicalTrialProjectRepository; + _trialDetailRepository = clinicalProjectDetailRepository; + _enrollRepository = intoGroupRepository; + _enrollDetailRepository = intoGroupDetailRepository; + } + + #region Reviewer 入组审核流程(select-submit-approve-confirm) + + /// + /// 入组流程-筛选医生 [select] + /// + public IResponseOutput SelectReviewer(Guid userId, Guid trialId, Guid[] doctorIdArray) + { + var trial = _trialRepository.GetAll().FirstOrDefault(t => t.Id == trialId); + if (trial != null) + { + //更新项目状态 + trial.TrialStatus = (int)TrialEnrollStatus.HasApplyDownLoadResume; + _trialRepository.Update(trial); + + //添加项目状态变化记录 + var trialDetail = new TrialStatusDetail() + { + + TrialId = trial.Id, + TrialStatus = (int)TrialEnrollStatus.HasApplyDownLoadResume, + }; + _trialDetailRepository.Add(trialDetail); + + // 入组表 入组状态跟踪表 + foreach (var doctorId in doctorIdArray) + { + _enrollRepository.Add(new Enroll() + { + DoctorId = doctorId, + TrialId = trialId, + EnrollStatus = (int)EnrollStatus.HasApplyDownloadResume, + }); + + _enrollDetailRepository.Add(new EnrollDetail() + { + DoctorId = doctorId, + TrialId = trialId, + EnrollStatus = (int)EnrollStatus.HasApplyDownloadResume, + OptUserType = (int)UserType.AdminUser, + }); + } + + return ResponseOutput.Result(_enrollRepository.SaveChanges()); + } + + return ResponseOutput.NotOk($"Cannot find trial {trialId}"); + } + + /// + /// 入组流程-向CRO提交医生[Submit] + /// + public IResponseOutput SubmitReviewer(Guid userId, Guid trialId, Guid[] doctorIdArray, int commitState) + { + var trial = _trialRepository.GetAll().FirstOrDefault(t => t.Id == trialId); + + if (trial != null) + { + if (commitState == 1) //确认提交CRO + { + //先判断项目状态 + var existItem = _trialRepository.FindSingleOrDefault(u => u.Id == trialId && u.TrialStatus >= (int)TrialEnrollStatus.HasCommitCRO); + if (existItem == null) + { + trial.TrialStatus = (int)TrialEnrollStatus.HasCommitCRO; + trial.TrialStatusStr = "Pending"; + } + + //trial.TrialStatus = (int)TrialStatus.HasCommitCRO; + //trial.TrialStatusStr = "Pending"; + _trialRepository.Update(trial); + + //添加项目详细记录 + var trialDetail = new TrialStatusDetail() + { + TrialId = trial.Id, + TrialStatus = (int)TrialEnrollStatus.HasCommitCRO + }; + _trialDetailRepository.Add(trialDetail); + + //更新入组表 + var intoGroupList = _enrollRepository.Find(t => t.TrialId == trialId).ToList(); + + intoGroupList.ForEach(intoGroupItem => + { + if (doctorIdArray.Contains(intoGroupItem.DoctorId)) + { + intoGroupItem.EnrollStatus = (int)EnrollStatus.HasCommittedToCRO; + _enrollRepository.Update(intoGroupItem); + + _enrollDetailRepository.Add(new EnrollDetail() + { + TrialDetailId = trialDetail.Id, + DoctorId = intoGroupItem.DoctorId, + TrialId = trialId, + EnrollStatus = (int)EnrollStatus.HasCommittedToCRO, + CreateTime = DateTime.Now, + CreateUserId = userId, + OptUserType = (int)UserType.AdminUser, //后台用户 + }); + } + }); + } + return ResponseOutput.Result(_enrollRepository.SaveChanges()); + } + return ResponseOutput.NotOk($"Cannot find trial {trialId}"); + } + + /// + /// 入组流程-CRO确定医生名单 [ Approve] + /// + public IResponseOutput ApproveReviewer(Guid userId, Guid trialId, Guid[] doctorIdArray, int auditState) + { + var trial = _trialRepository.GetAll().FirstOrDefault(t => t.Id == trialId); + + if (trial != null) + { + if (auditState == 1) //确认入组 + { + var existItem = _trialRepository.FindSingleOrDefault(u => u.Id == trialId && u.TrialStatus >= (int)TrialEnrollStatus.HasConfirmedDoctorNames); + if (existItem == null) + { + trial.TrialStatus = (int)TrialEnrollStatus.HasConfirmedDoctorNames; + trial.TrialStatusStr = "Approved"; + } + _trialRepository.Update(trial); + + //添加项目详细记录 + var trialDetail = new TrialStatusDetail() + { + TrialId = trial.Id, + TrialStatus = (int)TrialEnrollStatus.HasConfirmedDoctorNames + }; + _trialDetailRepository.Add(trialDetail); + + //更新入组表 + var intoGroupList = _enrollRepository.Find(t => t.TrialId == trialId).ToList(); + + intoGroupList.ForEach(intoGroupItem => + { + if (doctorIdArray.Contains(intoGroupItem.DoctorId)) + { + intoGroupItem.EnrollStatus = (int)EnrollStatus.InviteIntoGroup; + _enrollRepository.Update(intoGroupItem); + + _enrollDetailRepository.Add(new EnrollDetail() + { + DoctorId = intoGroupItem.DoctorId, + TrialId = trialId, + EnrollStatus = (int)EnrollStatus.InviteIntoGroup, + CreateTime = DateTime.Now, + CreateUserId = userId, + OptUserType = (int)UserType.AdminUser, //后台用户 + }); + } + }); + } + return ResponseOutput.Result(_enrollRepository.SaveChanges()); + } + return ResponseOutput.NotOk($"Cannot find trial {trialId}"); + + } + + /// + /// 入组流程-后台确认医生入组[Confirm] + /// + public IResponseOutput ConfirmReviewer(Guid userId, Guid trialId, Guid[] doctorIdArray, int confirmState) + { + var trial = _trialRepository.GetAll().FirstOrDefault(t => t.Id == trialId); + var existItem = _trialRepository.FindSingleOrDefault(u => u.Id == trialId && u.TrialStatus >= (int)TrialEnrollStatus.HasConfirmedDoctorNames); + + trial.TrialStatusStr = "Reading"; + //trial.TrialStatus = (int)TrialStatus.HasConfirmedDoctorNames; + _trialRepository.Update(trial); + + if (trial != null) + { + if (confirmState == 1) //确认入组 + { + + //更新入组表 + var intoGroupList = _enrollRepository.Find(t => t.TrialId == trialId).ToList(); + + intoGroupList.ForEach(intoGroupItem => + { + if (doctorIdArray.Contains(intoGroupItem.DoctorId)) + { + intoGroupItem.EnrollStatus = (int)EnrollStatus.ConfirmIntoGroup; + intoGroupItem.EnrollTime = DateTime.Now; + _enrollRepository.Update(intoGroupItem); + + _enrollDetailRepository.Add(new EnrollDetail() + { + DoctorId = intoGroupItem.DoctorId, + TrialId = trialId, + EnrollStatus = (int)EnrollStatus.ConfirmIntoGroup, + CreateTime = DateTime.Now, + CreateUserId = userId, + OptUserType = (int)UserType.AdminUser, //后台用户 + }); + } + }); + } + return ResponseOutput.Result(_enrollRepository.SaveChanges()); + } + return ResponseOutput.NotOk($"Cannot find trial {trialId}"); + } + #endregion + + } +} diff --git a/IRaCIS.Core.Application/Trial/Image/DicomArchiveService.cs b/IRaCIS.Core.Application/Trial/Image/DicomArchiveService.cs new file mode 100644 index 0000000..c92d3f2 --- /dev/null +++ b/IRaCIS.Core.Application/Trial/Image/DicomArchiveService.cs @@ -0,0 +1,554 @@ +using AutoMapper; +using AutoMapper.QueryableExtensions; +using Dicom; +using Dicom.Imaging.Codec; +using IRaCIS.Core.Application.Contracts.Dicom; +using IRaCIS.Core.Application.Contracts.Dicom.DTO; +using IRaCIS.Core.Domain.Interfaces; +using IRaCIS.Core.Domain.Models; +using IRaCIS.Core.Domain.Share; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Logging; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace IRaCIS.Core.Application.Dicom +{ + public class DicomArchiveService : IDicomArchiveService + { + private readonly IDicomStudyRepository _studyRepository; + private readonly IDicomSeriesRepository _seriesRepository; + private readonly IDicomInstanceRepository _instanceRepository; + private readonly IImageLabelRepository _imageLabelRepository; + private readonly IKeyInstanceRepository _keyInstanceRepository; + private readonly IMapper _mapper; + + private readonly IHostEnvironment _hostEnvironment; + + private static string _fileStorePath = string.Empty; + private readonly ILogger _logger; + public DicomArchiveService(IDicomStudyRepository studyRepository, + IDicomSeriesRepository seriesRepository, + IDicomInstanceRepository instanceRepository, + IImageLabelRepository imageLabelRepository, + IKeyInstanceRepository keyInstanceRepository, + IHostEnvironment hostEnvironment, + IConfiguration config, + ILogger logger, + IMapper mapper) + { + _studyRepository = studyRepository; + _seriesRepository = seriesRepository; + _instanceRepository = instanceRepository; + _imageLabelRepository = imageLabelRepository; + _keyInstanceRepository = keyInstanceRepository; + _mapper = mapper; + _logger = logger; + _hostEnvironment = hostEnvironment; + _fileStorePath = config.GetValue("DicomFileArchivedPath"); //Directory.GetParent(_hostEnvironment.ContentRootPath).FullName; + //TranscoderManager.SetImplementation(Efferent.Native.Codec.NativeTranscoderManager.Instance); + + + } + public async Task ArchiveDicomStreamAsync(Stream dicomStream, + DicomTrialSiteSubjectInfo addtionalInfo) + { + try + { + //TranscoderManager.SetImplementation(Efferent.Native.Codec.NativeTranscoderManager.Instance); + + DicomFile dicomFile = await DicomFile.OpenAsync(dicomStream, Encoding.Default); + DicomDataset dataset = dicomFile.Dataset; + + ////按照配置文件 匿名化 + //foreach (var anonymizeItem in SystemConfig.AnonymizeTagList) + //{ + // if (anonymizeItem.Enable) + // { + // ushort group = Convert.ToUInt16(anonymizeItem.Group, 16); + // ushort element = Convert.ToUInt16(anonymizeItem.Element, 16); + // dataset.AddOrUpdate(new DicomTag(group, element), anonymizeItem.ReplaceValue); + // } + //} + + if (SystemConfig.AddClinicalInfo) //是否需要写入临床信息 + { + //Dicom 文件中写入临床信息 + dataset.AddOrUpdate(DicomTag.ClinicalTrialProtocolID, addtionalInfo.TrialCode); //Trial + dataset.AddOrUpdate(DicomTag.ClinicalTrialProtocolName, addtionalInfo.TrialIndication); //indication + dataset.AddOrUpdate(DicomTag.ClinicalTrialSponsorName, addtionalInfo.Sponsor);//sponsor + dataset.AddOrUpdate(DicomTag.ClinicalTrialSiteID, addtionalInfo.SiteCode); //SiteId + dataset.AddOrUpdate(DicomTag.ClinicalTrialSiteName, addtionalInfo.SiteName);//SiteName + dataset.AddOrUpdate(DicomTag.ClinicalTrialSubjectID, addtionalInfo.SubjectCode + " " + addtionalInfo.SubjectSex);//SubjectId + dataset.AddOrUpdate(DicomTag.ClinicalTrialTimePointID, addtionalInfo.SubjectVisitNum.ToString()); // TimePoint + dataset.AddOrUpdate(DicomTag.ClinicalTrialTimePointDescription, addtionalInfo.SubjectVisitVisitName + " " + addtionalInfo.SubjectVisitSVUPDES); + } + + DicomStudy dicomStudy = CreateDicomStudy(dataset, addtionalInfo); + DicomSeries dicomSeries = CreateDicomSeries(dataset, dicomStudy); + DicomInstance dicomInstance = CreateDicomInstance(dataset, dicomStudy, dicomSeries); + + string filePath = CreateInstanceFilePath(dicomStudy, dicomSeries.Id, dicomInstance.Id); + + //await dicomFile.SaveAsync(filePath); + + var samplesPerPixel = dataset.GetSingleValueOrDefault(DicomTag.SamplesPerPixel, string.Empty); + var photometricInterpretation = dataset.GetSingleValueOrDefault(DicomTag.PhotometricInterpretation, string.Empty); + if (samplesPerPixel == "1" && (photometricInterpretation.ToUpper() == "MONOCHROME2" || photometricInterpretation.ToUpper() == "MONOCHROME1"))//MONOCHROME2 + { + if (dataset.InternalTransferSyntax.IsEncapsulated) await dicomFile.SaveAsync(filePath); + else await dicomFile.Clone(DicomTransferSyntax.JPEGLSLossless).SaveAsync(filePath); + } + else + { + if (dataset.InternalTransferSyntax.IsEncapsulated) await dicomFile.SaveAsync(filePath); + else await dicomFile.Clone(DicomTransferSyntax.RLELossless).SaveAsync(filePath); //RLELossless + } + + + + //try + //{ + // //var file = dicomFile.Clone(dicomFile.Dataset.InternalTransferSyntax); + // DicomTranscoder transcoder = new DicomTranscoder(dicomFile.Dataset.InternalTransferSyntax, + // DicomTransferSyntax.JPEGLSLossless); + // await transcoder.Transcode(dicomFile).SaveAsync(filePath); + //} + //catch (Exception ee) + //{ + // throw; + //} + + await _studyRepository.AddOrUpdateAsync(dicomStudy); + await _seriesRepository.AddOrUpdateAsync(dicomSeries); + await _instanceRepository.AddOrUpdateAsync(dicomInstance); + //_studyRepository.SaveChanges(); + return _mapper.Map(dicomInstance); + } + catch (Exception ex) + { + _logger.LogError(ex.Message); + throw; + } + } + + public ICollection GetArchivedStudyList(List archivedStudyIds) + { + return _studyRepository.Find(s => archivedStudyIds.Contains(s.Id)).ProjectTo(_mapper.ConfigurationProvider).ToList(); + } + public string GetStudyPreview(Guid studyId) + { + DicomInstance dicomInstance = _instanceRepository + .GetAll().FirstOrDefault(s => s.StudyId == studyId); + if (dicomInstance != null) + { + DicomStudy dicomStudy = _studyRepository.FindSingleOrDefault(s => s.Id == dicomInstance.StudyId); + if (dicomStudy != null) + { + return GetInstanceFilePath(dicomStudy, dicomInstance.SeriesId, dicomInstance.Id.ToString()); + } + } + return string.Empty; + } + + public DicomStudyDTO GetStudyItem(Guid studyId) + { + return _mapper.Map(_studyRepository.FindSingleOrDefault(s => s.Id == studyId)); + } + + public IEnumerable GetSeriesList(Guid studyId) + { + return _seriesRepository.Find(s => s.StudyId == studyId).OrderBy(s => s.SeriesNumber). + ThenBy(s => s.SeriesTime).ThenBy(s => s.CreateTime) + .ProjectTo(_mapper.ConfigurationProvider); + } + + public IEnumerable GetSeriesWithLabelList(Guid studyId, string tpCode) + { + //return _seriesRepository.Find(s => s.StudyId == studyId).OrderBy(s => s.SeriesNumber). + // ThenBy(s => s.SeriesTime).ThenBy(s => s.CreateTime) + //.Sele + + + + var seriesList = _seriesRepository.Find(s => s.StudyId == studyId).OrderBy(s => s.SeriesNumber). + ThenBy(s => s.SeriesTime).ThenBy(s => s.CreateTime) + .ProjectTo(_mapper.ConfigurationProvider).ToList(); + + bool hasKeyInstance = false; + var SeriesIdList = _imageLabelRepository.Find(u => u.TpCode == tpCode).Select(s => s.SeriesId).Distinct().ToList(); + var instanceIdList = _imageLabelRepository.Find(u => u.TpCode == tpCode).Select(s => s.InstanceId).Distinct().ToList(); + foreach (var item in seriesList) + { + if (SeriesIdList.Contains(item.Id)) + { + item.HasLabel = true; + hasKeyInstance = true; + } + else item.HasLabel = false; + } + if (hasKeyInstance) + { + seriesList.Add(new DicomSeriesWithLabelDTO + { + KeySeries = true, + Id = SeriesIdList[0], + InstanceCount = instanceIdList.Count, + HasLabel = true, + Modality = seriesList[0].Modality, + Description = "Key Series" + }); + } + var idList = _instanceRepository.Find(s => s.StudyId == studyId).ToList();//.GroupBy(u => u.SeriesId); + foreach (var item in seriesList) + { + if (item.KeySeries) + { + item.InstanceList = instanceIdList; + } + else + { + item.InstanceList = idList.Where(s => s.SeriesId == item.Id).OrderBy(t => t.InstanceNumber) + .ThenBy(s => s.InstanceTime).ThenBy(s => s.CreateTime).Select(u => u.Id).ToList(); + } + } + return seriesList; + } + + public string GetSeriesPreview(Guid seriesId) + { + DicomInstance dicomInstance = _instanceRepository + .GetAll().FirstOrDefault(s => s.SeriesId == seriesId); + if (dicomInstance != null) + { + DicomStudy dicomStudy = _studyRepository.FindSingleOrDefault(s => s.Id == dicomInstance.StudyId); + if (dicomStudy != null) + { + return GetInstanceFilePath(dicomStudy, dicomInstance.SeriesId, dicomInstance.Id.ToString()); + + } + } + return string.Empty;//new HttpResponseMessage(HttpStatusCode.NotFound); + } + + public IEnumerable GetInstanceList(Guid seriesId) + { + return _instanceRepository.Find(s => s.SeriesId == seriesId).OrderBy(s => s.InstanceNumber). + ThenBy(s => s.InstanceTime).ThenBy(s => s.CreateTime) + .ProjectTo(_mapper.ConfigurationProvider); + } + + public IEnumerable GetInstanceIdList(Guid seriesId, string tpCode, bool? key) + { + if (key != null && key.HasValue && key.Value) + { + return _keyInstanceRepository.Find(s => s.TpCode == tpCode) + .Select(t => t.InstanceId).Distinct(); + } + else + return _instanceRepository.Find(s => s.SeriesId == seriesId).OrderBy(s => s.InstanceNumber) + .Select(t => t.Id); + } + + public string GetInstancePreview(Guid instanceId) + { + DicomInstance dicomInstance = _instanceRepository + .GetAll().FirstOrDefault(s => s.Id == instanceId); + if (dicomInstance != null) + { + DicomStudy dicomStudy = _studyRepository.FindSingleOrDefault(s => s.Id == dicomInstance.StudyId); + if (dicomStudy != null) + { + return GetInstanceFilePath(dicomStudy, dicomInstance.SeriesId, dicomInstance.Id.ToString()); + + } + } + return string.Empty;//new HttpResponseMessage(HttpStatusCode.NotFound); + } + + public string GetInstanceContent(Guid instanceId) + { + + DicomInstance dicomInstance = _instanceRepository + .GetAll().FirstOrDefault(s => s.Id == instanceId); + if (dicomInstance != null) + { + DicomStudy dicomStudy = _studyRepository.FindSingleOrDefault(s => s.Id == dicomInstance.StudyId); + if (dicomStudy != null) + { + string path = string.Empty; + if (dicomInstance.Anonymize) //被匿名化 + { + path = GetInstanceFilePath(dicomStudy, dicomInstance.SeriesId, dicomInstance.Id + ".Anonymize"); + } + else path = GetInstanceFilePath(dicomStudy, dicomInstance.SeriesId, dicomInstance.Id.ToString()); + + return path; + } + } + return string.Empty; + } + + #region + private DicomStudy CreateDicomStudy(DicomDataset dataset, DicomTrialSiteSubjectInfo addtionalInfo) + { + string studyInstanceUid = dataset.GetString(DicomTag.StudyInstanceUID); + Guid studyId = IdentifierHelper.CreateGuid(studyInstanceUid, addtionalInfo.TrialId.ToString()); + + DicomStudy dicomStudy = _studyRepository.GetAll().FirstOrDefault(u => u.Id == studyId); + + //if (dicomStudy == null) + //{ + // dicomStudy = _studyRepository.GetAll().FirstOrDefault(s => s.StudyInstanceUid == studyInstanceUid); + //} + + + if (dicomStudy != null) return dicomStudy; + + + dicomStudy = new DicomStudy + { + Id = studyId, + StudyInstanceUid = studyInstanceUid, + StudyTime = dataset.GetSingleValueOrDefault(DicomTag.StudyDate, DateTime.Now).Add(dataset.GetSingleValueOrDefault(DicomTag.StudyTime, DateTime.Now).TimeOfDay),//dataset.GetDateTime(DicomTag.StudyDate, DicomTag.StudyTime), + Modalities = dataset.GetSingleValueOrDefault(DicomTag.Modality, string.Empty), + Description = dataset.GetSingleValueOrDefault(DicomTag.StudyDescription, string.Empty), + InstitutionName = dataset.GetSingleValueOrDefault(DicomTag.InstitutionName, string.Empty), + PatientId = dataset.GetSingleValueOrDefault(DicomTag.PatientID, string.Empty), + PatientName = dataset.GetSingleValueOrDefault(DicomTag.PatientName, string.Empty), + PatientAge = dataset.GetSingleValueOrDefault(DicomTag.PatientAge, string.Empty), + PatientSex = dataset.GetSingleValueOrDefault(DicomTag.PatientSex, string.Empty), + BodyPartExamined = dataset.GetSingleValueOrDefault(DicomTag.BodyPartExamined, string.Empty), + + StudyId = dataset.GetSingleValueOrDefault(DicomTag.StudyID, string.Empty), + AccessionNumber = dataset.GetSingleValueOrDefault(DicomTag.AccessionNumber, string.Empty), + PatientBirthDate = dataset.GetSingleValueOrDefault(DicomTag.PatientBirthDate, string.Empty), + AcquisitionTime = dataset.GetSingleValueOrDefault(DicomTag.AcquisitionTime, string.Empty), + AcquisitionNumber = dataset.GetSingleValueOrDefault(DicomTag.AcquisitionNumber, string.Empty), + TriggerTime = dataset.GetSingleValueOrDefault(DicomTag.TriggerTime, string.Empty), + + + SiteId = addtionalInfo.SiteId, + TrialId = addtionalInfo.TrialId, + SubjectId = addtionalInfo.SubjectId, + SubjectVisitId = addtionalInfo.SubjectVisitId, + IsDoubleReview = addtionalInfo.IsDoubleReview, + Comment = addtionalInfo.Comment, + SeriesCount = 0, + InstanceCount = 0 + }; + + #region Setting Code + + var last = _studyRepository.GetAll().Where(s => s.TrialId == addtionalInfo.TrialId).OrderByDescending(c => c.StudyCode).FirstOrDefault(); + if (last != null) + { + var len = last.StudyCode.Length; + if (len > 5 && int.TryParse(last.StudyCode.Substring(len - 5, 5), out var num)) + { + dicomStudy.StudyCode = "ST" + (++num).ToString().PadLeft(5, '0'); + } + else + { + return null; + } + } + else + { + dicomStudy.StudyCode = "ST" + 1.ToString().PadLeft(5, '0'); + } + + #endregion + + + return dicomStudy; + } + + private DicomSeries CreateDicomSeries(DicomDataset dataset, DicomStudy dicomStudy) + { + string seriesInstanceUid = dataset.GetString(DicomTag.SeriesInstanceUID); + Guid seriesId = IdentifierHelper.CreateGuid(dicomStudy.StudyInstanceUid, seriesInstanceUid, dicomStudy.TrialId.ToString()); + + DicomSeries dicomSeries = null; + + dicomSeries = _seriesRepository.FindSingleOrDefault(t => t.Id == seriesId); + if (dicomSeries != null) return dicomSeries; + + dicomSeries = new DicomSeries + { + Id = seriesId, + StudyId = dicomStudy.Id, + + StudyInstanceUid = dicomStudy.StudyInstanceUid, + SeriesInstanceUid = seriesInstanceUid, + SeriesNumber = dataset.GetSingleValueOrDefault(DicomTag.SeriesNumber, 1), + SeriesTime = dataset.GetSingleValueOrDefault(DicomTag.SeriesDate, DateTime.Now).Add(dataset.GetSingleValueOrDefault(DicomTag.SeriesTime, DateTime.Now).TimeOfDay), // dataset.GetDateTime(DicomTag.SeriesDate, DicomTag.SeriesTime), + Modality = dataset.GetSingleValueOrDefault(DicomTag.Modality, string.Empty), + Description = dataset.GetSingleValueOrDefault(DicomTag.SeriesDescription, string.Empty), + SliceThickness = dataset.GetSingleValueOrDefault(DicomTag.SliceThickness, string.Empty), + + ImagePositionPatient = dataset.GetSingleValueOrDefault(DicomTag.ImagePositionPatient, string.Empty), + ImageOrientationPatient = dataset.GetSingleValueOrDefault(DicomTag.ImageOrientationPatient, string.Empty), + BodyPartExamined = dataset.GetSingleValueOrDefault(DicomTag.BodyPartExamined, string.Empty), + SequenceName = dataset.GetSingleValueOrDefault(DicomTag.SequenceName, string.Empty), + ProtocolName = dataset.GetSingleValueOrDefault(DicomTag.ProtocolName, string.Empty), + ImagerPixelSpacing = dataset.GetSingleValueOrDefault(DicomTag.ImagerPixelSpacing, string.Empty), + + AcquisitionTime = dataset.GetSingleValueOrDefault(DicomTag.ImagerPixelSpacing, string.Empty), + AcquisitionNumber = dataset.GetSingleValueOrDefault(DicomTag.ImagerPixelSpacing, string.Empty), + TriggerTime = dataset.GetSingleValueOrDefault(DicomTag.ImagerPixelSpacing, string.Empty), + + SiteId = dicomStudy.SiteId, + TrialId = dicomStudy.TrialId, + SubjectId = dicomStudy.SubjectId, + SubjectVisitId = dicomStudy.SubjectVisitId, + + InstanceCount = 0 + }; + + ++dicomStudy.SeriesCount; + + return dicomSeries; + } + + private DicomInstance CreateDicomInstance(DicomDataset dataset, DicomStudy dicomStudy, DicomSeries dicomSeries) + { + string sopInstanceUid = dataset.GetString(DicomTag.SOPInstanceUID); + Guid instanceId = IdentifierHelper.CreateGuid(dicomStudy.StudyInstanceUid, dicomSeries.SeriesInstanceUid, sopInstanceUid, dicomStudy.TrialId.ToString()); + + DicomInstance dicomInstance = null; + + dicomInstance = _instanceRepository.FindSingleOrDefault(t => t.Id == instanceId); + if (dicomInstance != null) return dicomInstance; + + dicomInstance = new DicomInstance + { + Id = instanceId, + StudyId = dicomStudy.Id, + SeriesId = dicomSeries.Id, + + SiteId = dicomStudy.SiteId, + TrialId = dicomStudy.TrialId, + SubjectId = dicomStudy.SubjectId, + SubjectVisitId = dicomStudy.SubjectVisitId, + + StudyInstanceUid = dicomStudy.StudyInstanceUid, + SeriesInstanceUid = dicomSeries.SeriesInstanceUid, + SopInstanceUid = sopInstanceUid, + InstanceNumber = dataset.GetSingleValueOrDefault(DicomTag.InstanceNumber, 1), + InstanceTime = dataset.GetSingleValueOrDefault(DicomTag.ContentDate, DateTime.Now).Add(dataset.GetSingleValueOrDefault(DicomTag.ContentTime, DateTime.Now).TimeOfDay), + //dataset.GetSingleValueOrDefault(DicomTag.ContentDate,DateTime.Now);//, DicomTag.ContentTime) + CPIStatus = false, + ImageRows = dataset.GetSingleValueOrDefault(DicomTag.Rows, 0), + ImageColumns = dataset.GetSingleValueOrDefault(DicomTag.Columns, 0), + SliceLocation = dataset.GetSingleValueOrDefault(DicomTag.SliceLocation, 0), + + SliceThickness = dataset.GetSingleValueOrDefault(DicomTag.SliceThickness, string.Empty), + NumberOfFrames = dataset.GetSingleValueOrDefault(DicomTag.NumberOfFrames, 0), + PixelSpacing = dataset.GetSingleValueOrDefault(DicomTag.PixelSpacing, string.Empty), + ImagerPixelSpacing = dataset.GetSingleValueOrDefault(DicomTag.ImagerPixelSpacing, string.Empty), + FrameOfReferenceUID = dataset.GetSingleValueOrDefault(DicomTag.FrameOfReferenceUID, string.Empty), + WindowCenter = dataset.GetSingleValueOrDefault(DicomTag.WindowCenter, string.Empty), + WindowWidth = dataset.GetSingleValueOrDefault(DicomTag.WindowWidth, string.Empty), + }; + + ++dicomStudy.InstanceCount; + ++dicomSeries.InstanceCount; + + return dicomInstance; + } + + #endregion + + private string CreateInstanceFilePath(DicomStudy dicomStudy, Guid seriesId, Guid instanceId) + { + //string path = string.Empty; + //if (SystemConfig.Share) + //{ + // WNetAddConnectionHelper.Connect(); + // path = Path.Combine("W:\\IRC_DICOM_ARCHIVED", dicomStudy.CreateTime.Year.ToString(), dicomStudy.TrialId.ToString(), + // dicomStudy.SiteId.ToString(), dicomStudy.SubjectId.ToString(), dicomStudy.Id.ToString()); + //} + //else path = Path.Combine(_fileStorePath, dicomStudy.CreateTime.Year.ToString(), dicomStudy.TrialId.ToString(), + // dicomStudy.SiteId.ToString(), dicomStudy.SubjectId.ToString(), dicomStudy.Id.ToString()); + + var path = Path.Combine(_fileStorePath, dicomStudy.CreateTime.Year.ToString(), dicomStudy.TrialId.ToString(), + dicomStudy.SiteId.ToString(), dicomStudy.SubjectId.ToString(), dicomStudy.Id.ToString()); + try + { + //_logger.LogInformation("检查文件夹是否存在:" + Directory.Exists(path)); + if (!Directory.Exists(path)) + { + //_logger.LogInformation("不存在,创建文件夹:" + path); + Directory.CreateDirectory(path); + } + //_logger.LogInformation("创建文件夹后,检查文件夹是否创建成功:" + Directory.Exists(path)); + } + catch (Exception ex) + { + //_logger.LogError("创建文件夹异常:" + ex.Message); + throw; + } + + + return Path.Combine(path, instanceId.ToString() + ".dcm"); + } + + private string GetInstanceFilePath(DicomStudy dicomStudy, Guid seriesId, string instanceId) + { + return Path.Combine(_fileStorePath, dicomStudy.CreateTime.Year.ToString(), dicomStudy.TrialId.ToString(), + dicomStudy.SiteId.ToString(), dicomStudy.SubjectId.ToString(), dicomStudy.Id.ToString(), instanceId.ToString() + ".dcm"); + } + + private void RemoveStudyDirectory(DicomStudy dicomStudy) + { + string path = Path.Combine(_fileStorePath, dicomStudy.CreateTime.Year.ToString(), dicomStudy.TrialId.ToString(), + dicomStudy.SiteId.ToString(), dicomStudy.SubjectId.ToString(), dicomStudy.Id.ToString()); + if (Directory.Exists(path)) Directory.Delete(path, true); + } + + public IEnumerable GetImageLabel(string tpCode) + { + return _imageLabelRepository.Find(s => s.TpCode == tpCode) + .ProjectTo(_mapper.ConfigurationProvider); + } + + public bool SaveImageLabelList(ImageLabelCommand imageLabelCommand) + { + var success = _imageLabelRepository.Delete(u => u.TpCode == imageLabelCommand.TpCode); + _keyInstanceRepository.Delete(u => u.TpCode == imageLabelCommand.TpCode); + if (imageLabelCommand.ImageLabelList.Count == 0) + { + return true; + } + else + { + + foreach (var label in imageLabelCommand.ImageLabelList) + { + _imageLabelRepository.Add(new ImageLabel + { + TpCode = imageLabelCommand.TpCode, + StudyId = label.StudyId, + SeriesId = label.SeriesId, + InstanceId = label.InstanceId, + LabelValue = label.LabelValue + }); + _keyInstanceRepository.Add(new KeyInstance + { + TpCode = imageLabelCommand.TpCode, + SeriesId = label.SeriesId, + InstanceId = label.InstanceId, + }); + } + success = _imageLabelRepository.SaveChanges(); + return success; + } + } + } +} diff --git a/IRaCIS.Core.Application/Trial/Image/DicomFileStoreHelper.cs b/IRaCIS.Core.Application/Trial/Image/DicomFileStoreHelper.cs new file mode 100644 index 0000000..0497b6d --- /dev/null +++ b/IRaCIS.Core.Application/Trial/Image/DicomFileStoreHelper.cs @@ -0,0 +1,41 @@ +//using IRaCIS.Domain.Models; +//using Microsoft.Extensions.Hosting; +//using Microsoft.Extensions.Logging; +//using System; +//using System.IO; + +//namespace IRaCIS.Core.Application.Dicom +//{ +// public class DicomFileStoreHelper +// { +// private readonly IHostEnvironment _hostEnvironment; +// private static string _fileStorePath = string.Empty; + +// public DicomFileStoreHelper(IHostEnvironment hostEnvironment) +// { +// _hostEnvironment = hostEnvironment; +// _fileStorePath = Directory.GetParent(_hostEnvironment.ContentRootPath).FullName; +// } +// public static string CreateInstanceFilePath(DicomStudy dicomStudy, Guid seriesId, Guid instanceId) +// { +// string path = Path.Combine(_fileStorePath, "Dicom", dicomStudy.CreateTime.Year.ToString(), dicomStudy.TrialId.ToString(), +// dicomStudy.SiteId.ToString(), dicomStudy.SubjectId.ToString(), dicomStudy.Id.ToString()); +// if (!Directory.Exists(path)) Directory.CreateDirectory(path); + +// return Path.Combine(path, instanceId.ToString() + ".dcm"); +// } + +// public static string GetInstanceFilePath(DicomStudy dicomStudy, Guid seriesId, Guid instanceId) +// { +// return Path.Combine(_fileStorePath, "Dicom", dicomStudy.CreateTime.Year.ToString(), dicomStudy.TrialId.ToString(), +// dicomStudy.SiteId.ToString(), dicomStudy.SubjectId.ToString(), dicomStudy.Id.ToString(), instanceId.ToString() + ".dcm"); +// } + +// public static void RemoveStudyDirectory(DicomStudy dicomStudy) +// { +// string path = Path.Combine(_fileStorePath, "Dicom", dicomStudy.CreateTime.Year.ToString(), dicomStudy.TrialId.ToString(), +// dicomStudy.SiteId.ToString(), dicomStudy.SubjectId.ToString(), dicomStudy.Id.ToString()); +// if (Directory.Exists(path)) Directory.Delete(path, true); +// } +// } +//} \ No newline at end of file diff --git a/IRaCIS.Core.Application/Trial/Image/DicomRenderingHelper.cs b/IRaCIS.Core.Application/Trial/Image/DicomRenderingHelper.cs new file mode 100644 index 0000000..2d60b45 --- /dev/null +++ b/IRaCIS.Core.Application/Trial/Image/DicomRenderingHelper.cs @@ -0,0 +1,35 @@ +using Dicom.Imaging; +using System; +using System.Drawing.Imaging; +using System.IO; + +namespace IRaCIS.Core.Application.Dicom +{ + public static class DicomRenderingHelper + { + public static Stream RenderPreviewJpeg(string filePath) + { + string jpegPath = filePath + ".preview.jpg"; + + if (!File.Exists(jpegPath)) + { + using (Stream stream = new FileStream(jpegPath, FileMode.Create)) + { + DicomImage image = new DicomImage(filePath); + image.ShowOverlays = false; + image.Scale = Math.Min(Math.Min(128.0 / image.Width, 128.0 / image.Height), 1.0); + image.RenderImage().AsClonedBitmap() + .Save(stream, ImageFormat.Jpeg); + } + } + + return new FileStream(jpegPath, FileMode.Open); + } + + public static void RemovePreviewJpeg(string filePath) + { + string jpegPath = filePath + ".preview.jpg"; + if (File.Exists(jpegPath)) File.Delete(jpegPath); + } + } +} diff --git a/IRaCIS.Core.Application/Trial/Image/IdentifierHelper.cs b/IRaCIS.Core.Application/Trial/Image/IdentifierHelper.cs new file mode 100644 index 0000000..272bebe --- /dev/null +++ b/IRaCIS.Core.Application/Trial/Image/IdentifierHelper.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Security.Cryptography; +using System.Text; + +namespace IRaCIS.Core.Application.Dicom +{ + static class IdentifierHelper + { + private static MD5 md5 = new MD5CryptoServiceProvider(); + + public static Guid CreateGuid(params string[] parts) + { + return new Guid(md5.ComputeHash(Encoding.UTF8.GetBytes(string.Concat(parts)))); + } + } +} diff --git a/IRaCIS.Core.Application/Trial/Image/ImageService.cs b/IRaCIS.Core.Application/Trial/Image/ImageService.cs new file mode 100644 index 0000000..e273c64 --- /dev/null +++ b/IRaCIS.Core.Application/Trial/Image/ImageService.cs @@ -0,0 +1,159 @@ +using AutoMapper; +using IRaCIS.Application.ExpressionExtend; +using IRaCIS.Application.Interfaces; +using IRaCIS.Application.ViewModels; +using IRaCIS.Core.Application.Contracts.RequestAndResponse; +using IRaCIS.Domain.Interfaces; +using IRaCIS.Domain.Models; +using IRaCIS.Infra.Data.ExpressionExtend; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Expressions; + +namespace IRaCIS.Application.Services +{ + public class ImageService : IImageService + { + private readonly IImageRepository _imageRepository; + private readonly ISubjectRepository _subjectsRepository; + private readonly IDicomStudyRepository _visitPointRepository; + private readonly IMapper _mapper; + private readonly IVisitStageRepository _visitPlanRepository; + private readonly ISiteRepository _siteRepository; + public ImageService(IImageRepository imageRepository, + ISubjectRepository subjectsRepository, + IVisitStageRepository trialInterviewRepository, + ISiteRepository centerRepository, + IDicomStudyRepository visitPointRepository, IMapper mapper) + { + _imageRepository = imageRepository; + _subjectsRepository = subjectsRepository; + _visitPlanRepository = trialInterviewRepository; + _siteRepository = centerRepository; + _visitPointRepository = visitPointRepository; + _mapper = mapper; + } + public IResponseOutput AddImage(ImageCommand model, Guid userId) + { + //更新受试者访视阶段 + var subject = _subjectsRepository.GetAll().FirstOrDefault(t => t.Id == model.SubjectId); + subject.VisitStageId = model.VisitStageId; + + _subjectsRepository.Update(subject); + + //添加受试者访视点 + var visitPoint = new DicomStudy() + { + VisitStageId = model.VisitStageId, + + SubjectId = model.SubjectId, + StudyCode = string.Empty + }; + + _visitPointRepository.Add(visitPoint); + + //添加影像记录 + var image = _mapper.Map(model); + + image.State = 1; + //image.StudyId=Guid.Empty; + image.StudyDate=DateTime.Now; + image.Modalities = string.Empty; + //image.StudyId= visitPoint.Id; + + + var last = _imageRepository.Find(u => u.TrialId == model.TrialId).OrderByDescending(c => c.ImageNo).FirstOrDefault(); + if (last != null) + { + var num = 0; + var len = last.ImageNo.Length; + if (len > 4 && int.TryParse(last.ImageNo.Substring(len - 4, 4), out num)) + { + image.ImageNo = "I" + model.TrialCode + (++num).ToString().PadLeft(4, '0'); + } + else + { + return ResponseOutput.NotOk("Generated Code failed."); + } + } + else + { + image.ImageNo = "I" + model.TrialCode + 1.ToString().PadLeft(4, '0'); + } + + + var result = _imageRepository.Add(image); + bool isSuccess = _imageRepository.SaveChanges(); + return ResponseOutput.Result(isSuccess, result.Id.ToString()); + } + public IResponseOutput DeleteImage(Guid id) + { + var result = _imageRepository.Delete(u => u.Id == id); + return ResponseOutput.Result(result); + } + //public PageOutput GetImageList(ImageQueryDTO param) + //{ + //Expression> imageLambda = x => true; + //if (param.State != 0) + //{ + // imageLambda = imageLambda.And(t => t.State == param.State); + //} + //Expression> subjectlambda = x => true; + //if (!string.IsNullOrWhiteSpace(param.SubjectCode)) + //{ + // subjectlambda = subjectlambda.And(t => t.Code.Contains(param.SubjectCode)); + //} + + //Expression> visitStageLambda = x => true; + //visitStageLambda = visitStageLambda.And(t => t.TrialId == param.TrialId); + //if (param.VisitStageId != Guid.Empty) + //{ + // visitStageLambda = visitStageLambda.And(t => t.Id == param.VisitStageId); + //} + + //var query = from image in _imageRepository.Find(imageLambda).Where(u => u.TrialId == param.TrialId) + // join subject in _subjectsRepository.Find(subjectlambda) + // on image.SubjectId equals subject.Id + // join visitPoint in _visitPointRepository.Find() + // on image.StudyId equals visitPoint.Id //into d + // //from visitPointItem in d.DefaultIfEmpty() + // join visitPlan in _visitPlanRepository.Find(visitStageLambda) + // on visitPoint.VisitStageId equals visitPlan.Id //into e + // //from visitPlanItem in e.DefaultIfEmpty() + // join center in _siteRepository.GetAll() + // on image.SiteId equals center.Id + // select new ImageDetailDTO + // { + // Id = image.Id, + // TrialId = image.TrialId, + // SubjectId = subject == null ? Guid.Empty : subject.Id, + // StudyId = visitPoint == null ? Guid.Empty : visitPoint.Id, + // SiteId = center == null ? Guid.Empty : center.Id, + // ImageNo = image.ImageNo, + // SubjectCode = subject == null ? string.Empty : subject.Code, + // SiteName = center == null ? string.Empty : center.SiteName, + // Period = visitPlan == null ? string.Empty : visitPlan.Period, + // VisitStageId = visitPlan == null ? Guid.Empty : visitPlan.Id, + // MedicalNo = subject == null ? string.Empty : subject.MedicalNo, + // State = image.State, + // StudyDate = image.StudyDate, + // CreateTime = image.CreateTime, + // Modalities = image.Modalities + // }; + //var count = query.Count(); + + //var propName = param.SortField == string.Empty ? "CreateTime" : param.SortField; + + //query = param.Asc + // ? query.OrderBy(propName) + // : query.OrderByDescending(propName); + + //query = query.Skip((param.PageIndex - 1) * param.PageSize).Take(param.PageSize); + //var list = query.ToList(); + //return new PageOutput(param.PageIndex, + // param.PageSize, count, list); + //} + + } +} diff --git a/IRaCIS.Core.Application/Trial/QA/QARecordService.cs b/IRaCIS.Core.Application/Trial/QA/QARecordService.cs new file mode 100644 index 0000000..1fdd383 --- /dev/null +++ b/IRaCIS.Core.Application/Trial/QA/QARecordService.cs @@ -0,0 +1,330 @@ +using AutoMapper; +using IRaCIS.Application.ViewModels; +using IRaCIS.Core.Application.Contracts; +using IRaCIS.Core.Application.Contracts.DTO; +using IRaCIS.Core.Application.Contracts.RequestAndResponse; +using IRaCIS.Core.Domain.Interfaces; +using IRaCIS.Core.Domain.Models; +using IRaCIS.Core.Domain.Share; +using IRaCIS.Core.Domain.Share.AuthUser; +using Microsoft.EntityFrameworkCore.Internal; +using System; +using System.Collections.Generic; +using System.Linq; + +namespace IRaCIS.Application.Services.QA +{ + public class QARecordService : IQARecordService + { + private readonly IQARecordRepository _qaRecordRepository; + private readonly IQADictionaryRepository _qaDictionaryRepository; + private readonly IMapper _mapper; + private readonly IDictionaryRepository _dictionaryRepository; + private readonly IQADialogRepository _qaDialogRepository; + private readonly IUserRepository _userRepository; + + private readonly IDicomStudyRepository _studyRepository; + private readonly ISubjectRepository _subjectRepository; + private readonly ISubjectVisitRepository _subjectVisitRepository; + private readonly IAcquisitionSpecificationRepository _acquisitionSpecificationRepository; + private readonly IUserInfo _userInfo; + private readonly IStudyStatusDetailRepository _studyStatusDetailRepository; + + public QARecordService(IQARecordRepository qaRecordRepository, + IQADictionaryRepository qaDictionaryRepository, IMapper mapper, + IDictionaryRepository dictionaryRepository, IQADialogRepository qaDialogRepository, + IUserRepository userRepository, + IDicomStudyRepository studyRepository, + ISubjectRepository subjectRepository, + IAcquisitionSpecificationRepository acquisitionSpecificationRepository, + IStudyStatusDetailRepository studyStatusDetailRepository, + ISubjectVisitRepository subjectVisitRepository, + IUserInfo userInfo) + { + _qaRecordRepository = qaRecordRepository; + _qaDictionaryRepository = qaDictionaryRepository; + _mapper = mapper; + _dictionaryRepository = dictionaryRepository; + _qaDialogRepository = qaDialogRepository; + _userRepository = userRepository; + _studyRepository = studyRepository; + _subjectRepository = subjectRepository; + _acquisitionSpecificationRepository = acquisitionSpecificationRepository; + _studyStatusDetailRepository = studyStatusDetailRepository; + _subjectVisitRepository = subjectVisitRepository; + _userInfo = userInfo; + } + public IResponseOutput AddOrUpdateQARecord(QAToalCommand qaTotalCommand) + { + if (qaTotalCommand.QARecord.Id == null) + { + + var qaRecord = _mapper.Map(qaTotalCommand.QARecord); + + var qaDictionaryRecords = _mapper.Map>(qaTotalCommand.QADictionaryList); + + qaDictionaryRecords.ForEach(t => t.QARecordId = qaRecord.Id); + + //_qaDictionaryRepository.AddRange(qaDictionaryRecords); + + qaDictionaryRecords.ForEach(t => + { + qaRecord.QaDictionaryList.Add(t); + t.TrialId = qaTotalCommand.TrialId; + t.SiteId = qaTotalCommand.SiteId; + }); + + _qaRecordRepository.Add(qaRecord); + + var success = _qaRecordRepository.SaveChanges(); + + var study = _studyRepository.GetAll().FirstOrDefault(u => u.Id == qaTotalCommand.StudyId); + if (study.Status != (int)StudyStatus.QAing) + { + _studyStatusDetailRepository.Add(new StudyStatusDetail + { + Status = (int)StudyStatus.QAing, + StudyId = qaTotalCommand.StudyId, + Note = string.Empty, + OptUserName = _userInfo.RealName, + OptTime = DateTime.Now + }); + _studyStatusDetailRepository.SaveChanges(); + _studyRepository.Update(u => u.Id == qaTotalCommand.StudyId, t => new DicomStudy + { + Status = (int)StudyStatus.QAing + }); + } + return ResponseOutput.Result(success, qaRecord.Id); + + } + else + { + var qARecordId = qaTotalCommand.QARecord.Id; + var qaRecord = _qaRecordRepository.GetAll().FirstOrDefault(t => t.Id == qARecordId); + + _mapper.Map(qaTotalCommand.QARecord, qaRecord); + + + //删除中间表数据 + _qaDictionaryRepository.Delete(t => t.QARecordId == qaTotalCommand.QARecord.Id); + + var qaDictionaryRecords = _mapper.Map>(qaTotalCommand.QADictionaryList); + + qaDictionaryRecords.ForEach(t => + { + t.QARecordId = qaRecord.Id; + t.TrialId = qaTotalCommand.TrialId; + t.SiteId = qaTotalCommand.SiteId; + }); + + _qaDictionaryRepository.AddRange(qaDictionaryRecords); + //qaDictionaryRecords.ForEach(t => qaRecord.QaDictionaryList.Add(t)); + + _qaRecordRepository.Update(qaRecord); + + var success = _qaRecordRepository.SaveChanges(); + + return ResponseOutput.Result(success); + + } + + + } + + public IResponseOutput DeleteQARecord(Guid qaQARecordId) + { + var success1 = _qaRecordRepository.Delete(t => t.Id == qaQARecordId); + + var success2 = _qaDictionaryRepository.Delete(t => t.QARecordId == qaQARecordId); + + return ResponseOutput.Result(success1 || success2); + } + + public QADTO GetQARecordList(Guid studyId, Guid trialId) + { + var qaRecordsQuery = from qaRecord in _qaRecordRepository.GetAll().Where(t => t.StudyId == studyId) + join user in _userRepository.GetAll() on qaRecord.CreateUserId equals user.Id + select new QARecordWithUser + { + Id = qaRecord.Id, + CreateTime = qaRecord.CreateTime, + Note = qaRecord.Note, + DeadlineTime = qaRecord.DeadlineTime, + QATemplateId = qaRecord.QATemplateId, + StudyId = qaRecord.StudyId, + UserName = user.RealName + }; + var qaRecords = qaRecordsQuery.ToList(); + + var qaRecordIds = qaRecords.Select(t => t.Id).ToList(); + + var qaDictionaryQuery = + from qadic in _qaDictionaryRepository.GetAll().Where(t => qaRecordIds.Contains(t.QARecordId)) + join dictionary in _dictionaryRepository.GetAll() on qadic.DictionaryId equals dictionary.Id + select new QADicView() + { + QARecordId = qadic.QARecordId, + DictionaryId = qadic.DictionaryId, + Note = qadic.Note, + DictionaryValue = dictionary.Value + }; + + var qaReplyCountList = _qaDialogRepository.GetAll().Where(t => qaRecordIds.Contains(t.QARecordId)) + .GroupBy(t => t.QARecordId).Select(g => new + { + QARecordId = g.Key, + ReplyCount = g.Count() + }).ToList(); + + var qaDictionaryList = qaDictionaryQuery.ToList(); + + var recordList = new List(); + + qaRecords.ForEach(t => + { + var count = qaReplyCountList.FirstOrDefault(u => u.QARecordId == t.Id)?.ReplyCount; + t.ReplyCount = count ?? 0; + + recordList.Add(new QARecordDTO() { QARecord = t }); + }); + + recordList.ForEach(t => + { + var tt = qaDictionaryList.Where(u => u.QARecordId == t.QARecord.Id).ToList(); + t.QADictionaryList.AddRange(tt); + }); + + var studySubjectInfo = from study in _studyRepository.Find(s => s.Id == studyId) + join subject in _subjectRepository.GetAll() on study.SubjectId equals subject.Id + join subjectVisit in _subjectVisitRepository.GetAll() on study.SubjectVisitId equals subjectVisit.Id + select new StudySubjectInfoDTO + { + PatientAge = study.PatientAge, + PatientName = study.PatientName, + PatientSex = study.PatientSex, + SubjectName = subject.Name, + SubjectCode = subject.Code, + SubjectAge = subject.Age, + SubjectSex = subject.Sex, + StudyStatus = study.Status, + Modalities = study.Modalities, + InstanceCount = study.InstanceCount, + SeriesCount = study.SeriesCount, + Comment = study.Comment, + QAComment = study.QAComment, + + VisitNum = subjectVisit.VisitNum, + VisitName = subjectVisit.VisitName, + InPlan = subjectVisit.InPlan, + SVSTDTC = subjectVisit.SVSTDTC, + SVENDTC = subjectVisit.SVENDTC + + }; + var specification = _acquisitionSpecificationRepository.Find(u => u.TrialId == trialId && u.Type == "AcquisitionSpecification").FirstOrDefault(); + return new QADTO + { + QARecordList = recordList, + StudySubjectInfo = studySubjectInfo.SingleOrDefault(), + Specification = _mapper.Map(specification) + }; + + } + + + public IResponseOutput AddQAReply(QADialogCommand qaDialogCommand) + { + var qaReply = _mapper.Map(qaDialogCommand); + _qaDialogRepository.Add(qaReply); + + var success = _qaDialogRepository.SaveChanges(); + + return ResponseOutput.Result(success, qaReply.Id); + } + + public IResponseOutput DeleteQAReply(Guid qaReplyId) + { + var success = _qaDialogRepository.Delete(t => t.Id == qaReplyId); + + return ResponseOutput.Result(success); + + } + + public List GetQaRecordDialogList(Guid qaRecordId) + { + var query = from qaDialog in _qaDialogRepository.GetAll() + .Where(t => t.QARecordId == qaRecordId) + join user in _userRepository.GetAll() on qaDialog.CreateUserId equals user.Id + select new DialogNode + { + Id = qaDialog.Id, + TalkContent = qaDialog.TalkContent, + UserName = user.RealName, + UserId = user.Id, + ParentId = qaDialog.ParentId, + CreateTime = qaDialog.CreateTime + }; + + var qaDialogList = query.OrderBy(t => t.CreateTime).ToList(); + + var result = new List(); + + if (qaDialogList.Count > 0) + { + + var treeHeads = qaDialogList.Where(t => t.ParentId == Guid.Empty).OrderBy(t => t.CreateTime).ToList(); + + treeHeads.ForEach(dialogHead => + { + result.Add(new DialogDTO() + { + Id = dialogHead.Id, + CreateTime = dialogHead.CreateTime, + From = dialogHead.UserName, + UserId = dialogHead.UserId, + TalkContent = dialogHead.TalkContent, + To = "", + PreviousContent = "" + + }); + + + var list = GetDialogList(dialogHead, qaDialogList); + + result.AddRange(list); + + }); + + + } + return result; + + } + + private List GetDialogList(DialogNode firstNode, List qaDialogList) + { + var result = new List(); + + var chirdren = qaDialogList.Where(t => t.ParentId == firstNode.Id) + .OrderBy(t => t.CreateTime).ToList(); + + chirdren.ForEach(t => + { + result.Add(new DialogDTO() + { + Id = t.Id, + From = t.UserName, + TalkContent = t.TalkContent, + UserId = t.UserId, + CreateTime = t.CreateTime, + To = firstNode.UserName, + PreviousContent = firstNode.TalkContent + }); + + result.AddRange(GetDialogList(t, qaDialogList)); + }); + + return result; + } + } +} \ No newline at end of file diff --git a/IRaCIS.Core.Application/Trial/QA/QATemplateService.cs b/IRaCIS.Core.Application/Trial/QA/QATemplateService.cs new file mode 100644 index 0000000..95bab19 --- /dev/null +++ b/IRaCIS.Core.Application/Trial/QA/QATemplateService.cs @@ -0,0 +1,154 @@ +using AutoMapper; +using AutoMapper.QueryableExtensions; +using IRaCIS.Application.ExpressionExtend; +using IRaCIS.Core.Application.Contracts; +using IRaCIS.Core.Application.Contracts.DTO; +using IRaCIS.Core.Application.Contracts.RequestAndResponse; +using IRaCIS.Core.Domain.Interfaces; +using IRaCIS.Core.Domain.Models; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Expressions; + +namespace IRaCIS.Application.Services.QA +{ + public class QATemplateService : IQATemplateService + { + private readonly IQATemplateRepository _qaTemplateRepository; + private readonly IMapper _mapper; + private readonly IDictionaryRepository _dictionaryRepository; + private readonly IQATemplateDictionaryRepository _qaTemplateDictionaryRepository; + + + public QATemplateService(IQATemplateRepository qaTemplateRepository, IMapper mapper, IDictionaryRepository dictionaryRepository, IQATemplateDictionaryRepository qaTemplateDictionaryRepository + + ) + { + _qaTemplateRepository = qaTemplateRepository; + _mapper = mapper; + _dictionaryRepository = dictionaryRepository; + _qaTemplateDictionaryRepository = qaTemplateDictionaryRepository; + } + + public IResponseOutput AddOrUpdateQATemplate(QATemplateCommand qaTemplateCommand) + { + if (qaTemplateCommand.Id == null) + { + var qaTemplate = _mapper.Map(qaTemplateCommand); + _qaTemplateRepository.Add(qaTemplate); + var success = _qaTemplateRepository.SaveChanges(); + return ResponseOutput.Result(success, qaTemplate.Id); + } + else + { + var qaTemplate = _qaTemplateRepository.GetAll().FirstOrDefault(t => t.Id == qaTemplateCommand.Id); + + _mapper.Map(qaTemplateCommand, qaTemplate); + + _qaTemplateRepository.Update(qaTemplate); + var success = _qaTemplateRepository.SaveChanges(); + + return ResponseOutput.Result(success); + } + + + + } + + public IResponseOutput DeleteQATemplate(Guid qaTemplateId) + { + var success = _qaTemplateRepository.Delete(t => t.Id == qaTemplateId); + + return ResponseOutput.Result(success); + } + + public List GetQaTemplateSelectList() + { + var query = _qaTemplateRepository.GetAll() + .ProjectTo(_mapper.ConfigurationProvider); + + return query.ToList(); + + } + + public PageOutput GetQaTemplateList(QATemplateQueryDTO qaTemplateQuery) + { + Expression> qATemplateLambda = x => true; + + var query = _qaTemplateRepository.GetAll().Where(qATemplateLambda) + .ProjectTo(_mapper.ConfigurationProvider); + + var count = query.Count(); + + var propName = qaTemplateQuery.SortField == string.Empty ? "Name" : qaTemplateQuery.SortField; + + query = qaTemplateQuery.Asc + ? query.OrderBy(propName) + : query.OrderByDescending(propName); + + query = query.Skip((qaTemplateQuery.PageIndex - 1) * qaTemplateQuery.PageSize).Take(qaTemplateQuery.PageSize); + var list = query.ToList(); + return new PageOutput(qaTemplateQuery.PageIndex, + qaTemplateQuery.PageSize, count, list); + } + + + + + + public List GetQaTemplateConfigList(Guid qaTemplateId) + { + var query = from dic in _dictionaryRepository.GetAll().Where(t => t.Type == "QATemplate") + join qaDic in _qaTemplateDictionaryRepository.GetAll().Where(u => u.QATemplateId == qaTemplateId) + on dic.Id equals qaDic.DictionaryId into tt + from qaDic in tt.DefaultIfEmpty() + + + select new QATemplateItemSelect + { + DictionaryId = dic.Id, + DictionaryValue = dic.Value, + IsSelect = qaDic != null + }; + return query.ToList(); + } + + + + public IResponseOutput ConfigQATemplate(QATemplateConfigCommand qaTemplateConfigCommand) + { + var success = false; + if (qaTemplateConfigCommand.IsSelect) + { + + var qaTemplateDictionary = _mapper.Map(qaTemplateConfigCommand); + + _qaTemplateDictionaryRepository.Add(qaTemplateDictionary); + + success = _qaTemplateDictionaryRepository.SaveChanges(); + + } + else + { + success = _qaTemplateDictionaryRepository + .Delete(t => t.DictionaryId == qaTemplateConfigCommand.DictionaryId + && t.QATemplateId == qaTemplateConfigCommand.QATemplateId); + } + + return ResponseOutput.Result(success); + } + + public List GetQaTemplateItemsById(Guid qaTemplateId) + { + var query = from dic in _dictionaryRepository.GetAll().Where(t => t.Type == "QATemplate") + join qaDic in _qaTemplateDictionaryRepository.GetAll().Where(u => u.QATemplateId == qaTemplateId) on dic.Id equals qaDic.DictionaryId + select new QATemplateItemDTO + { + DictionaryId = qaDic.DictionaryId, + DictionaryValue = dic.Value + }; + return query.ToList(); + } + } +} \ No newline at end of file diff --git a/IRaCIS.Core.Application/Trial/Subject/StudyService.cs b/IRaCIS.Core.Application/Trial/Subject/StudyService.cs new file mode 100644 index 0000000..e547a94 --- /dev/null +++ b/IRaCIS.Core.Application/Trial/Subject/StudyService.cs @@ -0,0 +1,1068 @@ +using AutoMapper; +using AutoMapper.QueryableExtensions; +using Dicom; +using IRaCIS.Application.ExpressionExtend; +using IRaCIS.Application.Interfaces; +using IRaCIS.Application.ViewModels; +using IRaCIS.Core.Application.Contracts.Dicom.DTO; +using IRaCIS.Core.Application.Contracts.RequestAndResponse; +using IRaCIS.Core.Application.Dicom; +using IRaCIS.Core.Domain.Interfaces; +using IRaCIS.Core.Domain.Models; +using IRaCIS.Core.Domain.Share; +using IRaCIS.Core.Domain.Share.AuthUser; +using IRaCIS.Infra.Data.ExpressionExtend; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Hosting; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Linq.Expressions; +using System.Text; +using System.Threading.Tasks; +using IConfiguration = Microsoft.Extensions.Configuration.IConfiguration; + +namespace IRaCIS.Application.Services +{ + public class StudyService : IStudyService + { + private readonly IDicomStudyRepository _studyRepository; + private readonly IVisitStageRepository _visitStageRepository; + private readonly ISubjectRepository _subjectRepository; + private readonly ISiteRepository _siteRepository; + private readonly ITrialRepository _trialRepository; + private readonly ISubjectVisitRepository _subjectVisitRepository; + private readonly IDicomInstanceRepository _dicomInstanceRepository; + private readonly IDicomSeriesRepository _dicomSeriesRepository; + + private readonly IStudyReviewerRepository _studyReviewerRepository; + private readonly IDoctorRepository _doctorRepository; + private readonly IEnrollRepository _enrollRepository; + + //private readonly IDicomStudyRepository _dicomStudyRepository; + private readonly IStudyStatusDetailRepository _studyStatusDetailRepository; + private readonly IUserInfo _userInfo; + private readonly IUserRepository _userRepository; + private readonly IUserTrialRepository _userTrialRepository; + private readonly IDictionaryRepository _dictionaryRepository; + private readonly IWorkloadTPRepository _workloadTPRepository; + + private readonly IMapper _mapper; + + private readonly IHostEnvironment _hostEnvironment; + private readonly ISponsorRepository _sponsorRepository; + private static string _fileStorePath = string.Empty; + public StudyService(IDicomStudyRepository visitPointRepository, + IVisitStageRepository visitPlanRepository, + ISubjectRepository subjectRepository, + ISiteRepository siteRepository, + ITrialRepository trialRepository, + ISubjectVisitRepository subjectVisitRepository, + IDicomInstanceRepository dicomInstanceRepository, + IDicomSeriesRepository dicomSeriesRepository, + IHostEnvironment hostEnvironment, + ISponsorRepository sponsorRepository, + IStudyReviewerRepository studyReviewerRepository, + IDoctorRepository doctorRepository, + IEnrollRepository enrollRepository, + //IDicomStudyRepository dicomStudyRepository, + IStudyStatusDetailRepository studyStatusDetailRepository, + IUserInfo userInfo, + IUserRepository userRepository, + IUserTrialRepository userTrialRepository, + IDictionaryRepository dictionaryRepository, + IWorkloadTPRepository workloadTPRepository, + IConfiguration config, + IMapper mapper) + { + _enrollRepository = enrollRepository; + //_dicomStudyRepository = dicomStudyRepository; + _studyReviewerRepository = studyReviewerRepository; + _studyStatusDetailRepository = studyStatusDetailRepository; + _userInfo = userInfo; + _userRepository = userRepository; + _userTrialRepository = userTrialRepository; + _dictionaryRepository = dictionaryRepository; + _doctorRepository = doctorRepository; + _studyRepository = visitPointRepository; + _visitStageRepository = visitPlanRepository; + _subjectRepository = subjectRepository; + _siteRepository = siteRepository; + _trialRepository = trialRepository; + _subjectVisitRepository = subjectVisitRepository; + _dicomInstanceRepository = dicomInstanceRepository; + _dicomSeriesRepository = dicomSeriesRepository; + _mapper = mapper; + _hostEnvironment = hostEnvironment; + _sponsorRepository = sponsorRepository; + _workloadTPRepository = workloadTPRepository; + _fileStorePath = config.GetValue("DicomFileArchivedPath"); + //_fileStorePath = Directory.GetParent(_hostEnvironment.ContentRootPath).FullName; + } + + /// + /// 获取受试者访视 + /// + /// + /// + /// + /// + public IEnumerable GetStudyStatList(Guid trialId, Guid subjectId, Guid siteId) + { + + var query = from visitStage in _visitStageRepository.Find(u => u.TrialId == trialId) + join visit in (_studyRepository.GetAll() + .Where(t => t.TrialId == trialId && t.SubjectId == subjectId && t.SiteId == siteId) + .GroupBy(t => t.SubjectVisitId).Select(g => new + { + SubjectVisitId = g.Key, + VisitCount = g.Count() + })) + + on visitStage.Id equals visit.SubjectVisitId into t + from visit in t.DefaultIfEmpty() + + select new StudyStatDTO + { + + StudyCount = visit.VisitCount, + TrialId = visitStage.TrialId, + VisitNum = visitStage.VisitNum, + VisitName = visitStage.VisitName, + VisitDay = visitStage.VisitDay, + Description = visitStage.Description, + SubjectVisitId = visitStage.Id + }; + query = query.OrderBy(t => t.VisitNum); + var list = query.ToList(); + + return list; + + } + + public bool UpdateReUploadNewStudyCode(Guid studyId, Guid newStudyId) + { + var code = _studyRepository.GetAll().First(t => t.Id == studyId).StudyCode; + + return _studyRepository.Update(t => t.Id == newStudyId, u => new DicomStudy() + { + //StudyCode = u.StudyCode+"("+code+")" + StudyCode = code + }); + } + + public VerifyStudyUploadResult VerifyStudyAllowUpload(string studyInstanceUid, Guid trialId, Guid? abandonStudyId) + { + Guid expectStudyId = IdentifierHelper.CreateGuid(studyInstanceUid.Trim(), trialId.ToString()); + + var result = new VerifyStudyUploadResult(); + + var query = + from study in _studyRepository.GetAll().Where(t => t.TrialId == trialId && t.Id == expectStudyId) + join subject in _subjectRepository.GetAll() + on study.SubjectId equals subject.Id + join trial in _trialRepository.GetAll() on study.TrialId equals trial.Id + join subjectVisit in _subjectVisitRepository.GetAll() + on study.SubjectVisitId equals subjectVisit.Id + join site in _siteRepository.GetAll() on study.SiteId equals site.Id + + select new StudyDTO() + { + PatientAge = study.PatientAge, + PatientSex = study.PatientSex, + PatientName = study.PatientName, + SubjectAge = subject.Age, + SubjectCode = subject.Code, + SubjectId = subject.Id, + SubjectName = subject.Name, + SubjectSex = subject.Sex, + + Id = study.Id, + TrialId = study.TrialId, + + Modalities = study.Modalities, + StudyCode = study.StudyCode, + SeriesCount = study.SeriesCount, + InstanceCount = study.InstanceCount, + StudyStatus = study.Status, + StudyDate = study.StudyTime, + IsDoubleReview = study.IsDoubleReview, + StudyDescription = study.Description, + BodyPartExamined = study.BodyPartExamined, + Comment = study.Comment, + + SiteId = study.SiteId, + SiteName = site.SiteName, + + SubjectVisitId = study.SubjectVisitId, + VisitName = subjectVisit.VisitName, + VisitNum = subjectVisit.VisitNum, + VisitDay = subjectVisit.VisitDay, + SVUPDES = subjectVisit.SVUPDES, + SVENDTC = subjectVisit.SVENDTC, + SVSTDTC = subjectVisit.SVSTDTC + }; + + + result.StudyInfo = query.FirstOrDefault(); + + + //如果是上传 看当前项目有没有已经上传过该检查 存在就不允许上传 + if (abandonStudyId == null || abandonStudyId == Guid.Empty) + { + result.AllowUpload = result.StudyInfo is null; + } + else + { + //如果是重传 已经上传的 在此传可以的, + if ( abandonStudyId.GetValueOrDefault()== expectStudyId) + { + result.AllowUpload = true; + } + //重传的时候换了新的影像 在数据库不存在该影像 也允许上传 + else if(result.StudyInfo == null ) + { + result.AllowUpload = true; + } + else + { + result.AllowUpload = false; + } + + } + + return result; + + } + + public PageOutput GetStudyList(StudyQueryDTO queryDto) + { + + Expression> studyLambda = x => x.TrialId == queryDto.TrialId; + + Expression> subjectVisitLambda = x => x.TrialId == queryDto.TrialId; + + if (queryDto.SubjectId != null) + { + studyLambda = studyLambda.And(t => t.SubjectId == queryDto.SubjectId); + } + if (queryDto.Status != null) + { + studyLambda = studyLambda.And(t => t.Status == queryDto.Status); + } + + if (queryDto.SubjectVisitId != null) + { + studyLambda = studyLambda.And(t => t.SubjectVisitId == queryDto.SubjectVisitId); + } + + if (!string.IsNullOrWhiteSpace(queryDto.VisitPlanInfo)) + { + var visitInfo = queryDto.VisitPlanInfo.Trim(); + + if (visitInfo.Contains('.')) + + { + + subjectVisitLambda = subjectVisitLambda.And(t => t.VisitNum.ToString().Contains(".")); + + + } + else + { + if (int.TryParse(visitInfo, out var visitNum)) + { + subjectVisitLambda = subjectVisitLambda.And(t => t.VisitNum == visitNum); + } + } + + //if (int.TryParse(visitInfo, out var visitNum)) + //{ + // subjectVisitLambda = subjectVisitLambda.And(t => t.VisitNum==visitNum); + //} + //else + //{ + // subjectVisitLambda = subjectVisitLambda.And(t => t.VisitName.Contains(visitInfo)); + //} + + } + + if (queryDto.StudyTimeBegin != null) + { + studyLambda = studyLambda.And(t => t.StudyTime >= queryDto.StudyTimeBegin); + } + if (queryDto.StudyTimeEnd != null) + { + studyLambda = studyLambda.And(t => t.StudyTime <= queryDto.StudyTimeEnd); + } + + if (queryDto.UpdateTimeBegin != null) + { + studyLambda = studyLambda.And(t => t.UpdateTime >= queryDto.UpdateTimeBegin); + } + if (queryDto.UpdateTimeEnd != null) + { + studyLambda = studyLambda.And(t => t.UpdateTime <= queryDto.UpdateTimeEnd); + } + + if (queryDto.SiteId != null) + { + studyLambda = studyLambda.And(t => t.SiteId == queryDto.SiteId); + } + else + { + //是CRC 需要过滤 + var userId = _userInfo.Id; + var exist = _userRepository.GetAll() + .Any(t => t.Id == userId && t.UserType.Contains(StaticData.CRC)); + + if (exist) + { + //找到CRC负责的site + var siteIds = _userTrialRepository.GetAll().Where(t => t.SiteId != Guid.Empty && t.UserId == userId && t.TrialId == queryDto.TrialId) + .Select(u => u.SiteId); + + studyLambda = studyLambda.And(t => siteIds.Contains(t.SiteId)); + } + } + Expression> subjectLambda = x => true; + if (!string.IsNullOrWhiteSpace(queryDto.SubjectInfo)) + { + var subjectInfo = queryDto.SubjectInfo.Trim(); + subjectLambda = subjectLambda.And(t => t.Code.Contains(subjectInfo) || t.Name.Contains(subjectInfo)); + } + + var query = + from study in _studyRepository.GetAll().Where(studyLambda) + join subject in _subjectRepository.Find(subjectLambda) + on study.SubjectId equals subject.Id + join trial in _trialRepository.GetAll() on study.TrialId equals trial.Id + join subjectVisit in _subjectVisitRepository.GetAll().Where(subjectVisitLambda) + on study.SubjectVisitId equals subjectVisit.Id + join site in _siteRepository.GetAll() on study.SiteId equals site.Id + + select new StudyDTO() + { + PatientId = study.PatientId, + PatientAge = study.PatientAge, + PatientSex = study.PatientSex, + PatientName = study.PatientName, + AccessionNumber = study.AccessionNumber, + PatientBirthDate = study.PatientBirthDate, + StudyId = study.StudyId, + SubjectAge = subject.Age, + SubjectCode = subject.Code, + SubjectId = subject.Id, + SubjectName = subject.Name, + SubjectSex = subject.Sex, + + Id = study.Id, + TrialId = study.TrialId, + + Modalities = study.Modalities, + StudyCode = study.StudyCode, + SeriesCount = study.SeriesCount, + InstanceCount = study.InstanceCount, + StudyStatus = study.Status, + StudyDate = study.StudyTime, + IsDoubleReview = study.IsDoubleReview, + StudyDescription = study.Description, + BodyPartExamined = study.BodyPartExamined, + Comment = study.Comment, + UpdateTime = study.UpdateTime, + + SiteId = study.SiteId, + SiteName = site.SiteName, + + SubjectVisitId = study.SubjectVisitId, + VisitName = subjectVisit.VisitName, + VisitNum = subjectVisit.VisitNum, + VisitDay = subjectVisit.VisitDay, + SVUPDES = subjectVisit.SVUPDES, + SVENDTC = subjectVisit.SVENDTC, + SVSTDTC = subjectVisit.SVSTDTC + }; + var count = query.Count(); + + // 默认按照 StudyCode 降序 + var propName = queryDto.SortField == string.Empty ? "StudyCode" : queryDto.SortField; + if (string.IsNullOrWhiteSpace(queryDto.SortField)) + { + queryDto.Asc = false; + } + query = queryDto.Asc + ? query.OrderBy(propName).ThenBy(t => t.StudyCode).ThenBy(t => t.SiteName).ThenBy(u => u.SubjectCode).ThenBy(u => u.VisitNum) + : query.OrderByDescending(propName).ThenBy(t => t.StudyCode).ThenBy(t => t.SiteName).ThenBy(u => u.SubjectCode).ThenBy(u => u.VisitNum); + + + + query = query.Skip((queryDto.PageIndex - 1) * queryDto.PageSize).Take(queryDto.PageSize); + + var list = query.ToList(); + + + // 可以看到分配的医生 + //var studyIds = list.Select(t => t.Id).ToList(); + + //var studyReviewerQuery = + // from studyReviewer in _studyReviewerRepository.GetAll().Where(t => studyIds.Contains(t.StudyId)) + // join doctor in _doctorRepository.GetAll() on studyReviewer.ReviewerId equals doctor.Id + // select new DistributeReviewer() + // { + // ReviewerId = doctor.Id, + // StudyId = studyReviewer.StudyId, + // NameCN = doctor.ChineseName, + // Name = doctor.LastName + " / " + doctor.FirstName, + // Status = studyReviewer.WorkloadType + // }; + //var studyReviewerList = studyReviewerQuery.ToList(); + + //list.ForEach(t => + //{ + // t.DistributeReviewers = studyReviewerList.Where(u => u.StudyId == t.Id).OrderBy(c => c.NameCN).ToList(); + //}); + + + + return new PageOutput(queryDto.PageIndex, + queryDto.PageSize, count, list); + + } + + /// 更新访视点和受试者 研究中心 项目的绑定关系 + public async Task UpdateStudyBinding(StudyEditCommand model) + { + var dicomStudy = _studyRepository.FindSingleOrDefault(s => s.Id == model.Id); + + //var reviewModel = (from trial in _trialRepository.GetAll().Where(t => t.Id == model.TrialId) + // join dic in _dictionaryRepository.GetAll() on trial.ReviewModeId equals dic.Id + // select dic.Value).ToList(); + + var saveInfo = GetSaveToDicomInfo(new StudyCommand() + { + SiteId = model.SiteId, + SubjectVisitId = model.SubjectVisitId, + SubjectId = model.SubjectId, + TrialId = model.TrialId + }); + if (SystemConfig.AddClinicalInfo) + { + UpdateDicomFile(dicomStudy, saveInfo); + } + + + var isSuccess = _studyRepository.Update(t => t.Id == model.Id, u => new DicomStudy() + { + SiteId = model.SiteId, + SubjectId = model.SubjectId, + SubjectVisitId = model.SubjectVisitId, + Comment = model.Comment + }); + + var isSuccess2 = _dicomSeriesRepository.Update(t => t.StudyId == model.Id, u => new DicomSeries() + { + SiteId = model.SiteId, + SubjectId = model.SubjectId, + SubjectVisitId = model.SubjectVisitId, + }); + + var isSuccess3 = _dicomInstanceRepository.Update(t => t.StudyId == model.Id, u => new DicomInstance() + { + SiteId = model.SiteId, + SubjectId = model.SubjectId, + SubjectVisitId = model.SubjectVisitId + }); + + return ResponseOutput.Result(isSuccess || isSuccess2 || isSuccess3); + } + + + /// 删除项目访视点 + public IResponseOutput DeleteStudy(Guid id) + { + var success1 = _studyRepository.Delete(t => t.Id == id); + var succeess2 = _dicomInstanceRepository.Delete(t => t.StudyId == id); + var success3 = _dicomSeriesRepository.Delete(t => t.StudyId == id); + + return ResponseOutput.Result(success1 || succeess2 || success3); + + } + + public DicomTrialSiteSubjectInfo GetSaveToDicomInfo(StudyCommand addtionalCommand) + { + var query = from subject in _subjectRepository.GetAll() + .Where(t => t.TrialId == addtionalCommand.TrialId && t.SiteId == addtionalCommand.SiteId && + t.Id == addtionalCommand.SubjectId) + join trial in _trialRepository.GetAll().Where(t => t.Id == addtionalCommand.TrialId) on subject.TrialId + equals trial.Id + //join subjectVisit in _subjectVisitRepository.GetAll() + // .Where(t => t.Id == addtionalCommand.SubjectVisitId) on subject.SubjectVisitId equals subjectVisit + // .Id + join site in _siteRepository.GetAll().Where(t => t.Id == addtionalCommand.SiteId) on subject.SiteId + equals site.Id + join sponsor in _sponsorRepository.GetAll() on trial.SponsorId equals sponsor.Id into tt + from sponsor in tt.DefaultIfEmpty() + join dictionary in _dictionaryRepository.GetAll() on trial.ReviewModeId equals dictionary.Id into cc + from dictionary in cc.DefaultIfEmpty() + select new DicomTrialSiteSubjectInfo + { + SiteName = site.SiteName, + SiteCode = site.SiteCode, + SubjectName = subject.Name, + SubjectCode = subject.Code, + SubjectSex = subject.Sex, + SubjectAge = subject.Age, + + //SubjectVisitNum = subjectVisit.VisitNum, + + //SubjectVisitSVUPDES = subjectVisit.SVUPDES, + //SubjectVisitVisitName = subjectVisit.VisitName, + + TrialCode = trial.Code, + TrialIndication = trial.Indication, + + ReviewMode = dictionary.Value, + + Sponsor = sponsor.SponsorName, + + TrialId = addtionalCommand.TrialId, + SiteId = addtionalCommand.SiteId, + SubjectId = addtionalCommand.SubjectId, + SubjectVisitId = addtionalCommand.SubjectVisitId + }; + + + var result = query.First(); + if (result.ReviewMode.Contains("Double")) + { + result.IsDoubleReview = true; + } + + var subjectVisitInfo = _subjectVisitRepository.GetAll() + .First(t => t.Id == addtionalCommand.SubjectVisitId); + + result.SubjectVisitNum = subjectVisitInfo.VisitNum; + result.SubjectVisitSVUPDES = subjectVisitInfo.SVUPDES; + result.SubjectVisitVisitName = subjectVisitInfo.VisitName; + + + + + return result; + } + + + public Guid AddSubjectVisit(Guid subjectId, Guid siteId, Guid visitStageId, DateTime? SVSTDTC, DateTime? SVENDTC) + { + var visitPlanItem = _visitStageRepository.GetAll().First(t => t.Id == visitStageId); + var subjectVisit = new SubjectVisit() + { + TrialId = visitPlanItem.TrialId, + SiteId = siteId, + SubjectId = subjectId, + VisitName = visitPlanItem.VisitName, + VisitDay = visitPlanItem.VisitDay, + VisitNum = visitPlanItem.VisitNum, + SVSTDTC = SVSTDTC, + SVENDTC = SVENDTC + }; + + _subjectVisitRepository.Add(subjectVisit); + + _subjectVisitRepository.SaveChanges(); + + + + return subjectVisit.Id; + + } + + public void UpdateSubjectLatestInfo( Guid subjectId,Guid trialId ) + { + //更新最新得受试者访视 + var latest = _subjectVisitRepository.GetAll() + .Where(t => t.SubjectId == subjectId && t.TrialId == trialId) + .OrderByDescending(t => t.SVSTDTC).FirstOrDefault(); + + if (latest != null) + { + _subjectRepository.Update(t => t.Id == subjectId, u => new Subject() + { + SubjectVisitId = latest.Id + }); + } + + } + + public bool UpdateSubjectVisit(Guid subjectVisitId, DateTime? SVSTDTC, DateTime? SVENDTC) + { + return _subjectVisitRepository.Update(t => t.Id == subjectVisitId, u => new SubjectVisit() + { + SVENDTC = SVENDTC, + SVSTDTC = SVSTDTC, + StudyUploaded = true + }); + } + + + private async Task UpdateDicomFile(DicomStudy dicomStudy, DicomTrialSiteSubjectInfo addtionalInfo) + { + //string studyPath = string.Empty; + //if (SystemConfig.Share) + //{ + // WNetAddConnectionHelper.Connect(); + // studyPath = Path.Combine("W:\\IRC_DICOM_ARCHIVED", dicomStudy.CreateTime.Year.ToString(), dicomStudy.TrialId.ToString(), + // dicomStudy.SiteId.ToString(), dicomStudy.SubjectId.ToString(), dicomStudy.Id.ToString()); + //} + //else studyPath = Path.Combine(_fileStorePath, dicomStudy.CreateTime.Year.ToString(), dicomStudy.TrialId.ToString(), + // dicomStudy.SiteId.ToString(), dicomStudy.SubjectId.ToString(), dicomStudy.Id.ToString()); + + var studyPath = Path.Combine(_fileStorePath, dicomStudy.CreateTime.Year.ToString(), dicomStudy.TrialId.ToString(), + dicomStudy.SiteId.ToString(), dicomStudy.SubjectId.ToString(), dicomStudy.Id.ToString()); + DirectoryInfo root = new DirectoryInfo(studyPath); + FileInfo[] files = root.GetFiles(); + foreach (var file in files) + { + DicomFile dicomFile = await DicomFile.OpenAsync(file.FullName, Encoding.Default); + DicomDataset dataset = dicomFile.Dataset; + + dataset.AddOrUpdate(DicomTag.ClinicalTrialProtocolID, addtionalInfo.TrialCode); //Trial + dataset.AddOrUpdate(DicomTag.ClinicalTrialProtocolName, addtionalInfo.TrialIndication); //indication + dataset.AddOrUpdate(DicomTag.ClinicalTrialSponsorName, addtionalInfo.Sponsor);//sponsor + dataset.AddOrUpdate(DicomTag.ClinicalTrialSiteID, addtionalInfo.SiteCode); //SiteId + dataset.AddOrUpdate(DicomTag.ClinicalTrialSiteName, addtionalInfo.SiteName);//SiteName + dataset.AddOrUpdate(DicomTag.ClinicalTrialSubjectID, addtionalInfo.SubjectCode + " " + addtionalInfo.SubjectName + " " + addtionalInfo.SubjectSex);//SubjectId + dataset.AddOrUpdate(DicomTag.ClinicalTrialTimePointID, addtionalInfo.SubjectVisitNum.ToString()); // TimePoint + dataset.AddOrUpdate(DicomTag.ClinicalTrialTimePointDescription, addtionalInfo.SubjectVisitVisitName + " " + addtionalInfo.SubjectVisitSVUPDES); + + + await dicomFile.SaveAsync(file.FullName); + } + } + + #region Study 分配给 Reviewer + public bool DistributeStudy(StudyReviewerCommand studyReviewer) + { + //更新Study表中,总的状态 + // 插入中间表 + + studyReviewer.StudyList.ForEach(study => + { + var workloadType = 1; + StudyStatus studyStatus = StudyStatus.Distributed; + + if (study.Status >= (int)StudyStatus.NeedAd) + { + workloadType = 2; + studyStatus = StudyStatus.AdDistributed; + } + var tempStudy = _studyRepository.FindSingleOrDefault(s => s.Id == study.StudyId); + tempStudy.Status = (int)studyStatus; + _studyRepository.Update(tempStudy); + + _studyReviewerRepository.Add(new StudyReviewer() + { + ReviewerId = studyReviewer.ReviewerId, + StudyId = study.StudyId, + WorkloadType = workloadType, + TrialId = studyReviewer.TrialId, + Status = (int)studyStatus + }); + }); + + return _studyReviewerRepository.SaveChanges(); + } + + + public IResponseOutput EditStudyReviewer(StudyReviewerEditCommand studyReviewerEditCommand) + { + _studyReviewerRepository.Delete(t => studyReviewerEditCommand.StudyId == t.StudyId); + + if (studyReviewerEditCommand.IsDoubleReview) + { + if (studyReviewerEditCommand.ReviewerId1 != null) + { + _studyReviewerRepository.Add( + new StudyReviewer() + { + StudyId = studyReviewerEditCommand.StudyId, + TrialId = studyReviewerEditCommand.TrialId, + ReviewerId = studyReviewerEditCommand.ReviewerId1.Value, + WorkloadType = 1 + }); + } + if (studyReviewerEditCommand.ReviewerId2 != null) + { + _studyReviewerRepository.Add( + new StudyReviewer() + { + StudyId = studyReviewerEditCommand.StudyId, + TrialId = studyReviewerEditCommand.TrialId, + ReviewerId = studyReviewerEditCommand.ReviewerId2.Value, + WorkloadType = 1 + }); + } + if (studyReviewerEditCommand.ReviewerIdForAD != null) + { + _studyReviewerRepository.Add( + new StudyReviewer() + { + StudyId = studyReviewerEditCommand.StudyId, + TrialId = studyReviewerEditCommand.TrialId, + ReviewerId = studyReviewerEditCommand.ReviewerIdForAD.Value, + WorkloadType = 2 + }); + } + + if (studyReviewerEditCommand.ReviewerId2 == null || studyReviewerEditCommand.ReviewerId1 == null) + { + _studyRepository.Update(t => t.Id == studyReviewerEditCommand.StudyId, + u => new DicomStudy() + { + Status = (int)StudyStatus.QAFinish + }); + } + } + else + { + if (studyReviewerEditCommand.ReviewerId1 != null) + { + _studyReviewerRepository.Add( + new StudyReviewer() + { + StudyId = studyReviewerEditCommand.StudyId, + TrialId = studyReviewerEditCommand.TrialId, + ReviewerId = studyReviewerEditCommand.ReviewerId1.Value, + WorkloadType = 1 + }); + } + else + { + _studyRepository.Update(t => t.Id == studyReviewerEditCommand.StudyId, + u => new DicomStudy() + { + Status = (int)StudyStatus.QAFinish + }); + } + } + + var success = _studyReviewerRepository.SaveChanges(); + + return ResponseOutput.Result(success); + + } + public List GetReviewerListByTrialId(Guid trialId) + { + var query = from enrollItem in _enrollRepository + .Find(t => t.TrialId == trialId && t.EnrollStatus >= 10) + join doctorItem in _doctorRepository.GetAll() + on enrollItem.DoctorId equals doctorItem.Id into g + from doctor in g.DefaultIfEmpty() + select new + { + Code = doctor.Code, + FirstName = doctor.FirstName, + LastName = doctor.LastName, + ReviewerId = enrollItem.DoctorId, + ActivelyReading = doctor.ActivelyReading, + }; + + return query.Where(s => s.ActivelyReading).Select(s => new ReviewerDistributionDTO + { + Code = s.Code, + FirstName = s.FirstName, + LastName = s.LastName, + ReviewerId = s.ReviewerId, + + }).ToList(); + } + #endregion + + public bool UpdateStudyModaliyAndComment(Guid studyId, string modaliy,string comment) + { + return _studyRepository.Update(s => s.Id == studyId, u => new DicomStudy + { + Modalities = modaliy, + Comment = comment + }); + } + + #region 更新检查状态,并记录操作记录 + public bool UpdateStudyStatus(StudyStatusDetailCommand studyStatus, string optUserName) + { + var study = _studyRepository.FindSingleOrDefault(u => u.Id == studyStatus.StudyId); + study.Status = studyStatus.Status; + if (studyStatus.Status == (int)StudyStatus.QAFInishNotPass) + { + study.QAComment = studyStatus.QAComment; + } + _studyRepository.Update(study); + //如果状态QA完成就要添加一条TP工作量,待分配 QAFinish, + //QA 完成后,需要对Dicom文件进行匿名化 + //if (studyStatus.Status == (int)StudyStatus.QAFinish) + //{ + // _workloadTPRepository.Add(new WorkloadTP + // { + // SiteId = study.SiteId, + // StudyId = study.Id, + // SubjectId = study.SubjectId, + // SubjectVisitId = study.SubjectVisitId, + // Status = 0, + // ReviewerId = Guid.Empty, + // TrialId = study.TrialId, + // UpdateTime = DateTime.Now, + // TimepointCode = study.StudyCode + "T01" + // }); + // if (study.IsDoubleReview)//双重阅片,则再添加一条,编号变为T02 + // { + // _workloadTPRepository.Add(new WorkloadTP + // { + // SiteId = study.SiteId, + // StudyId = study.Id, + // SubjectId = study.SubjectId, + // SubjectVisitId = study.SubjectVisitId, + // Status = 0, + // ReviewerId = Guid.Empty, + // TrialId = study.TrialId, + // UpdateTime = DateTime.Now, + // TimepointCode = study.StudyCode + "T02" + // }); + // } + + //} + + _studyStatusDetailRepository.Add(new StudyStatusDetail + { + Status = studyStatus.Status, + StudyId = studyStatus.StudyId, + Note = studyStatus.Note, + OptUserName = optUserName, + OptTime = DateTime.Now + }); + return _studyStatusDetailRepository.SaveChanges(); + } + public async Task DicomAnonymize(Guid studyId, string optUserName) + { + var study = _studyRepository.FindSingleOrDefault(u => u.Id == studyId); + + study.Status = (int)StudyStatus.Anonymize; + _studyRepository.Update(study); + _studyStatusDetailRepository.Add(new StudyStatusDetail + { + Status = (int)StudyStatus.Anonymize, + StudyId = studyId, + Note = string.Empty, + OptUserName = optUserName, + OptTime = DateTime.Now + }); + _workloadTPRepository.Add(new WorkloadTP + { + SiteId = study.SiteId, + StudyId = study.Id, + SubjectId = study.SubjectId, + SubjectVisitId = study.SubjectVisitId, + Status = 0, + ReviewerId = Guid.Empty, + TrialId = study.TrialId, + UpdateTime = DateTime.Now, + TimepointCode = study.StudyCode + "T01" + }); + if (study.IsDoubleReview)//双重阅片,则再添加一条,编号变为T02 + { + _workloadTPRepository.Add(new WorkloadTP + { + SiteId = study.SiteId, + StudyId = study.Id, + SubjectId = study.SubjectId, + SubjectVisitId = study.SubjectVisitId, + Status = 0, + ReviewerId = Guid.Empty, + TrialId = study.TrialId, + UpdateTime = DateTime.Now, + TimepointCode = study.StudyCode + "T02" + }); + } + //读取Dicom 文件,匿名化 + + //按照配置文件 匿名化 + var dicomSeries = _dicomSeriesRepository.Find(s => s.StudyId == studyId).ToList(); + foreach (var seriesItem in dicomSeries) + { + var dicomInstances = _dicomInstanceRepository.Find(s => s.SeriesId == seriesItem.Id); + foreach (var instanceItem in dicomInstances) + { + try + { + string filePath = CreateInstanceFilePath(study, seriesItem.Id, instanceItem.Id); + DicomFile dicomFile = await DicomFile.OpenAsync(filePath, Encoding.Default); + //DicomDataset dataset = dicomFile.Dataset; + foreach (var anonymizeItem in SystemConfig.AnonymizeTagList) + { + if (anonymizeItem.Enable) + { + ushort group = Convert.ToUInt16(anonymizeItem.Group, 16); + ushort element = Convert.ToUInt16(anonymizeItem.Element, 16); + dicomFile.Dataset.AddOrUpdate(new DicomTag(group, element), anonymizeItem.ReplaceValue); + } + } + + //string path = string.Empty; + //if (SystemConfig.Share) + //{ + // WNetAddConnectionHelper.Connect(); + // path = Path.Combine("W:\\IRC_DICOM_ARCHIVED", study.CreateTime.Year.ToString(), study.TrialId.ToString(), + // study.SiteId.ToString(), study.SubjectId.ToString(), study.Id.ToString()); + //} + //else + //{ + // path = Path.Combine(_fileStorePath, study.CreateTime.Year.ToString(), study.TrialId.ToString(), + // study.SiteId.ToString(), study.SubjectId.ToString(), study.Id.ToString(), study.ToString() + ".dcm"); + //} + string path = Path.Combine(_fileStorePath, study.CreateTime.Year.ToString(), study.TrialId.ToString(), + study.SiteId.ToString(), study.SubjectId.ToString(), study.Id.ToString()); + await dicomFile.SaveAsync(Path.Combine(path, instanceItem.Id.ToString() + ".Anonymize" + ".dcm")); + instanceItem.Anonymize = true; + _dicomInstanceRepository.Update(instanceItem); + } + catch (Exception ex) + { + + } + } + + } + return _dicomInstanceRepository.SaveChanges(); + } + + private string CreateInstanceFilePath(DicomStudy dicomStudy, Guid seriesId, Guid instanceId) + { + //string path = string.Empty; + //if (SystemConfig.Share) + //{ + // WNetAddConnectionHelper.Connect(); + // path = Path.Combine("W:\\IRC_DICOM_ARCHIVED", dicomStudy.CreateTime.Year.ToString(), dicomStudy.TrialId.ToString(), + // dicomStudy.SiteId.ToString(), dicomStudy.SubjectId.ToString(), dicomStudy.Id.ToString()); + //} + //else + //{ + // path = Path.Combine(_fileStorePath, dicomStudy.CreateTime.Year.ToString(), dicomStudy.TrialId.ToString(), + // dicomStudy.SiteId.ToString(), dicomStudy.SubjectId.ToString(), dicomStudy.Id.ToString(), instanceId.ToString() + ".dcm"); + //} + + string path = Path.Combine(_fileStorePath, dicomStudy.CreateTime.Year.ToString(), dicomStudy.TrialId.ToString(), + dicomStudy.SiteId.ToString(), dicomStudy.SubjectId.ToString(), dicomStudy.Id.ToString()); + if (!Directory.Exists(path)) Directory.CreateDirectory(path); + + return Path.Combine(path, instanceId.ToString() + ".dcm"); + } + + public bool UpdateStudyStatus(List studyStatus, string optUserName) + { + foreach (var studyItem in studyStatus) + { + var study = _studyRepository.FindSingleOrDefault(u => u.Id == studyItem.StudyId); + study.Status = studyItem.Status; + _studyRepository.Update(study); + _studyStatusDetailRepository.Add(new StudyStatusDetail + { + Status = studyItem.Status, + StudyId = studyItem.StudyId, + OptUserName = optUserName, + OptTime = DateTime.Now, + Note = studyItem.Note + }); + } + + return _studyStatusDetailRepository.SaveChanges(); + } + + public List GetStudyStatusDetailList(Guid studyId) + { + return _studyStatusDetailRepository.Find(s => s.StudyId == studyId).OrderByDescending(s => s.OptTime) + .ProjectTo(_mapper.ConfigurationProvider).ToList(); + } + + public PageOutput GetDistributeStudyList(StudyStatusQueryDTO studyStatusQueryDto) + { + + Expression> studyReviewerLambda = x => x.TrialId == studyStatusQueryDto.TrialId; + + if (studyStatusQueryDto.ReviewerId != null) + { + studyReviewerLambda = studyReviewerLambda.And(t => t.ReviewerId == studyStatusQueryDto.ReviewerId); + } + + if (studyStatusQueryDto.StudyStatus != null) + { + studyReviewerLambda = studyReviewerLambda.And(t => t.Status == studyStatusQueryDto.StudyStatus); + } + + var query = from studyReviewer in _studyReviewerRepository.GetAll().Where(studyReviewerLambda) + join doctor in _doctorRepository.GetAll() on studyReviewer.ReviewerId equals doctor.Id + join study in _studyRepository.GetAll() on studyReviewer.StudyId equals study.Id + select new DistributeReviewerStudyStatusDTO() + { + Name = doctor.LastName + " / " + doctor.FirstName, + NameCN = doctor.ChineseName, + ReviewerCode = doctor.Code, + Status = studyReviewer.Status, + StudyCode = study.StudyCode + }; + + var count = query.Count(); + + var propName = studyStatusQueryDto.SortField == string.Empty ? "ReviewerCode" : studyStatusQueryDto.SortField; + + query = studyStatusQueryDto.Asc + ? query.OrderBy(propName) + : query.OrderByDescending(propName); + + + + query = query.Skip((studyStatusQueryDto.PageIndex - 1) * studyStatusQueryDto.PageSize).Take(studyStatusQueryDto.PageSize); + + var list = query.ToList(); + + return new PageOutput(studyStatusQueryDto.PageIndex, + studyStatusQueryDto.PageSize, count, list); + } + + public IEnumerable GetRelationVisitList(decimal visitNum, string tpCode) + { + string tpGroup = tpCode.Substring(tpCode.Length - 3, 3); + var tp = _workloadTPRepository.FindSingleOrDefault(u => u.TimepointCode == tpCode); + var query = from workloadTp in _workloadTPRepository.GetAll().Where(u => u.SubjectId == tp.SubjectId + && u.TrialId == tp.TrialId && u.TimepointCode.Contains(tpGroup)) + join subjectVisit in _subjectVisitRepository.GetAll().Where(u => u.VisitNum <= visitNum) + on workloadTp.SubjectVisitId equals subjectVisit.Id + select new RelationVisitDTO + { + StudyId = workloadTp.StudyId, + TpCode = workloadTp.TimepointCode, + VisitName = subjectVisit.VisitName + }; + return query.ToList(); + } + + public List GetSubjectVisitStudyList(Guid trialId, Guid siteId, Guid subjectId, Guid subjectVisitId) + { + var query = _studyRepository.GetAll().Where(t => + t.TrialId == trialId && t.SiteId == siteId && t.SubjectId == t.SubjectId && + t.SubjectVisitId == subjectVisitId) + .Select(u => new SubjectVisitStudyDTO() + { + Modalities = u.Modalities, + StudyCode = u.StudyCode, + StudyId = u.Id, + Status = u.Status + }); + + return query.ToList(); + + } + + + #endregion + } +} diff --git a/IRaCIS.Core.Application/Trial/Subject/SubjectService.cs b/IRaCIS.Core.Application/Trial/Subject/SubjectService.cs new file mode 100644 index 0000000..3610268 --- /dev/null +++ b/IRaCIS.Core.Application/Trial/Subject/SubjectService.cs @@ -0,0 +1,271 @@ +using AutoMapper; +using IRaCIS.Application.ExpressionExtend; +using IRaCIS.Application.Interfaces; +using IRaCIS.Application.ViewModels; +using IRaCIS.Core.Application.Contracts.RequestAndResponse; +using IRaCIS.Core.Domain.Interfaces; +using IRaCIS.Core.Domain.Models; +using IRaCIS.Infra.Data.ExpressionExtend; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Expressions; +using EasyCaching.Core.Configurations; +using IRaCIS.Core.Domain.Share; +using IRaCIS.Core.Domain.Share.AuthUser; + +namespace IRaCIS.Application.Services +{ + public class SubjectService : ISubjectService + { + private readonly ISubjectRepository _subjectsRepository; + private readonly IVisitStageRepository _visitStageRepository; + private readonly ISiteRepository _siteRepository; + private readonly IMapper _mapper; + private readonly ISubjectVisitRepository _subjectVisitRepository; + private readonly IDicomStudyRepository _studyRepository; + private readonly IUserInfo _userInfo; + private readonly IUserRepository _userRepository; + private readonly IUserTrialRepository _userTrialRepository; + private readonly ITrialRepository _trialRepository; + + public SubjectService(ISubjectRepository subjectRepository, + IVisitStageRepository visitStageRepository, + ISiteRepository siteRepository, IMapper mapper, + ISubjectVisitRepository subjectVisitRepository, IDicomStudyRepository studyRepository, + IUserInfo userInfo, IUserRepository userRepository, IUserTrialRepository userTrialRepository,ITrialRepository trialRepository) + { + _subjectsRepository = subjectRepository; + _visitStageRepository = visitStageRepository; + _siteRepository = siteRepository; + _mapper = mapper; + _subjectVisitRepository = subjectVisitRepository; + _studyRepository = studyRepository; + _userInfo = userInfo; + _userRepository = userRepository; + _userTrialRepository = userTrialRepository; + _trialRepository = trialRepository; + } + public IResponseOutput AddOrUpdateSubject(SubjectCommand model) + { + model.Code = model.Code.Trim(); + if (model.Id == Guid.Empty || model.Id == null) //add + { + var saveItem = _mapper.Map(model); + + saveItem.StudyCount = 0; + saveItem.SubjectVisitId = Guid.Empty; + saveItem.Modalities = string.Empty; + + //var last = _subjectsRepository.GetAll() + // .OrderByDescending(c => c.Code).FirstOrDefault(); + //if (last != null) + //{ + // var len = last.Code.Length; + // if (len > 9 && int.TryParse(last.Code.Substring(len - 9, 9), out var num)) + // { + // saveItem.Code = "S" + (++num).ToString().PadLeft(9, '0'); + // } + // else + // { + // return ResponseOutput.NotOk("Generated Code failed.", new DicomStudy()); + // } + //} + //else + //{ + // saveItem.Code = "S" + 1.ToString().PadLeft(9, '0'); + //} + var subject = _subjectsRepository.GetAll().FirstOrDefault(u => u.Code == model.Code && u.TrialId == model.TrialId); + if (subject != null) + { + return ResponseOutput.NotOk("该项目下已经存在相同受试者编码的受试者。"); + } + + if (!_trialRepository.GetAll().Any(t => t.Id == model.TrialId && t.VisitPlanConfirmed)) + { + return ResponseOutput.NotOk("该项目访视计划未确认,无法添加受试者及其访视计划安排"); + } + var result = _subjectsRepository.Add(saveItem); + + //获取访视计划列表 + + var visitPlan= _visitStageRepository.GetAll().Where(t => t.TrialId == model.TrialId).ToList(); + + var subjectVisitPlanList=new List(); + + visitPlan.ForEach(plan=>subjectVisitPlanList.Add(new SubjectVisit() + { + TrialId = model.TrialId, + SubjectId = result.Id, + SiteId = model.SiteId, + InPlan =true, + VisitNum=plan.VisitNum, + VisitName= plan.VisitName, + VisitDay = plan.VisitDay + + })); + + + _subjectVisitRepository.AddRange(subjectVisitPlanList); + + var isSuccess = _subjectsRepository.SaveChanges(); + + return ResponseOutput.Result(isSuccess, result.Id.ToString()); + + } + else // update + { + var subject = _subjectsRepository.GetAll().FirstOrDefault(t => t.Id == model.Id); + _mapper.Map(model, subject); + + var temp = _subjectsRepository.GetAll().FirstOrDefault(u => u.Code == model.Code + && u.TrialId == model.TrialId && u.Id != model.Id); + if (temp != null) + { + return ResponseOutput.NotOk("该项目下已经存在相同受试者编码的受试者。"); + } + _subjectsRepository.Update(subject); + + var isSuccess = _subjectsRepository.SaveChanges(); + + return ResponseOutput.Result(isSuccess); + } + } + + public IResponseOutput DeleteSubject(Guid id) + { + if (_studyRepository.GetAll().Any(t => t.SubjectId == id) || + _subjectVisitRepository.GetAll().Any(u => u.SubjectId == id)) + { + return ResponseOutput.NotOk("Subject’s visit or study data exists under the subject"); + } + + var isSuccess = _subjectsRepository.Delete(u => u.Id == id); + return ResponseOutput.Result(isSuccess); + } + + public PageOutput GetSubjectList(SubjectQueryParam param) + { + Expression> subjectLambda = x => true; + Expression> studyLambda = x => x.TrialId == param.TrialId&& x.Status != (int)StudyStatus.Abandon; + Expression> subjectVisitLambda = x => x.TrialId == param.TrialId; + + if (!string.IsNullOrWhiteSpace(param.Code)) + { + subjectLambda = subjectLambda.And(t => t.Code.Contains(param.Code.Trim())); + } + if (!string.IsNullOrWhiteSpace(param.Name)) + { + subjectLambda = subjectLambda.And(t => t.Name.Contains(param.Name.Trim())); + } + if (!string.IsNullOrWhiteSpace(param.Sex)) + { + subjectLambda = subjectLambda.And(t => t.Sex==param.Sex.Trim()); + } + if (param.Status != null) + { + subjectLambda = subjectLambda.And(t => t.Status == param.Status); + } + + + if (param.SiteId != null) + { + subjectLambda = subjectLambda.And(t => t.SiteId == param.SiteId); + + studyLambda = studyLambda.And(t => t.SiteId == param.SiteId); + + + } + else + { + //是CRC 需要过滤 + var userId = _userInfo.Id; + var exist = _userRepository.GetAll() + .Any(t => t.Id == userId && t.UserType.Contains(StaticData.CRC)); + + if (exist) + { + var siteIds = _userTrialRepository.GetAll().Where(t => t.SiteId != Guid.Empty && t.UserId == userId && t.TrialId== param.TrialId) + .Select(u => u.SiteId); + + subjectLambda = subjectLambda.And(t => siteIds.Contains(t.SiteId)); + + studyLambda = studyLambda.And(t => siteIds.Contains(t.SiteId)); + } + + } + + var query = from subject in _subjectsRepository.Find(u => u.TrialId == param.TrialId).Where(subjectLambda) + join subjectVisit in _subjectVisitRepository.Find(u => u.TrialId == param.TrialId) + on subject.SubjectVisitId equals subjectVisit.Id into h + from subjectVisit in h.DefaultIfEmpty() + join site in _siteRepository.GetAll() + on subject.SiteId equals site.Id + + join studyStat in _studyRepository.GetAll().Where(studyLambda) + .GroupBy(u => u.SubjectId).Select(g => new { SubjectId = g.Key, StudyCount = g.Count() }) + on subject.Id equals studyStat.SubjectId into cc + from studyStatItem in cc.DefaultIfEmpty() + + join visitStat in _subjectVisitRepository.Find(subjectVisitLambda).GroupBy(u => u.SubjectId).Select(g => new { SubjectId = g.Key, VisitCount = g.Count() }) on subject.Id equals visitStat.SubjectId into dd + from visitStatItem in dd.DefaultIfEmpty() + + join subjectVisitStat2 in _subjectVisitRepository.Find(t => t.TrialId == param.TrialId && t.StudyUploaded ).GroupBy(t => t.SubjectId).Select(g => new { SubjectId = g.Key, VisitCount = g.Count() }) on subject.Id equals subjectVisitStat2.SubjectId into SSV2 + from subjectVisitStatItem2 in SSV2.DefaultIfEmpty() + + select new SubjectQueryModel() + { + Id = subject.Id, + TrialId = subject.TrialId, + Name = subject.Name, + Code = subject.Code, + SubjectVisitId = subject.SubjectVisitId, + Sex = subject.Sex, + Age = subject.Age, + MedicalNo = subject.MedicalNo, + + Modalities = subject.Modalities, + SiteId = subject.SiteId, + SiteName = site.SiteName, + Status = subject.Status, + UpdateTime = subject.UpdateTime, + CreateTime = subject.CreateTime, + Reason = subject.Reason, + + StudyCount = studyStatItem.StudyCount, + PlanVisitCount = visitStatItem.VisitCount, + VisitCount = subjectVisitStatItem2.VisitCount, + + VisitName = subjectVisit.VisitName, + }; + var count = query.Count(); + + var propName = param.SortField == string.Empty ? "Code" : param.SortField; + + query = param.Asc + ? query.OrderBy(propName).ThenBy(t => t.SiteName).ThenBy(t => t.Code) + : query.OrderByDescending(propName).ThenBy(t => t.SiteName).ThenBy(t => t.Code); + + query = query.Skip((param.PageIndex - 1) * param.PageSize).Take(param.PageSize); + var list = query.ToList(); + + return new PageOutput(param.PageIndex, + param.PageSize, count, list); + + } + + public List GetSubjectListBySiteId(Guid siteId, Guid trialId) + { + var query = _subjectsRepository.GetAll().Where(t => t.SiteId == siteId && t.TrialId == trialId).Select(u => new SubjectSelect() + { + Code = u.Code, + Name = u.Name, + Sex = u.Sex, + SubjectId = u.Id, + Age = u.Age + }); + + return query.ToList(); + } + } +} diff --git a/IRaCIS.Core.Application/Trial/Subject/SubjectVisitService.cs b/IRaCIS.Core.Application/Trial/Subject/SubjectVisitService.cs new file mode 100644 index 0000000..c5ff018 --- /dev/null +++ b/IRaCIS.Core.Application/Trial/Subject/SubjectVisitService.cs @@ -0,0 +1,419 @@ +using AutoMapper; +using IRaCIS.Application.ExpressionExtend; +using IRaCIS.Application.ViewModels; +using IRaCIS.Core.Application.Contracts.RequestAndResponse; +using IRaCIS.Core.Application.Contracts.Trial; +using IRaCIS.Core.Domain.Interfaces; +using IRaCIS.Core.Domain.Models; +using IRaCIS.Infra.Data.ExpressionExtend; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Expressions; +using IRaCIS.Core.Domain.Share.AuthUser; +using IRaCIS.Core.Domain.Share; + +namespace IRaCIS.Core.Application.Trial +{ + public class SubjectVisitService : ISubjectVisitService + { + private readonly ISubjectVisitRepository _subjectVisitRepository; + private readonly IDicomStudyRepository _studyRepository; + private readonly IVisitStageRepository _visitStageRepository; + private readonly ISubjectRepository _subjectRepository; + private readonly IUserInfo _userInfo; + private readonly IUserRepository _userRepository; + private readonly IUserTrialRepository _userTrialRepository; + private readonly ISiteRepository _siteRepository; + + private readonly IMapper _mapper; + + public SubjectVisitService(ISubjectVisitRepository visitPointRepository, + IDicomStudyRepository studyRepository, + IVisitStageRepository visitStageRepository, + ISubjectRepository subjectRepository, + IUserInfo userInfo, + IUserRepository userRepository, + IUserTrialRepository userTrialRepository, + + ISiteRepository siteRepository, + IMapper mapper) + { + _subjectVisitRepository = visitPointRepository; + _studyRepository = studyRepository; + _visitStageRepository = visitStageRepository; + _subjectRepository = subjectRepository; + _userInfo = userInfo; + _userRepository = userRepository; + _userTrialRepository = userTrialRepository; + _siteRepository = siteRepository; + _mapper = mapper; + } + public List GetSubjectVisitSelectList(Guid trialId, Guid siteId, Guid subjectId) + { + + + var subjectVisitQuery = from subjectVisit in _subjectVisitRepository.GetAll() + .Where(t => t.TrialId == trialId && t.SubjectId == subjectId) + select new SubjectVisitSelectDTO + { + SubjectVisitId = subjectVisit.Id, + VisitName = subjectVisit.VisitName, + VisitNum = subjectVisit.VisitNum, + SVUPDES = subjectVisit.SVUPDES, + SVSTDTC = subjectVisit.SVSTDTC, + SVENDTC = subjectVisit.SVENDTC, + StudyUploaded = subjectVisit.StudyUploaded + }; + + var subjectVisitList = subjectVisitQuery.OrderBy(t => t.VisitNum).ToList(); + + var subjectVisitIds = subjectVisitList.Select(t => t.SubjectVisitId).ToList(); + + //获取访视下面的study列表 + var studyQuery = _studyRepository.GetAll().Where(t => + t.TrialId == trialId && t.SiteId == siteId && t.SubjectId == subjectId && + subjectVisitIds.Contains(t.SubjectVisitId)) + .Select(u => new SubjectVisitStudyDTO() + { + SubjectVisitId = u.SubjectVisitId, + Modalities = u.Modalities, + StudyCode = u.StudyCode, + StudyId = u.Id, + Status = u.Status + }); + var studyList = studyQuery.ToList(); + + subjectVisitList.ForEach(t => + { + t.StudyList = studyList.Where(u => u.SubjectVisitId == t.SubjectVisitId).ToList(); + }); + + + return subjectVisitList; + + #region 受试者访视一次次加 改为 添加受试者的时候一次性加时 遗弃 不用处理访视计划表 + + + //var visitPlanQuery = _visitStageRepository.Find(u => u.TrialId == trialId).Select(u => + // new SubjectVisitSelectDTO() + // { + // VisitStageId = u.Id, + // VisitName = u.VisitName, + // VisitNum = u.VisitNum, + // SVUPDES = u.Description + // }); + + //var visitPlanList = visitPlanQuery.OrderBy(t => t.VisitNum).ToList(); + + ////如果不存在受试者访视记录 直接返回方式计划 + //if (!subjectVisitList.Any()) + //{ + // return visitPlanList; + //} + //else + //{ + // visitPlanList.ForEach(t => + // { + // // 当前访视计划号 不在受试者访视表中 那么需要返回 + // if (!subjectVisitList.Any(u => Math.Abs(t.VisitNum - u.VisitNum) < 0.01)) + // { + // subjectVisitList.Add(t); + // } + // }); + + // return subjectVisitList.OrderBy(t => t.VisitNum).ToList(); + //} + + #endregion + + + } + + + public IEnumerable GetSubjectVisitList(Guid trialId, Guid subjectId) + { + + //受试者已经访视得列表 + study统计 + var query = + from subjectVisit in _subjectVisitRepository.GetAll() + .Where(t => t.TrialId == trialId && t.SubjectId == subjectId) + //join visitStage in _visitStageRepository.Find(u => u.TrialId == trialId) on + // new { subjectVisit.TrialId, subjectVisit.VisitDay } equals new + // { visitStage.TrialId, visitStage.VisitDay } into dd + //from visitStage in dd.DefaultIfEmpty() + + join subjectVisitStat in _studyRepository.GetAll().Where(t => t.TrialId == trialId && t.SubjectId == subjectId) + .GroupBy(u => u.SubjectVisitId).Select(g => new { SubjectVisitId = g.Key, StudyCount = g.Count() }) + on subjectVisit.Id equals subjectVisitStat.SubjectVisitId into cc + from subjectVisitStat in cc.DefaultIfEmpty() + select new SubjectVisitDTO + { + Id = subjectVisit.Id, + InPlan = subjectVisit.InPlan, + TrialId = subjectVisit.TrialId, + SubjectId = subjectVisit.SubjectId, + VisitNum = subjectVisit.VisitNum, + VisitName = subjectVisit.VisitName, + VisitDay = subjectVisit.VisitDay, + SVUPDES = subjectVisit.SVUPDES, + SVSTDTC = subjectVisit.SVSTDTC, + SVENDTC = subjectVisit.SVENDTC, + + StudyCount = subjectVisitStat.StudyCount + }; + + var list = query.OrderBy(t => t.VisitNum).ToList(); + + #region 受试者访视一次次加 改为 添加受试者的时候一次性加时 遗弃 不用处理访视计划表 + + ////受试者未访视得列表 + //Expression> visitStageLambda = x => x.TrialId == trialId; + + //IQueryable subjectVisitQuery = _subjectVisitRepository.GetAll() + // .Where(t => t.TrialId == trialId && t.SubjectId == subjectId).Select(u => u.VisitNum); + + //visitStageLambda = visitStageLambda.And(t => !subjectVisitQuery.Contains(t.VisitNum)); + //var planVisitList = _visitStageRepository.GetAll().Where(visitStageLambda).Select(t => new SubjectVisitDTO + //{ + + // TrialId = t.TrialId, + // SubjectId = subjectId, + // VisitNum = t.VisitNum, + // VisitName = t.VisitName, + // VisitDay = t.VisitDay + //}).ToList(); + + + //list.AddRange(planVisitList); + + //return list.OrderBy(t => t.VisitNum).ToList(); + #endregion + + return list; + } + + + public IResponseOutput AddOrUpdateSV(SubjectVisitCommand svCommand) + { + + if (svCommand.Id == Guid.Empty || svCommand.Id == null) + { + var sv = _subjectVisitRepository.Add(_mapper.Map(svCommand)); + + var success = _subjectVisitRepository.SaveChanges(); + + var latest = _subjectVisitRepository.GetAll() + .Where(t => t.SubjectId == svCommand.SubjectId && t.TrialId == svCommand.TrialId) + .OrderByDescending(t => t.SVSTDTC).FirstOrDefault(); + + if (latest != null) + { + _subjectRepository.Update(t => t.Id == svCommand.SubjectId, u => new Subject() + { + SubjectVisitId = latest.Id + }); + } + + return ResponseOutput.Result(success, sv.Id.ToString()); + + + } + else + { + var success = _subjectVisitRepository.Update(t => t.Id == svCommand.Id, u => new SubjectVisit() + { + SubjectId = svCommand.SubjectId, + TrialId = svCommand.TrialId, + SiteId = svCommand.SiteId, + VisitDay = svCommand.VisitDay, + VisitNum = svCommand.VisitNum, + VisitName = svCommand.VisitName, + SVENDTC = svCommand.SVENDTC, + SVSTDTC = svCommand.SVSTDTC, + SVUPDES = svCommand.SVUPDES, + InPlan = svCommand.InPlan, + UpdateTime = DateTime.Now + + }); + + var latest = _subjectVisitRepository.GetAll() + .Where(t => t.SubjectId == svCommand.SubjectId && t.TrialId == svCommand.TrialId) + .OrderByDescending(t => t.SVSTDTC).FirstOrDefault(); + + if (latest != null) + { + _subjectRepository.Update(t => t.Id == svCommand.SubjectId, u => new Subject() + { + SubjectVisitId = latest.Id + }); + } + + return ResponseOutput.Result(success); + } + } + + public IResponseOutput DeleteSV(Guid id) + { + + if (_studyRepository.GetAll().Any(t => t.SubjectVisitId == id)) + { + return ResponseOutput.NotOk("There are Study data under the subject’s visit"); + } + + return ResponseOutput.Result( _subjectVisitRepository.Delete(s => s.Id == id)); + } + + public PageOutput GetVisitList(SubjectVisitSearchDTO subjectVisitSearch) + { + Expression> subjectLambda = x => true; + + Expression> subjectVisitLambda = x => x.TrialId == subjectVisitSearch.TrialId; + Expression> studyLambda = x => x.TrialId == subjectVisitSearch.TrialId&&x.Status!= (int)StudyStatus.Abandon; + //Expression> visitPlanLambda = x => x.TrialId == subjectVisitSearch.TrialId; + + + if (subjectVisitSearch.SiteId != null&& subjectVisitSearch.SiteId != Guid.Empty) + { + subjectVisitLambda = subjectVisitLambda.And(t => t.SiteId ==subjectVisitSearch.SiteId.Value); + studyLambda = studyLambda.And(t => t.SiteId == subjectVisitSearch.SiteId.Value); + } + + if (subjectVisitSearch.SubjectId != null && subjectVisitSearch.SubjectId != Guid.Empty) + { + subjectLambda = subjectLambda.And(t => t.Id == subjectVisitSearch.SubjectId.Value); + + studyLambda= studyLambda.And(t => t.SubjectId == subjectVisitSearch.SubjectId.Value); + } + + if (!string.IsNullOrEmpty(subjectVisitSearch.SubjectInfo)) + { + var search = subjectVisitSearch.SubjectInfo.Trim(); + subjectLambda = subjectLambda.And(t => t.Name.Contains(search) ||t.Code.Contains(search)); + } + + if (!string.IsNullOrWhiteSpace(subjectVisitSearch.VisitPlanInfo)) + { + var visitInfo = subjectVisitSearch.VisitPlanInfo.Trim(); + + if (visitInfo.Contains('.')) + + { + + subjectVisitLambda = subjectVisitLambda.And(t => t.VisitNum.ToString().Contains(".")); + + + } + else + { + if (int.TryParse(visitInfo, out var visitNum)) + { + subjectVisitLambda = subjectVisitLambda.And(t => t.VisitNum == visitNum); + } + } + + } + var requestUser = _userRepository.GetAll().First(t => t.Id == _userInfo.Id); + + IQueryable query = default; + + if (requestUser.SuperAdmin || requestUser.UserType == StaticData.CROCoordinator || + requestUser.UserType == StaticData.PM || requestUser.UserType == StaticData.QC) + { + query = from subjectVisit in _subjectVisitRepository.Find(subjectVisitLambda) + join subject in _subjectRepository.Find(subjectLambda) on subjectVisit.SubjectId equals subject.Id + join site in _siteRepository.GetAll() on subjectVisit.SiteId equals site.Id + + join study in _studyRepository.Find(studyLambda).GroupBy(t=>t.SubjectVisitId).Select(g=>new { SubjectVisitId= g.Key,StudyCount=g.Count()} ) on subjectVisit.Id equals study.SubjectVisitId into d + from study in d.DefaultIfEmpty() + + + select new SubjectVisitNewDTO() + { + Id= subjectVisit.Id, + //VisitPlanId = visitStage.Id, + SubjectId = subjectVisit.SubjectId, + TrialId = subjectVisit.TrialId, + SiteId = subjectVisit.SiteId, + + VisitDay = subjectVisit.VisitDay, + VisitNum = subjectVisit.VisitNum, + VisitName = subjectVisit.VisitName, + SVENDTC = subjectVisit.SVENDTC, + SVSTDTC = subjectVisit.SVSTDTC, + SVUPDES = subjectVisit.SVUPDES, + InPlan = subjectVisit.InPlan, + StudyUploaded = subjectVisit.StudyUploaded, + UpdateTime = subjectVisit.UpdateTime, + + SubjectCode = subject.Code, + SubjectName = subject.Name, + + StudyCount = study.StudyCount, + + + SiteCode = site.SiteCode, + SiteName = site.SiteName + + }; + } + else//CRC 或者其他的 + { + //CRC 只能看到他负责得site下的用户、访视 + var siteQuery = _userTrialRepository.Find(t => t.SiteId != Guid.Empty && t.UserId == requestUser.Id) + .Select(t => t.SiteId).Distinct(); + + + subjectVisitLambda = subjectVisitLambda.And(t => siteQuery.Contains(t.SiteId)); + + query = from subjectVisit in _subjectVisitRepository.Find(subjectVisitLambda) + join subject in _subjectRepository.Find(subjectLambda) on subjectVisit.SubjectId equals subject.Id + join site in _siteRepository.GetAll() on subjectVisit.SiteId equals site.Id + join study in _studyRepository.Find(studyLambda).GroupBy(t => t.SubjectVisitId).Select(g => new { SubjectVisitId = g.Key, StudyCount = g.Count() }) on subjectVisit.Id equals study.SubjectVisitId into d + from study in d.DefaultIfEmpty() + select new SubjectVisitNewDTO() + { + Id = subjectVisit.Id, + SubjectId = subjectVisit.SubjectId, + TrialId = subjectVisit.TrialId, + SiteId = subjectVisit.SiteId, + + VisitDay = subjectVisit.VisitDay, + VisitNum = subjectVisit.VisitNum, + VisitName = subjectVisit.VisitName, + SVENDTC = subjectVisit.SVENDTC, + SVSTDTC = subjectVisit.SVSTDTC, + SVUPDES = subjectVisit.SVUPDES, + InPlan = subjectVisit.InPlan, + StudyUploaded = subjectVisit.StudyUploaded, + UpdateTime = subjectVisit.UpdateTime, + + SubjectCode = subject.Code, + SubjectName = subject.Name, + + StudyCount = study.StudyCount, + + SiteCode = site.SiteCode, + SiteName = site.SiteName, + + }; + } + + + + var count = query.Count(); + + var propName = subjectVisitSearch.SortField == string.Empty ? "UpdateTime" : subjectVisitSearch.SortField; + + query = subjectVisitSearch.Asc + ? query.OrderBy(t=>t.SubjectId) + : query.OrderByDescending(propName); + + query = query.Skip((subjectVisitSearch.PageIndex - 1) * subjectVisitSearch.PageSize).Take(subjectVisitSearch.PageSize); + var list = query.ToList(); + + return new PageOutput(subjectVisitSearch.PageIndex, + subjectVisitSearch.PageSize, count, list); + } + } +} diff --git a/IRaCIS.Core.Application/Trial/TrialAttachmentService.cs b/IRaCIS.Core.Application/Trial/TrialAttachmentService.cs new file mode 100644 index 0000000..d428bea --- /dev/null +++ b/IRaCIS.Core.Application/Trial/TrialAttachmentService.cs @@ -0,0 +1,144 @@ +using AutoMapper; +using IRaCIS.Application.Interfaces; +using IRaCIS.Application.ViewModels; +using IRaCIS.Core.Application.Contracts.RequestAndResponse; +using IRaCIS.Core.Domain.Interfaces; +using IRaCIS.Core.Domain.Models; +using IRaCIS.Infra.Data.ExpressionExtend; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Expressions; + + +namespace IRaCIS.Application.Services +{ + public class TrialAttachmentService : ITrialAttachmentService + { + private readonly IAcquisitionSpecificationRepository _specificationRepository; + private readonly IUserRepository _userRepository; + private readonly ITrialRepository _trialRepository; + private readonly IDictionaryRepository _dictionaryRepository; + private readonly IMapper _mapper; + + public TrialAttachmentService(IAcquisitionSpecificationRepository specificationRepository, + IUserRepository userRepository, ITrialRepository trialRepository, IDictionaryRepository dictionaryRepository,IMapper mapper) + { + _specificationRepository = specificationRepository; + _userRepository = userRepository; + _trialRepository = trialRepository; + _dictionaryRepository = dictionaryRepository; + _mapper = mapper; + } + public IResponseOutput AddOrUpdateSpecification(TrialAttachmentCommand model, Guid userId) + { + var temp = _mapper.Map(model); + if (model.Id == Guid.Empty|| model.Id ==null) //insert + { + var returnItem = _specificationRepository.Add(temp); + var isSuccess = _specificationRepository.SaveChanges(); + + return ResponseOutput.Result(isSuccess, temp.Id.ToString()); + + } + else + { + var specification= _specificationRepository.GetAll().FirstOrDefault(t => t.Id == model.Id); + + _mapper.Map(model, specification); + + _specificationRepository.Update(specification); + + var isSuccess = _specificationRepository.SaveChanges(); + + return ResponseOutput.Result(isSuccess); + + } + } + + public IResponseOutput DeleteSpecification(Guid id) + { + var result = _specificationRepository.Delete(u => u.Id == id); + + return ResponseOutput.Result(result); + + } + + public IEnumerable GetSpecificationList(Guid trialId, string type) + { + Expression < Func > trialAttachmentLambda = x => x.TrialId==trialId; + + if (!string.IsNullOrEmpty(type)) + { + var attachmentType = type.Trim(); + trialAttachmentLambda = trialAttachmentLambda.And(x => x.Type == attachmentType); + } + + var query = from specification in _specificationRepository.Find(trialAttachmentLambda) + join user in _userRepository.GetAll() on specification.UpdateUserId equals user.Id into h + from userItem in h.DefaultIfEmpty() + join trial in _trialRepository.Find(u => u.Id == trialId) on specification.TrialId equals trial.Id into g + from trialItem in g.DefaultIfEmpty() + + select new AcquisitionSpecificationDTO() + { + Id = specification.Id, + TrialId = trialItem.Id, + TrialCode = trialItem.Code, + Indication = trialItem.Indication, + OptUserName = userItem.RealName, + Type = specification.Type, + + DocumentName = specification.DocumentName, + DocumentPath = specification.DocumentPath, + CreateTime = specification.CreateTime + }; + + return query.ToList(); + } + + //public PageOutput GetSpecificationList(ImageAcquisitionSpecificationQueryDTO param) + //{ + + // var query = from specification in _specificationRepository.Find(u => u.TrialId == param.TrialId) + // join user in _userRepository.GetAll() on specification.UpdateUserId equals user.Id into h + // from userItem in h.DefaultIfEmpty() + // join trial in _trialRepository.Find(u => u.Id == param.TrialId) on specification.TrialId equals trial.Id into g + // from trialItem in g.DefaultIfEmpty() + // join dic in _dictionaryRepository.GetAll() on specification.DeviceTypeId equals dic.Id into e + // from dicItem in e.DefaultIfEmpty() + // select new AcquisitionSpecificationDTO() + // { + // Id = specification.Id, + // TrialId = trialItem.Id, + // TrialCode = trialItem.Code, + // Indication = trialItem.Indication, + // OptUserName = userItem.RealName, + // AcquisitionPeriod = specification.AcquisitionPeriod, + // DeviceParam = specification.DeviceParam, + // Type = specification.DeviceTypeId, + // DeviceTypeName = dicItem.Value, + // LayerThickness = specification.LayerThickness, + // SeriesCount = specification.SeriesCount, + // SeriesDescription = specification.SeriesDescription, + // DocumentCode = specification.DocumentCode, + // DocumentName = specification.DocumentName, + // DocumentPath = specification.DocumentPath, + // CreateTime = specification.CreateTime + // }; + // var count = query.Count(); + // var propName = param.SortField == string.Empty ? "CreateTime" : param.SortField; + + // query = param.Asc + // ? query.OrderBy(propName) + // : query.OrderByDescending(propName); + + // query = query.Skip((param.PageIndex - 1) * param.PageSize).Take(param.PageSize); + // var list = query.ToList(); + + // return new PageOutput(param.PageIndex, + // param.PageSize, count, list); + + //} + } +} diff --git a/IRaCIS.Core.Application/Trial/TrialRevenuesPriceVerificationService.cs b/IRaCIS.Core.Application/Trial/TrialRevenuesPriceVerificationService.cs new file mode 100644 index 0000000..7a27491 --- /dev/null +++ b/IRaCIS.Core.Application/Trial/TrialRevenuesPriceVerificationService.cs @@ -0,0 +1,194 @@ +using IRaCIS.Application.Interfaces; +using IRaCIS.Core.Application.Contracts.Trial.DTO; +using IRaCIS.Core.Domain.Interfaces; +using IRaCIS.Core.Domain.Models; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Expressions; + +namespace IRaCIS.Core.Application.Trial +{ + public class TrialRevenuesPriceVerificationService : ITrialRevenuesPriceVerificationService + { + private readonly ITrialRevenuesPriceVerificationRepository _trialRevenuesPriceVerificationRepository; + private readonly ITrialRepository _trialRepository; + private readonly IDoctorRepository _doctorRepository; + private readonly IPaymentRepository _paymentRepository; + + public TrialRevenuesPriceVerificationService(ITrialRevenuesPriceVerificationRepository trialRevenuesPriceVerificationRepository, + ITrialRepository trialRepository,IDoctorRepository doctorRepository,IPaymentRepository paymentRepository) + { + _trialRevenuesPriceVerificationRepository = trialRevenuesPriceVerificationRepository; + _trialRepository = trialRepository; + _doctorRepository = doctorRepository; + _paymentRepository = paymentRepository; + } + + public AnalysisVerifyResultDTO GetAnalysisVerifyList(RevenusVerifyQueryDTO param) + { + AnalysisVerifyResultDTO result=new AnalysisVerifyResultDTO(); + result.RevenuesVerifyList = GetTrialRevenuesVerifyResultList(param); + + + var bDate = new DateTime(param.BeginDate.Year, param.BeginDate.Month, 1); + var eDate = new DateTime(param.EndDate.Year, param.EndDate.Month, 1); + eDate = eDate.AddMonths(1).AddSeconds(-1); + + Expression> paymentLambda = x => x.YearMonthDate >= bDate && x.YearMonthDate <= eDate&&!x.IsLock; + + var query = from payment in _paymentRepository.GetAll().Where(paymentLambda) + join doctor in _doctorRepository.GetAll() on payment.DoctorId equals doctor.Id + select new AnalysisNeedLockDTO() + { + YearMonth = payment.YearMonth, + ReviewerCode = doctor.Code, + ReviewerName = doctor.LastName + " / " + doctor.FirstName, + ReviewerNameCN = doctor.ChineseName + }; + + result.MonthVerifyResult = query.ToList().GroupBy(t => t.YearMonth).Select(g => new MonthlyResult + { + YearMonth = g.Key, + ReviewerNameList = g.Select(t => t.ReviewerName).ToList(), + ReviewerNameCNList = g.Select(t => t.ReviewerNameCN).ToList(), + ReviewerCodeList = g.Select(t => t.ReviewerCode).ToList() + + }).OrderBy(t=>t.YearMonth).ToList(); + + return result; + } + + + + public List GetTrialRevenuesVerifyResultList(RevenusVerifyQueryDTO param) + { + var bDate = new DateTime(param.BeginDate.Year, param.BeginDate.Month, 1); + var eDate = new DateTime(param.EndDate.Year, param.EndDate.Month, 1); + Expression> trialRevenuesPriceVerificationLambda = x => x.WorkLoadDate >= bDate && x.WorkLoadDate <= eDate; + + var query = (from trialVerify in _trialRevenuesPriceVerificationRepository.GetAll().Where(trialRevenuesPriceVerificationLambda) + join trail in _trialRepository.GetAll() on trialVerify.TrialId equals trail.Id + select new RevenusVerifyDTO + { + TrialCode = trail.Code, + Timepoint = trialVerify.Timepoint, + TimepointIn24H = trialVerify.TimepointIn24H, + TimepointIn48H = trialVerify.TimepointIn48H, + Adjudication = trialVerify.Adjudication, + AdjudicationIn24H = trialVerify.AdjudicationIn24H, + AdjudicationIn48H = trialVerify.AdjudicationIn48H, + Global = trialVerify.Global, + Downtime = trialVerify.Downtime, + Training = trialVerify.Training + }).Distinct(); + + + return query.ToList(); + } + + + + //废弃 + public List GetRevenuesVerifyResultList(RevenusVerifyQueryDTO param) + { + var bDate = new DateTime(param.BeginDate.Year, param.BeginDate.Month, 1); + var eDate = new DateTime(param.EndDate.Year, param.EndDate.Month, 1); + Expression> trialRevenuesPriceVerificationLambda = x => x.WorkLoadDate >= bDate && x.WorkLoadDate <= eDate; + + var query = (from trialVerify in _trialRevenuesPriceVerificationRepository.GetAll().Where(trialRevenuesPriceVerificationLambda) + join trail in _trialRepository.GetAll() on trialVerify.TrialId equals trail.Id + select new RevenusVerifyDTO + { + TrialCode = trail.Code, + Timepoint = trialVerify.Timepoint, + TimepointIn24H = trialVerify.TimepointIn24H, + TimepointIn48H = trialVerify.TimepointIn48H, + Adjudication = trialVerify.Adjudication, + AdjudicationIn24H = trialVerify.AdjudicationIn24H, + AdjudicationIn48H = trialVerify.AdjudicationIn48H, + Global = trialVerify.Global, + Downtime = trialVerify.Downtime, + Training = trialVerify.Training + }).Distinct(); + + + return query.ToList(); + #region 提示 old + //query = from trialVerify in _trialRevenuesPriceVerificationRepository.GetAll() + // join trail in _trialRepository.GetAll() on trialVerify.TrialId equals trail.Id + // join reviewer in _doctorRepository.GetAll() on trialVerify.ReviewerId equals reviewer.Id + // select new RevenusVerifyDTO() + // { + // ReviewerCode = reviewer.Code, + // TrialCode = trail.Code, + // YearMonth = trialVerify.YearMonth + // }; + + + + + + + + + + + ////0是Detail 1是按照项目 2是按照人 3按照月份 + //if (param.StatType == 0) + //{ + // query = from trialVerify in _trialRevenuesPriceVerificationRepository.GetAll() + // join trail in _trialRepository.GetAll() on trialVerify.TrialId equals trail.Id + // join reviewer in _doctorRepository.GetAll() on trialVerify.ReviewerId equals reviewer.Id + // select new RevenusVerifyDTO() + // { + // ReviewerCode = reviewer.Code, + // TrialCode = trail.Code, + // YearMonth = trialVerify.YearMonth + // }; + + //} + //else if (param.StatType == 1) + //{ + // query = (from trialVerify in _trialRevenuesPriceVerificationRepository.GetAll() + // join trail in _trialRepository.GetAll() on trialVerify.TrialId equals trail.Id + // select new RevenusVerifyDTO() + // { + // ReviewerCode = "", + // TrialCode = trail.Code, + // YearMonth = "" + // }).Distinct(); + //} + //else if (param.StatType == 2) + //{ + // query = (from trialVerify in _trialRevenuesPriceVerificationRepository.GetAll() + // join trail in _trialRepository.GetAll() on trialVerify.TrialId equals trail.Id + // join reviewer in _doctorRepository.GetAll() on trialVerify.ReviewerId equals reviewer.Id + // select new RevenusVerifyDTO() + // { + // ReviewerCode = reviewer.Code, + // TrialCode = trail.Code, + // YearMonth = "" + // }).Distinct(); + //} + //else + //{ + // query = from trialVerify in _trialRevenuesPriceVerificationRepository.GetAll() + // join trail in _trialRepository.GetAll() on trialVerify.TrialId equals trail.Id + // join reviewer in _doctorRepository.GetAll() on trialVerify.ReviewerId equals reviewer.Id + // select new RevenusVerifyDTO() + // { + // ReviewerCode = reviewer.Code, + // TrialCode = trail.Code, + // YearMonth = trialVerify.YearMonth + // }; + //} + + + #endregion + + + + } + } +} \ No newline at end of file diff --git a/IRaCIS.Core.Application/Trial/TrialService.cs b/IRaCIS.Core.Application/Trial/TrialService.cs new file mode 100644 index 0000000..b844d3b --- /dev/null +++ b/IRaCIS.Core.Application/Trial/TrialService.cs @@ -0,0 +1,1104 @@ +using AutoMapper; +using AutoMapper.QueryableExtensions; +using IRaCIS.Application.ExpressionExtend; +using IRaCIS.Application.Interfaces; +using IRaCIS.Application.ViewModels; +using IRaCIS.Core.Application.Contracts.RequestAndResponse; +using IRaCIS.Core.Domain.Interfaces; +using IRaCIS.Core.Domain.Models; +using IRaCIS.Core.Domain.Share; +using IRaCIS.Core.Domain.Share.AuthUser; +using IRaCIS.Infra.Data.ExpressionExtend; +using Microsoft.EntityFrameworkCore; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Expressions; + +namespace IRaCIS.Application.Services +{ + public class TrialService : ITrialService + { + private readonly ITrialRepository _trialRepository; + private readonly IDictionaryRepository _dictionaryRepository; + + private readonly IUserRepository _userRepository; + private readonly IEnrollRepository _enrollRepository; + private readonly IEnrollDetailRepository _enrollDetailRepository; + private readonly IWorkloadRepository _workloadRepository; + private readonly ITrialDictionaryRepository _trialDictionaryRepository; + + private readonly IUserTrialRepository _userTrialRepository; + private readonly ICRORepository _croRepository; + private readonly ISponsorRepository _sponsorRepository; + private readonly ITrialPaymentPriceRepository _trialPaymentPriceRepository; + private readonly IMapper _mapper; + private readonly IUserInfo _userInfo; + private readonly ISubjectRepository _subjectRepository; + private readonly IDicomStudyRepository _studyRepository; + private readonly ISubjectVisitRepository _subjectVisitRepository; + + public bool TrialExpeditedChange { get; set; } = false; + + + public TrialService(ITrialRepository clinicalTrialProjectRepository, IDictionaryRepository sysDicRepository, + IUserRepository sysUserRepository, + IEnrollRepository intoGroupRepository, + IEnrollDetailRepository intoGroupDetailRepository, + ITrialDictionaryRepository projectDictionaryRepository, + IUserTrialRepository userTrialRepository, + ICRORepository croCompanyRepository, + ISponsorRepository sponsorRepository, + ITrialPaymentPriceRepository trialExtRepository, + IWorkloadRepository workloadRepository, + IUserInfo userInfo, + ISubjectRepository subjectRepository, + IDicomStudyRepository studyRepository, + ISubjectVisitRepository subjectVisitRepository, + IMapper mapper) + { + _trialRepository = clinicalTrialProjectRepository; + _dictionaryRepository = sysDicRepository; + _userRepository = sysUserRepository; + _enrollRepository = intoGroupRepository; + _enrollDetailRepository = intoGroupDetailRepository; + + _workloadRepository = workloadRepository; + _trialDictionaryRepository = projectDictionaryRepository; + + _userTrialRepository = userTrialRepository; + _croRepository = croCompanyRepository; + _sponsorRepository = sponsorRepository; + + _trialPaymentPriceRepository = trialExtRepository; + _userInfo = userInfo; + _subjectRepository = subjectRepository; + _studyRepository = studyRepository; + _subjectVisitRepository = subjectVisitRepository; + _mapper = mapper; + } + + /// + /// 分页获取临床项目列表 默认后台加急状态为3 查所有的 + /// + /// + /// + /// + public PageOutput GetTrialList(TrialQueryDTO searchParam, + Guid userId) + { + + var trialLambda = GetTrialSearchLambda(searchParam); + + var multiSelectCount = searchParam.ModalityIds.Count; + //有多选信息 + if (multiSelectCount > 0) + { + + var trialIdFilterQuery = _trialDictionaryRepository.GetAll() + .Where(t => searchParam.ModalityIds.Contains(t.DictionaryId)).GroupBy(t => t.TrialId).Select(g => + new + { + TrialId = g.Key, + Count = g.Count() + }).Where(t => t.Count == multiSelectCount).Select(t => t.TrialId); + + trialLambda = trialLambda.And(t => trialIdFilterQuery.Contains(t.Id)); + } + + IQueryable trialQueryable = default; + + var user = _userRepository.GetAll().First(t => t.Id == userId); + //超级管理员,查看所有 + if (user.SuperAdmin) + { + trialQueryable = from trial in _trialRepository.GetAll().Where(trialLambda) + join cro in _croRepository.GetAll() on trial.CROId equals cro.Id into t + from croItem in t.DefaultIfEmpty() + join sponsor in _sponsorRepository.GetAll() on trial.SponsorId equals sponsor.Id into d + from sponsorItem in d.DefaultIfEmpty() + + //加入site 统计 注意 site因为跟对接人是一对多的关系 所以得去重 + join siteStat in _userTrialRepository.Find(t => t.SiteId != Guid.Empty).Select(u=>new{ TrialId = u.TrialId,SiteId =u.SiteId} ).Distinct() + .GroupBy(t=>t.TrialId).Select(g=>new {TrialId=g.Key,SiteCount=g.Count()}) + on trial.Id equals siteStat.TrialId into ST + from siteStatItem in ST.DefaultIfEmpty() + + //加入subject统计 + join subjectStat in _subjectRepository.GetAll().GroupBy(t => t.TrialId).Select(g => new { TrialId = g.Key, SubjectCount = g.Count() }) on trial.Id equals subjectStat.TrialId into SS + from subjectStatItem in SS.DefaultIfEmpty() + + //加入 Visit统计 + join subjectVisit in _subjectVisitRepository.GetAll().GroupBy(t => t.TrialId).Select(g => new { TrialId = g.Key, VisitCount = g.Count() }) on trial.Id equals subjectVisit.TrialId into SSV + from subjectVisitItem in SSV.DefaultIfEmpty() + + //加入 study统计 + join studyStat in _studyRepository.GetAll().Where(t=>t.Status!=(int)StudyStatus.Abandon).GroupBy(t => t.TrialId).Select(g => new { TrialId = g.Key, StudyCount = g.Count() }) on trial.Id equals studyStat.TrialId into SSTU + from studyStatItem in SSTU.DefaultIfEmpty() + + //join subjectVisit in _subjectVisitRepository + + select new TrialDetailDTO() + { + Sponsor = sponsorItem.SponsorName, + CRO = croItem.CROName, + + Id = trial.Id, + Code = trial.Code, + SponsorId = trial.SponsorId, + CROId = trial.CROId, + Indication = trial.Indication, + Note = trial.Note, + ExpectedPatients = trial.ExpectedPatients, + TimePointsPerPatient = trial.TimePointsPerPatient, + CriterionId = trial.CriterionId, + ReviewModeId = trial.ReviewModeId, + TurnaroundTime = trial.TurnaroundTime, + Expedited = trial.Expedited, + ReviewProtocol = trial.ReviewProtocol, + MessageFromClient = trial.MessageFromClient, + ReviewProtocolName = trial.ReviewProtocolName, + MessageFromClientName = trial.MessageFromClientName, + GRRReviewers = trial.GRRReviewers, + TotalReviewers = trial.TotalReviewers, + TrialStatus = trial.TrialStatus, + TrialStatusStr = trial.TrialStatusStr, + CreateTime = trial.CreateTime, + VisitPlanConfirmed=trial.VisitPlanConfirmed, + ModalityIds = trial.TrialDicList.Where(u => u.KeyName == StaticData.Modality) + .Select(z => z.DictionaryId).ToList(), + Phase = trial.Phase, + ReviewTypeId = trial.ReviewTypeId, + + SiteCount = siteStatItem.SiteCount, + //VisitCount= subjectVisitItem.VisitCount, + SubjectCount = subjectStatItem.SubjectCount, + StudyCount = studyStatItem.StudyCount + }; + } + else// 不是超级管理员, + { + // 协调者,查看自己所在机构下的 + // 其他人员,只能查看自己参与的 + + if (user.UserType == StaticData.CROCoordinator)//协调者查看自己机构的 + { + searchParam.CROId = user.OrganizationId; + var trialLambdaT = GetTrialSearchLambda(searchParam); + trialQueryable = from trial in _trialRepository.GetAll().Where(trialLambdaT) + join cro in _croRepository.GetAll() on trial.CROId equals cro.Id into t + from croItem in t.DefaultIfEmpty() + join sponsor in _sponsorRepository.GetAll() on trial.SponsorId equals sponsor.Id into d + from sponsorItem in d.DefaultIfEmpty() + //加入site 统计 注意 site因为跟对接人是一对多的关系 所以得去重 + join siteStat in _userTrialRepository.Find(t => t.SiteId != Guid.Empty).Select(u => new { TrialId = u.TrialId, SiteId = u.SiteId }).Distinct() + .GroupBy(t => t.TrialId).Select(g => new { TrialId = g.Key, SiteCount = g.Count() }) + on trial.Id equals siteStat.TrialId into ST + from siteStatItem in ST.DefaultIfEmpty() + + //加入subject统计 + join subjectStat in _subjectRepository.GetAll().GroupBy(t => t.TrialId).Select(g => new { TrialId = g.Key, SubjectCount = g.Count() }) on trial.Id equals subjectStat.TrialId into SS + from subjectStatItem in SS.DefaultIfEmpty() + + ////加入 Visit统计 + //join subjectVisit in _subjectVisitRepository.GetAll().GroupBy(t => t.TrialId).Select(g => new { TrialId = g.Key, VisitCount = g.Count() }) on trial.Id equals subjectVisit.TrialId into SSV + //from subjectVisitItem in SSV.DefaultIfEmpty() + + //加入 study统计 + join studyStat in _studyRepository.GetAll().Where(t => t.Status != (int)StudyStatus.Abandon).GroupBy(t => t.TrialId).Select(g => new { TrialId = g.Key, StudyCount = g.Count() }) on trial.Id equals studyStat.TrialId into SSTU + from studyStatItem in SSTU.DefaultIfEmpty() + select new TrialDetailDTO() + { + Sponsor = sponsorItem.SponsorName, + CRO = croItem.CROName, + Id = trial.Id, + Code = trial.Code, + SponsorId = trial.SponsorId, + CROId = trial.CROId, + Indication = trial.Indication, + Note = trial.Note, + ExpectedPatients = trial.ExpectedPatients, + TimePointsPerPatient = trial.TimePointsPerPatient, + CriterionId = trial.CriterionId, + ReviewModeId = trial.ReviewModeId, + TurnaroundTime = trial.TurnaroundTime, + Expedited = trial.Expedited, + ReviewProtocol = trial.ReviewProtocol, + MessageFromClient = trial.MessageFromClient, + ReviewProtocolName = trial.ReviewProtocolName, + MessageFromClientName = trial.MessageFromClientName, + GRRReviewers = trial.GRRReviewers, + TotalReviewers = trial.TotalReviewers, + TrialStatus = trial.TrialStatus, + TrialStatusStr = trial.TrialStatusStr, + CreateTime = trial.CreateTime, + VisitPlanConfirmed = trial.VisitPlanConfirmed, + ModalityIds = trial.TrialDicList.Where(u => u.KeyName == StaticData.Modality) + .Select(z => z.DictionaryId).ToList(), + Phase = trial.Phase, + ReviewTypeId = trial.ReviewTypeId, + + + SiteCount = siteStatItem.SiteCount, + //VisitCount = subjectVisitItem.VisitCount, + SubjectCount = subjectStatItem.SubjectCount, + StudyCount = studyStatItem.StudyCount + }; + } + //不是协调者,只能自己参与的项目 + //if (user.IsZhiZhun || user.UserType == StaticData.PM) + else if(user.UserType == StaticData.CRC) + { + + //CRC 只能看到他负责得site下的用户、访视、study 这种情况得到的siteId 不准确 因为 这个SiteId 有可能是因为他是其他项目对接人产生的 + //var siteQuery = _userTrialRepository.Find(t => t.SiteId != Guid.Empty && t.UserId == userId) + // .Select(t => t.SiteId).Distinct(); + + //CRC 只能看到他负责得site下的用户、访视、study 这种情况得到的siteId 不准确 因为 这个SiteId 有可能是因为他是其他项目对接人产生的 因而要加入trialId过滤 + + // 参与了这个项目 并且是对接人 才算拥有这个site + + //var siteQuery = _userTrialRepository.Find(t => t.SiteId != Guid.Empty && t.UserId == userId).Join(_userTrialRepository.Find(t => t.SiteId == Guid.Empty && t.UserId == userId), p =>new { p.TrialId ,p.SiteId} , q => new { q.TrialId, q.SiteId }, (p, q) => p.SiteId).Distinct();// + var siteQuery = _userTrialRepository.Find(t => t.SiteId != Guid.Empty && t.UserId == userId) + .Select(t => new { t.SiteId, t.TrialId }).Distinct(); + + + //通过site过滤受试者 + //var subjectQuery = _subjectRepository.Find(t => siteQuery.Contains(t.SiteId)).Select(u=>u.Id); + + + trialQueryable = from trial in _trialRepository.GetAll().Where(trialLambda) + join cro in _croRepository.GetAll() on trial.CROId equals cro.Id into t + from croItem in t.DefaultIfEmpty() + join sponsor in _sponsorRepository.GetAll() on trial.SponsorId equals sponsor.Id + into d + from sponsorItem in d.DefaultIfEmpty() + join userTrial in _userTrialRepository.GetAll().Where(t => t.UserId == userId && t.SiteId == Guid.Empty) on trial.Id equals userTrial.TrialId + + //加入site 统计 注意 site因为跟对接人是一对多的关系 所以得去重 + join siteStat in _userTrialRepository.Find(t => t.SiteId != Guid.Empty&& t.UserId == userId).Select(u => new { TrialId = u.TrialId, SiteId = u.SiteId }).Distinct() + .GroupBy(t => t.TrialId).Select(g => new { TrialId = g.Key, SiteCount = g.Count() }) + on trial.Id equals siteStat.TrialId into ST + from siteStatItem in ST.DefaultIfEmpty() + + //加入subject统计 过滤site下的subject + join subjectStat in _subjectRepository.GetAll().Join(siteQuery, p => new { p.TrialId, p.SiteId }, q => new { q.TrialId, q.SiteId }, (p, q)=>p).GroupBy(t => t.TrialId).Select(g => new { TrialId = g.Key, SubjectCount = g.Count() }) on trial.Id equals subjectStat.TrialId into SS + from subjectStatItem in SS.DefaultIfEmpty() + + + ////加入 Visit统计 通过site下的受试者过滤visit + //join subjectVisit in _subjectVisitRepository.Find(t=> subjectQuery.Contains(t.SubjectId)).GroupBy(t => t.TrialId).Select(g => new { TrialId = g.Key, VisitCount = g.Count() }) on trial.Id equals subjectVisit.TrialId into SSV + //from subjectVisitItem in SSV.DefaultIfEmpty() + + // //受试者访视加入siteId字段 修改 + + //join subjectVisit in _subjectVisitRepository.GetAll().Join(siteQuery, p => new { p.TrialId, p.SiteId }, q => new { q.TrialId, q.SiteId }, (p, q) => p).GroupBy(t => t.TrialId).Select(g => new { TrialId = g.Key, VisitCount = g.Count() }) on trial.Id equals subjectVisit.TrialId into SSV + //from subjectVisitItem in SSV.DefaultIfEmpty() + + + //加入 study统计 过滤site下的study + join studyStat in _studyRepository.GetAll().Join(siteQuery, p => new { p.TrialId, p.SiteId }, q => new { q.TrialId, q.SiteId }, (p, q) => p).Where(t => t.Status != (int)StudyStatus.Abandon).GroupBy(t => t.TrialId).Select(g => new { TrialId = g.Key, StudyCount = g.Count() }) on trial.Id equals studyStat.TrialId into SSTU + from studyStatItem in SSTU.DefaultIfEmpty() + + select new TrialDetailDTO() + { + Sponsor = sponsorItem.SponsorName, + CRO = croItem.CROName, + + Id = trial.Id, + Code = trial.Code, + SponsorId = trial.SponsorId, + CROId = trial.CROId, + Indication = trial.Indication, + Note = trial.Note, + ExpectedPatients = trial.ExpectedPatients, + TimePointsPerPatient = trial.TimePointsPerPatient, + CriterionId = trial.CriterionId, + ReviewModeId = trial.ReviewModeId, + TurnaroundTime = trial.TurnaroundTime, + + ReviewProtocol = trial.ReviewProtocol, + MessageFromClient = trial.MessageFromClient, + ReviewProtocolName = trial.ReviewProtocolName, + MessageFromClientName = trial.MessageFromClientName, + GRRReviewers = trial.GRRReviewers, + TotalReviewers = trial.TotalReviewers, + TrialStatus = trial.TrialStatus, + TrialStatusStr = trial.TrialStatusStr, + CreateTime = trial.CreateTime, + VisitPlanConfirmed = trial.VisitPlanConfirmed, + ModalityIds = trial.TrialDicList.Where(u => u.KeyName == StaticData.Modality) + .Select(z => z.DictionaryId).ToList(), + Phase = trial.Phase, + ReviewTypeId = trial.ReviewTypeId, + + + SiteCount = siteStatItem.SiteCount, + //VisitCount = subjectVisitItem.VisitCount, + SubjectCount = subjectStatItem.SubjectCount, + StudyCount = studyStatItem.StudyCount + }; + } + else //QC 和PM 参与项目的 完整统计 + { + + trialQueryable = from trial in _trialRepository.GetAll().Where(trialLambda) + join cro in _croRepository.GetAll() on trial.CROId equals cro.Id into t + from croItem in t.DefaultIfEmpty() + join sponsor in _sponsorRepository.GetAll() on trial.SponsorId equals sponsor.Id + into d + from sponsorItem in d.DefaultIfEmpty() + join userTrial in _userTrialRepository.GetAll().Where(t => t.UserId == userId && t.SiteId == Guid.Empty) on trial.Id equals userTrial.TrialId + + //加入site 统计 注意 site因为跟对接人是一对多的关系 所以得去重 + join siteStat in _userTrialRepository.Find(t => t.SiteId != Guid.Empty).Select(u => new { TrialId = u.TrialId, SiteId = u.SiteId }).Distinct() + .GroupBy(t => t.TrialId).Select(g => new { TrialId = g.Key, SiteCount = g.Count() }) + on trial.Id equals siteStat.TrialId into ST + from siteStatItem in ST.DefaultIfEmpty() + + //加入subject统计 + join subjectStat in _subjectRepository.GetAll().GroupBy(t => t.TrialId).Select(g => new { TrialId = g.Key, SubjectCount = g.Count() }) on trial.Id equals subjectStat.TrialId into SS + from subjectStatItem in SS.DefaultIfEmpty() + + ////加入 Visit统计 + //join subjectVisit in _subjectVisitRepository.GetAll().GroupBy(t => t.TrialId).Select(g => new { TrialId = g.Key, VisitCount = g.Count() }) on trial.Id equals subjectVisit.TrialId into SSV + //from subjectVisitItem in SSV.DefaultIfEmpty() + + //加入 study统计 + join studyStat in _studyRepository.GetAll().Where(t => t.Status != (int)StudyStatus.Abandon).GroupBy(t => t.TrialId).Select(g => new { TrialId = g.Key, StudyCount = g.Count() }) on trial.Id equals studyStat.TrialId into SSTU + from studyStatItem in SSTU.DefaultIfEmpty() + + select new TrialDetailDTO() + { + Sponsor = sponsorItem.SponsorName, + CRO = croItem.CROName, + + Id = trial.Id, + Code = trial.Code, + SponsorId = trial.SponsorId, + CROId = trial.CROId, + Indication = trial.Indication, + Note = trial.Note, + ExpectedPatients = trial.ExpectedPatients, + TimePointsPerPatient = trial.TimePointsPerPatient, + CriterionId = trial.CriterionId, + ReviewModeId = trial.ReviewModeId, + TurnaroundTime = trial.TurnaroundTime, + + ReviewProtocol = trial.ReviewProtocol, + MessageFromClient = trial.MessageFromClient, + ReviewProtocolName = trial.ReviewProtocolName, + MessageFromClientName = trial.MessageFromClientName, + GRRReviewers = trial.GRRReviewers, + TotalReviewers = trial.TotalReviewers, + TrialStatus = trial.TrialStatus, + TrialStatusStr = trial.TrialStatusStr, + CreateTime = trial.CreateTime, + VisitPlanConfirmed = trial.VisitPlanConfirmed, + ModalityIds = trial.TrialDicList.Where(u => u.KeyName == StaticData.Modality) + .Select(z => z.DictionaryId).ToList(), + Phase = trial.Phase, + ReviewTypeId = trial.ReviewTypeId, + + + SiteCount = siteStatItem.SiteCount, + //VisitCount = subjectVisitItem.VisitCount, + SubjectCount = subjectStatItem.SubjectCount, + StudyCount = studyStatItem.StudyCount + }; + + } + + } + + var propName = string.IsNullOrWhiteSpace(searchParam.SortField) ? "CreateTime" : searchParam.SortField; + //处理升序和降序 + trialQueryable = searchParam.Asc + ? trialQueryable.OrderBy(propName).ThenBy(t => t.Code) + : trialQueryable.OrderByDescending(propName).ThenBy(t => t.Code); + + + var count = trialQueryable.Count(); + trialQueryable = trialQueryable + .Skip((searchParam.PageIndex - 1) * searchParam.PageSize) + .Take(searchParam.PageSize); + var tempTrialList = trialQueryable.ToList(); + + + if (tempTrialList.Count != 0) + { + var dic = GetDic(); + //处理项目Code 是否锁定 不能编辑 + //var trialIds = tempTrialList.Select(t => t.Id).ToList(); + + //var lockQuery = _workloadRepository.GetAll().Where(t => t.DataFrom == (int)WorkLoadFromStatus.FinalConfirm ).Select(t=>t.TrialId) + //var lockTrialIds = lockQuery.Distinct().ToList(); + + tempTrialList.ForEach(trialViewItem => + { + + //trialViewItem.LockTrialCode = lockTrialIds.Contains(trialViewItem.Id); + ConnectTrialInfo(trialViewItem, dic); + }); + + + return new PageOutput(searchParam.PageIndex, + searchParam.PageSize, count, tempTrialList); + + + } + + return new PageOutput(searchParam.PageIndex, searchParam.PageSize, 0, + new List()); + + } + + + #region 项目基本信息 查询、添加、删除和更新 + + /// + /// 获取项目基本信息 + /// + /// + /// + public TrialDetailDTO GetTrialInfoAndLockState(Guid projectId) + { + var trialQueryable = from trial in _trialRepository.Find(o => o.Id == projectId) + .Include(t => t.TrialDicList) + join cro in _croRepository.GetAll() on trial.CROId equals cro.Id into d + from croItem in d.DefaultIfEmpty() + join sponsor in _sponsorRepository.GetAll() on trial.SponsorId equals sponsor.Id into e + from sponsorItem in e.DefaultIfEmpty() + join trialExt in _trialPaymentPriceRepository.GetAll() on trial.Id equals trialExt.TrialId into f + from trialExt in f.DefaultIfEmpty() + select new TrialDetailDTO() + { + Id = trial.Id, + Code = trial.Code, + Indication = trial.Indication, + TrialStatus = trial.TrialStatus, + TrialStatusStr = trial.TrialStatusStr, + Phase = trial.Phase, + + CRO = croItem.CROName, + CROId = trial.CROId, + SponsorId = trial.SponsorId, + Sponsor = sponsorItem.SponsorName, + ReviewTypeId = trial.ReviewTypeId, + CriterionId = trial.CriterionId, + Note = trial.Note, + + TurnaroundTime = trial.TurnaroundTime, + ReviewModeId = trial.ReviewModeId, + Expedited = trial.Expedited, + ExpectedPatients = trial.ExpectedPatients, + TimePointsPerPatient = trial.TimePointsPerPatient, + + GRRReviewers = trial.GRRReviewers, + TotalReviewers = trial.TotalReviewers, + ReviewProtocol = trial.ReviewProtocol, + ReviewProtocolName = trial.ReviewProtocolName, + MessageFromClient = trial.MessageFromClient, + MessageFromClientName = trial.MessageFromClientName, + CreateTime = trial.CreateTime, + VisitPlanConfirmed = trial.VisitPlanConfirmed, + ModalityIds = trial.TrialDicList.Where(u => u.KeyName == StaticData.Modality) + .Select(z => z.DictionaryId).ToList(), + SowName = trialExt.SowName, + SowPath = trialExt.SowPath, + + AttendedReviewerType = trial.AttendedReviewerType, + }; + + var trialInfo = trialQueryable.FirstOrDefault(); + + if (trialInfo != null) + { + var dic = GetDic(); + + trialInfo.IsLocked = _workloadRepository.GetAll().Any(u => u.TrialId == trialInfo.Id && + u.DataFrom == + (int)WorkLoadFromStatus.FinalConfirm); + return ConnectTrialInfo(trialInfo, dic); + } + + return null; + } + + + + public int GetTrialMaxState(Guid trialId) + { + return _enrollDetailRepository.GetAll().Where(t => t.TrialId == trialId).Max(u => (int?)u.EnrollStatus) ?? 0; + } + + public int GetTrialExpeditedState(Guid trialId) + { + return _trialRepository.GetAll().First(u => u.Id == trialId).Expedited; + } + + + /// + /// 添加项目 + /// + /// + /// + /// + public IResponseOutput AddOrUpdateTrial(TrialCommand trialAddModel, Guid userId) + { + + if (trialAddModel.Id == Guid.Empty) + { + var existItem = _trialRepository.FindSingleOrDefault(u => u.Code == trialAddModel.Code); + if (existItem != null) + { + return ResponseOutput.NotOk("Same Trial ID already exists."); + + } + var trial = _mapper.Map(trialAddModel); + + trialAddModel.ModalityIds.ForEach(modalityId => trial.TrialDicList.Add( + new TrialDictionary() + { + DictionaryId = modalityId, + KeyName = StaticData.Modality, + TrialId = trialAddModel.Id + + })); + + //添加项目后 项目状态变更为申请下载简历 + trial.TrialStatus = (int)TrialEnrollStatus.ChooseDoctor; + trial.TrialStatusStr = "RFP"; + + //状态变更详细表 + trial.ClinicalTrialProjectDetails.Add(new TrialStatusDetail() + { + TrialId = trial.Id, + TrialStatus = (int)TrialEnrollStatus.ChooseDoctor + + }); + + trial = _trialRepository.Add(trial); + //如果是PM, 则需要将该人员添加到 运维人员表 + + + var user = _userRepository.GetAll().FirstOrDefault(t => t.Id == userId); + if (user != null) + { + _userTrialRepository.Add(new UserTrial() + { + //SiteIds = siteIds, + //UserType = "PM", + //OrganizationType = dicitem.Value, + //OrganizationTypeId = dicitem.Id + TrialId = trial.Id, + UserId = userId, + OrganizationId = user.OrganizationId, + OrganizationName = user.OrganizationName, + UserTypeId = user.UserTypeId, + OrganizationType = user.OrganizationType, + OrganizationTypeId = user.OrganizationTypeId, + UserType = user.UserType, + UserRealName = user.RealName + + }); + + } + + // 添加扩展信息表记录 + _trialPaymentPriceRepository.Add(new TrialPaymentPrice() {TrialId = trial.Id}); + + var success = _trialRepository.SaveChanges(); + + return ResponseOutput.Result(success, trial.Id.ToString()); + + + } + else + { + var updateModel = trialAddModel; + // 判断项目Id 是否已经存在 + + var existItem = _trialRepository.FindSingleOrDefault(u => u.Code == updateModel.Code && u.Id != updateModel.Id); + if (existItem != null) + { + return ResponseOutput.NotOk("Same Trial ID already exists."); + + } + var trial = _trialRepository.Find(t => t.Id == updateModel.Id).FirstOrDefault(); + + if (trial != null) + { + //删除中间表 Title对应的记录 + _trialDictionaryRepository.Delete(t => t.TrialId == updateModel.Id && t.KeyName == StaticData.Modality); + + //重新插入新的 Title记录 + updateModel.ModalityIds.ForEach(modalityId => _trialDictionaryRepository.Add(new TrialDictionary() + { + TrialId = updateModel.Id, + KeyName = StaticData.Modality, + DictionaryId = modalityId + })); + + if (updateModel.Expedited != trial.Expedited && updateModel.Expedited != null) + { + TrialExpeditedChange = true; + TrialExpeditedStatusChange(trial.Id, trial.Expedited, (int)updateModel.Expedited); + } + + _mapper.Map(updateModel, trial); + _trialRepository.Update(trial); + var success = _trialRepository.SaveChanges(); + + return ResponseOutput.Result(success); + + } + else + { + return ResponseOutput.NotOk(" Update failed. Database can not find this trial record ID"); + } + } + } + + private void TrialExpeditedStatusChange(Guid trialId, int oldState, int newState) + { + switch (oldState) + { + case (int)TrialExpedited.None: + switch (newState) + { + case (int)TrialExpedited.ExpeditedIn24H: + _workloadRepository.Update(t => t.IsLock == false && t.TrialId == trialId, u => new Workload() + { + TimepointIn24H = u.Timepoint, + AdjudicationIn24H = u.Adjudication, + Timepoint = 0, + Adjudication = 0 + }); + break; + case (int)TrialExpedited.ExpeditedIn48H: + _workloadRepository.Update(t => t.IsLock == false && t.TrialId == trialId, u => new Workload() + { + TimepointIn48H = u.Timepoint, + AdjudicationIn48H = u.Adjudication, + Timepoint = 0, + Adjudication = 0 + }); + break; + } + //_workloadRepository.Update(t => t.IsLock == false && t.TrialId == trialId, u => new Workload() + //{ + // Timepoint = 0, + // Adjudication = 0 + //}); + + break; + case (int)TrialExpedited.ExpeditedIn24H: + + switch (newState) + { + case (int)TrialExpedited.None: + _workloadRepository.Update(t => t.IsLock == false && t.TrialId == trialId, u => new Workload() + { + Timepoint = u.TimepointIn24H, + Adjudication = u.AdjudicationIn24H, + TimepointIn24H = 0, + AdjudicationIn24H = 0 + }); + break; + case (int)TrialExpedited.ExpeditedIn48H: + _workloadRepository.Update(t => t.IsLock == false && t.TrialId == trialId, u => new Workload() + { + TimepointIn48H = u.TimepointIn24H, + AdjudicationIn48H = u.AdjudicationIn24H, + TimepointIn24H = 0, + AdjudicationIn24H = 0 + }); + + break; + } + + //_workloadRepository.Update(t => t.IsLock == false && t.TrialId == trialId, u => new Workload() + //{ + // TimepointIn24H = 0, + // AdjudicationIn24H = 0 + //}); + + break; + case (int)TrialExpedited.ExpeditedIn48H: + switch (newState) + { + case (int)TrialExpedited.None: + _workloadRepository.Update(t => t.IsLock == false && t.TrialId == trialId, u => new Workload() + { + Timepoint = u.TimepointIn48H, + Adjudication = u.AdjudicationIn48H, + TimepointIn48H = 0, + AdjudicationIn48H = 0 + }); + break; + case (int)TrialExpedited.ExpeditedIn24H: + _workloadRepository.Update(t => t.IsLock == false && t.TrialId == trialId, u => new Workload() + { + TimepointIn24H = u.TimepointIn48H, + AdjudicationIn24H = u.AdjudicationIn48H, + TimepointIn48H = 0, + AdjudicationIn48H = 0 + }); + break; + } + + //_workloadRepository.Update(t => t.IsLock == false && t.TrialId == trialId, u => new Workload() + //{ + // TimepointIn48H = 0, + // AdjudicationIn48H = 0 + //}); + break; + } + } + + /// + /// 手动更新项目状态 + /// + /// 项目Id + /// 状态值 + /// + public IResponseOutput UpdateTrialStatus(Guid trialId, string statusStr) + { + if (statusStr.ToUpper().Contains("FINISH")) + { + _enrollRepository.Update(u => u.TrialId == trialId, e => new Enroll + { + EnrollStatus = (int)EnrollStatus.End + }); + } + return ResponseOutput.Result(_trialRepository.Update(u => u.Id == trialId, s => new Trial { TrialStatusStr = statusStr })); + + } + /// + /// 删除项目 + /// + /// + /// + public IResponseOutput DeleteTrial(Guid trialId) + { + return ResponseOutput.Result(_trialRepository.Delete(o => o.Id == trialId)); + } + + #endregion //end 项目基本增删改查 + + + #region 获取字典表、 连接字典表、表达式树查询条件 + + /// + /// 获取字典表 + /// + /// + private List GetDic() + { + return //字典表 后面做缓存 + _dictionaryRepository.GetAll().ProjectTo(_mapper.ConfigurationProvider).OrderBy(t => t.KeyName) + .ThenBy(t => t.ShowOrder).ToList(); + } + + /// + /// 连接字典表处理--私有方法 + /// + private TrialDetailDTO ConnectTrialInfo(TrialDetailDTO transformModel, List dic) + { + foreach (var item in dic) + { + if (transformModel.ModalityIds.Contains(item.Id)) + { + transformModel.ModalityList.AddRange(dic.Where(u => u.Id == item.Id).Select(h => h.Value)); + } + } + + transformModel.Criterion = dic.FirstOrDefault(o => o.Id == transformModel.CriterionId)?.Value ?? string.Empty; + transformModel.ReviewMode = dic.FirstOrDefault(o => o.Id == transformModel.ReviewModeId)?.Value ?? string.Empty; + transformModel.ReviewType = dic.FirstOrDefault(o => o.Id == transformModel.ReviewTypeId)?.Value ?? string.Empty; + + + return transformModel; + } + + + /// + /// 项目查询 [多选] + /// + private Expression> GetTrialSearchLambda(TrialQueryDTO trialSearchModel) + { + Expression> trialLambda = x => true; + + if (!string.IsNullOrEmpty(trialSearchModel.TrialStatus)) + { + var trialStatus = trialSearchModel.TrialStatus.Trim(); + trialLambda = trialLambda.And(o => o.TrialStatusStr.Contains(trialStatus)); + } + + if (trialSearchModel.CriterionId != Guid.Empty && trialSearchModel.CriterionId != null) + { + trialLambda = trialLambda.And(o => o.CriterionId == trialSearchModel.CriterionId); + } + + if (trialSearchModel.SponsorId != Guid.Empty && trialSearchModel.SponsorId != null) + { + trialLambda = trialLambda.And(o => o.SponsorId == trialSearchModel.SponsorId); + } + if (trialSearchModel.Expedited != (int)TrialExpedited.All && trialSearchModel.Expedited != null) + { + trialLambda = trialLambda.And(o => o.Expedited == trialSearchModel.Expedited); + } + + if (!string.IsNullOrEmpty(trialSearchModel.Code)) + { + var code = trialSearchModel.Code.Trim(); + trialLambda = trialLambda.And(o => o.Code.Contains(code)); + } + + if (!string.IsNullOrWhiteSpace(trialSearchModel.Indication)) + { + var indication = trialSearchModel.Indication.Trim(); + trialLambda = trialLambda.And(o => o.Indication.Contains(indication)); + } + if (!string.IsNullOrWhiteSpace(trialSearchModel.Phase)) + { + trialLambda = trialLambda.And(o => o.Phase == trialSearchModel.Phase); + } + if (trialSearchModel.CROId != Guid.Empty && trialSearchModel.CROId != null) + { + trialLambda = trialLambda.And(o => o.CROId == trialSearchModel.CROId); + } + if (trialSearchModel.ReviewTypeId != Guid.Empty && trialSearchModel.ReviewTypeId != null) + { + trialLambda = trialLambda.And(o => o.ReviewTypeId == trialSearchModel.ReviewTypeId); + } + + if (trialSearchModel.BeginDate != null) + { + var beginDate = new DateTime(trialSearchModel.BeginDate.Value.Year, trialSearchModel.BeginDate.Value.Month, trialSearchModel.BeginDate.Value.Day); + + trialLambda = trialLambda.And(o => o.CreateTime >= beginDate); + } + + if (trialSearchModel.EndDate != null) + { + var endDate = new DateTime(trialSearchModel.EndDate.Value.Year, trialSearchModel.EndDate.Value.Month, trialSearchModel.EndDate.Value.Day); + trialLambda = trialLambda.And(o => o.CreateTime <= endDate); + } + if (trialSearchModel.AttendedReviewerType != null) + { + trialLambda = trialLambda.And(o => o.AttendedReviewerType == trialSearchModel.AttendedReviewerType); + } + return trialLambda; + + } + + #endregion + + + public PageOutput GetReviewerTrialListByEnrollmentStatus(TrialByStatusQueryDTO param) + { + Expression> enrollExpression = u => u.DoctorId == param.DoctorId; + switch (param.Status) + { + case 5: + enrollExpression = enrollExpression.And(u => u.EnrollStatus == (int)EnrollStatus.HasCommittedToCRO); + break; + case 8: + enrollExpression = enrollExpression.And(u => u.EnrollStatus == (int)EnrollStatus.InviteIntoGroup); + break; + case 10: + enrollExpression = enrollExpression.And(u => u.EnrollStatus == (int)EnrollStatus.DoctorReading); + break; + default: + break; + } + + var trialQueryable = from enrollItem in _enrollRepository.Find(enrollExpression) + join trial in _trialRepository.GetAll() + on enrollItem.TrialId equals trial.Id into d + from trialItem in d.DefaultIfEmpty() + join cro in _croRepository.GetAll() on trialItem.CROId equals cro.Id into tt + from cro in tt.DefaultIfEmpty() + join sponsor in _sponsorRepository.GetAll() on trialItem.SponsorId equals sponsor.Id into uu + from sponsor in uu.DefaultIfEmpty() + + select new TrialDetailDTO() + { + Sponsor = sponsor.SponsorName, + CRO = cro.CROName, + + Id = trialItem.Id, + Code = trialItem.Code, + SponsorId = trialItem.SponsorId, + CROId = trialItem.CROId, + Indication = trialItem.Indication, + Note = trialItem.Note, + ExpectedPatients = trialItem.ExpectedPatients, + TimePointsPerPatient = trialItem.TimePointsPerPatient, + CriterionId = trialItem.CriterionId, + ReviewTypeId = trialItem.ReviewTypeId, + //ReviewMode = trial.Re, + ReviewModeId = trialItem.ReviewModeId, + TurnaroundTime = trialItem.TurnaroundTime, + Expedited = trialItem.Expedited, + ReviewProtocol = trialItem.ReviewProtocol, + GRRReviewers = trialItem.GRRReviewers, + TotalReviewers = trialItem.TotalReviewers, + TrialStatus = trialItem.TrialStatus, + CreateTime = trialItem.CreateTime, + Phase = trialItem.Phase, + ModalityIds = trialItem.TrialDicList.Where(u => u.KeyName == StaticData.Modality) + .Select(z => z.DictionaryId).ToList() + + }; + var count = trialQueryable.Count(); + var propName = param.SortField == "" ? "CreateTime" : param.SortField; + trialQueryable = param.Asc + ? trialQueryable.OrderBy(propName) + : trialQueryable.OrderByDescending(propName); + trialQueryable = trialQueryable + .Skip((param.PageIndex - 1) * param.PageSize) + .Take(param.PageSize); + var trialList = trialQueryable.ToList(); + + if (trialList.Count != 0) + { + var dic = GetDic(); + + trialList.ForEach(trialViewItem => ConnectTrialInfo(trialViewItem, dic)); + + return new PageOutput(param.PageIndex, + param.PageSize, count, trialList); + + } + + return new PageOutput(param.PageIndex, param.PageSize, 0, + new List()); + + } + + + /// + /// 根据项目Id 获取医生Id,用于出发计算费用 + /// + public List GetTrialEnrollmentReviewerIds(Guid trialId) + { + return _enrollRepository.Find(u => u.TrialId == trialId && + u.EnrollStatus >= (int)EnrollStatus.DoctorReading).Select(u => u.DoctorId).Distinct().ToList(); + } + + + #region 医生用户接口 + public PageOutput GetTrialListByReviewer(ReviewerTrialQueryDTO trialSearchModel, Guid reviewerId) + { + Expression> trialLambda = x => true; + if (!string.IsNullOrEmpty(trialSearchModel.Code)) + { + var code = trialSearchModel.Code.Trim(); + trialLambda = trialLambda.And(o => o.Code.Contains(code)); + } + if (!string.IsNullOrWhiteSpace(trialSearchModel.Indication)) + { + var indication = trialSearchModel.Indication.Trim(); + trialLambda = trialLambda.And(o => o.Indication.Contains(indication)); + } + if (trialSearchModel.Expedited != (int)TrialExpedited.All && trialSearchModel.Expedited != null) + { + trialLambda = trialLambda.And(o => o.Expedited == trialSearchModel.Expedited); + } + + Expression> enrollLambda = x => true; + enrollLambda = enrollLambda.And(o => o.DoctorId == reviewerId); + if (trialSearchModel.EnrollStatus != null) + { + if ((int)trialSearchModel.EnrollStatus == 10) + { + enrollLambda = enrollLambda.And(o => o.EnrollStatus >= 10 && o.EnrollStatus <= 13); + } + else enrollLambda = enrollLambda.And(o => o.EnrollStatus == trialSearchModel.EnrollStatus); + } + + IQueryable trialQueryable = default; + + trialQueryable = from trial in _trialRepository.GetAll().Where(trialLambda) + join cro in _croRepository.GetAll() on trial.CROId equals cro.Id into t + from croItem in t.DefaultIfEmpty() + join sponsor in _sponsorRepository.GetAll() on trial.SponsorId equals sponsor.Id + into d + from sponsorItem in d.DefaultIfEmpty() + join enroll in _enrollRepository.GetAll().Where(enrollLambda) on trial.Id equals enroll.TrialId + select new TrialDetailDTO() + { + Sponsor = sponsorItem.SponsorName, + CRO = croItem.CROName, + Id = trial.Id, + Code = trial.Code, + SponsorId = trial.SponsorId, + CROId = trial.CROId, + Indication = trial.Indication, + Note = trial.Note, + ExpectedPatients = trial.ExpectedPatients, + TimePointsPerPatient = trial.TimePointsPerPatient, + CriterionId = trial.CriterionId, + ReviewModeId = trial.ReviewModeId, + TurnaroundTime = trial.TurnaroundTime, + Expedited = trial.Expedited, + CreateTime = trial.CreateTime, + ModalityIds = trial.TrialDicList.Where(u => u.KeyName == StaticData.Modality) + .Select(z => z.DictionaryId).ToList(), + Phase = trial.Phase, + EnrollStatus = enroll.EnrollStatus + }; + + var propName = string.IsNullOrWhiteSpace(trialSearchModel.SortField) ? "CreateTime" : trialSearchModel.SortField; + //处理升序和降序 + trialQueryable = trialSearchModel.Asc + ? trialQueryable.OrderBy(propName).ThenBy(t => t.Code) + : trialQueryable.OrderByDescending(propName).ThenBy(t => t.Code); + var count = trialQueryable.Count(); + trialQueryable = trialQueryable + .Skip((trialSearchModel.PageIndex - 1) * trialSearchModel.PageSize) + .Take(trialSearchModel.PageSize); + var tempTrialList = trialQueryable.ToList(); + + if (tempTrialList.Count != 0) + { + var dic = GetDic(); + tempTrialList.ForEach(trialViewItem => + { + ConnectTrialInfo(trialViewItem, dic); + }); + return new PageOutput(trialSearchModel.PageIndex, + trialSearchModel.PageSize, count, tempTrialList); + } + return new PageOutput(trialSearchModel.PageIndex, trialSearchModel.PageSize, 0, + new List()); + + } + + public IResponseOutput UpdateEnrollStatus(Guid trialId, int status) + { + _enrollDetailRepository.Add(new EnrollDetail() + { + DoctorId = _userInfo.Id, + TrialId = trialId, + EnrollStatus = status, + OptUserType = (int)UserType.DoctorUser, + }); + return ResponseOutput.Result(_enrollRepository.Update(u => u.TrialId == trialId && u.DoctorId == _userInfo.Id, e => new Enroll + { + EnrollStatus = status + })); + } + + public IResponseOutput ConfirmTrialVisitPlan(Guid trialId) + { + return ResponseOutput.Result(_trialRepository.Update(u => u.Id == trialId, + t => new Trial() {VisitPlanConfirmed = true})); + } + #endregion + } + +} \ No newline at end of file diff --git a/IRaCIS.Core.Application/Trial/UserTrialService.cs b/IRaCIS.Core.Application/Trial/UserTrialService.cs new file mode 100644 index 0000000..7e3e32f --- /dev/null +++ b/IRaCIS.Core.Application/Trial/UserTrialService.cs @@ -0,0 +1,546 @@ +using AutoMapper; +using AutoMapper.QueryableExtensions; +using IRaCIS.Application.ExpressionExtend; +using IRaCIS.Application.Interfaces; +using IRaCIS.Application.ViewModels; +using IRaCIS.Core.Application.Contracts.RequestAndResponse; +using IRaCIS.Core.Domain.Interfaces; +using IRaCIS.Core.Domain.Models; +using IRaCIS.Infra.Data.ExpressionExtend; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Expressions; +using IRaCIS.Core.Domain.Share; +using IRaCIS.Core.Domain.Share.AuthUser; +using Microsoft.EntityFrameworkCore; + +namespace IRaCIS.Application.Servicess +{ + public class UserTrialService : IUserTrialService + { + private readonly IUserTrialRepository _userTrialRepository; + private readonly IDictionaryRepository _dictionaryRepository; + private readonly IUserRepository _userRepository; + private readonly ISiteRepository _siteRepository; + private readonly IMapper _mapper; + private readonly IUserInfo _userInfo; + private readonly ISubjectRepository _subjectRepository; + private readonly IDicomStudyRepository _studyRepository; + private readonly ISubjectVisitRepository _subjectVisitRepository; + + public UserTrialService(IUserTrialRepository userTrialRepository, + IDictionaryRepository dictionaryRepository, + IUserRepository userRepository, + ISiteRepository researchCenterRepository, IMapper mapper, IUserInfo userInfo,ISubjectRepository subjectRepository,IDicomStudyRepository studyRepository,ISubjectVisitRepository subjectVisitRepository) + { + _userTrialRepository = userTrialRepository; + _dictionaryRepository = dictionaryRepository; + _userRepository = userRepository; + _siteRepository = researchCenterRepository; + _mapper = mapper; + _userInfo = userInfo; + _subjectRepository = subjectRepository; + _studyRepository = studyRepository; + _subjectVisitRepository = subjectVisitRepository; + } + + public IEnumerable GetTrialSiteSelect(Guid trialId) + { + var userId = _userInfo.Id; + var exist = _userRepository.GetAll() + .Any(t => t.Id == userId && t.UserType.Contains(StaticData.CRC)); + IQueryable query = default; + + if (exist) + { + query = from userTrial in _userTrialRepository.GetAll() + .Where(t => t.TrialId == trialId && t.SiteId != Guid.Empty && t.UserId == userId) + join site in _siteRepository.GetAll() on userTrial.SiteId equals site.Id + select new TrialSiteSelect() + { + Id = site.Id, + SiteName = site.SiteName + }; + + } + else + { + query = (from userTrial in _userTrialRepository.GetAll() + .Where(t => t.TrialId == trialId && t.SiteId != Guid.Empty) + join site in _siteRepository.GetAll() on userTrial.SiteId equals site.Id + select new TrialSiteSelect() + { + Id = site.Id, + SiteName = site.SiteName + }).Distinct(); + + } + + + + + return query.OrderBy(t => t.SiteName).ToList(); + } + + public IEnumerable GetMaintenanceUserList(TrialMaintenanceQuery param) + { + Expression> userTrialLambda = x => x.SiteId == Guid.Empty; + + + if (param.UserTypeId != Guid.Empty && param.UserTypeId != null) + { + userTrialLambda = userTrialLambda.And(t => t.UserTypeId == param.UserTypeId); + } + + Expression> userLambda = x => true; + if (!string.IsNullOrWhiteSpace(param.UserName)) + { + userLambda = userLambda.And(t => t.UserName.Contains(param.UserName.Trim())); + } + + var query = from userTrial in _userTrialRepository.Find(t => t.TrialId == param.TrialId).Where(userTrialLambda) + join user in _userRepository.GetAll().Where(userLambda) on userTrial.UserId equals user.Id + + select new UserTrialDTO() + { + Id = userTrial.Id, + UserId = userTrial.UserId, + UserRealName = user.RealName, + UserName = user.UserName, + + TrialId = userTrial.TrialId, + + UserTypeId = userTrial.UserTypeId, + + OrganizationTypeId = userTrial.OrganizationTypeId, + OrganizationType = userTrial.OrganizationType, + + OrganizationId = userTrial.OrganizationId, + OrganizationName = userTrial.OrganizationName, + UpdateTime = userTrial.UpdateTime, + UserType = userTrial.UserType + }; + + return query.OrderBy(t => t.UpdateTime).ToList(); + } + + public PageOutput GetUserTrialList(UserTrialListQueryDTO param) + { + + Expression> userTrialLambda = x => x.SiteId == Guid.Empty; + + if (param.UserTypeId != Guid.Empty && param.UserTypeId != null) + { + userTrialLambda = userTrialLambda.And(t => t.UserTypeId == param.UserTypeId); + } + + Expression> userLambda = x => true; + if (!string.IsNullOrWhiteSpace(param.UserName)) + { + userLambda = userLambda.And(t => t.UserName.Contains(param.UserName.Trim())); + } + + var query = from userTrial in _userTrialRepository.Find(t => t.TrialId == param.TrialId).Where(userTrialLambda) + join user in _userRepository.GetAll().Where(userLambda) on userTrial.UserId equals user.Id + + select new UserTrialDTO() + { + Id = userTrial.Id, + UserId = userTrial.UserId, + UserRealName = user.RealName, + + TrialId = userTrial.TrialId, + + UserTypeId = userTrial.UserTypeId, + + OrganizationId = userTrial.OrganizationId, + OrganizationName = userTrial.OrganizationName, + UpdateTime = userTrial.UpdateTime, + UserType = userTrial.UserType + + //OrganizationTypeId = userTrial.OrganizationTypeId, + //OrganizationType = userTrial.OrganizationType, + }; + var count = query.Count(); + var propName = string.IsNullOrWhiteSpace(param.SortField) ? "UserRealName" : param.SortField; + + query = param.Asc + ? query.OrderBy(propName) + : query.OrderByDescending(propName); + query = query.Skip((param.PageIndex - 1) * param.PageSize).Take(param.PageSize); + var list = query.ToList(); + + return new PageOutput(param.PageIndex, + param.PageSize, count, list); + + } + + public IEnumerable GetUserSelectionList(Guid userTypeId, Guid institutionId) + { + var query = _userRepository.Find(u => u.UserTypeId == userTypeId && u.OrganizationId == institutionId).ProjectTo(_mapper.ConfigurationProvider); + + return query.ToList(); + + } + + + /// 添加或更新运维人员 + public IResponseOutput AddOrUpdateUserTrial(UserTrialCommand param) + { + + if (param.Id == Guid.Empty || param.Id == null)//新增 + { + + if (_userTrialRepository.GetAll().Any(u => u.UserId == param.UserId + && u.TrialId == param.TrialId && u.SiteId == Guid.Empty)) + { + + return ResponseOutput.NotOk("Trial participants already exist"); + } + + if (param.UserType == "PM" && param.OrganizationName == "ZhiZhun") + { + //&& t.OrganizationType == param.OrganizationType) + if (_userTrialRepository.GetAll().Any(t => t.TrialId == param.TrialId && t.UserType == "PM" && t.OrganizationName == "ZhiZhun" && t.SiteId == Guid.Empty)) + { + + return ResponseOutput.NotOk("Trial can only have one ZhiZhun PM"); + } + } + + + var temp = _mapper.Map(param); + temp.SiteId = Guid.Empty; + + + var result = _userTrialRepository.Add(temp); + bool isSuccess = _userTrialRepository.SaveChanges(); + + return ResponseOutput.Result(isSuccess); + + } + else //更新 + { + //此处过滤一定要加上 u.SiteId==Guid.Empty 一个用户可能负责多个site 不加过滤 会存在提示出问题 + if (_userTrialRepository.GetAll().Any(u => u.UserId == param.UserId + && u.TrialId == param.TrialId && u.Id != param.Id && u.SiteId == Guid.Empty)) + { + return ResponseOutput.NotOk("Trial participants already exist"); + } + + if (param.UserType == "PM" && param.OrganizationName == "ZhiZhun") + { + //&& t.OrganizationType == param.OrganizationType + if (_userTrialRepository.GetAll().Any(t => t.Id != param.Id && t.UserType == "PM" && t.TrialId == param.TrialId && t.OrganizationName == "ZhiZhun" && t.SiteId == Guid.Empty)) + { + return ResponseOutput.NotOk("Trial can only have one ZhiZhun PM"); + } + + } + + var isSuccess = _userTrialRepository.Update(u => u.Id == param.Id, t => new UserTrial + { + TrialId = param.TrialId, + UserId = param.UserId, + UserTypeId = param.UserTypeId, + UserType = param.UserType, + SiteId = Guid.Empty, + OrganizationTypeId = param.OrganizationTypeId, + OrganizationType = param.OrganizationType, + OrganizationId = param.OrganizationId, + OrganizationName = param.OrganizationName, + UserRealName = param.UserRealName, + UpdateTime = DateTime.Now + }); + + + return ResponseOutput.Result(isSuccess); + } + } + + /// 删除运维人员 + public IResponseOutput DeleteUserTrial(Guid id) + { + + var user= _userTrialRepository.GetAll().FirstOrDefault(t => t.Id == id); + + if (_userTrialRepository.GetAll().Any(t => t.UserId == user.UserId&&t.SiteId!=Guid.Empty&&t.TrialId==user.TrialId)) + { + return ResponseOutput.NotOk("Participant has participated in site maintenance"); + } + + var isSuccess = _userTrialRepository.Delete(u => u.Id == id); + return ResponseOutput.Result(isSuccess); + } + + public PageOutput GetSiteCRCList(SiteCrcQueryDTO param) + { + + + Expression> userLambda = x => true; + if (!string.IsNullOrWhiteSpace(param.UserRealName)) + { + userLambda = userLambda.And(t => t.RealName.Contains(param.UserRealName.Trim())); + } + + Expression> siteLambda = x => true; + if (!string.IsNullOrWhiteSpace(param.SiteName)) + { + siteLambda = siteLambda.And(t => t.SiteName.Contains(param.SiteName.Trim())); + } + + #region before + + //var query = from userTrial in _userTrialRepository.Find(t => t.TrialId == param.TrialId && t.SiteId != Guid.Empty)/*.Where(userTrialLambda)*/ + // join user in _userRepository.GetAll().Where(userLambda) on userTrial.UserId equals user.Id + // join site in _siteRepository.GetAll().Where(siteLambda) on userTrial.SiteId equals site.Id + // select new SiteCrcDTO() + // { + // Id = userTrial.Id, + // UserId = userTrial.UserId, + // UserRealName = user.RealName, + // UserName = user.UserName, + + // TrialId = userTrial.TrialId, + // Phone = user.Phone, + // UserTypeId = userTrial.UserTypeId, + // UserType = userTrial.UserType, + // OrganizationTypeId = userTrial.OrganizationTypeId, + // OrganizationType = userTrial.OrganizationType, + // OrganizationId = userTrial.OrganizationId, + // OrganizationName = userTrial.OrganizationName, + // UpdateTime = userTrial.UpdateTime, + // SiteId = site.Id, + // Site = site.SiteName, + // City = site.City, + // Country = site.Country + // }; + + #endregion + + IQueryable siteStatQuery = default; + + var requestUser = _userRepository.GetAll().First(t => t.Id == _userInfo.Id); + + if (requestUser.SuperAdmin|| requestUser.UserType == StaticData.CROCoordinator|| requestUser.UserType == StaticData.PM|| requestUser.UserType == StaticData.QC) + { + siteStatQuery = from site in _siteRepository.GetAll().Where(siteLambda) + + join userTrialStat in _userTrialRepository + .Find(t => t.TrialId == param.TrialId && t.SiteId != Guid.Empty).GroupBy(u => u.SiteId) + .Select(g => new { SiteId = g.Key, UserCount = g.Count() }) on site.Id equals userTrialStat.SiteId + + join subjectStat in _subjectRepository.Find(t => t.TrialId == param.TrialId).GroupBy(u => u.SiteId) + .Select(g => new { SiteId = g.Key, SubjectCount = g.Count() }) on site.Id equals subjectStat + .SiteId + into ST + from subjectStatItem in ST.DefaultIfEmpty() + + ////加入 Visit统计 通过site下的受试者过滤visit 加入siteId 后修改 不用通过site下的用户过滤 + //join subjectVisitStat in _subjectVisitRepository.Find(t=>t.TrialId==param.TrialId).GroupBy(t => t.SiteId).Select(g => new { SiteId = g.Key, VisitCount = g.Count() }) on site.Id equals subjectVisitStat.SiteId into SSV + //from subjectVisitStatItem in SSV.DefaultIfEmpty() + + //join subjectVisitStat2 in _subjectVisitRepository.Find(t => t.TrialId == param.TrialId&&t.StudyUploaded).GroupBy(t => t.SiteId).Select(g => new { SiteId = g.Key, VisitCount = g.Count() }) on site.Id equals subjectVisitStat2.SiteId into SSV2 + //from subjectVisitStatItem2 in SSV2.DefaultIfEmpty() + + join studyStat in _studyRepository.Find(t => t.TrialId == param.TrialId && t.Status != (int)StudyStatus.Abandon).GroupBy(u => u.SiteId).Select(g => new { SiteId = g.Key, StudyCount = g.Count() }) on site.Id equals studyStat.SiteId into STT + from studyStatItem in STT.DefaultIfEmpty() + select new SiteStatDTO() + { + SiteId = site.Id, + Site = site.SiteName, + City = site.City, + Country = site.Country, + + //VisitCount = subjectVisitStatItem2.VisitCount, + //PlanVisitCount = subjectVisitStatItem.VisitCount, + StudyCount = studyStatItem.StudyCount, + UserCount = userTrialStat.UserCount, + SubjectCount = subjectStatItem.SubjectCount + }; + } + else //CRC 或者其他的 + { + + + //CRC 只能看到他负责得site下的用户、访视、study 这种情况得到的siteId 不准确 因为 这个SiteId 有可能是因为他是其他项目对接人产生的 因而要加入trialId过滤 这里不用 自连接过滤 因为 指定了trialId + //var userId = requestUser.Id; + //var siteQuery = _userTrialRepository.Find(t => t.SiteId != Guid.Empty && t.UserId == userId).Join(_userTrialRepository.Find(t => t.SiteId == Guid.Empty && t.UserId == userId), p => p.TrialId, q => q.TrialId, (p, q) => p.SiteId).Distinct(); + + // CRC 只能看到他负责得site下的用户、访视、study + var siteQuery = _userTrialRepository.Find(t => t.SiteId != Guid.Empty && t.UserId == requestUser.Id) + .Select(t => t.SiteId).Distinct(); + + //通过site过滤受试者 + //var subjectQuery = _subjectRepository.Find(t => siteQuery.Contains(t.SiteId)).Select(u => u.Id); + + + //过滤site + siteLambda = siteLambda.And(t => siteQuery.Contains(t.Id)); + + siteStatQuery = from site in _siteRepository.GetAll().Where(siteLambda) + join userTrialStat in _userTrialRepository + .Find(t => t.TrialId == param.TrialId && t.SiteId != Guid.Empty && t.UserId == requestUser.Id).GroupBy(u => u.SiteId) + .Select(g => new { SiteId = g.Key, UserCount = g.Count() }) on site.Id equals userTrialStat.SiteId + + // subject 过滤site + join subjectStat in _subjectRepository.Find(t => t.TrialId == param.TrialId&& siteQuery.Contains(t.SiteId)).GroupBy(u => u.SiteId) + .Select(g => new { SiteId = g.Key, SubjectCount = g.Count() }) on site.Id equals subjectStat + .SiteId + into ST + from subjectStatItem in ST.DefaultIfEmpty() + + ////加入 Visit统计 通过site下的受试者过滤visit 加入siteId 后修改 不用通过site下的用户过滤 + //join subjectVisitStat in _subjectVisitRepository.Find(t => siteQuery.Contains(t.SiteId)&& t.TrialId == param.TrialId).GroupBy(t => t.SiteId).Select(g => new { SiteId = g.Key, VisitCount = g.Count() }) on site.Id equals subjectVisitStat.SiteId into SSV + //from subjectVisitStatItem in SSV.DefaultIfEmpty() + + //join subjectVisitStat2 in _subjectVisitRepository.Find(t => t.TrialId == param.TrialId && t.StudyUploaded&& siteQuery.Contains(t.SiteId)).GroupBy(t => t.SiteId).Select(g => new { SiteId = g.Key, VisitCount = g.Count() }) on site.Id equals subjectVisitStat2.SiteId into SSV2 + //from subjectVisitStatItem2 in SSV2.DefaultIfEmpty() + + // study 过滤site + join studyStat in _studyRepository.Find(t => t.TrialId == param.TrialId && t.Status != (int)StudyStatus.Abandon && siteQuery.Contains(t.SiteId)).GroupBy(u => u.SiteId) + .Select(g => new { SiteId = g.Key, StudyCount = g.Count() }) on site.Id equals studyStat.SiteId + into + STT + from studyStatItem in STT.DefaultIfEmpty() + select new SiteStatDTO() + { + SiteId = site.Id, + Site = site.SiteName, + City = site.City, + Country = site.Country, + + //VisitCount = subjectVisitStatItem2.VisitCount, + //PlanVisitCount = subjectVisitStatItem.VisitCount, + + StudyCount = studyStatItem.StudyCount, + UserCount = userTrialStat.UserCount, + SubjectCount = subjectStatItem.SubjectCount + }; + } + + + + + var count = siteStatQuery.Count(); + var propName = string.IsNullOrWhiteSpace(param.SortField) ? "Site" : param.SortField; + + siteStatQuery = param.Asc + ? siteStatQuery.OrderBy(propName) + : siteStatQuery.OrderByDescending(propName); + siteStatQuery = siteStatQuery.Skip((param.PageIndex - 1) * param.PageSize).Take(param.PageSize); + var list = siteStatQuery.ToList(); + + var siteIds = list.Select(t => t.SiteId).ToList(); + + var userQuery = from userTrial in _userTrialRepository + .Find(t => t.TrialId == param.TrialId && siteIds.Contains(t.SiteId)) + join user in _userRepository.GetAll().Where(userLambda) on userTrial.UserId equals user.Id + select new + { + Id = userTrial.Id, + SiteId = userTrial.SiteId, + Phone = user.Phone, + UserId = userTrial.UserId, + UserRealName = user.RealName, + UserName = user.UserName, + TrialId = userTrial.TrialId, + UserTypeId = userTrial.UserTypeId, + UserType = userTrial.UserType, + OrganizationTypeId = userTrial.OrganizationTypeId, + OrganizationType = userTrial.OrganizationType, + OrganizationId = userTrial.OrganizationId, + OrganizationName = userTrial.OrganizationName, + UpdateTime = userTrial.UpdateTime, + }; + var userList = userQuery.ToList(); + + list.ForEach(t=> t.UserList= userList.Where(u=>u.SiteId==t.SiteId).Select(userTrial=>new UserTrialDTO() + { + Id = userTrial.Id, + SiteId = t.SiteId, + Phone = userTrial.Phone, + UserId = userTrial.UserId, + UserRealName = userTrial.UserRealName, + UserName = userTrial.UserName, + TrialId = userTrial.TrialId, + UserTypeId = userTrial.UserTypeId, + UserType = userTrial.UserType, + OrganizationTypeId = userTrial.OrganizationTypeId, + OrganizationType = userTrial.OrganizationType, + OrganizationId = userTrial.OrganizationId, + OrganizationName = userTrial.OrganizationName, + UpdateTime = userTrial.UpdateTime, + }).ToList()); + + + + return new PageOutput(param.PageIndex, + param.PageSize, count, list); + + } + + public IResponseOutput AddOrUpdateSiteCRC(SiteCRCCommand param) + { + if (param.Id == Guid.Empty || param.Id == null)//新增 + { + + if (_userTrialRepository.GetAll().Any(u => u.UserId == param.UserId + && u.TrialId == param.TrialId && u.SiteId == param.SiteId)) + { + + return ResponseOutput.NotOk("the same Site already exist the same CRC participants "); + } + + var temp = _mapper.Map(param); + temp.UpdateTime = DateTime.Now; + + var result = _userTrialRepository.Add(temp); + bool isSuccess = _userTrialRepository.SaveChanges(); + + + return ResponseOutput.Result(isSuccess); + } + else //更新 + { + + if (_userTrialRepository.GetAll().Any(u => u.UserId == param.UserId + && u.TrialId == param.TrialId && u.SiteId == param.SiteId && u.Id != param.Id)) + { + + return ResponseOutput.NotOk("the same Site already exist the same CRC participants "); + } + + var isSuccess = _userTrialRepository.Update(u => u.Id == param.Id, t => new UserTrial + { + TrialId = param.TrialId, + UserId = param.UserId, + UserTypeId = param.UserTypeId, + UserType = param.UserType, + SiteId = param.SiteId, + + OrganizationTypeId = param.OrganizationTypeId, + OrganizationType = param.OrganizationType, + OrganizationId = param.OrganizationId, + OrganizationName = param.OrganizationName, + UserRealName = param.UserRealName, + UpdateTime = DateTime.Now + }); + + return ResponseOutput.Result(isSuccess); + + } + } + + public IResponseOutput DeleteSiteCRC(Guid id) + { + var isSuccess = _userTrialRepository.Delete(u => u.Id == id); + + return ResponseOutput.Result(isSuccess); + + } + + + } +} diff --git a/IRaCIS.Core.Application/Trial/VisitStageService.cs b/IRaCIS.Core.Application/Trial/VisitStageService.cs new file mode 100644 index 0000000..3c239fc --- /dev/null +++ b/IRaCIS.Core.Application/Trial/VisitStageService.cs @@ -0,0 +1,134 @@ +using AutoMapper; +using AutoMapper.QueryableExtensions; +using IRaCIS.Application.ExpressionExtend; +using IRaCIS.Application.Interfaces; +using IRaCIS.Application.ViewModels; +using IRaCIS.Core.Application.Contracts.RequestAndResponse; +using IRaCIS.Core.Domain.Interfaces; +using IRaCIS.Core.Domain.Models; +using IRaCIS.Infra.Data.ExpressionExtend; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Expressions; + + +namespace IRaCIS.Application.Services +{ + public class VisitStageService : IVisitPlanService + { + private readonly IVisitStageRepository _visitStageRepository; + private readonly IMapper _mapper; + private readonly ISubjectVisitRepository _subjectVisitRepository; + + public VisitStageService(IVisitStageRepository visitStageRepository, IMapper mapper,ISubjectVisitRepository subjectVisitRepository) + { + _visitStageRepository = visitStageRepository; + _mapper = mapper; + _subjectVisitRepository = subjectVisitRepository; + } + + ///暂时不用 + /// 获取项目访视计划 + public PageOutput GetTrialVisitStageList(VisitPlanQueryDTO param) + { + if (param.TrialId == Guid.Empty) + { + ResponseOutput.NotOk("Trial Id should not be empty",new PageOutput()); + } + Expression> lambda = x => true; + + if (!string.IsNullOrWhiteSpace(param.Keyword)) + { + lambda = lambda.And(t => t.VisitName.Contains(param.Keyword)); + } + var query = from interview in _visitStageRepository.Find(lambda).Where(u => u.TrialId == param.TrialId) + select new VisitStageDTO + { + Id = interview.Id, + TrialId = interview.TrialId, + //PlanTime = interview.PlanTime, + VisitName = interview.VisitName, + VisitDay = interview.VisitDay, + Description = interview.Description, + CreateTime = interview.CreateTime + }; + + var count = query.Count(); + + query = param.Asc + ? query.OrderBy("CreateTime") + : query.OrderByDescending("CreateTime"); + + query = query.Skip((param.PageIndex - 1) * param.PageSize).Take(param.PageSize); + var list = query.ToList(); + + return new PageOutput(param.PageIndex, + param.PageSize, count, list); + + } + + public IEnumerable GetVisitStageList(Guid trialId) + { + var query = _visitStageRepository.GetAll().Where(u => u.TrialId == trialId) + .ProjectTo(_mapper.ConfigurationProvider).OrderBy(t => t.VisitNum); + var list = query.ToList(); + + return list; + } + public IEnumerable GetTrialVisitStageSelect(Guid trialId) + { + var query = _visitStageRepository.GetAll().Where(u => u.TrialId == trialId) + .ProjectTo(_mapper.ConfigurationProvider).OrderBy(t => t.VisitDay); + var list = query.ToList(); + return list; + } + + + /// 添加或更新项目访视阶段 + public IResponseOutput AddOrUpdateVisitStage(VisitPlanCommand param) + { + if (param.Id == Guid.Empty|| param.Id ==null)//add + { + var temp = _mapper.Map(param); + + var result = _visitStageRepository.Add(temp); + var success = _visitStageRepository.SaveChanges(); + + return ResponseOutput.Result(success, new + { + NewId = result.Id + }); + + + } + else//update + { + var stage = _visitStageRepository.GetAll().FirstOrDefault(t => t.Id == param.Id); + + _mapper.Map(param, stage); + _visitStageRepository.Update(stage); + var isSuccess = _visitStageRepository.SaveChanges(); + + return ResponseOutput.Result(isSuccess) ; + } + + } + + /// 删除项目访视计划 + public IResponseOutput DeleteVisitStage(Guid id) + { + var visitPlan = _visitStageRepository.GetAll().FirstOrDefault(); + + if (_subjectVisitRepository.GetAll().Any(t => t.VisitNum == visitPlan.VisitNum)) + { + return ResponseOutput.NotOk("Some subjects have the visit data"); + } + + var result = _visitStageRepository.Delete(u => u.Id == id); + return ResponseOutput.Result(result); + } + + + } +} diff --git a/IRaCIS.Core.Application/Trial/Workload/TrialWorkloadService.cs b/IRaCIS.Core.Application/Trial/Workload/TrialWorkloadService.cs new file mode 100644 index 0000000..bd3b8f0 --- /dev/null +++ b/IRaCIS.Core.Application/Trial/Workload/TrialWorkloadService.cs @@ -0,0 +1,791 @@ +using AutoMapper; +using AutoMapper.QueryableExtensions; +using IRaCIS.Application.ExpressionExtend; +using IRaCIS.Application.Interfaces; +using IRaCIS.Application.ViewModels; +using IRaCIS.Core.Application.Contracts.RequestAndResponse; +using IRaCIS.Core.Domain.Interfaces; +using IRaCIS.Core.Domain.Models; +using IRaCIS.Core.Domain.Share; +using IRaCIS.Infra.Data.ExpressionExtend; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Expressions; + +namespace IRaCIS.Application.Services +{ + public class TrialWorkloadService : ITrialWorkloadService + { + private readonly ITrialRepository _trialRepository; + private readonly IEnrollRepository _enrollRepository; + private readonly IDoctorRepository _doctorRepository; + private readonly IWorkloadRepository _doctorWorkloadRepository; + private readonly IAttachmentRepository _attachmentRepository; + private readonly IPaymentRepository _costStatisticsRepository; + private readonly ITrialRevenuesPriceRepository _trialRevenuesPriceRepository; + private readonly ITrialRevenuesPriceVerificationRepository _trialRevenuesPriceVerificationRepository; + private readonly IMapper _mapper; + + public TrialWorkloadService(ITrialRepository clinicalTrialProjectRepository, + IEnrollRepository intoGroupRepository, + IDoctorRepository doctorInfoRepository, + IWorkloadRepository doctorWorkloadRepository, + IAttachmentRepository attachmentRepository, + IPaymentRepository costStatisticsRepository, + ITrialRevenuesPriceRepository trialRevenuesPriceRepository, + ITrialRevenuesPriceVerificationRepository trialRevenuesPriceVerificationRepository, + IMapper mapper) + { + _trialRepository = clinicalTrialProjectRepository; + _enrollRepository = intoGroupRepository; + _doctorRepository = doctorInfoRepository; + _doctorWorkloadRepository = doctorWorkloadRepository; + _attachmentRepository = attachmentRepository; + _costStatisticsRepository = costStatisticsRepository; + _trialRevenuesPriceRepository = trialRevenuesPriceRepository; + _trialRevenuesPriceVerificationRepository = trialRevenuesPriceVerificationRepository; + _mapper = mapper; + } + + #region 入组工作量统计列表 具体详情 增删改查相关 上传\删除协议 + /// + /// 上传入组后的Ack-SOW + /// + public IResponseOutput UploadReviewerAckSOW(Guid userId, Guid trialId, + ReviewerAckDTO attachmentViewModel) + { + + var intoGroupItem = _enrollRepository.GetAll().FirstOrDefault(t => t.TrialId == trialId && t.DoctorId == attachmentViewModel.DoctorId); + + if (intoGroupItem != null) + { + + if (attachmentViewModel.Id != Guid.Empty) + { + _attachmentRepository.Delete(t => t.Id == attachmentViewModel.Id); + } + + var attach = _mapper.Map(attachmentViewModel); + var attachment = _attachmentRepository.Add(attach); + + intoGroupItem.AttachmentId = attachment.Id; + _enrollRepository.Update(intoGroupItem); + + + var success = _enrollRepository.SaveChanges(); + + return ResponseOutput.Result(success, attachment.Id.ToString()); + + + } + + return ResponseOutput.NotOk("Database cannot find enroment data"); + + } + + /// + /// 删除Ack-SOW + /// + public IResponseOutput DeleteReviewerAckSOW(Guid trialId, Guid doctorId, Guid attachmentId) + { + var success1 = _attachmentRepository.Delete(a => a.Id == attachmentId); + var success2 = _enrollRepository.Update(t => t.TrialId == trialId && t.DoctorId == doctorId, u => + new Enroll() + { + AttachmentId = Guid.Empty + }); + return ResponseOutput.Result(success1 && success2); + } + + public IResponseOutput UpdateReviewerReadingType(Guid trialId, Guid doctorId, int type) + { + var success2 = _enrollRepository.Update(t => t.TrialId == trialId && t.DoctorId == doctorId, u => + new Enroll() + { + ReviewerReadingType = type + }); + return ResponseOutput.Result(success2); + } + + /// + /// 获取某个项目入组的医生工作量统计列表 + /// + public PageOutput GetTrialEnrollmentWorkloadStats(WorkLoadDoctorQueryDTO doctorSearchModel) + { + //https://blog.csdn.net/sunshineblog/article/details/78636389 + + var trialId = doctorSearchModel.TrialId; + Expression> intoGroupLambda = x => x.TrialId == trialId && x.EnrollStatus >= (int)EnrollStatus.ConfirmIntoGroup; + + Expression> workloadLambda = t => t.TrialId == trialId && t.DataFrom == (int)WorkLoadFromStatus.FinalConfirm; + + var doctorIntoGroupQueryable = + + from intoGroup in _enrollRepository.GetAll().Where(intoGroupLambda) + join doctor in _doctorRepository.GetAll() on intoGroup.DoctorId equals doctor.Id + join attachmentItem in _attachmentRepository.GetAll() on intoGroup.AttachmentId equals attachmentItem.Id into cc + from attachment in cc.DefaultIfEmpty() + join doctorWorkLoad in _doctorWorkloadRepository.GetAll().Where(workloadLambda).GroupBy(t => t.DoctorId).Select( + g => new + { + DoctorId = g.Key, + + Training = g.Sum(t => t.Training), + Downtime = g.Sum(t => t.Downtime), + Timepoint = g.Sum(t => t.Timepoint), + TimepointIn24H = g.Sum(t => t.TimepointIn24H), + TimepointIn48H = g.Sum(t => t.TimepointIn48H), + Global = g.Sum(t => t.Global), + Adjudication = g.Sum(t => t.Adjudication), + AdjudicationIn24H = g.Sum(t => t.AdjudicationIn24H), + AdjudicationIn48H = g.Sum(t => t.AdjudicationIn48H), + RefresherTraining= g.Sum(t => t.RefresherTraining) + } + + ) on intoGroup.DoctorId equals doctorWorkLoad.DoctorId into tt //连接为了得到入组时间 + from doctorWorkLoad in tt.DefaultIfEmpty()//不是每个医生都有工作量 + + select new WorkLoadAndAgreementDTO() + { + + DoctorId = doctor.Id, + Code = doctor.Code, + FirstName = doctor.FirstName, + LastName = doctor.LastName, + ChineseName = doctor.ChineseName, + + EnrollTime = intoGroup.EnrollTime, + AgreementId = intoGroup.AttachmentId, + ReviewerReadingType = intoGroup.ReviewerReadingType, + AgreementPath = attachment.Path, + + Timepoint = doctorWorkLoad.Timepoint, + TimepointIn24H = doctorWorkLoad.TimepointIn24H, + TimepointIn48H = doctorWorkLoad.TimepointIn48H, + + Adjudication = doctorWorkLoad.Adjudication, + AdjudicationIn24H = doctorWorkLoad.AdjudicationIn24H, + AdjudicationIn48H = doctorWorkLoad.AdjudicationIn48H, + + Global = doctorWorkLoad.Global, + + RefresherTraining= doctorWorkLoad.RefresherTraining, + TrainingTimes = doctorWorkLoad.Training, + Downtime = doctorWorkLoad.Downtime + + }; + + var count = doctorIntoGroupQueryable.Count(); + if (string.IsNullOrWhiteSpace(doctorSearchModel.SortField)) + { + doctorIntoGroupQueryable = doctorIntoGroupQueryable.OrderByDescending("EnrollTime").ThenBy(u => u.Code); + } + else + { + if (doctorSearchModel.SortField == "FirstName" || doctorSearchModel.SortField == "LastName") + { + if (doctorSearchModel.Asc) + { + doctorIntoGroupQueryable = doctorIntoGroupQueryable.OrderBy("LastName").ThenBy(u => u.FirstName); + } + else + { + doctorIntoGroupQueryable = doctorIntoGroupQueryable.OrderByDescending("LastName").ThenByDescending(u => u.FirstName); + } + } + else + { + var propName = doctorSearchModel.SortField == "" ? "EnrollTime" : doctorSearchModel.SortField; + doctorIntoGroupQueryable = doctorSearchModel.Asc + ? doctorIntoGroupQueryable.OrderBy(propName) + : doctorIntoGroupQueryable.OrderByDescending(propName); + } + } + //分页 + doctorIntoGroupQueryable = doctorIntoGroupQueryable + .Skip((doctorSearchModel.PageIndex - 1) * doctorSearchModel.PageSize) + .Take(doctorSearchModel.PageSize); + //从数据库提取数据 + var intoGroupList = doctorIntoGroupQueryable.ToList(); + + return new PageOutput(doctorSearchModel.PageIndex, + doctorSearchModel.PageSize, count, intoGroupList); + + } + + /// + /// 获取入组某个项目的医生的最近几个月的工作量详情(带有填充数据) + /// + public PageOutput GetEnrollmentWorkloadStatsDetail(WorkLoadStatsQueryDTO workLoadSearch) + { + #region 条件查询 + Expression> workloadLambda = x => true; + if (workLoadSearch.TrialId != Guid.Empty && workLoadSearch.TrialId != null) + { + workloadLambda = workloadLambda.And(x => x.TrialId == workLoadSearch.TrialId); + } + if (workLoadSearch.DoctorId != Guid.Empty && workLoadSearch.DoctorId != null) + { + workloadLambda = workloadLambda.And(t => t.DoctorId == workLoadSearch.DoctorId); + } + if (workLoadSearch.SearchBeginDateTime != null) + { + var bDate = workLoadSearch.SearchBeginDateTime; + var eDate = workLoadSearch.SearchEndDateTime.Value.AddMonths(1); + var beginDate = new DateTime(bDate.Value.Year, bDate.Value.Month, 1); + DateTime endDate = new DateTime(eDate.Year, eDate.Month, 1); + + workloadLambda = workloadLambda.And(t => + t.WorkTime >= beginDate && t.WorkTime < endDate); + } + + + + #endregion + + IQueryable workLoadQueryable = default; + + var tempWorkload = new List(); + if (workLoadSearch.WorkLoadFromStatus.Contains(1)) + { + workLoadQueryable = from workLoad in _doctorWorkloadRepository.GetAll().Where(workloadLambda.And(t => t.DataFrom == (int)WorkLoadFromStatus.CRO)) + join doctor in _doctorRepository.GetAll() on workLoad.DoctorId equals doctor.Id + join trial in _trialRepository.GetAll() on workLoad.TrialId equals trial.Id + + select new WorkLoadDetailDTO() + { + Id = workLoad.Id, + DoctorId = workLoad.DoctorId, + ChineseName = doctor.ChineseName, + FirstName = doctor.FirstName, + LastName = doctor.LastName, + + YearMonthStr = workLoad.YearMonth, + CreateTime = workLoad.CreateTime, + WorkTime = workLoad.WorkTime, + + DataFrom = workLoad.DataFrom, + TrialId = workLoad.TrialId, + Indication = trial.Indication, + Code = trial.Code, + + Timepoint = workLoad.Timepoint, + TimepointIn24H = workLoad.TimepointIn24H, + TimepointIn48H = workLoad.TimepointIn48H, + Global = workLoad.Global, + RefresherTraining = workLoad.RefresherTraining, + Adjudication = workLoad.Adjudication, + AdjudicationIn24H = workLoad.AdjudicationIn24H, + AdjudicationIn48H = workLoad.AdjudicationIn48H, + + + Training = workLoad.Training, + Downtime = workLoad.Downtime, + IsLock = workLoad.IsLock + }; + tempWorkload.AddRange(workLoadQueryable.ToList()); + } + + + if (workLoadSearch.WorkLoadFromStatus.Contains(2)) + { + workLoadQueryable = from workLoad in _doctorWorkloadRepository.GetAll().Where(workloadLambda.And(t => t.DataFrom == (int)WorkLoadFromStatus.FinalConfirm)) + join doctor in _doctorRepository.GetAll() on workLoad.DoctorId equals doctor.Id + join trial in _trialRepository.GetAll() on workLoad.TrialId equals trial.Id + + select new WorkLoadDetailDTO() + { + Id = workLoad.Id, + DoctorId = workLoad.DoctorId, + ChineseName = doctor.ChineseName, + FirstName = doctor.FirstName, + LastName = doctor.LastName, + + YearMonthStr = workLoad.YearMonth, + CreateTime = workLoad.CreateTime, + WorkTime = workLoad.WorkTime, + + DataFrom = workLoad.DataFrom, + TrialId = workLoad.TrialId, + Indication = trial.Indication, + Code = trial.Code, + + Timepoint = workLoad.Timepoint, + TimepointIn24H = workLoad.TimepointIn24H, + TimepointIn48H = workLoad.TimepointIn48H, + Global = workLoad.Global, + RefresherTraining = workLoad.RefresherTraining, + Adjudication = workLoad.Adjudication, + AdjudicationIn24H = workLoad.AdjudicationIn24H, + AdjudicationIn48H = workLoad.AdjudicationIn48H, + + Training = workLoad.Training, + Downtime = workLoad.Downtime, + IsLock = workLoad.IsLock + }; + tempWorkload.AddRange(workLoadQueryable.ToList()); + } + + if (workLoadSearch.WorkLoadFromStatus.Contains(0)) + { + workLoadQueryable = + from workLoad in (from workLoadItem in _doctorWorkloadRepository.GetAll().Where(workloadLambda.And(t => t.DataFrom == (int)WorkLoadFromStatus.Doctor)) + group workLoadItem by new { workLoadItem.YearMonth, workLoadItem.DoctorId, workLoadItem.TrialId, workLoadItem.IsLock } into g + select new + { + Id = Guid.NewGuid(), + DoctorId = g.Key.DoctorId, + DataFrom = 0, + TrialId = g.Key.TrialId, + IsLock = g.Key.IsLock, + YearMonthStr = g.Key.YearMonth, + Timepoint = g.Sum(workLoad => workLoad.Timepoint), + TimepointIn24H = g.Sum(workLoad => workLoad.TimepointIn24H), + TimepointIn48H = g.Sum(workLoad => workLoad.TimepointIn48H), + Global = g.Sum(workLoad => workLoad.Global), + RefresherTraining = g.Sum(workLoad => workLoad.RefresherTraining), + Adjudication = g.Sum(workLoad => workLoad.Adjudication), + AdjudicationIn24H = g.Sum(workLoad => workLoad.AdjudicationIn24H), + AdjudicationIn48H = g.Sum(workLoad => workLoad.AdjudicationIn48H), + + Training = g.Sum(workLoad => workLoad.Training), + Downtime = g.Sum(workLoad => workLoad.Downtime) + }) + join doctor in _doctorRepository.GetAll() on workLoad.DoctorId equals doctor.Id + join trial in _trialRepository.GetAll() on workLoad.TrialId equals trial.Id + select new WorkLoadDetailDTO() + { + Id = workLoad.Id, + DoctorId = workLoad.DoctorId, + ChineseName = doctor.ChineseName, + FirstName = doctor.FirstName, + LastName = doctor.LastName, + YearMonthStr = workLoad.YearMonthStr, + + DataFrom = workLoad.DataFrom, + TrialId = workLoad.TrialId, + Indication = trial.Indication, + Code = trial.Code, + + Timepoint = workLoad.Timepoint, + TimepointIn24H = workLoad.TimepointIn24H, + TimepointIn48H = workLoad.TimepointIn48H, + Global = workLoad.Global, + RefresherTraining = workLoad.RefresherTraining, + Adjudication = workLoad.Adjudication, + AdjudicationIn24H = workLoad.AdjudicationIn24H, + AdjudicationIn48H = workLoad.AdjudicationIn48H, + + Training = workLoad.Training, + Downtime = workLoad.Downtime, + IsLock = workLoad.IsLock + }; + tempWorkload.AddRange(workLoadQueryable.ToList()); + } + + //workLoadQueryable = workLoadQueryable.OrderByDescending(t => t.YearMonthStr).ThenBy(t => t.DataFrom); + + //取选取月份的数据 + var month = (workLoadSearch.SearchEndDateTime?.Year - workLoadSearch.SearchBeginDateTime?.Year) * 12 + (workLoadSearch.SearchEndDateTime?.Month - workLoadSearch.SearchBeginDateTime?.Month) + 1; + var count = (month ?? 1) * workLoadSearch.WorkLoadFromStatus.Count; + //tempWorkload = tempWorkload.Take(count); + tempWorkload.OrderByDescending(t => t.YearMonthStr).ThenBy(t => t.DataFrom).Take(count); + //var workLoadList = workLoadQueryable.ToList(); + return BuildFullData(tempWorkload, workLoadSearch); + } + + /// + /// 获取来自Reviewer自己的数据,某个月添加的多条 + /// + public List GetReviewerWorkLoadListDetail( + WorkLoadDetailQueryDTO workLoadSearch) + { + Expression> workloadLambda = t => t.DataFrom == (int)WorkLoadFromStatus.Doctor && t.YearMonth == workLoadSearch.YearMonthStr; + + if (workLoadSearch.TrialId != Guid.Empty) + { + workloadLambda = workloadLambda.And(x => x.TrialId == workLoadSearch.TrialId); + } + + if (workLoadSearch.DoctorId != Guid.Empty) + { + workloadLambda = workloadLambda.And(t => t.DoctorId == workLoadSearch.DoctorId); + } + + var workLoadQueryable = from workLoad in _doctorWorkloadRepository.GetAll().Where(workloadLambda) + join doctor in _doctorRepository.GetAll() on workLoad.DoctorId equals doctor.Id + join trial in _trialRepository.GetAll() on workLoad.TrialId equals trial.Id + + select new WorkLoadDetailViewModel() + { + Id = workLoad.Id, + DoctorId = workLoad.DoctorId, + ChineseName = doctor.ChineseName, + FirstName = doctor.FirstName, + LastName = doctor.LastName, + YearMonthStr = workLoad.YearMonth, + CreateTime = workLoad.CreateTime, + WorkTime = workLoad.WorkTime, + + DataFrom = workLoad.DataFrom, + TrialId = workLoad.TrialId, + Indication = trial.Indication, + Code = trial.Code, + + Timepoint = workLoad.Timepoint, + TimepointIn24H = workLoad.TimepointIn24H, + TimepointIn48H = workLoad.TimepointIn48H, + Global = workLoad.Global, + Adjudication = workLoad.Adjudication, + AdjudicationIn24H = workLoad.AdjudicationIn24H, + AdjudicationIn48H = workLoad.AdjudicationIn48H, + RefresherTraining = workLoad.RefresherTraining, + + Training = workLoad.Training, + Downtime = workLoad.Downtime, + IsLock = workLoad.IsLock + }; + + workLoadQueryable = workLoadQueryable.OrderBy("WorkTime"); + + var workLoadList = workLoadQueryable.ToList(); + + workLoadList.ForEach(t => t.RowGuid = Guid.NewGuid()); + + return workLoadList; + + } + + /// + /// 工作量是否存在,用于判断只能添加一条的工作量记录 + /// + public IResponseOutput WorkloadExist(WorkloadExistQueryDTO param) + { + var isExist = false; + var exist = _doctorWorkloadRepository.FindSingleOrDefault(u => u.TrialId == param.TrialId && u.DoctorId == param.DoctorId + && u.WorkTime == param.WorkDate && u.DataFrom == 0); + if (exist != null) + { + isExist = true; + } + return ResponseOutput.Ok(new ExistWorkloadViewModel + { + IsExist = isExist, + WorkLoad = _mapper.Map(exist), + }); + } + + /// + /// 添加或更新工作量 + /// + public IResponseOutput AddOrUpdateWorkload(WorkloadCommand workLoadAddOrUpdateModel, + Guid userId) + { + var yearMonthStr = workLoadAddOrUpdateModel.WorkTime.ToString("yyyy-MM"); + + + if (workLoadAddOrUpdateModel.Id == Guid.Empty || workLoadAddOrUpdateModel.Id == null) + { + //确定是那个医生 那个项目 那个月份做的 + Expression> workloadLambda = x => x.DoctorId == workLoadAddOrUpdateModel.DoctorId && x.TrialId == workLoadAddOrUpdateModel.TrialId && x.YearMonth == yearMonthStr; + + //只要是来自CRO或者最终确认的 只能有一条 + switch (workLoadAddOrUpdateModel.DataFrom) + { + case (int)WorkLoadFromStatus.CRO: //1 来自CRO的 + workloadLambda = workloadLambda.And(t => t.DataFrom == (int)WorkLoadFromStatus.CRO); + break; + + case (int)WorkLoadFromStatus.FinalConfirm: //2 最终确认的 + workloadLambda = workloadLambda.And(t => t.DataFrom == (int)WorkLoadFromStatus.FinalConfirm); + + var isExist = _costStatisticsRepository.GetAll().Any(u => u.YearMonth == yearMonthStr && u.DoctorId == workLoadAddOrUpdateModel.DoctorId); + if (!isExist) + { + _costStatisticsRepository.Add(new Payment + { + DoctorId = workLoadAddOrUpdateModel.DoctorId, + YearMonth = yearMonthStr, + YearMonthDate = DateTime.Parse(yearMonthStr), + IsLock = false + }); + } + + //处理 验证项目收入价格是否都填写了 + + var revenuesPriceExist = _trialRevenuesPriceRepository.GetAll() + .FirstOrDefault(t => t.TrialId == workLoadAddOrUpdateModel.TrialId); + + //没填写收入价格 插入记录 所有的都是false + if (revenuesPriceExist == null) + { + _trialRevenuesPriceVerificationRepository.Add(new TrialRevenuesPriceVerification() + { + TrialId = workLoadAddOrUpdateModel.TrialId, + ReviewerId = workLoadAddOrUpdateModel.DoctorId, + YearMonth = yearMonthStr, + WorkLoadDate = workLoadAddOrUpdateModel.WorkTime + }); + } + else //有价格 校验 看全不全 + { + + var tpNeedSetPrice = workLoadAddOrUpdateModel.Timepoint > 0 && + revenuesPriceExist.Timepoint <= 0; + var tp24HNeedSetPrice = workLoadAddOrUpdateModel.TimepointIn24H > 0 && + revenuesPriceExist.TimepointIn24H <= 0; + var tp48NeedSetPrice = workLoadAddOrUpdateModel.TimepointIn48H > 0 && + revenuesPriceExist.TimepointIn48H <= 0; + var adNeedSetPrice = workLoadAddOrUpdateModel.Adjudication > 0 && + revenuesPriceExist.Adjudication <= 0; + var ad24NeedSetPrice = workLoadAddOrUpdateModel.AdjudicationIn24H > 0 && + revenuesPriceExist.AdjudicationIn24H <= 0; + var ad48NeedSetPrice = workLoadAddOrUpdateModel.AdjudicationIn48H > 0 && + revenuesPriceExist.AdjudicationIn48H <= 0; + var downtimeNeedSetPrice = workLoadAddOrUpdateModel.Downtime > 0 && + revenuesPriceExist.Downtime <= 0; + var globalNeedSetPrice = workLoadAddOrUpdateModel.Global > 0 && + revenuesPriceExist.Global <= 0; + var trainingNeedSetPrice = workLoadAddOrUpdateModel.Training > 0 && + revenuesPriceExist.Training <= 0; + + var refresherTrainingTrainingNeedSetPrice = workLoadAddOrUpdateModel.RefresherTraining > 0 && + revenuesPriceExist.RefresherTraining <= 0; + + + + + var needAdd = tpNeedSetPrice || tp24HNeedSetPrice || tp48NeedSetPrice || adNeedSetPrice || ad24NeedSetPrice || + ad48NeedSetPrice || downtimeNeedSetPrice || globalNeedSetPrice && trainingNeedSetPrice|| refresherTrainingTrainingNeedSetPrice; + + //验证不通过 增加 + if (needAdd) + { + _trialRevenuesPriceVerificationRepository.Add(new TrialRevenuesPriceVerification() + { + TrialId = workLoadAddOrUpdateModel.TrialId, + ReviewerId = workLoadAddOrUpdateModel.DoctorId, + YearMonth = yearMonthStr, + WorkLoadDate = workLoadAddOrUpdateModel.WorkTime, + //需要设置价格和 有价格是相反的 数据库此字段存储的时候对应项是否有价格 + Timepoint = !tpNeedSetPrice, + TimepointIn24H = !tp24HNeedSetPrice, + TimepointIn48H = !tp48NeedSetPrice, + Adjudication = !adNeedSetPrice, + AdjudicationIn24H = !ad24NeedSetPrice, + AdjudicationIn48H = !ad48NeedSetPrice, + Downtime = !downtimeNeedSetPrice, + Global = !globalNeedSetPrice, + Training = !trainingNeedSetPrice, + RefresherTraining = !refresherTrainingTrainingNeedSetPrice + }); + } + + } + + + break; + } + if (workLoadAddOrUpdateModel.DataFrom != (int)WorkLoadFromStatus.Doctor) + { + if (_doctorWorkloadRepository.GetAll().Any(workloadLambda)) + { + + return ResponseOutput.NotOk("This type of data can only have one"); + + } + } + if (workLoadAddOrUpdateModel.DataFrom == (int)WorkLoadFromStatus.Doctor) + { + Expression> doctorworkloadLambda = x => x.DoctorId == workLoadAddOrUpdateModel.DoctorId && x.TrialId == workLoadAddOrUpdateModel.TrialId && x.YearMonth == yearMonthStr && workLoadAddOrUpdateModel.WorkTime == x.WorkTime; + + doctorworkloadLambda = doctorworkloadLambda.And(t => t.DataFrom == (int)WorkLoadFromStatus.Doctor); + if (_doctorWorkloadRepository.GetAll().Any(doctorworkloadLambda)) + { + return ResponseOutput.NotOk("This type of data can only have one"); + } + } + + var workLoad = _mapper.Map(workLoadAddOrUpdateModel); + + workLoad.YearMonth = yearMonthStr; + + _doctorWorkloadRepository.Add(workLoad); + + _enrollRepository.Update( + t => t.DoctorId == workLoadAddOrUpdateModel.DoctorId && t.TrialId == workLoadAddOrUpdateModel.TrialId, u => new Enroll() + { + EnrollStatus = (int)EnrollStatus.DoctorReading, + UpdateTime = DateTime.Now + }); + + var success = _doctorWorkloadRepository.SaveChanges(); + + return ResponseOutput.Result(success, workLoad.Id); + + } + else + { + //判断是否已经被锁定 + var isLocked = _costStatisticsRepository.GetAll().Any(u => u.DoctorId == workLoadAddOrUpdateModel.DoctorId && + u.YearMonth == yearMonthStr && u.IsLock); + if (isLocked) + { + + return ResponseOutput.NotOk("Expenses have been settled and workload cannot be modified."); + + } + + var success = _doctorWorkloadRepository.Update(t => t.Id == workLoadAddOrUpdateModel.Id, + u => new Workload() + { + Timepoint = workLoadAddOrUpdateModel.Timepoint, + TimepointIn24H = workLoadAddOrUpdateModel.TimepointIn24H, + TimepointIn48H = workLoadAddOrUpdateModel.TimepointIn48H, + + Adjudication = workLoadAddOrUpdateModel.Adjudication, + AdjudicationIn24H = workLoadAddOrUpdateModel.AdjudicationIn24H, + AdjudicationIn48H = workLoadAddOrUpdateModel.AdjudicationIn48H, + + RefresherTraining = workLoadAddOrUpdateModel.RefresherTraining, + + Downtime = workLoadAddOrUpdateModel.Downtime, + Training = workLoadAddOrUpdateModel.Training, + Global = workLoadAddOrUpdateModel.Global, + UpdateTime = DateTime.Now, + UpdateUserId = userId, + + WorkTime = workLoadAddOrUpdateModel.WorkTime, + YearMonth = yearMonthStr + }); + return ResponseOutput.Result(success); + + } + } + + + + + /// + /// 删除工作量 + /// + public IResponseOutput DeleteWorkload(Guid workloadId) + { + return ResponseOutput.Result(_doctorWorkloadRepository.Delete(t => t.Id == workloadId)); + } + + /// + /// 获取工作量详情(用于判断工作量锁定时,调用) + /// + public WorkloadDTO GetWorkloadDetailById(Guid id) + { + var workload = _doctorWorkloadRepository.FindSingleOrDefault(u => u.Id == id); + return _mapper.Map(workload); + } + + #endregion + + private PageOutput BuildFullData( + List workLoadList, WorkLoadStatsQueryDTO workLoadSearch) + { + var doctor = _doctorRepository.GetAll().Where(t => t.Id == workLoadSearch.DoctorId).ProjectTo(_mapper.ConfigurationProvider).FirstOrDefault(); + //查询 1-3月的 共3个月 + var month = (workLoadSearch.SearchEndDateTime?.Year - workLoadSearch.SearchBeginDateTime?.Year) * 12 + + (workLoadSearch.SearchEndDateTime?.Month - workLoadSearch.SearchBeginDateTime?.Month) + 1; + + var needCount = month * workLoadSearch.WorkLoadFromStatus.Count ?? 1; + + if (workLoadSearch.WorkLoadFromStatus.Contains((int)WorkLoadFromStatus.FinalConfirm)) + { + if (workLoadList.Count != needCount) + { + for (int i = 0; i < month; i++) + { + var yearMonthStr = workLoadSearch.SearchBeginDateTime?.AddMonths(i).ToString("yyyy-MM"); + if (!workLoadList.Any(t => t.YearMonthStr == yearMonthStr && + t.DataFrom == (int)WorkLoadFromStatus.FinalConfirm)) + { + workLoadList.Add(new WorkLoadDetailDTO() + { + Id = Guid.Empty, + DataFrom = (int)WorkLoadFromStatus.FinalConfirm, + YearMonthStr = yearMonthStr, + ChineseName = doctor.ChineseName, + FirstName = doctor.FirstName, + LastName = doctor.LastName, + Code = doctor.Code + }); + } + } + } + } + if (workLoadSearch.WorkLoadFromStatus.Contains((int)WorkLoadFromStatus.CRO)) + { + if (workLoadList.Count != needCount) + { + for (int i = 0; i < month; i++) + { + var yearMonthStr = workLoadSearch.SearchBeginDateTime?.AddMonths(i).ToString("yyyy-MM"); + if (!workLoadList.Any(t => t.YearMonthStr == yearMonthStr && + t.DataFrom == (int)WorkLoadFromStatus.CRO)) + { + workLoadList.Add(new WorkLoadDetailDTO() + { + Id = Guid.Empty, + DataFrom = (int)WorkLoadFromStatus.CRO, + YearMonthStr = yearMonthStr, + ChineseName = doctor.ChineseName, + FirstName = doctor.FirstName, + LastName = doctor.LastName, + Code = doctor.Code + }); + } + } + } + } + if (workLoadSearch.WorkLoadFromStatus.Contains((int)WorkLoadFromStatus.Doctor)) + { + if (workLoadList.Count != needCount) + { + for (int i = 0; i < month; i++) + { + var yearMonthStr = workLoadSearch.SearchBeginDateTime?.AddMonths(i).ToString("yyyy-MM"); + if (!workLoadList.Any(t => t.YearMonthStr == yearMonthStr && + t.DataFrom == (int)WorkLoadFromStatus.Doctor)) + { + workLoadList.Add(new WorkLoadDetailDTO() + { + Id = Guid.Empty, + DataFrom = (int)WorkLoadFromStatus.Doctor, + YearMonthStr = yearMonthStr, + ChineseName = doctor.ChineseName, + FirstName = doctor.FirstName, + LastName = doctor.LastName, + Code = doctor.Code + }); + } + } + } + + } + + workLoadList = workLoadList.OrderByDescending(t => t.YearMonthStr).ThenBy(t => t.DataFrom) + .ToList(); + int tempRowId = 0; + foreach (var workLoad in workLoadList) + { + workLoad.RowGuid = Guid.NewGuid(); + workLoad.RowIntId = tempRowId + 1; + tempRowId++; + } + + return new PageOutput(1, workLoadList.Count, + workLoadList.Count, workLoadList); + + + } + + + } +} diff --git a/IRaCIS.Core.Application/Trial/WorkloadDistribution/WorkloadDistributionService.cs b/IRaCIS.Core.Application/Trial/WorkloadDistribution/WorkloadDistributionService.cs new file mode 100644 index 0000000..4fdd55f --- /dev/null +++ b/IRaCIS.Core.Application/Trial/WorkloadDistribution/WorkloadDistributionService.cs @@ -0,0 +1,540 @@ +using IRaCIS.Application.ViewModels; +using IRaCIS.Core.Application.Contracts; +using IRaCIS.Core.Application.Contracts.RequestAndResponse; +using System; +using System.Linq; +using System.Linq.Expressions; +using IRaCIS.Application.ExpressionExtend; +using IRaCIS.Core.Domain.Interfaces; +using IRaCIS.Core.Domain.Models; +using IRaCIS.Core.Domain.Share; +using IRaCIS.Infra.Data.ExpressionExtend; +using IRaCIS.Core.Domain.Share.AuthUser; +using System.Collections.Generic; + +namespace IRaCIS.Core.Application.Trial.WorkloadDistribution +{ + public class WorkloadDistributionService : IWorkloadDistributionService + { + private readonly IWorkloadTPRepository _workloadTpRepository; + private readonly IWorkloadGlobalRepository _workloadGlobalRepository; + private readonly IWorkloadADRepository _workloadAdRepository; + private readonly ISubjectVisitRepository _subjectVisitRepository; + private readonly IDicomStudyRepository _studyRepository; + private readonly IDoctorRepository _doctorRepository; + private readonly ISubjectRepository _subjectRepository; + private readonly ISiteRepository _siteRepository; + private readonly IWorkloadDetailRepository _workloadDetailRepository; + private readonly IUserInfo _userInfo; + + public WorkloadDistributionService(IWorkloadTPRepository workloadTpRepository, + IWorkloadGlobalRepository workloadGlobalRepository, + IWorkloadADRepository workloadAdRepository, + ISubjectVisitRepository subjectVisitRepository, IDicomStudyRepository studyRepository, + IDoctorRepository doctorRepository, ISubjectRepository subjectRepository, + ISiteRepository siteRepository, + IWorkloadDetailRepository workloadDetailRepository, + IUserInfo userInfo) + { + _workloadTpRepository = workloadTpRepository; + _workloadGlobalRepository = workloadGlobalRepository; + _workloadAdRepository = workloadAdRepository; + _subjectVisitRepository = subjectVisitRepository; + _studyRepository = studyRepository; + _doctorRepository = doctorRepository; + _subjectRepository = subjectRepository; + _siteRepository = siteRepository; + _workloadDetailRepository = workloadDetailRepository; + _userInfo = userInfo; + } + + public IResponseOutput DistributeTP(WorkloadTPCommand workloadTPCommand) + { + //当前采用的是没有提示到具体的TP,如有需要在修改下 + var studyIdList = workloadTPCommand.TpList.Select(u => u.StudyId); + var temp = _workloadTpRepository.Find(u => studyIdList.Contains(u.StudyId) && u.ReviewerId == workloadTPCommand.ReviewerId); + if (temp.Count() > 0) + { + return ResponseOutput.NotOk("把相同Study的不同TP 分配给同一个医生了,无法保存"); + } + var success = false; + workloadTPCommand.TpList.ForEach(t => + { + _workloadDetailRepository.Add(new WorkloadDetail + { + WorkloadId = t.Id, + OptUserName = _userInfo.RealName, + OptTime = DateTime.Now, + Status = (int)WorkloadStatus.Distributed, + ReviewerId = workloadTPCommand.ReviewerId + }); + _workloadDetailRepository.SaveChanges(); + success = _workloadTpRepository.Update(u => u.Id == t.Id, k => new WorkloadTP() + { + ReviewerId = workloadTPCommand.ReviewerId, + Status = (int)WorkloadStatus.Distributed + }); + }); + return ResponseOutput.Result(success); + } + + public bool DistributeAD(WorkloadAdCommand workloadTPCommand) + { + var success = false; + workloadTPCommand.IdList.ForEach(t => + { + _workloadDetailRepository.Add(new WorkloadDetail + { + WorkloadId = t, + OptUserName = _userInfo.RealName, + OptTime = DateTime.Now, + Status = (int)WorkloadStatus.Distributed, + ReviewerId = workloadTPCommand.ReviewerId + }); + _workloadDetailRepository.SaveChanges(); + success = _workloadAdRepository.Update(u => u.Id == t, k => new WorkloadAD() + { + ReviewerId = workloadTPCommand.ReviewerId, + Status = (int)WorkloadStatus.Distributed + }); + }); + return success; + } + + public IResponseOutput DistributeGlobal(WorkloadGlobalCommand workloadGCommand) + { + var temp = _workloadGlobalRepository.Find(u => workloadGCommand.GlobalList.Select(s => s.SubjectId).Contains(u.SubjectId) + && workloadGCommand.GlobalList.Select(s => s.VisitNum).Contains(u.VisitNum) && + u.ReviewerId == workloadGCommand.ReviewerId); + if (temp.Count() > 0) + { + return ResponseOutput.NotOk("不能把相同受试者Global分配给相同的Reviewer"); + } + + var success = false; + workloadGCommand.GlobalList.ForEach(t => + { + _workloadDetailRepository.Add(new WorkloadDetail + { + WorkloadId = t.Id, + OptUserName = _userInfo.RealName, + OptTime = DateTime.Now, + Status = (int)WorkloadStatus.Distributed, + ReviewerId = workloadGCommand.ReviewerId + }); + _workloadDetailRepository.SaveChanges(); + success = _workloadGlobalRepository.Update(u => u.Id == t.Id, k => new WorkloadGlobal() + { + ReviewerId = workloadGCommand.ReviewerId, + Status = (int)WorkloadStatus.Distributed + }); + }); + return ResponseOutput.Result(success); + } + + public PageOutput GetWorkloadGlobalList(WorkloadDistributionQueryParam param) + { + IQueryable query = null; + Expression> workloadTPLambda = x => x.TrialId == param.TrialId; + if (param.SiteId != null) + { + workloadTPLambda = workloadTPLambda.And(t => t.SiteId == param.SiteId); + } + + if (param.Status != null) + { + workloadTPLambda = workloadTPLambda.And(t => t.Status == param.Status); + } + if (!string.IsNullOrEmpty(param.WorkloadCode)) + { + var globalCode = param.WorkloadCode.Trim(); + workloadTPLambda = workloadTPLambda.And(t => t.GlobalCode.Contains(globalCode)); + } + if (param.GroupId != null && param.GroupId > 0) + { + var groupCode = "G0" + param.GroupId; + workloadTPLambda = workloadTPLambda.And(t => t.GlobalCode.Contains(groupCode)); + } + + Expression> subjectLambda = x => x.TrialId == param.TrialId; + if (!string.IsNullOrEmpty(param.SubjectCode)) + { + var subjectCode = param.SubjectCode.Trim(); + subjectLambda = subjectLambda.And(t => t.Code.Contains(subjectCode)); + } + Expression> doctorLambda = x => true; + if (!string.IsNullOrEmpty(param.Reviewer)) + { + var reviewer = param.Reviewer.Trim(); + + doctorLambda = doctorLambda.And(t => t.ChineseName.Contains(reviewer) + || t.FirstName.Contains(reviewer) || t.LastName.Contains(reviewer)); + query = from workloadG in _workloadGlobalRepository.GetAll().Where(workloadTPLambda) + join subject in _subjectRepository.GetAll().Where(subjectLambda) on workloadG.SubjectId equals subject.Id + join site in _siteRepository.GetAll() on workloadG.SiteId equals site.Id + join doctor in _doctorRepository.GetAll().Where(doctorLambda) on workloadG.ReviewerId equals doctor.Id + select new WorkloadGlobalDTO() + { + Id = workloadG.Id, + ReviewerCode = doctor.Code, + ReviewerChineseName = doctor.ChineseName, + ReviewerFirstName = doctor.FirstName, + ReviewerId = doctor.Id, + ReviewerLastName = doctor.LastName, + SiteId = workloadG.SiteId, + SiteName = site.SiteName, + Status = workloadG.Status, + GlobalCode = workloadG.GlobalCode, + SubjectCode = subject.Code, + VisitId = workloadG.VisitId, + UpdateTime = workloadG.UpdateTime, + SubjectId = workloadG.SubjectId, + VisitNum = workloadG.VisitNum, + VisitName = workloadG.VisitName + }; + } + else + { + query = from workloadG in _workloadGlobalRepository.GetAll().Where(workloadTPLambda) + join subject in _subjectRepository.GetAll().Where(subjectLambda) on workloadG.SubjectId equals subject.Id + join site in _siteRepository.GetAll() on workloadG.SiteId equals site.Id + join doctor in _doctorRepository.GetAll().Where(doctorLambda) on workloadG.ReviewerId equals doctor.Id into cc + from doctor in cc.DefaultIfEmpty() + select new WorkloadGlobalDTO() + { + Id = workloadG.Id, + ReviewerCode = doctor.Code, + ReviewerChineseName = doctor.ChineseName, + ReviewerFirstName = doctor.FirstName, + ReviewerId = doctor.Id, + ReviewerLastName = doctor.LastName, + SiteId = workloadG.SiteId, + SiteName = site.SiteName, + Status = workloadG.Status, + GlobalCode = workloadG.GlobalCode, + SubjectCode = subject.Code, + VisitId = workloadG.VisitId, + UpdateTime = workloadG.UpdateTime, + SubjectId = workloadG.SubjectId, + VisitNum = workloadG.VisitNum, + VisitName = workloadG.VisitName + }; + } + + var count = query.Count(); + + var propName = param.SortField == string.Empty ? "GlobalCode" : param.SortField; + + query = param.Asc + ? query.OrderBy(propName).ThenBy(t => t.SiteName).ThenBy(t => t.SubjectCode) + : query.OrderByDescending(propName).ThenBy(t => t.SiteName).ThenBy(t => t.SubjectCode); + + query = query.Skip((param.PageIndex - 1) * param.PageSize).Take(param.PageSize); + var list = query.ToList(); + + return new PageOutput(param.PageIndex, + param.PageSize, count, list); + } + + public PageOutput GetWorkloadADList(WorkloadDistributionQueryParam param) + { + IQueryable query = null; + Expression> workloadAdLambda = x => x.TrialId == param.TrialId; + if (param.SiteId != null) + { + workloadAdLambda = workloadAdLambda.And(t => t.SiteId == param.SiteId); + } + + if (param.Status != null) + { + workloadAdLambda = workloadAdLambda.And(t => t.Status == param.Status); + } + if (!string.IsNullOrEmpty(param.WorkloadCode)) + { + var adCode = param.WorkloadCode.Trim(); + workloadAdLambda = workloadAdLambda.And(t => t.ADCode.Contains(adCode)); + } + + Expression> subjectLambda = x => x.TrialId == param.TrialId; + if (!string.IsNullOrEmpty(param.SubjectCode)) + { + var subjectCode = param.SubjectCode.Trim(); + subjectLambda = subjectLambda.And(t => t.Code.Contains(subjectCode)); + + } + Expression> doctorLambda = x => true; + if (!string.IsNullOrEmpty(param.Reviewer)) + { + var reviewer = param.Reviewer.Trim(); + doctorLambda = doctorLambda.And(t => t.ChineseName.Contains(reviewer) + || t.FirstName.Contains(reviewer) || t.LastName.Contains(reviewer)); + query = from workloadAd in _workloadAdRepository.GetAll().Where(workloadAdLambda) + join subject in _subjectRepository.GetAll().Where(subjectLambda) on workloadAd.SubjectId equals subject.Id + join site in _siteRepository.GetAll() on workloadAd.SiteId equals site.Id + join doctor in _doctorRepository.GetAll().Where(doctorLambda) on workloadAd.ReviewerId equals doctor.Id + select new WorkloadADDTO() + { + Id = workloadAd.Id, + ReviewerCode = doctor.Code, + ReviewerChineseName = doctor.ChineseName, + ReviewerFirstName = doctor.FirstName, + ReviewerId = doctor.Id, + ReviewerLastName = doctor.LastName, + SiteId = workloadAd.SiteId, + SiteName = site.SiteName, + Status = workloadAd.Status, + ADCode = workloadAd.ADCode, + SubjectCode = subject.Code, + SubjectId = workloadAd.SubjectId, + UpdateTime = workloadAd.UpdateTime + }; + } + else + { + query = from workloadAd in _workloadAdRepository.GetAll().Where(workloadAdLambda) + join subject in _subjectRepository.GetAll().Where(subjectLambda) on workloadAd.SubjectId equals subject.Id + + join site in _siteRepository.GetAll() on workloadAd.SiteId equals site.Id + join doctor in _doctorRepository.GetAll().Where(doctorLambda) on workloadAd.ReviewerId equals doctor.Id into cc + from doctor in cc.DefaultIfEmpty() + select new WorkloadADDTO() + { + Id = workloadAd.Id, + ReviewerCode = doctor.Code, + ReviewerChineseName = doctor.ChineseName, + ReviewerFirstName = doctor.FirstName, + ReviewerId = doctor.Id, + ReviewerLastName = doctor.LastName, + SiteId = workloadAd.SiteId, + SiteName = site.SiteName, + Status = workloadAd.Status, + ADCode = workloadAd.ADCode, + SubjectCode = subject.Code, + SubjectId = workloadAd.SubjectId, + UpdateTime = workloadAd.UpdateTime + }; + + } + var count = query.Count(); + + var propName = param.SortField == string.Empty ? "ADCode" : param.SortField; + + query = param.Asc + ? query.OrderBy(propName).ThenBy(t => t.SiteName).ThenBy(t => t.SubjectCode) + : query.OrderByDescending(propName).ThenBy(t => t.SiteName).ThenBy(t => t.SubjectCode); + + query = query.Skip((param.PageIndex - 1) * param.PageSize).Take(param.PageSize); + var list = query.ToList(); + + return new PageOutput(param.PageIndex, + param.PageSize, count, list); + } + + public PageOutput GetWorkloadTPList(WorkloadDistributionQueryParam param) + { + IQueryable query = null; + Expression> workloadTPLambda = x => x.TrialId == param.TrialId; + if (param.SiteId != null) + { + workloadTPLambda = workloadTPLambda.And(t => t.SiteId == param.SiteId); + } + + if (param.Status != null) + { + workloadTPLambda = workloadTPLambda.And(t => t.Status == param.Status); + } + if (!string.IsNullOrEmpty(param.WorkloadCode)) + { + var timepoint = param.WorkloadCode.Trim(); + + workloadTPLambda = workloadTPLambda.And(t => t.TimepointCode.Contains(timepoint)); + } + if (param.GroupId != null && param.GroupId > 0) + { + var groupCode = "T0" + param.GroupId; + workloadTPLambda = workloadTPLambda.And(t => t.TimepointCode.Contains(groupCode)); + } + + Expression> subjectLambda = x => x.TrialId == param.TrialId; + if (!string.IsNullOrEmpty(param.SubjectCode)) + { + var subjectCode = param.SubjectCode.Trim(); + subjectLambda = subjectLambda.And(t => t.Code.Contains(subjectCode)); + } + Expression> doctorLambda = x => true; + if (!string.IsNullOrEmpty(param.Reviewer)) + { + var reviewer = param.Reviewer.Trim(); + doctorLambda = doctorLambda.And(t => t.ChineseName.Contains(reviewer) + || t.FirstName.Contains(reviewer) || t.LastName.Contains(reviewer)); + query = from workloadTp in _workloadTpRepository.GetAll().Where(workloadTPLambda) + join subject in _subjectRepository.GetAll().Where(subjectLambda) on workloadTp.SubjectId equals subject.Id + join subjectVisit in _subjectVisitRepository.GetAll() on workloadTp.SubjectVisitId equals subjectVisit.Id + join study in _studyRepository.GetAll() on workloadTp.StudyId equals study.Id + join site in _siteRepository.GetAll() on workloadTp.SiteId equals site.Id + join doctor in _doctorRepository.GetAll().Where(doctorLambda) on workloadTp.ReviewerId equals doctor.Id + + select new WorkloadTPDTO() + { + Id = workloadTp.Id, + ReviewerCode = doctor.Code, + ReviewerChineseName = doctor.ChineseName, + ReviewerFirstName = doctor.FirstName, + ReviewerId = doctor.Id, + ReviewerLastName = doctor.LastName, + SiteId = workloadTp.SiteId, + SiteName = site.SiteName, + Status = workloadTp.Status, + StudyCode = study.StudyCode, + StudyId = workloadTp.StudyId, + TimepointCode = workloadTp.TimepointCode, + SubjectCode = subject.Code, + SubjectVisitId = workloadTp.SubjectVisitId, + SubjectId = workloadTp.SubjectId, + VisitNum = subjectVisit.VisitNum, + VisitName = subjectVisit.VisitName, + UpdateTime = workloadTp.UpdateTime + }; + } + else + { + query = from workloadTp in _workloadTpRepository.GetAll().Where(workloadTPLambda) + join subject in _subjectRepository.GetAll().Where(subjectLambda) on workloadTp.SubjectId equals subject.Id + join subjectVisit in _subjectVisitRepository.GetAll() on workloadTp.SubjectVisitId equals subjectVisit.Id + join study in _studyRepository.GetAll() on workloadTp.StudyId equals study.Id + join site in _siteRepository.GetAll() on workloadTp.SiteId equals site.Id + join doctor in _doctorRepository.GetAll().Where(doctorLambda) on workloadTp.ReviewerId equals doctor.Id into cc + from doctor in cc.DefaultIfEmpty() + select new WorkloadTPDTO() + { + Id = workloadTp.Id, + ReviewerCode = doctor.Code, + ReviewerChineseName = doctor.ChineseName, + ReviewerFirstName = doctor.FirstName, + ReviewerId = doctor.Id, + ReviewerLastName = doctor.LastName, + SiteId = workloadTp.SiteId, + SiteName = site.SiteName, + Status = workloadTp.Status, + StudyCode = study.StudyCode, + StudyId = workloadTp.StudyId, + TimepointCode = workloadTp.TimepointCode, + SubjectCode = subject.Code, + SubjectVisitId = workloadTp.SubjectVisitId, + SubjectId = workloadTp.SubjectId, + VisitNum = subjectVisit.VisitNum, + VisitName = subjectVisit.VisitName, + UpdateTime = workloadTp.UpdateTime + }; + + } + var count = query.Count(); + + var propName = param.SortField == string.Empty ? "TimepointCode" : param.SortField; + query = param.Asc + ? query.OrderBy(propName).ThenBy(t => t.SiteName).ThenBy(t => t.SubjectCode) + : query.OrderByDescending(propName).ThenBy(t => t.SiteName).ThenBy(t => t.SubjectCode); + query = query.Skip((param.PageIndex - 1) * param.PageSize).Take(param.PageSize); + var list = query.ToList(); + + return new PageOutput(param.PageIndex, + param.PageSize, count, list); + } + + public bool UpdateDistributeAD(Guid tpId, Guid reviewerId) + { + _workloadDetailRepository.Add(new WorkloadDetail + { + WorkloadId = tpId, + OptUserName = _userInfo.RealName, + OptTime = DateTime.Now, + Status = (int)WorkloadStatus.Distributed, + ReviewerId = reviewerId + }); + _workloadDetailRepository.SaveChanges(); + return _workloadAdRepository.Update(t => t.Id == tpId, u => new WorkloadAD() + { + ReviewerId = reviewerId, + Status = (int)WorkloadStatus.Distributed + }); + } + + public IResponseOutput UpdateDistributeGlobal(Guid tpId, Guid reviewerId, Guid subjectId, decimal visitNum) + { + var temp = _workloadGlobalRepository.Find(u => u.SubjectId == subjectId && + u.VisitNum == visitNum && + u.ReviewerId == reviewerId && u.Id != tpId); + if (temp.Count() > 0) + { + return ResponseOutput.NotOk("已经有相同的Global 分配给该医生了,无法继续分配。"); + } + + _workloadDetailRepository.Add(new WorkloadDetail + { + WorkloadId = tpId, + OptUserName = _userInfo.RealName, + OptTime = DateTime.Now, + Status = (int)WorkloadStatus.Distributed, + ReviewerId = reviewerId + }); + _workloadDetailRepository.SaveChanges(); + return ResponseOutput.Result(_workloadGlobalRepository.Update(t => t.Id == tpId, u => new WorkloadGlobal() + { + ReviewerId = reviewerId, + Status = (int)WorkloadStatus.Distributed + })); + } + + public IResponseOutput UpdateDistributeTP(Guid tpId, Guid reviewerId, Guid studyId) + { + var temp = _workloadTpRepository.Find(u => u.StudyId == studyId && u.ReviewerId == reviewerId && u.Id != tpId); + if (temp.Count() > 0) + { + return ResponseOutput.NotOk("当前Study的另一个TP已经分配给该Reviewer了,无法继续分配。"); + } + + _workloadDetailRepository.Add(new WorkloadDetail + { + WorkloadId = tpId, + OptUserName = _userInfo.RealName, + OptTime = DateTime.Now, + Status = (int)WorkloadStatus.Distributed, + ReviewerId = reviewerId + }); + _workloadDetailRepository.SaveChanges(); + return ResponseOutput.Result(_workloadTpRepository.Update(t => t.Id == tpId, u => new WorkloadTP() + { + ReviewerId = reviewerId, + Status = (int)WorkloadStatus.Distributed + })); + } + + public IResponseOutput> GetWorkloadDetail(Guid WorkloadId) + { + IQueryable query = null; + query = from detail in _workloadDetailRepository.GetAll().Where(u => u.WorkloadId == WorkloadId) + join doctor in _doctorRepository.GetAll() on detail.ReviewerId equals doctor.Id into cc + from doctor in cc.DefaultIfEmpty() + select new WorkloadDetailDTO() + { + OptTime = detail.OptTime, + OptUserName = detail.OptUserName, + ReviewerChineseName = doctor.ChineseName, + ReviewerFirstName = doctor.FirstName, + ReviewerLastName = doctor.LastName, + Status = detail.Status + }; + var list = query.OrderByDescending(u => u.OptTime).ToList(); + return ResponseOutput.Ok(list); + } + + public IResponseOutput UpdateGlobalStatus(Guid globalId) + { + return ResponseOutput.Result(_workloadGlobalRepository.Update(u => u.Id == globalId, t => new WorkloadGlobal() + { + Status = 0 + })); + } + + } +} diff --git a/IRaCIS.Core.Application/ViewModels/AttachmentViewModel.cs b/IRaCIS.Core.Application/ViewModels/AttachmentViewModel.cs new file mode 100644 index 0000000..e534dd2 --- /dev/null +++ b/IRaCIS.Core.Application/ViewModels/AttachmentViewModel.cs @@ -0,0 +1,62 @@ +using System; + +namespace IRaCIS.Application.ViewModels +{ + public class AttachmentDTO + { + public Guid Id { get; set; } + public Guid DoctorId { get; set; } + public bool IsOfficial { get; set; } + public string Type { get; set; } + public string Path { get; set; } + public string FullPath => WebAppConfig.RootUrl + Path; + public string FileName { get; set; } = string.Empty; + + public DateTime? UpdateTime { get; set; } + + } + + public class ReviewerAckDTO + { + public Guid Id { get; set; } + public Guid DoctorId { get; set; } + public string Type { get; set; } + public string Path { get; set; } + public string FullPath => WebAppConfig.RootUrl + Path; + public string FileName { get; set; } = string.Empty; + } + + + public class TrialSOWPathDTO + { + public Guid TrialId { get; set; } + + public string SowName { get; set; } + public string SowPath { get; set; } + } + + public class DeleteSowPathDTO + { + public Guid TrialId { get; set; } + public string Path { get; set; } + + } + + public class UploadAgreementAttachmentDTO + { + public Guid Id { get; set; } + + public Guid DoctorId { get; set; } + public string Type { get; set; } + public string Path { get; set; } + public string FullPath => WebAppConfig.RootUrl + Path; + + public string FileName { get; set; } = string.Empty; + } + + public class AttachementCommand + { + public Guid Id { get; set; } + public string Path { get; set; } + } +} diff --git a/IRaCIS.Core.Application/ViewModels/ClinicalStudySubjects/ClinicalStudySubjects.cs b/IRaCIS.Core.Application/ViewModels/ClinicalStudySubjects/ClinicalStudySubjects.cs new file mode 100644 index 0000000..d6c8e8a --- /dev/null +++ b/IRaCIS.Core.Application/ViewModels/ClinicalStudySubjects/ClinicalStudySubjects.cs @@ -0,0 +1,51 @@ +using System; +using IRaCIS.Common.Model; + +namespace IRaCIS.Application.ViewModels +{ + public class ClinicalStudySubjectsDTO + { + public Guid Id { get; set; } + public string Code { get; set; }//患者匿名编码 + public string NameAbbreviation { get; set; } + public string Age { get; set; } + public string Sex { get; set; } + public Guid ResearchCenterId { get; set; } + public Guid VisitPlanId { get; set; } + public Guid TrialId { get; set; } + public string MedicalRecordNo { get; set; } + public int ImageCount { get; set; } + public string ImageType { get; set; } + public int State { get; set; } + public string OutReason { get; set; } + } + + public class ClinicalStudySubjectsCommand + { + public Guid Id { get; set; } + public string Code { get; set; }//患者匿名编码 + public string NameAbbreviation { get; set; } + public string Age { get; set; } + public string Sex { get; set; } + public Guid ResearchCenterId { get; set; } + public Guid TrialId { get; set; } + public string MedicalRecordNo { get; set; } + + public int State { get; set; } + public string OutReason { get; set; } + } + public class ClinicalStudySubjectsQueryModel: ClinicalStudySubjectsDTO + { + public DateTime CreateTime { get; set; } + public DateTime UpdateTime { get; set; } + public string ResearchCenterName { get; set; } + public string VisitPlanName { get; set; } + } + public class SubjectQueryParam : PageInput + { + public Guid TrialId { get; set; } = Guid.Empty; + public string Code { get; set; } = string.Empty; + public Guid VisitPlanId { get; set; } = Guid.Empty; + public int State { get; set; } = 0; + } +} diff --git a/IRaCIS.Core.Application/ViewModels/Dictionary/CROCompanyViewModel.cs b/IRaCIS.Core.Application/ViewModels/Dictionary/CROCompanyViewModel.cs new file mode 100644 index 0000000..3954e1e --- /dev/null +++ b/IRaCIS.Core.Application/ViewModels/Dictionary/CROCompanyViewModel.cs @@ -0,0 +1,29 @@ +using System; +using IRaCIS.Common.Model; + +namespace IRaCIS.Application.ViewModels +{ + public class CROCompanyDTO + { + public Guid Id { get; set; } + public string CROName { get; set; } = string.Empty; + public string CROCode { get; set; } + } + + public class CroSelectDTO + { + public Guid Id { get; set; } + public string CROName { get; set; } = string.Empty; + public string CROCode { get; set; } + } + + public class CROCompanyQueryDTO : PageInput + { + public string CROName { get; set; } = string.Empty; + } + + public class CROCompanySelectSearchDTO + { + public string CROName { get; set; } = string.Empty; + } +} \ No newline at end of file diff --git a/IRaCIS.Core.Application/ViewModels/Dictionary/DictionaryViewModel.cs b/IRaCIS.Core.Application/ViewModels/Dictionary/DictionaryViewModel.cs new file mode 100644 index 0000000..5b81781 --- /dev/null +++ b/IRaCIS.Core.Application/ViewModels/Dictionary/DictionaryViewModel.cs @@ -0,0 +1,32 @@ +using System; +using System.Collections.Generic; +using IRaCIS.Common.Model; + +namespace IRaCIS.Application.ViewModels +{ + public class DicViewModelDTO + { + public Guid Id { get; set; } + public string KeyName { get; set; } + public string Value { get; set; } + public int ShowOrder { get; set; } + public string Type { get; set; } + } + + public class DicQueryDTO : PageInput + { + public string KeyName { get; set; } + } + + public class KeyNameType + { + public Guid KeyId { get; set; } + public string KeyName { get; set; } + public string Type { get; set; } + } + + public class DicResultDTO + { + public Dictionary> DicList = new Dictionary>(); + } +} diff --git a/IRaCIS.Core.Application/ViewModels/Dictionary/HospitalViewModel.cs b/IRaCIS.Core.Application/ViewModels/Dictionary/HospitalViewModel.cs new file mode 100644 index 0000000..3afd58f --- /dev/null +++ b/IRaCIS.Core.Application/ViewModels/Dictionary/HospitalViewModel.cs @@ -0,0 +1,27 @@ +using System; +using IRaCIS.Common.Model; + +namespace IRaCIS.Application.ViewModels +{ + public class HospitalDTO : HospitalCommand + { + + } + + public class HospitalCommand + { + public Guid Id { get; set; } + public string HospitalName { get; set; } + public string UniversityAffiliated { get; set; } + public string Country { get; set; } + public string Province { get; set; } + public string City { get; set; } + } + + public class HospitalQueryDTO : PageInput + { + public string HospitalName { get; set; } = string.Empty; + public string Province { get; set; } = string.Empty; + public string City { get; set; } = string.Empty; + } +} diff --git a/IRaCIS.Core.Application/ViewModels/Dictionary/SiteViewModel.cs b/IRaCIS.Core.Application/ViewModels/Dictionary/SiteViewModel.cs new file mode 100644 index 0000000..e2f855f --- /dev/null +++ b/IRaCIS.Core.Application/ViewModels/Dictionary/SiteViewModel.cs @@ -0,0 +1,44 @@ +using System; +using IRaCIS.Common.Model; + +namespace IRaCIS.Application.ViewModels +{ + public class SiteDTO: SiteCommand + { + + } + + public class SiteCommand + { + public Guid Id { get; set; } + public string SiteName { get; set; } + public string SiteCode { get; set; } + public string City { get; set; } = string.Empty; + public string Country { get; set; } = string.Empty; + public Guid HospitalId { get; set; } + public string DirectorName { get; set; } = string.Empty; + public string DirectorPhone { get; set; } = string.Empty; + public string ContactName { get; set; } = string.Empty; + public string ContactPhone { get; set; } = string.Empty; + } + + public class SiteSelectionDTO + { + public Guid Id { get; set; } + public string SiteName { get; set; } + public string City { get; set; } + public string Country { get; set; } + } + + public class SiteSelectDTO : SiteDTO + { + public string HospitalName { get; set; } + public bool IsSelect { get; set; } + } + + public class SiteQueryParam : PageInput + { + public string SiteName { get; set; } + public Guid UserId { get; set; } = Guid.Empty; + } +} \ No newline at end of file diff --git a/IRaCIS.Core.Application/ViewModels/Dictionary/SponsorViewModel.cs b/IRaCIS.Core.Application/ViewModels/Dictionary/SponsorViewModel.cs new file mode 100644 index 0000000..4fa7ede --- /dev/null +++ b/IRaCIS.Core.Application/ViewModels/Dictionary/SponsorViewModel.cs @@ -0,0 +1,28 @@ +using System; +using IRaCIS.Common.Model; + +namespace IRaCIS.Application.ViewModels +{ + public class SponsorDTO + { + public Guid Id { get; set; } + public string SponsorName { get; set; } = string.Empty; + } + + public class SponsorCommand + { + public Guid Id { get; set; } + public string SponsorName { get; set; } = string.Empty; + } + + public class SponsorQueryDTO : PageInput + { + public string SponsorName { get; set; } = string.Empty; + } + + public class SponsorSelectDTO + { + public Guid Id { get; set; } + public string SponsorName { get; set; } = string.Empty; + } +} \ No newline at end of file diff --git a/IRaCIS.Core.Application/ViewModels/Doctor/DoctorAccountRegisterDTO.cs b/IRaCIS.Core.Application/ViewModels/Doctor/DoctorAccountRegisterDTO.cs new file mode 100644 index 0000000..aa1d2a6 --- /dev/null +++ b/IRaCIS.Core.Application/ViewModels/Doctor/DoctorAccountRegisterDTO.cs @@ -0,0 +1,12 @@ +using System; + +namespace IRaCIS.Application.ViewModels +{ + public class DoctorAccountRegisterDTO : DoctorAccountLoginDTO + { + public string FirstName { get; set; } + public string LastName { get; set; } + public string EMail { get; set; } + public DateTime RegisterTime { get; set; } + } +} \ No newline at end of file diff --git a/IRaCIS.Core.Application/ViewModels/Doctor/DoctorViewModel.cs b/IRaCIS.Core.Application/ViewModels/Doctor/DoctorViewModel.cs new file mode 100644 index 0000000..ac31732 --- /dev/null +++ b/IRaCIS.Core.Application/ViewModels/Doctor/DoctorViewModel.cs @@ -0,0 +1,440 @@ +using IRaCIS.Common.Model; +using System; +using System.Collections.Generic; + +namespace IRaCIS.Application.ViewModels +{ + + #region 医生管理列表 + + public class DoctorDTO + { + public DoctorDTO() + { + TitleList = new List(); + TitleIdList = new List(); + ReadingTypeList = new List(); + ReadingTypeIds = new List(); + SubspecialityList = new List(); + SubspecialityIds = new List(); + } + + public Guid Id { get; set; } + public DateTime? RegisterTime { get; set; } + public string Code { get; set; }//GUID + public string FirstName { get; set; } = string.Empty; + public string LastName { get; set; } = string.Empty; + public string ChineseName { get; set; } = string.Empty; + public List TitleIdList { get; set; } + public List TitleList { get; set; } + public string Phone { get; set; } = string.Empty; + public string Introduction { get; set; } = string.Empty; + public string EMail { get; set; } = string.Empty; + public string WeChat { get; set; } = string.Empty; + + //部门 + public string Department { get; set; } = string.Empty; + public Guid DepartmentId { get; set; } + public string DepartmentOther { get; set; } + + //增加的 + public Guid SpecialityId { get; set; } = Guid.Empty; + public string Speciality { get; set; } = string.Empty; + public string SpecialityOther { get; set; } = string.Empty; + + //职称 + public string Rank { get; set; } = string.Empty; + public Guid RankId { get; set; } + public string RankOther { get; set; } + + //职位 + public string Position { get; set; } = string.Empty; + public Guid PositionId { get; set; } + public string PositionOther { get; set; } + + //医院 + public string HospitalName { get; set; } = string.Empty; + public string HospitalOther { get; set; } + public Guid HospitalId { get; set; } + + //临床实践中使用的模式 + public List ReadingTypeList { get; set; } + + public List ReadingTypeIds { get; set; } + public string ReadingTypeOther { get; set; } + + //第二专业 + + public List SubspecialityList { get; set; } + public List SubspecialityIds { get; set; } + public string SubspecialityOther { get; set; } + + public int GCP { get; set; } + public Guid GCPId { get; set; } + public string ResumePath { get; set; } = string.Empty; + public bool HasResume + { + get; set; + } + public bool Reconfirmed { get; set; } + public int CooperateStatus { get; set; } + public int ResumeStatus { get; set; } + public bool AcceptingNewTrial { get; set; } = false; + public bool ActivelyReading { get; set; } = false; + public string City { get; set; } + public string Country { get; set; } + public int Reading { get; set; } + public int Approved { get; set; } + public int Submitted { get; set; } + } + + /// + /// Reviewer 列表查询参数 + /// + + public class DoctorSearchDTO : PageInput + { + public DoctorSearchDTO() + { + ReadingTypeIdList = new List(); + SubspecialityIdList = new List(); + TitleIdList = new List(); + } + public string Name { get; set; } + public List ReadingTypeIdList { get; set; } + public List SubspecialityIdList { get; set; } + public List TitleIdList { get; set; } + public Guid? DepartmentId { get; set; } = Guid.Empty; + public Guid? SpecialityId { get; set; } = Guid.Empty; + public Guid? PositionId { get; set; } = Guid.Empty; + public Guid? RankId { get; set; } = Guid.Empty; + public Guid? HospitalId { get; set; } = Guid.Empty; + + //合作状态 + public int? ContractorStatus { get; set; } + + // 简历审核状态 + public int? InformationConfirmed { get; set; } + public int? EnrollStatus { get; set; } //入组状态 + + public bool? AcceptingNewTrial { get; set; }//是否接受新的项目 + public bool? ActivelyReading { get; set; }// 是否接受新的读片任务 + } + + /// + /// 入组 Selection 列表查询参数 + /// + public class ReviewerSelectionQueryDTO : DoctorSearchDTO + { + public Guid TrialId { get; set; } = Guid.Empty; + } + + public class ReviewerSubmissionQueryDTO : PageInput + { + public Guid TrialId { get; set; } = Guid.Empty; + public int IntoGroupSearchState { get; set; } + } + + public class ReviewerConfirmationQueryDTO : PageInput + { + public Guid TrialId { get; set; } = Guid.Empty; + } + + public class SelectionReviewerDTO : DoctorDTO + { + public int DoctorTrialState { get; set; } + public string OptUserName { get; set; } = string.Empty; + public DateTime? OptTime { get; set; } + public string OptTimeStr => OptTime?.ToString("yyyy-MM-dd HH:mm:ss"); + } + + public class DoctorOptDTO + { + public Guid Id { get; set; } + public string Code { get; set; }//GUID + public string FirstName { get; set; } = string.Empty; + public string LastName { get; set; } = string.Empty; + public string ChineseName { get; set; } = string.Empty; + + public string City { get; set; } = string.Empty; + public string HospitalName { get; set; } = string.Empty; + public string Country { get; set; } = string.Empty; + } + + + public class ConfirmationReviewerDTO : DoctorOptDTO + { + public int DoctorTrialState { get; set; } + public string OptUserName { get; set; } = string.Empty; + public DateTime? OptTime { get; set; } + public string OptTimeStr => OptTime?.ToString("yyyy-MM-dd HH:mm:ss"); + } + public class DoctorStateModelDTO + { + public Guid DoctorId { get; set; } + public int IntoGroupState { get; set; } + public string OptUserName { get; set; } + public DateTime? OptTime { get; set; } + + } + + #endregion + + public class DoctorDetailDTO + { + public DoctorBasicInfoDTO BasicInfoView { get; set; } + public EmploymentDTO EmploymentView { get; set; } + public SpecialtyDTO SpecialtyView { get; set; } + public IEnumerable EducationList { get; set; } + public IEnumerable PostgraduateList { get; set; } + public ResearchPublicationDTO ResearchPublicationView { get; set; } + public TrialExperienceViewModel TrialExperienceView { get; set; } + public ResumeConfirmDTO AuditView { get; set; } + public IEnumerable AttachmentList { get; set; } + + public List SowList { get; set; } + public List AckSowList { get; set; } + + public DoctorEnrollInfoDTO IntoGroupInfo { get; set; } + + public bool InHoliday { get; set; } + public DoctorDetailDTO() + { + BasicInfoView = new DoctorBasicInfoDTO(); + EmploymentView = new EmploymentDTO(); + SpecialtyView = new SpecialtyDTO(); + EducationList = new List(); + PostgraduateList = new List(); + ResearchPublicationView = new ResearchPublicationDTO(); + TrialExperienceView = new TrialExperienceViewModel(); + AuditView = new ResumeConfirmDTO(); + AttachmentList = new List(); + IntoGroupInfo = new DoctorEnrollInfoDTO(); + SowList = new List(); + AckSowList = new List(); + } + } + + public class DoctorEnrollInfoDTO + { + public Guid DoctorId { get; set; } + public int Submitted { get; set; } + public int Approved { get; set; } + public int Reading { get; set; } + } + + + + #region 基本信息模型 + + public class DoctorBasicInfo + { + public Guid? Id { get; set; } + public string Code { get; set; } = string.Empty; + public string FirstName { get; set; } + public string LastName { get; set; } + public string ChineseName { get; set; } + public int Sex { get; set; } + public string Phone { get; set; } + public string Introduction { get; set; } + public string EMail { get; set; } + public string WeChat { get; set; } + + } + + public class DoctorBasicInfoCommand: DoctorBasicInfo + { + public DoctorBasicInfoCommand() + { + TitleIds = new List(); + } + + //职称 + public List TitleIds { get; set; } + } + + public class DoctorBasicInfoDTO : DoctorBasicInfo + { + //public Guid DoctorId { get; set; } + public DoctorBasicInfoDTO() + { + TitleList = new List(); + TitleIds = new List(); + } + //职称 + public List TitleIds { get; set; } + public List TitleList { get; set; } + } + + public class SowDTO + { + public string FileName { get; set; } + public string TrialCode { get; set; } + public string FilePath { get; set; } + public string FullPath { get { return WebAppConfig.RootUrl + FilePath; } } + public DateTime? UpdateTime { get; set; } + } + + + #endregion + + + #region 工作信息模型 + + public class EmploymentDTO : EmploymentInfo + { + public string Department { get; set; } + + public string Rank { get; set; } + + public string Position { get; set; } + + #region 医院信息 + public string HospitalName { get; set; } + + public string UniversityAffiliated { get; set; } + public string Country { get; set; } + + public string Province { get; set; } + + public string City { get; set; } + + #endregion + } + + public class EmploymentCommand : EmploymentInfo + { + + } + + public class EmploymentInfo + { + public Guid Id { get; set; } + //部门 + public Guid DepartmentId { get; set; } = Guid.Empty; + public string DepartmentOther { get; set; } + //职称 + public Guid RankId { get; set; } = Guid.Empty; + public string RankOther { get; set; } + //职位 主席 副主席 + public Guid PositionId { get; set; } = Guid.Empty; + public string PositionOther { get; set; } + + public Guid HospitalId { get; set; } = Guid.Empty; + + } + + #endregion + + #region Specialty模型 + public class SpecialtyDTO : SpecialtyCommand + { + public SpecialtyDTO() + { + ReadingTypeList = new List(); + SubspecialityList = new List(); + } + + public List ReadingTypeList { get; set; } + public List SubspecialityList { get; set; } + } + + public class SpecialtyCommand + { + public SpecialtyCommand() + { + ReadingTypeIds = new List(); + SubspecialityIds = new List(); + } + + public Guid Id { get; set; } + public string OtherSkills { get; set; } = string.Empty; + //临床实践中使用的模式 + public List ReadingTypeIds { get; set; } + public string ReadingTypeOther { get; set; } = string.Empty; + //亚专科 + public List SubspecialityIds { get; set; } + public string SubspecialityOther { get; set; } = string.Empty; + + public Guid SpecialityId { get; set; } = Guid.Empty; + public string Speciality { get; set; } = string.Empty; + public string SpecialityOther { get; set; } = string.Empty; + + //public Guid DepartmentId { get; set; } = Guid.Empty; + //public string DepartmentName { get; set; } = string.Empty; + //public string DepartmentOther { get; set; } = string.Empty; + + } + + + #endregion + + #region 医生账户 + public class DoctorAccountLoginDTO + { + public string Phone { get; set; } + public string Password { get; set; } + } + + public class DoctorAccountDTO + { + public Guid Id { get; set; } + public string FirstName { get; set; } + public string LastName { get; set; } + public string Phone { get; set; } + public string PhotoPath { get; set; } + } + + public class DoctorAccountUpdatePasswordCommand + { + public string Phone { get; set; } + public string OldPassword { get; set; } + public string NewPassword { get; set; } + } + #endregion + + #region 审核模型 + + public class ResumeConfirmCommand + { + //int userId, int doctorId, int status, string memo + //public Guid FromUserId { get; set; } + public Guid Id { get; set; } + public int ResumeStatus { get; set; } + public int ReviewStatus { get; set; } + public bool AcceptingNewTrial { get; set; } = false; + public bool ActivelyReading { get; set; } = false; + public string AdminComment { get; set; } + public string MessageContent { get; set; } + public int CooperateStatus { get; set; } + } + + public class ResumeConfirmDTO + { + public Guid Id { get; set; } + public int CooperateStatus { get; set; } + public int ResumeStatus { get; set; } + public int ReviewStatus { get; set; } //复审状态 + public bool AcceptingNewTrial { get; set; } + public bool ActivelyReading { get; set; } + public string AdminComment { get; set; } + public bool InHoliday { get; set; } + } + + #endregion + + + public class TrialPaymentPriceQueryDTO : PageInput + { + public string KeyWord { get; set; } + + public Guid CroId { get; set; } = Guid.Empty; + + } + + public class DoctorPaymentInfoQueryDTO : PageInput + { + public string SearchName { get; set; } + public Guid? HospitalId { get; set; } = Guid.Empty; + } +} diff --git a/IRaCIS.Core.Application/ViewModels/Doctor/EducationViewModel.cs b/IRaCIS.Core.Application/ViewModels/Doctor/EducationViewModel.cs new file mode 100644 index 0000000..7968dd8 --- /dev/null +++ b/IRaCIS.Core.Application/ViewModels/Doctor/EducationViewModel.cs @@ -0,0 +1,69 @@ +using System; +using System.Collections.Generic; + +namespace IRaCIS.Application.ViewModels +{ + public class EducationCommand + { + public Guid? Id { get; set; } + public Guid DoctorId { get; set; } + public DateTime BeginDate { get; set; } + public DateTime EndDate { get; set; } + public string Degree { get; set; } + public string Major { get; set; } + public string Organization { get; set; } + public string Country { get; set; } + public string Province { get; set; } + public string City { get; set; } + + } + + public class EducationInfoViewModel : EducationCommand + { + public DateTime? CreateTime { get; set; } + public string BeginDateStr => BeginDate.ToString("yyyy-MM"); + public string EndDateStr => EndDate.ToString("yyyy-MM"); + + } + public class PostgraduateCommand + { + public Guid? Id { get; set; } + public Guid DoctorId { get; set; } + + public DateTime BeginDate { get; set; } + + public DateTime EndDate { get; set; } + + public string Training { get; set; } + + public string Major { get; set; } + + public string Hospital { get; set; } + + public string School { get; set; } + + public string Country { get; set; } + + public string Province { get; set; } + + public string City { get; set; } + + + } + + + public class PostgraduateViewModel: PostgraduateCommand + { + public DateTime? CreateTime { get; set; } + public string BeginDateStr => BeginDate.ToString("yyyy-MM"); + + public string EndDateStr => EndDate.ToString("yyyy-MM"); + } + public class DoctorEducationExperienceDTO + { + public IEnumerable EducationList=new List(); + + public IEnumerable PostgraduateList = new List(); + } + +} \ No newline at end of file diff --git a/IRaCIS.Core.Application/ViewModels/Doctor/HolidayViewModel.cs b/IRaCIS.Core.Application/ViewModels/Doctor/HolidayViewModel.cs new file mode 100644 index 0000000..3a35d7b --- /dev/null +++ b/IRaCIS.Core.Application/ViewModels/Doctor/HolidayViewModel.cs @@ -0,0 +1,13 @@ +using System; + +namespace IRaCIS.Application.ViewModels +{ + public class VacationDTO + { + public Guid Id { get; set; } + public Guid DoctorId { get; set; } + public DateTime StartDate { get; set; } + public DateTime EndDate { get; set; } + public int Status { get; set; } = 1; + } +} diff --git a/IRaCIS.Core.Application/ViewModels/Doctor/ResearchPublicationViewModel.cs b/IRaCIS.Core.Application/ViewModels/Doctor/ResearchPublicationViewModel.cs new file mode 100644 index 0000000..6885758 --- /dev/null +++ b/IRaCIS.Core.Application/ViewModels/Doctor/ResearchPublicationViewModel.cs @@ -0,0 +1,14 @@ +using System; + +namespace IRaCIS.Application.ViewModels +{ + public class ResearchPublicationDTO + { + public Guid Id { get; set; } + public Guid DoctorId { get; set; } + public string Research { get; set; } + public string Grants { get; set; } + public string Publications { get; set; } + public string AwardsHonors { get; set; } + } +} \ No newline at end of file diff --git a/IRaCIS.Core.Application/ViewModels/Doctor/TrialExperienceViewModel.cs b/IRaCIS.Core.Application/ViewModels/Doctor/TrialExperienceViewModel.cs new file mode 100644 index 0000000..146fa02 --- /dev/null +++ b/IRaCIS.Core.Application/ViewModels/Doctor/TrialExperienceViewModel.cs @@ -0,0 +1,62 @@ +using System; +using System.Collections.Generic; + +namespace IRaCIS.Application.ViewModels +{ + public class TrialExperienceCommand + { + public Guid Id { get; set; } + + public Guid DoctorId { get; set; } + + public string Term { get; set; } + + public string EvaluationCriteria { get; set; } + + public string EvaluationContent { get; set; } + } + + + public class TrialExperienceViewModel: GcpAndOtherExperienceDTO + { + public List ClinicalTrialExperienceList=new List(); + + public string ExpiryDateStr { get; set; } = string.Empty; + public string GCPFullPath => WebAppConfig.RootUrl + Path; + + } + + + public class GcpAndOtherExperienceDTO + { + public Guid Id { get; set; } + + public int GCP { get; set; } + + public Guid GCPId { get; set; } + + public string OtherClinicalExperience { get; set; } + + public string Type { get; set; } = string.Empty; + + public string Path { get; set; } = string.Empty; + + public string FileName { get; set; } = string.Empty; + + } + + public class GCPExperienceCommand + { + public Guid Id { get; set; } + public int GCP { get; set; } + + public Guid GCPId { get; set; } + } + + public class ClinicalExperienceCommand + { + public Guid DoctorId { get; set; } + + public string OtherClinicalExperience { get; set; } + } +} \ No newline at end of file diff --git a/IRaCIS.Core.Application/ViewModels/FileViewModel.cs b/IRaCIS.Core.Application/ViewModels/FileViewModel.cs new file mode 100644 index 0000000..9a521bf --- /dev/null +++ b/IRaCIS.Core.Application/ViewModels/FileViewModel.cs @@ -0,0 +1,16 @@ +using System; + +namespace IRaCIS.Application.ViewModels +{ + + + public class UploadFileInfoDTO + { + public Guid Id { get; set; } + public string FilePath { get; set; } + public string FullFilePath => WebAppConfig.RootUrl + FilePath; + + } + + +} \ No newline at end of file diff --git a/IRaCIS.Core.Application/ViewModels/Image/ImageViewModel.cs b/IRaCIS.Core.Application/ViewModels/Image/ImageViewModel.cs new file mode 100644 index 0000000..22bcccc --- /dev/null +++ b/IRaCIS.Core.Application/ViewModels/Image/ImageViewModel.cs @@ -0,0 +1,41 @@ +using System; +using IRaCIS.Common.Model; + +namespace IRaCIS.Application.ViewModels +{ + public class ImageDTO + { + public Guid Id { get; set; } + public Guid TrialId { get; set; } + public string ImageNo { get; set; } = string.Empty; + public Guid StudyId { get; set; } = Guid.Empty; + public Guid? SubjectId { get; set; } = Guid.Empty; + public Guid? SiteId { get; set; } = Guid.Empty; + public Guid? VisitPointId { get; set; } = Guid.Empty; + public Guid VisitPlanId { get; set; } = Guid.Empty; + public int State { get; set; } = 1; + public DateTime StudyDate { get; set; } = DateTime.Now; + public string Modalities { get; set; } = string.Empty; + } + public class ImageCommand : ImageDTO + { + public string TrialCode { get; set; } + } + + public class ImageDetailDTO : ImageDTO + { + public string SubjectCode { get; set; }//受试者编号 + public string SiteName { get; set; } + public string MedicalRecordNo { get; set; } + public string VisitPlanName { get; set; } + public DateTime CreateTime { get; set; } + } + + public class ImageQueryDTO : PageInput + { + public Guid TrialId { get; set; } = Guid.Empty; + public string SubjectCode { get; set; } = string.Empty; + public Guid VisitPlanId { get; set; } = Guid.Empty; + public int State { get; set; } = 0; + } +} diff --git a/IRaCIS.Core.Application/ViewModels/Management/InstitutionViewModel.cs b/IRaCIS.Core.Application/ViewModels/Management/InstitutionViewModel.cs new file mode 100644 index 0000000..b56e645 --- /dev/null +++ b/IRaCIS.Core.Application/ViewModels/Management/InstitutionViewModel.cs @@ -0,0 +1,10 @@ +using System; + +namespace IRaCIS.Application.ViewModels +{ + public class InstitutionDTO + { + public Guid Id { get; set; } + public string InstitutionName { get; set; } + } +} \ No newline at end of file diff --git a/IRaCIS.Core.Application/ViewModels/Management/MenuViewModel.cs b/IRaCIS.Core.Application/ViewModels/Management/MenuViewModel.cs new file mode 100644 index 0000000..0fe07f7 --- /dev/null +++ b/IRaCIS.Core.Application/ViewModels/Management/MenuViewModel.cs @@ -0,0 +1,44 @@ +using System; +using System.Collections.Generic; + +namespace IRaCIS.Application.ViewModels +{ + public class MenuFunctionCommand : MenuFunctionDTO + { + + } + + + + public class MenuFunctionDTO + { + public Guid Id { get; set; } = Guid.Empty; + public Guid ParentId { get; set; } = Guid.Empty; + public string RouteName { get; set; } = string.Empty; + public string MenuName { get; set; } + public string Component { get; set; } = string.Empty; + public string Redirect { get; set; } = string.Empty; + public string Path { get; set; } = string.Empty; + public string MetaTitle { get; set; } = string.Empty; + public bool MetaBreadcrumb { get; set; } + public string MetaIcon { get; set; } = string.Empty; + public string MetaActiveMenu { get; set; } = string.Empty; + public string FunctionName { get; set; } = string.Empty; + public bool IsFunction { get; set; } = false; + public string Note { get; set; } = string.Empty; + public int ShowOrder { get; set; } + public int Status { get; set; } = 1; + public bool Hidden { get; set; } + //public DateTime CreateTime { get; set; } = DateTime.Now; + //public Guid CreateUserId { get; set; } = Guid.Empty; + //public DateTime UpdateTime { get; set; } = DateTime.Now; + //public Guid UpdateUserId { get; set; } = Guid.Empty; + } + + public class RoleMenuFunctionSelectDTO + { + public Guid RoleId { get; set; } + public List MenuFunctionId { get; set; } + } + +} diff --git a/IRaCIS.Core.Application/ViewModels/Management/RoleViewModel.cs b/IRaCIS.Core.Application/ViewModels/Management/RoleViewModel.cs new file mode 100644 index 0000000..4b17927 --- /dev/null +++ b/IRaCIS.Core.Application/ViewModels/Management/RoleViewModel.cs @@ -0,0 +1,30 @@ +using System; + +namespace IRaCIS.Application.ViewModels +{ + public class RoleDTO + { + public Guid Id { get; set; } = Guid.Empty; + public string RoleName { get; set; } + public string RoleDescription { get; set; } = string.Empty; + public int PrivilegeLevel { get; set; } + } + + public class UserRoleSelectDTO + { + public Guid userId { get; set; } + public Guid roleId { get; set; } + public bool isSelect { get; set; } + } + + + public class UserSelectRoleDTO : RoleDTO + { + public bool IsSelect { get; set; } + } + + public class RoleCommand : RoleDTO + { + + } +} diff --git a/IRaCIS.Core.Application/ViewModels/Management/SysUserViewModel.cs b/IRaCIS.Core.Application/ViewModels/Management/SysUserViewModel.cs new file mode 100644 index 0000000..3aa9f26 --- /dev/null +++ b/IRaCIS.Core.Application/ViewModels/Management/SysUserViewModel.cs @@ -0,0 +1,174 @@ +using System; +using System.Collections.Generic; +using IRaCIS.Common.Model; +using Newtonsoft.Json; + +namespace IRaCIS.Application.ViewModels +{ + public class UserLoginDTO + { + public string UserName { get; set; } + public string Password { get; set; } + } + + public class LoginReturnDTO + { + public UserBasicInfo BasicInfo { get; set; } = new UserBasicInfo(); + public string JWTStr { get; set; } + + public List MenuTree = new List(); + + //public List FuncTree = new List(); + + public Dictionary> FuncDictionary=new Dictionary>(); + + } + + public class UserBasicInfo + { + public Guid Id { get; set; } + public string UserName { get; set; } + public string RealName { get; set; } + public int Sex { get; set; } // 1-男 2-女 + public bool IsAdmin { get; set; } = false; + } + + public class MenuFuncTreeNodeView + { + [JsonIgnore] + public Guid Id { get; set; } + [JsonIgnore] + public Guid ParentId { get; set; } = Guid.Empty; + [JsonIgnore] + public int ShowOrder { get; set; } + public string routeName { get; set; } = string.Empty; + public string component { get; set; } = string.Empty; + public string redirect { get; set; } = string.Empty; + public string path { get; set; } = string.Empty; + public Meta meta { get; set; } + public bool hidden { get; set; } + public List Childrens { get; set; } + } + + public class Meta + { + public string MetaTitle { get; set; } = string.Empty; + public bool MetaBreadcrumb { get; set; } = false; + public string MetaIcon { get; set; } = string.Empty; + public string MetaActiveMenu { get; set; } = string.Empty; + } + + + public class FunctionTreeNodeDTO + { + [JsonIgnore] + public Guid Id { get; set; } + [JsonIgnore] + public Guid ParentId { get; set; } = Guid.Empty; + [JsonIgnore] + public int ShowOrder { get; set; } + + public string RouteName { get; set; } = string.Empty; + public string FunctionName { get; set; } = string.Empty; + + public List Childrens { get; set; } + } + + + + public class UserDetailDTO : UserInfo + { + public string UserTypeName { get; set; } + } + + public class UserInfo + { + public Guid Id { get; set; } + public string UserName { get; set; } + public string Password { get; set; } + public string RealName { get; set; } + public int Sex { get; set; } // 1-男 2-女 + + public int Status { get; set; } = 1; // 0-已删除 1-正常 + + public string Phone { get; set; } = string.Empty; + public string EMail { get; set; } = string.Empty; + public Guid UserTypeId { get; set; } = Guid.Empty; + public string OrganizationName { get; set; } = string.Empty; + public Guid OrganizationId { get; set; } + public string Code { get; set; } + + public bool IsZhiZhun { get; set; } + + public string UserType { get; set; } + public Guid OrganizationTypeId { get; set; } = Guid.Empty; + public string OrganizationType { get; set; } = String.Empty; + public string DepartmentName { get; set; } = String.Empty; + public string PositionName { get; set; } = String.Empty; + } + + /// + /// 添加用户是的返回模型 + /// + public class UserAddedReturnDTO + { + public Guid Id { get; set; } + public string Code { get; set; } + } + + //public class ResumePermission + //{ + // public bool ReviewPermission { get; set; } + // public bool EditPermission { get; set; } + // public bool ShowSow { get; set; } + //} + public class UserCommand : UserInfo + { + } + + public class EditPasswordCommand + { + public Guid UserId { get; set; } + public string NewPassWord { get; set; } + public string OldPassWord { get; set; } + } + + public class UserListQueryDTO : PageInput + { + public string UserName { get; set; } = string.Empty; + public string Phone { get; set; } = string.Empty; + public string OrganizationName { get; set; } = string.Empty; + public Guid? UserType { get; set; } = Guid.Empty; + public int? UserState { get; set; } + } + + public class UserRoleInfoDTO + { + public List RoleList { get; set; } = new List(); + public int MaxPrivilegeLevel { get; set; } + } + + public class UserListDTO : UserInfo + { + public string UserTypeName { get; set; } + public IEnumerable RoleNameList { get; set; } = new List(); + } + + + public class UserIdRoleName : RoleDTO + { + public Guid UserId { get; set; } + } + public class UserIdRoleNameList + { + public Guid UserId { get; set; } + public IEnumerable RoleList { get; set; } + } + public class ResetPasswordCommand + { + public string EmailOrPhone { get; set; } + public int VerificationType { get; set; } + public string VerificationCode { get; set; } + public string NewPwd { get; set; } + } +} diff --git a/IRaCIS.Core.Application/ViewModels/MessageViewModel.cs b/IRaCIS.Core.Application/ViewModels/MessageViewModel.cs new file mode 100644 index 0000000..34ef955 --- /dev/null +++ b/IRaCIS.Core.Application/ViewModels/MessageViewModel.cs @@ -0,0 +1,13 @@ +using IRaCIS.Common.Model; + +namespace IRaCIS.Application.ViewModels +{ + public class MessageViewModel + { + + } + + + + +} \ No newline at end of file diff --git a/IRaCIS.Core.Application/ViewModels/Pay/AwardPriceViewModel.cs b/IRaCIS.Core.Application/ViewModels/Pay/AwardPriceViewModel.cs new file mode 100644 index 0000000..e30f86d --- /dev/null +++ b/IRaCIS.Core.Application/ViewModels/Pay/AwardPriceViewModel.cs @@ -0,0 +1,37 @@ +using System; +using IRaCIS.Application.ViewModels; +using IRaCIS.Common.Model; + +namespace IRaCIS.Application.Interfaces +{ + public class AwardPriceDTO: AwardPriceCalculateDTO + { + public Guid Id { get; set; } + } + + public class AwardPriceCalculateDTO + { + public double Price { get; set; } + public int Max { get; set; } + public int Min { get; set; } + } + + public class AwardPriceCommand + { + public Guid Id { get; set; } + public double Price { get; set; } + public int Min { get; set; } + public int Max { get; set; } + public Guid OptUserId { get; set; } + } + + public class AwardPriceQueryDTO : PageInput + { + } + + public class ExchangeRateQueryDTO : PageInput + { + public DateTime? SearchMonth { get; set; } + } + +} \ No newline at end of file diff --git a/IRaCIS.Core.Application/ViewModels/Pay/CalculateViewModel.cs b/IRaCIS.Core.Application/ViewModels/Pay/CalculateViewModel.cs new file mode 100644 index 0000000..7565f32 --- /dev/null +++ b/IRaCIS.Core.Application/ViewModels/Pay/CalculateViewModel.cs @@ -0,0 +1,12 @@ +using System; + +namespace IRaCIS.Application.ViewModels +{ + public class CalculateNeededDTO + { + public Guid Id { get; set; } + public Guid DoctorId { get; set; } + public string YearMonth { get; set; } + public bool IsLock { get; set; } + } +} diff --git a/IRaCIS.Core.Application/ViewModels/Pay/ExchangeRateViewModel.cs b/IRaCIS.Core.Application/ViewModels/Pay/ExchangeRateViewModel.cs new file mode 100644 index 0000000..61a0c4d --- /dev/null +++ b/IRaCIS.Core.Application/ViewModels/Pay/ExchangeRateViewModel.cs @@ -0,0 +1,11 @@ +using System; + +namespace IRaCIS.Application.ViewModels +{ + public class ExchangeRateDTO + { + public Guid Id { get; set; } + public string YearMonth { get; set; } + public double Rate { get; set; } + } +} diff --git a/IRaCIS.Core.Application/ViewModels/Pay/PaymentAdjustmentViewModel.cs b/IRaCIS.Core.Application/ViewModels/Pay/PaymentAdjustmentViewModel.cs new file mode 100644 index 0000000..c56d9f9 --- /dev/null +++ b/IRaCIS.Core.Application/ViewModels/Pay/PaymentAdjustmentViewModel.cs @@ -0,0 +1,54 @@ +using System; +using IRaCIS.Common.Model; + +namespace IRaCIS.Application.ViewModels.Pay +{ + public class PaymentAdjustmentCommand + { + public Guid Id { get; set; } + public Guid ReviewerId { get; set; } + public DateTime AdjustedYearMonth { get; set; } + public double AdjustPaymentUSD { get; set; } + public double AdjustPaymentCNY { get; set; } + public string Note { get; set; } = string.Empty; + } + + public class PaymentAdjustmentDTO + { + public Guid Id { get; set; } + public Guid ReviewerId { get; set; } + public string YearMonth { get; set; } + public DateTime YearMonthDate { get; set; } + public bool IsLock { get; set; } + public double AdjustPaymentUSD { get; set; } + public double AdjustPaymentCNY { get; set; } + public string Note { get; set; } + } + + public class PaymentAdjustmentDetailDTO: PaymentAdjustmentDTO + { + public string ReviewerCode { get; set; } + public string FirstName { get; set; } + public string LastName { get; set; } + public string FullName => LastName + " / " + FirstName; + public string ChineseName { get; set; } + } + + public class PaymentAdjustmentQueryDTO:PageInput + { + public string TrialCode { get; set; } = string.Empty; + public string Reviewer { get; set; } = string.Empty; + public DateTime BeginDate { get; set; } = DateTime.Now; + public DateTime EndDate { get; set; } = DateTime.Now; + } + + public class DoctorSelectDTO + { + public Guid Id { get; set; } + public string Code { get; set; } = string.Empty; + public string FirstName { get; set; } + public string LastName { get; set; } + public string FullName => LastName + " / " + FirstName; + public string ChineseName { get; set; } + } +} \ No newline at end of file diff --git a/IRaCIS.Core.Application/ViewModels/Pay/PaymentDetailViewModel.cs b/IRaCIS.Core.Application/ViewModels/Pay/PaymentDetailViewModel.cs new file mode 100644 index 0000000..5504c74 --- /dev/null +++ b/IRaCIS.Core.Application/ViewModels/Pay/PaymentDetailViewModel.cs @@ -0,0 +1,190 @@ +using System; +using System.Collections.Generic; +using IRaCIS.Common.Model; + +namespace IRaCIS.Application.ViewModels.Pay +{ + public class PaymentDetailDTO + { + public Guid Id { get; set; } + public Guid PaymentId { get; set; } + public string YearMonth { get; set; } + public Guid DoctorId { get; set; } + public Guid TrialId { get; set; } + public string TrialCode { get; set; } + public string PaymentType { get; set; } + public int Count { get; set; } + public double BasePrice { get; set; } + public double PersonalAdditional { get; set; } + public double TrialAdditional { get; set; } + public int ShowTypeOrder { get; set; } + public int ShowCodeOrder { get; set; } + + public double ExchangeRate { get; set; } + + public double PaymentUSD { get; set; } + public double PaymentCNY { get; set; } + + public double TotalUnitPrice => Math.Round(BasePrice + PersonalAdditional + TrialAdditional, 2, MidpointRounding.AwayFromZero); + + public AdjustmentDTO AdjustmentView { get; set; } + + } + + public class AdjustmentDTO + { + public double AdjustPaymentUSD { get; set; } + + public double AdjustPaymentCNY { get; set; } + + public DateTime? ErrorYearMonth { get; set; } + public string AdjustType + { + get + { + if (AdjustPaymentUSD > 0) + { + return "+"; + } + else if (AdjustPaymentUSD < 0) + { + return "-"; + } + else { return string.Empty; } + } + } + public string Note { get; set; } + } + + + public class PaymentDetailCommand : PaymentDetailDTO + { + + } + + public class PayDetailDTO + { + public IEnumerable DetailList = new List(); + public DoctorPayInfo DoctorInfo { get; set; } = new DoctorPayInfo(); + } + + public class LockPaymentDTO + { + public List ReviewerIdList { get; set; } + public DateTime Month { get; set; } + } + + public class DoctorPayInfo + { + public Guid DoctorId { get; set; } + public string DoctorChineseName { get; set; } + public string FirstName { get; set; } + public string LastName { get; set; } + public string Phone { get; set; } + public string PayTitle { get; set; } + public string Code { get; set; } + } + + public class ReviewerPaymentUSD + { + public Guid RecordId { get; set; } + public Guid DoctorId { get; set; } + public double PaymentUSD { get; set; } + } + + public class PaymentQueryDTO : PageInput + { + public string Reviewer { get; set; } + public DateTime BeginMonth { get; set; } + public DateTime EndMonth { get; set; } + } + public class MonthlyPaymentDTO + { + public Guid ReviewerId { get; set; } + public string ReviewerCode { get; set; } + public string ChineseName { get; set; } + public string FirstName { get; set; } + public string LastName { get; set; } + + public double AdjustmentUSD { get; set; } + public double AdjustmentCNY { get; set; } + public double PaymentUSD { get; set; } + public double PaymentCNY { get; set; } + + public double TotalUSD => AdjustmentUSD + PaymentUSD; + public double TotalCNY => AdjustmentCNY + PaymentCNY; + + } + + public class VolumeStatisticsDTO + { + public Guid StatisticsId { get; set; } + public string Month { get; set; } + public double VolumeReward { get; set; } + public double ExchangeRate { get; set; } + + public double AdjustmentUSD { get; set; } + public double AdjustmentCNY { get; set; } + public double PaymentUSD { get; set; } + public double PaymentCNY { get; set; } + public double TotalCNY => AdjustmentCNY + PaymentCNY; + public double TotalUSD => AdjustmentUSD + PaymentUSD; + + public List TrialPaymentList = new List(); + } + + public class TrialPaymentDTO + { + public Guid TrialId { get; set; } + public string TrialCode { get; set; } + public double TrialPayment { get; set; } + + } + public class VolumeQueryDTO + { + public DateTime BeginMonth { get; set; } + public DateTime EndMonth { get; set; } + public Guid ReviewerId { get; set; } + } + + public class RevenuesDTO + { + public List MissingTrialCodes = new List(); + public Guid Id { get; set; } + public string TrialCode { get; set; } + public Guid TrialId { get; set; } + public string Indication { get; set; } + public Guid CroId { get; set; } + public string Cro { get; set; } = string.Empty; + + public int Expedited { get; set; } + public string ChineseName { get; set; } = string.Empty; + + public string FirstName { get; set; } = string.Empty; + public string LastName { get; set; } = string.Empty; + public string ReviewerCode { get; set; } = string.Empty; + + public double Training { get; set; } + public double Downtime { get; set; } + public double Timepoint { get; set; } + public double TimepointIn24H { get; set; } + public double TimepointIn48H { get; set; } + public double Adjudication { get; set; } + public double AdjudicationIn24H { get; set; } + public double AdjudicationIn48H { get; set; } + public double Global { get; set; } + public double Total + { + get + { + return Training + Downtime + Timepoint + TimepointIn24H + +TimepointIn48H + Adjudication + AdjudicationIn24H + AdjudicationIn48H ++ Global; + } + } + + public string YearMonth { get; set; } + } + + +} \ No newline at end of file diff --git a/IRaCIS.Core.Application/ViewModels/Pay/PaymentViewModel.cs b/IRaCIS.Core.Application/ViewModels/Pay/PaymentViewModel.cs new file mode 100644 index 0000000..c809996 --- /dev/null +++ b/IRaCIS.Core.Application/ViewModels/Pay/PaymentViewModel.cs @@ -0,0 +1,138 @@ +using IRaCIS.Common.Model; +using System; +using System.Collections.Generic; + +namespace IRaCIS.Application.ViewModels +{ + public class PaymentDTO + { + public PageOutput CostList { get; set; } + public double ExchangeRate { get; set; } + } + public class PaymentViewModel + { + public Guid Id { get; set; } + public string RankName { get; set; } + public Guid DoctorId { get; set; } + public string YearMonth { get; set; } + public DateTime YearMonthDate { get; set; } + public DateTime? CalculateTime { get; set; } + public string CalculateUser { get; set; } + + //额外信息 + public string Code { get; set; } + public string FirstName { get; set; } + public string LastName { get; set; } + + public string ChineseName { get; set; } + public string Phone { get; set; } + public string DoctorNameInBank { get; set; } + public string IDCard { get; set; } + public string BankCardNumber { get; set; } + public string BankName { get; set; } + + public bool IsLock { get; set; } = false; + + public double ExchangeRate { get; set; } + + public double PaymentCNY { get; set; } + + public double AdjustPaymentCNY { get; set; } + public double TotalPaymentCNY => AdjustPaymentCNY + PaymentCNY; + public double PaymentUSD { get; set; } + + public double AdjustPaymentUSD { get; set; } + public double TotalPaymentUSD => AdjustPaymentUSD + PaymentUSD; + } + + public class PaymentCommand + { + public Guid Id { get; set; } + public Guid DoctorId { get; set; } + public string YearMonth => new DateTime(Year, Month, 1).ToString("yyyy-MM"); + public int Year { get; set; } + public int Month { get; set; } + public double PaymentUSD { get; set; } + public DateTime CalculateTime { get; set; } + public double PaymentCNY { get; set; } + public double ExchangeRate { get; set; } + public string CalculateUser { get; set; } + } + + public class MonthlyPaymentQueryDTO : PageInput + { + public DateTime StatisticsDate { get; set; } + public string KeyWord { get; set; } + } + + + public class TrialAnalysisDTO + { + public Guid TrialId { get; set; } + public string Indication { get; set; } + + public string TrialCode { get; set; } + public string Cro { get; set; } = string.Empty; + + public int Expedited { get; set; } + + public string Type { get; set; } + + public double PaymentUSD { get; set; } + public double RevenusUSD { get; set; } + public double GrossProfit => RevenusUSD - PaymentUSD; + public double GrossProfitMargin + { + get { + if (RevenusUSD == 0) + return 0; + else + { + return GrossProfit / RevenusUSD; + } + } + } + + } + + public class ReviewerAnalysisDTO + { + public List MissingTrialCodes = new List(); + public string ChineseName { get; set; } + public string FirstName { get; set; } + public string LastName { get; set; } + + public Guid ReviewerId { get; set; } + public string ReviewerCode { get; set; } + + public double PaymentUSD { get; set; } + public double RevenusUSD { get; set; } + public double GrossProfit => RevenusUSD - PaymentUSD; + + public double GrossProfitMargin + { + get { + if (RevenusUSD == 0) + return 0; + else + { + return GrossProfit / RevenusUSD; + } + } + } + } + public class AnalysisQueryDTO + { + public string Reviewer { get; set; } + public DateTime BeginDate { get; set; } + public DateTime EndDate { get; set; } + } + + public class TrialAnalysisQueryDTO + { + public Guid? CroId { get; set; } + public string TrialCode { get; set; } + public DateTime BeginDate { get; set; } + public DateTime EndDate { get; set; } + } +} \ No newline at end of file diff --git a/IRaCIS.Core.Application/ViewModels/Pay/RankPriceViewModel.cs b/IRaCIS.Core.Application/ViewModels/Pay/RankPriceViewModel.cs new file mode 100644 index 0000000..6f7df2c --- /dev/null +++ b/IRaCIS.Core.Application/ViewModels/Pay/RankPriceViewModel.cs @@ -0,0 +1,45 @@ +using System; +using IRaCIS.Common.Model; + +namespace IRaCIS.Application.ViewModels +{ + public class RankPriceDTO + { + public Guid Id { get; set; } + public string RankName { get; set; } + public double Timepoint { get; set; } + public double TimepointIn24H { get; set; } + public double TimepointIn48H { get; set; } + public double Adjudication { get; set; } + public double AdjudicationIn24H { get; set; } + public double AdjudicationIn48H { get; set; } + public double Global { get; set; } + public double Training { get; set; } + public double Downtime { get; set; } + public int ShowOrder { get; set; } + } + + public class RankDic + { + public Guid Id { get; set; } + public string RankName { get; set; } + } + + public class RankPriceCOmmand + { + public Guid Id { get; set; } + public string RankName { get; set; } + public double Timepoint { get; set; } + public double TimepointIn24H { get; set; } + public double TimepointIn48H { get; set; } + public double Adjudication { get; set; } + public double AdjudicationIn24H { get; set; } + public double AdjudicationIn48H { get; set; } + public double Global { get; set; } + public double Training { get; set; } + public double Downtime { get; set; } + } + public class RankPriceQueryDTO : PageInput + { + } +} \ No newline at end of file diff --git a/IRaCIS.Core.Application/ViewModels/Pay/ReviewerPayInfoViewModel.cs b/IRaCIS.Core.Application/ViewModels/Pay/ReviewerPayInfoViewModel.cs new file mode 100644 index 0000000..a554698 --- /dev/null +++ b/IRaCIS.Core.Application/ViewModels/Pay/ReviewerPayInfoViewModel.cs @@ -0,0 +1,40 @@ +using System; + +namespace IRaCIS.Application.ViewModels +{ + public class ReviewerPayInfoQueryDTO + { + public Guid DoctorId { get; set; } + public string FirstName { get; set; } + public string LastName { get; set; } + public string ChineseName { get; set; } + public string Code { get; set; } + public string Phone { get; set; } + public string DoctorNameInBank { get; set; } + public string IDCard { get; set; } + public string BankCardNumber { get; set; } + public string BankName { get; set; } + public Guid? RankId { get; set; } + public double? Additional { get; set; } + public DateTime? CreateTime { get; set; } + } + + public class DoctorPayInfoQueryListDTO : ReviewerPayInfoQueryDTO + { + public string Hospital { get; set; } + public string RankName { get; set; } + } + + public class ReviewerPayInfoCommand + { + //public Guid Id { get; set; } + public Guid DoctorId { get; set; } + public string DoctorNameInBank { get; set; } + public string IDCard { get; set; } + public string BankCardNumber { get; set; } + public string BankName { get; set; } + public Guid RankId { get; set; } + public double Additional { get; set; } + } +} + diff --git a/IRaCIS.Core.Application/ViewModels/Pay/TrialPaymentPriceViewModel.cs b/IRaCIS.Core.Application/ViewModels/Pay/TrialPaymentPriceViewModel.cs new file mode 100644 index 0000000..232d2b9 --- /dev/null +++ b/IRaCIS.Core.Application/ViewModels/Pay/TrialPaymentPriceViewModel.cs @@ -0,0 +1,28 @@ +using System; + +namespace IRaCIS.Application.ViewModels +{ + public class TrialPaymentPriceDTO + { + public Guid TrialId { get; set; } + public string TrialCode { get; set; } + public string Indication { get; set; } + public string Cro { get; set; } + public int Expedited { get; set; } + public double? TrialAdditional { get; set; } + public DateTime? CreateTime { get; set; } + public string SowName { get; set; } + public string SowPath { get; set; } + public string SowFullPath => WebAppConfig.RootUrl + SowPath; + } + + public class TrialPaymentPriceCommand + { + //public Guid Id { get; set; } + public Guid TrialId { get; set; } + public double TrialAdditional { get; set; } + + //public string SowName { get; set; } + //public string SowPath { get; set; } + } +} diff --git a/IRaCIS.Core.Application/ViewModels/StatisticsViewModel.cs b/IRaCIS.Core.Application/ViewModels/StatisticsViewModel.cs new file mode 100644 index 0000000..cca33df --- /dev/null +++ b/IRaCIS.Core.Application/ViewModels/StatisticsViewModel.cs @@ -0,0 +1,223 @@ +using System; +using System.Collections.Generic; +using IRaCIS.Common.Model; + +namespace IRaCIS.Application.ViewModels +{ + + public class EnrollStatByReviewerDTO + { + public Guid Id { get; set; } + public string Hospital { get; set; } + public string ChineseName { get; set; } = string.Empty; + + public string FirstName { get; set; } = string.Empty; + public string LastName { get; set; } = string.Empty; + public string ReviewerCode { get; set; } = string.Empty; + + public int Pending { get; set; } + public int Approved { get; set; } + public int Reading { get; set; } + public int Finished { get; set; } + public int Total { get { return Pending + Approved + Reading + Finished; } } + public double EntryRate + { + get + { + if (Total == 0) + { + return 0; + } + return Math.Round(((Reading + Finished) / (double)Total) * 100, 1, MidpointRounding.AwayFromZero); + ; + } + } + + } + + + public class EnrollStatByTrialDTO + { + public string TrialCode { get; set; } + public Guid TrialId { get; set; } + public string Indication { get; set; } + //public Guid CroId { get; set; } + public string Cro { get; set; } = string.Empty; + + public int EnrollCount { get; set; } + + public List ReviewerNameCNList=new List(); + + public List ReviewerNameList=new List(); + } + + + #region 统计 20200413 add by dingke + public class WorkloadByTrialAndReviewerDTO + { + public Guid Id { get; set; } + public string TrialCode { get; set; } + public Guid TrialId { get; set; } + public string Indication { get; set; } + public Guid CroId { get; set; } + public string Cro { get; set; } = string.Empty; + public string ChineseName { get; set; } = string.Empty; + + public string FirstName { get; set; } = string.Empty; + public string LastName { get; set; } = string.Empty; + public string ReviewerCode { get; set; } = string.Empty; + + public int Training { get; set; } + public int Downtime { get; set; } + public int Timepoint { get; set; } + public int TimepointIn24H { get; set; } + public int TimepointIn48H { get; set; } + public int Adjudication { get; set; } + public int AdjudicationIn24H { get; set; } + public int AdjudicationIn48H { get; set; } + public int Global { get; set; } + + public int PersonalTotal => Timepoint + TimepointIn24H + TimepointIn48H + Adjudication + AdjudicationIn24H + + AdjudicationIn48H + Global; + } + + + public class StatisticsQueryDTO : PageInput + { + public Guid? CroId { get; set; } = Guid.Empty; + public string TrialCode { get; set; } = string.Empty; + public string Reviewer { get; set; } = string.Empty; + public DateTime BeginDate { get; set; } = DateTime.Now; + public DateTime EndDate { get; set; } = DateTime.Now; + public int StatType { get; set; } + + } + + public class RevenuesStatQueryDTO : PageInput + { + public Guid CroId { get; set; } = Guid.Empty; + + public string Reviewer { get; set; } = string.Empty; + public string TrialCode { get; set; } = string.Empty; + public DateTime BeginDate { get; set; } = DateTime.Now; + public DateTime EndDate { get; set; } = DateTime.Now; + + public int StatType { get; set; } + } + + + public class EnrollStatByReviewerQueryDTO : PageInput + { + public Guid? HospitalId { get; set; } = Guid.Empty; + public string Reviewer { get; set; } = string.Empty; + public DateTime BeginDate { get; set; } = DateTime.Now; + public DateTime EndDate { get; set; } = DateTime.Now; + } + + + public class EnrollStatByTrialQueryDTO : PageInput + { + public string TrialCode { get; set; } + + public string Indication { get; set; } + public DateTime? BeginDate { get; set; } = DateTime.Now; + public DateTime? EndDate { get; set; } = DateTime.Now; + + public Guid? CROId { get; set; } + + public int? Expedited { get; set; } + } + #endregion + + #region dashbord + + /// + /// 读片数量分类统计 + /// + public class ReadingDataDTO + { + public int Timepoint { get; set; } + public int Adjudication { get; set; } + public int Global { get; set; } + } + + public class ReadingDataMonthDTO : ReadingDataDTO + { + public string Month { get; set; } + } + + public class ReadingDataRankDTO : ReadingDataDTO + { + public int TotalReadingCount { get; set; } + public Guid ReviewerId { get; set; } + public string ReviewerCode { get; set; } + public string FirstName { get; set; } + public string LastName { get; set; } + public string ChineseName { get; set; } + } + + public class RankReviewersDTO + { + public Guid RankId { get; set; } + public string RankName { get; set; } + public string RankNameAbbreviation + { + get + { + var arr = RankName.Split(' '); + return arr[0]; + } + } + public int ReviewerCount { get; set; } + } + + public class EnrollDataDTO + { + public int Year { get; set; } + public int Month { get; set; } + public string QuarterStr => Year + "-Q" + (Month / 3 + (Month % 3 == 0 ? 0 : 1)); + public string YearMonth => new DateTime(Year, Month, 1).ToString("yyyy-MM"); + public int EnrollCount { get; set; } + } + + + public class EnrollQuartDataDTO + { + //public int Year { get; set; } + + public string ViewStr { get; set; } + + public int EnrollCount { get; set; } + } + + public class LatestWorkLoadDTO : ReadingDataDTO + { + public int TotalReadingCount => Timepoint + Adjudication + Global; + public Guid ReviewerId { get; set; } + public string ReviewerCode { get; set; } + public string FirstName { get; set; } + public string LastName { get; set; } + public string ChineseName { get; set; } + public string TrialCode { get; set; } + } + + + + + public class TrialDataRankDTO + { + public Guid ReviewerId { get; set; } + public string ReviewerCode { get; set; } + public string FirstName { get; set; } + public string LastName { get; set; } + public string ChineseName { get; set; } + + public int TrialCount { get; set; } + } + + #endregion + + + + +} diff --git a/IRaCIS.Core.Application/ViewModels/SysMessageViewModel.cs b/IRaCIS.Core.Application/ViewModels/SysMessageViewModel.cs new file mode 100644 index 0000000..0e74ed2 --- /dev/null +++ b/IRaCIS.Core.Application/ViewModels/SysMessageViewModel.cs @@ -0,0 +1,16 @@ +using System; + +namespace IRaCIS.Application.ViewModels +{ + public class SysMessageDTO + { + public int Id { get; set; } + public int ToDoctorId { get; set; } + public int FromUserId { get; set; } + public string Title { get; set; } = string.Empty; + public string Content { get; set; } = string.Empty; + public string MessageTime { get; set; } + public bool HasRead { get; set; } + public string Memo { get; set; } = string.Empty; + } +} diff --git a/IRaCIS.Core.Application/ViewModels/SystemLog.cs b/IRaCIS.Core.Application/ViewModels/SystemLog.cs new file mode 100644 index 0000000..658b2f8 --- /dev/null +++ b/IRaCIS.Core.Application/ViewModels/SystemLog.cs @@ -0,0 +1,24 @@ +using System; +using IRaCIS.Common.Model; + +namespace IRaCIS.Application.ViewModels +{ + public class SystemLogDTO + { + public Guid Id { get; set; } + public string LogCategory { get; set; } = string.Empty; + public string LogTitle { get; set; } = string.Empty; + public string LogContent { get; set; } = string.Empty; + public Guid OptUserId { get; set; } = Guid.Empty; + public string OptUserName { get; set; } = string.Empty; + public DateTime OptTime { get; set; } = DateTime.Now; + } + + public class QueryLogQueryDTO : PageInput + { + public string Keyword { get; set; } = string.Empty; + public string LogCategory { get; set; } = string.Empty; + public DateTime BeginTime { get; set; } = DateTime.Now; + public DateTime EndTime { get; set; } = DateTime.Now; + } +} diff --git a/IRaCIS.Core.Application/ViewModels/TreeNode.cs b/IRaCIS.Core.Application/ViewModels/TreeNode.cs new file mode 100644 index 0000000..c8f0b22 --- /dev/null +++ b/IRaCIS.Core.Application/ViewModels/TreeNode.cs @@ -0,0 +1,67 @@ +using System; +using System.Collections.Generic; + +namespace IRaCIS.Application.ViewModels +{ + + public class DictionaryTreeNode + { + public Guid Id { get; set; } + public string KeyName { get; set; } = string.Empty; + public string Type { get; set; } + public List Children { get; set; } + } + + public class MenuTreeNodeSelect + { + public Guid Id { get; set; } + public Guid ParentId { get; set; } + public string RouteName { get; set; } + public string MenuName { get; set; } + //public string Component { get; set; } + //public string Redirect { get; set; } + //public string Path { get; set; } + //public string MetaTitle { get; set; } + //public bool MetaBreadcrumb { get; set; } + //public string MetaIcon { get; set; } + //public string MetaActiveMenu { get; set; } + public string FunctionName { get; set; } + //public bool IsFunction { get; set; } + public string Note { get; set; } + public int ShowOrder { get; set; } + //public int Status { get; set; } + //public DateTime CreateTime { get; set; } + //public Guid CreateUserId { get; set; } + //public DateTime UpdateTime { get; set; } + //public Guid UpdateUserId { get; set; } + //public bool Hidden { get; set; } + public List Children { get; set; } + public bool IsSelect { get; set; } = false; + } + public class MenuTreeNode + { + public Guid Id { get; set; } + public Guid ParentId { get; set; } + public string RouteName { get; set; } + public string MenuName { get; set; } + public string Component { get; set; } + public string Redirect { get; set; } + public string Path { get; set; } + public string MetaTitle { get; set; } + public bool MetaBreadcrumb { get; set; } + public string MetaIcon { get; set; } + public string MetaActiveMenu { get; set; } + public string FunctionName { get; set; } + public bool IsFunction { get; set; } + public string Note { get; set; } + public int ShowOrder { get; set; } + public int Status { get; set; } + public DateTime CreateTime { get; set; } + public Guid CreateUserId { get; set; } + public DateTime UpdateTime { get; set; } + public Guid UpdateUserId { get; set; } + public bool Hidden { get; set; } + public List Children { get; set; } + } + +} \ No newline at end of file diff --git a/IRaCIS.Core.Application/ViewModels/Trial/DoctorWorkLoadViewModel.cs b/IRaCIS.Core.Application/ViewModels/Trial/DoctorWorkLoadViewModel.cs new file mode 100644 index 0000000..4ddfe15 --- /dev/null +++ b/IRaCIS.Core.Application/ViewModels/Trial/DoctorWorkLoadViewModel.cs @@ -0,0 +1,225 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.Linq; +using IRaCIS.Common.Model; + +namespace IRaCIS.Application.ViewModels +{ + /// + ///后台 工作量审核视图模型 + /// + public class WorkLoadDetailDTO : WorkloadDTO + { + public DateTime DeclareTime { get; set; } + public string ChineseName { get; set; } + + public string FirstName { get; set; } + public string LastName { get; set; } + public string Code { get; set; } + public string Indication { get; set; } + public int RowIntId { get; set; } + public Guid RowGuid { get; set; } + public string YearMonthStr { get; set; } + + public string WorkTimeStr => YearMonthStr; + + public bool IsLock { get; set; } = false; + } + + public class WorkLoadDetailViewModel : WorkloadDTO + { + public DateTime DeclareTime { get; set; } + public string ChineseName { get; set; } + public string FirstName { get; set; } + public string LastName { get; set; } + public string Code { get; set; } + public string Indication { get; set; } + + public Guid RowGuid { get; set; } + public string YearMonthStr { get; set; } + public string DeclareTimeStr => DeclareTime.ToString("yyyy-MM-dd"); + + public string WorkTimeStr => WorkTime.ToString("yyyy-MM-dd"); + } + + + + public class CalculatePaymentDTO : WorkloadDTO + { + public string TrialCode { get; set; } + public double? TrialAdditional { get; set; } + //public double RankPrice { get; set; } + public double PersonalAdditional { get; set; } + public double TimepointPrice { get; set; } + public double TimepointIn24HPrice { get; set; } + public double TimepointIn48HPrice { get; set; } + public double AdjudicationPrice { get; set; } + public double AdjudicationIn24HPrice { get; set; } + public double AdjudicationIn48HPrice { get; set; } + public double GlobalPrice { get; set; } + public double TrainingPrice { get; set; } + public double DowntimePrice { get; set; } + } + + /// + /// 工作量审核数据库查询模型 + /// + public class WorkloadDTO + { + public Guid? Id { get; set; } + + public Guid TrialId { get; set; } + + public Guid DoctorId { get; set; } + + public int DataFrom { get; set; } + + public DateTime WorkTime { get; set; } + + public int Training { get; set; } + + public int Downtime { get; set; } + + public int Timepoint { get; set; } + + public int TimepointIn24H { get; set; } + + public int TimepointIn48H { get; set; } + + public int Adjudication { get; set; } + + public int AdjudicationIn24H { get; set; } + + public int AdjudicationIn48H { get; set; } + + public int Global { get; set; } + + + + } + + /// + /// 工作量分页列表模型 医生端查询模型 + /// + public class WorkLoadQueryDTO : PageInput + { + public Guid TrialId { get; set; } + public int WorkLoadFromStatus { get; set; } // 关联枚举 + public DateTime? SearchBeginDateTime { get; set; } + public DateTime? SearchEndDateTime { get; set; } + } + + /// + /// 后台查询模型 + /// + public class WorkLoadStatsQueryDTO : PageInput + { + public Guid? TrialId { get; set; } + public Guid? DoctorId { get; set; } = Guid.Empty; + public List WorkLoadFromStatus { get; set; } = new List(); // 关联枚举 + public DateTime? SearchBeginDateTime { get; set; } + public DateTime? SearchEndDateTime { get; set; } + } + + + public class WorkLoadDetailQueryDTO + { + public Guid TrialId { get; set; } = Guid.Empty; + public Guid DoctorId { get; set; } = Guid.Empty; + public string YearMonthStr { get; set; } + } + + public class CalculateDoctorAndMonthDTO + { + [Required(ErrorMessage = "需要有效的时间")] + public DateTime CalculateMonth { get; set; } + + [Required(ErrorMessage = "需要有效的医生列表")] + public List NeedCalculateReviewers { get; set; } + } + + public class WorkLoadDoctorQueryDTO : PageInput + { + public Guid TrialId { get; set; } = Guid.Empty; + } + + public class WorkLoadCommand : WorkloadDTO + { + public Guid CreateUserId { get; set; } + public int CreateUserType { get; set; } + public Guid UpdateUserId { get; set; } + } + + + public class ExistWorkloadViewModel + { + public bool IsExist { get; set; } + public WorkloadDTO WorkLoad { get; set; } + } + + public class WorkloadCommand : WorkloadDTO + { + } + + public class WorkloadExistQueryDTO + { + public Guid TrialId { get; set; } + public Guid DoctorId { get; set; } + public DateTime WorkDate { get; set; } + } + + + + public class WorkLoadAndTrainingDTO + { + + public Guid DoctorId { get; set; }/*=Guid.Empty;*/ + public string Code { get; set; } + public string FirstName { get; set; } + public string LastName { get; set; } + public string ChineseName { get; set; } + + public DateTime? EnrollTime { get; set; } + + public string EnrollTimeStr => EnrollTime?.ToString("yyyy-MM-dd HH:mm:ss"); + + public DateTime? UpdateTime { get; set; } + + public string UpdateTimeStr => UpdateTime?.ToString("yyyy-MM-dd HH:mm:ss"); + + public int TrainingTimes { get; set; } + public int Downtime { get; set; } + + //读片点 + public int Timepoint { get; set; } + public int TimepointIn24H { get; set; } + public int TimepointIn48H { get; set; } + + //裁判阅片 + public int Adjudication { get; set; } + public int AdjudicationIn24H { get; set; } + public int AdjudicationIn48H { get; set; } + + //全局阅片 + public int Global { get; set; } + + + + } + + + public class WorkLoadAndAgreementDTO : WorkLoadAndTrainingDTO + { + public Guid AgreementId { get; set; } + + public string AgreementPath { get; set; } + + public string AgreementFileName => AgreementPath?.Split('/').Last(); + + public string AgreementFullPath => WebAppConfig.RootUrl + AgreementPath; + } + + + +} \ No newline at end of file diff --git a/IRaCIS.Core.Application/ViewModels/Trial/ImageAcquisitionSpecificationViewModel.cs b/IRaCIS.Core.Application/ViewModels/Trial/ImageAcquisitionSpecificationViewModel.cs new file mode 100644 index 0000000..27acff7 --- /dev/null +++ b/IRaCIS.Core.Application/ViewModels/Trial/ImageAcquisitionSpecificationViewModel.cs @@ -0,0 +1,42 @@ +using System; +using IRaCIS.Common.Model; + +namespace IRaCIS.Application.ViewModels +{ + /// + /// 影像采集规范 + /// + public class ImageAcquisitionSpecificationDTO + { + public Guid Id { get; set; } + public Guid TrialId { get; set; } + public Guid DeviceTypeId { get; set; } + public string LayerThickness { get; set; } + public string AcquisitionPeriod { get; set; } + public int SeriesCount { get; set; } + public string SeriesDescription { get; set; } + public string DeviceParam { get; set; } + public string DocCode { get; set; } + public string DocName { get; set; } + public string DocPath { get; set; } + public string DocFullPath + { + get { return WebAppConfig.RootUrl + DocPath; } + } + public DateTime CreateTime { get; set; } + + } + + public class ImageAcquisitionSpecificationDetailDTO : ImageAcquisitionSpecificationDTO + { + public string TrialCode { get; set; } + public string TrialName { get; set; } + public string Preparer { get; set; } + public string DeviceTypeName { get; set; } + } + + public class ImageAcquisitionSpecificationQueryDTO : PageInput + { + public Guid TrialId { get; set; } + } +} diff --git a/IRaCIS.Core.Application/ViewModels/Trial/TrialInterViewViewModel.cs b/IRaCIS.Core.Application/ViewModels/Trial/TrialInterViewViewModel.cs new file mode 100644 index 0000000..95867a0 --- /dev/null +++ b/IRaCIS.Core.Application/ViewModels/Trial/TrialInterViewViewModel.cs @@ -0,0 +1,21 @@ +using System; +using IRaCIS.Common.Model; + +namespace IRaCIS.Application.ViewModels +{ + public class TrialInterviewDTO + { + public Guid Id { get; set; } + public Guid TrialId { get; set; } + public string Stage { get; set; } + public string InterViewTime { get; set; } + public string Description { get; set; } + public DateTime CreateTime { get; set; } + } + + public class InterviewQueryDTO : PageInput + { + public Guid TrialId { get; set; } = Guid.Empty; + public string Keyword { get; set; } = string.Empty; + } +} diff --git a/IRaCIS.Core.Application/ViewModels/Trial/TrialResearchCenter.cs b/IRaCIS.Core.Application/ViewModels/Trial/TrialResearchCenter.cs new file mode 100644 index 0000000..cc8072c --- /dev/null +++ b/IRaCIS.Core.Application/ViewModels/Trial/TrialResearchCenter.cs @@ -0,0 +1,28 @@ +using System; +using IRaCIS.Common.Model; + +namespace IRaCIS.Application.ViewModels +{ + public class TrialResearchCenterDTO + { + public Guid Id { get; set; } + public Guid TrialId { get; set; } + public Guid ResearchCenterId { get; set; } + public string MainCenter { get; set; } + public DateTime OptTime { get; set; } + public int State { get; set; } + } + + public class TrialResearchCenterDetailDTO : TrialResearchCenterDTO + { + public string TrialCode { get; set; } + public string TrialName { get; set; } + public string ResearchCenterName { get; set; } + } + + public class TrialCenterQueryDTO : PageInput + { + public Guid TrialId { get; set; } + public Guid CenterId { get; set; } + } +} diff --git a/IRaCIS.Core.Application/ViewModels/Trial/TrialRevenuesPriceViewModel.cs b/IRaCIS.Core.Application/ViewModels/Trial/TrialRevenuesPriceViewModel.cs new file mode 100644 index 0000000..f6ca3b9 --- /dev/null +++ b/IRaCIS.Core.Application/ViewModels/Trial/TrialRevenuesPriceViewModel.cs @@ -0,0 +1,34 @@ +using System; +using IRaCIS.Common.Model; + +namespace IRaCIS.Application.ViewModels +{ + public class TrialRevenuesPriceDTO + { + public Guid Id { get; set; } + public Guid TrialId { get; set; } + public double Timepoint { get; set; } + public double TimepointIn24H { get; set; } + public double TimepointIn48H { get; set; } + public double Adjudication { get; set; } + public double AdjudicationIn24H { get; set; } + public double AdjudicationIn48H { get; set; } + public double Global { get; set; } + public double Training { get; set; } + public double Downtime { get; set; } + } + + public class TrialRevenuesPriceDetialDTO : TrialRevenuesPriceDTO + { + public string TrialCode { get; set; } + public string Indication { get; set; } + public int Expedited { get; set; } + public string ReviewMode { get; set; } + public string Cro { get; set; } + } + public class TrialRevenuesPriceQueryDTO : PageInput + { + public string KeyWord { get; set; } + public Guid? CroId { get; set; } + } +} diff --git a/IRaCIS.Core.Application/ViewModels/Trial/TrialViewModel.cs b/IRaCIS.Core.Application/ViewModels/Trial/TrialViewModel.cs new file mode 100644 index 0000000..bb09504 --- /dev/null +++ b/IRaCIS.Core.Application/ViewModels/Trial/TrialViewModel.cs @@ -0,0 +1,147 @@ +using System; +using System.Collections.Generic; +using IRaCIS.Common.Model; +using IRaCIS.Core.Domain.Share; + +namespace IRaCIS.Application.ViewModels +{ + public class TrialDTO: TrialDbModel + { + + public string ReviewType { get; set; } + + public string Criterion { get; set; } + + public string CRO { get; set; } + + public string Sponsor { get; set; } + + + } + + + public class TrialDbModel + { + public Guid Id { get; set; } + public string Code { get; set; } = string.Empty; + public string Indication { get; set; } = string.Empty; + public int TrialStatus { get; set; } + public string TrialStatusStr { get; set; } = string.Empty; + public string Phase { get; set; } = string.Empty; + public Guid? ReviewTypeId { get; set; } = Guid.Empty; + public Guid? CriterionId { get; set; } = Guid.Empty; + public Guid? CROId { get; set; } = Guid.Empty; + public Guid? SponsorId { get; set; } = Guid.Empty; + public Guid? ReviewModeId { get; set; } = Guid.Empty; + public string Note { get; set; } = string.Empty; + public string TurnaroundTime { get; set; } = string.Empty; + public int ExpectedPatients { get; set; } + public int TimePointsPerPatient { get; set; } + public int GRRReviewers { get; set; } + public int TotalReviewers { get; set; } + public string ReviewProtocol { get; set; } = string.Empty; + public string MessageFromClient { get; set; } = string.Empty; + public DateTime? CreateTime { get; set; } + public string ReviewProtocolName { get; set; } = string.Empty; + public string MessageFromClientName { get; set; } = string.Empty; + public int Expedited { get; set; } + } + + + + + public class TrialDetailDTO : TrialDTO + { + public TrialDetailDTO() + { + ModalityIds = new List(); + ModalityList = new List(); + } + + + public string ReviewMode { get; set; } + + public string ReviewProtocolFullPath => WebAppConfig.RootUrl + ReviewProtocol; + + public string MessageFromClientFullPath => WebAppConfig.RootUrl + MessageFromClient; + public string SowFullPath => WebAppConfig.RootUrl + SowPath; + public List ModalityList { get; set; } //成像设备 多选 + public List ModalityIds { get; set; } + + //统计字段 + public string SowName { get; set; } + public string SowPath { get; set; } + + public bool IsLocked { get; set; } + + //public bool LockTrialCode { get; set; } + + //public int Submitted { get; set; } + //public int Approved { get; set; } + //public int Trained { get; set; } + //public int Reading { get; set; } + } + + public class TrialAndTrialStateVieModel + { + public TrialDetailDTO TrialView { get; set; } + + public int TrialMaxState { get; set; } + } + + + + public class TrialCommand : TrialDbModel + { + public Guid UserId { get; set; } + public List ModalityIds { get; set; } = new List(); + } + + + + + + + + public class TrialQueryDTO : PageInput + { + public TrialQueryDTO() + { + ModalityIds = new List(); + } + + public Guid? CriterionId { get; set; } = Guid.Empty; + public Guid? SponsorId { get; set; } = Guid.Empty; + public Guid? CROId { get; set; } = Guid.Empty; + + public Guid? ReviewTypeId { get; set; } = Guid.Empty; + public List ModalityIds { get; set; } + + public string Code { get; set; } = string.Empty; + + public string Indication { get; set; } = string.Empty; + public string Phase { get; set; } = string.Empty; + public string TrialStatus { get; set; } + + public DateTime? BeginDate { get; set; } + public DateTime? EndDate { get; set; } + public int? Expedited { get; set; } = (int)TrialExpedited.All; + } + + + + + + public class TrialByStatusQueryDTO : PageInput + { + public Guid DoctorId { get; set; } + public int Status { get; set; } + } + + + + + + + +} \ No newline at end of file diff --git a/IRaCIS.Core.Application/ViewModels/Trial/UserTrialViewModel.cs b/IRaCIS.Core.Application/ViewModels/Trial/UserTrialViewModel.cs new file mode 100644 index 0000000..8af6634 --- /dev/null +++ b/IRaCIS.Core.Application/ViewModels/Trial/UserTrialViewModel.cs @@ -0,0 +1,68 @@ +using System; +using System.Collections.Generic; +using IRaCIS.Common.Model; + +namespace IRaCIS.Application.ViewModels +{ + public class UserTrialDTO: UserTrialCommand + { + public DateTime UpdateTime { get; set; } = DateTime.Now; + } + + public class SiteCRCCommand : UserTrialCommand + { + public Guid OrganizationTypeId { get; set; } + public string OrganizationType { get; set; } + + public Guid SiteId { get; set; } = Guid.Empty; + } + + public class UserTrialCommand + { + public Guid Id { get; set; } + public Guid UserId { get; set; } + public Guid TrialId { get; set; } + public Guid UserTypeId { get; set; } + public string UserType { get; set; } + + public Guid OrganizationId { get; set; } + public string OrganizationName { get; set; } + + public string UserRealName { get; set; } + + } + public class SiteCrcDTO : UserTrialDTO + { + public Guid SiteId { get; set; } = Guid.Empty; + public Guid OrganizationTypeId { get; set; } + public string OrganizationType { get; set; } + public string Site { get; set; } + public string City { get; set; } + public string Country { get; set; } + + + } + public class UserSelectionModel + { + public Guid Id { get; set; } + public string RealName { get; set; } + } + + public class UserTrialListQueryDTO : PageInput + { + public Guid TrialId { get; set; } = Guid.Empty; + public string UserName { get; set; } = string.Empty; + public Guid? UserTypeId { get; set; } = Guid.Empty; + } + + public class SiteCrcQueryDTO : PageInput + { + public Guid TrialId { get; set; } = Guid.Empty; + public string UserName { get; set; } = string.Empty; + + public Guid? OrganizationTypeId { get; set; } = Guid.Empty; + //public Guid SiteId { get; set; } = Guid.Empty; + + public string SiteName { get; set; } = string.Empty; + } +} diff --git a/IRaCIS.Core.Application/ViewModels/Trial/VisitPlanViewModel.cs b/IRaCIS.Core.Application/ViewModels/Trial/VisitPlanViewModel.cs new file mode 100644 index 0000000..327446b --- /dev/null +++ b/IRaCIS.Core.Application/ViewModels/Trial/VisitPlanViewModel.cs @@ -0,0 +1,27 @@ +using System; +using IRaCIS.Common.Model; + +namespace IRaCIS.Application.ViewModels +{ + public class VisitPlanDTO + { + public Guid Id { get; set; } + public Guid TrialId { get; set; } + public string VisitPlanNum { get; set; } + public string VisitPlanName { get; set; } + public string VisitPlanTime { get; set; } + public string Description { get; set; } + public DateTime CreateTime { get; set; } + } + + public class VisitPlanAddReturnDTO + { + public Guid NewId { get; set; } + public string VisitPlanNum { get; set; } + } + public class VisitPlanQueryDTO : PageInput + { + public Guid TrialId { get; set; } = Guid.Empty; + public string Keyword { get; set; } = string.Empty; + } +} diff --git a/IRaCIS.Core.Application/ViewModels/Trial/VisitPointViewModel.cs b/IRaCIS.Core.Application/ViewModels/Trial/VisitPointViewModel.cs new file mode 100644 index 0000000..28d7a22 --- /dev/null +++ b/IRaCIS.Core.Application/ViewModels/Trial/VisitPointViewModel.cs @@ -0,0 +1,23 @@ +using System; + +namespace IRaCIS.Application.ViewModels +{ + public class VisitPointDTO + { + public Guid? Id { get; set; } = Guid.Empty; + public Guid SubjectId { get; set; } + public Guid VisitPlanId { get; set; } + public DateTime? VisitTime { get; set; } = DateTime.Now; + } + + public class VisitPointDetailDTO : VisitPointDTO + { + + public Guid TrialId { get; set; } + public string VisitPlanNum { get; set; } + public string VisitPlanName { get; set; } + public string VisitPlanTime { get; set; } + public string Description { get; set; } + public DateTime CreateTime { get; set; } + } +} diff --git a/IRaCIS.Core.Application/WebAppConfig.cs b/IRaCIS.Core.Application/WebAppConfig.cs new file mode 100644 index 0000000..639e67c --- /dev/null +++ b/IRaCIS.Core.Application/WebAppConfig.cs @@ -0,0 +1,47 @@ +using System.Collections.Generic; +using System.Configuration; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Configuration.Json; + +namespace IRaCIS.Application +{ + //public class WebAppConfig + //{ + // public static string RootUrl = ConfigurationManager.AppSettings["rootUrl"].ToString(); + // public static string CodePrefix = ConfigurationManager.AppSettings["CodePrefix"].ToString(); + // public static string UserCodePrefix = ConfigurationManager.AppSettings["UserCodePrefix"].ToString(); + // public static string VisitPlanNumPrefix = ConfigurationManager.AppSettings["VisitPlanNumPrefix"].ToString(); + + // public static int CodeLength { get; private set; } + // public static List ExcludeCodeList { get; private set; } + + //} + + + // .net core 迁移替换 + public class WebAppConfig + { + public static string RootUrl { get; set; } + public static string CodePrefix { get; set; } + public static string UserCodePrefix { get; set; } + public static string VisitPlanNumPrefix { get; set; } + + public static int CodeLength { get; private set; } + public static List ExcludeCodeList { get; private set; } + static WebAppConfig() + { + var configuration = new ConfigurationBuilder() + .Add(new JsonConfigurationSource { Path = "appsettings.json", ReloadOnChange = true }) + .Build(); + + RootUrl = configuration.GetSection("RootUrl").Value; + + CodePrefix = configuration.GetSection("CodePrefix").Value; + + UserCodePrefix = configuration.GetSection("UserCodePrefix").Value; + + VisitPlanNumPrefix = configuration.GetSection("VisitPlanNumPrefix").Value; + } + + } +} \ No newline at end of file diff --git a/IRaCIS.Core.Application/WorkloadDistribution/ReadingService.cs b/IRaCIS.Core.Application/WorkloadDistribution/ReadingService.cs new file mode 100644 index 0000000..d5e1368 --- /dev/null +++ b/IRaCIS.Core.Application/WorkloadDistribution/ReadingService.cs @@ -0,0 +1,182 @@ +using IRaCIS.Application.Interfaces; +using IRaCIS.Application.ViewModels; +using IRaCIS.Core.Application.Contracts.RequestAndResponse; +using IRaCIS.Core.Domain.Interfaces; +using System.Linq; +using IRaCIS.Core.Domain.Share.AuthUser; +using IRaCIS.Application.ExpressionExtend; +using IRaCIS.Core.Domain.Models; +using System.Linq.Expressions; +using System; +using IRaCIS.Infra.Data.ExpressionExtend; + +namespace IRaCIS.Core.Application.ReviewerReading +{ + public class ReadingService : IReviewerReadingService + { + private readonly IWorkloadTPRepository _workloadTPRepository; + private readonly IWorkloadGlobalRepository _workloadGlobalRepository; + private readonly IWorkloadADRepository _workloadADRepository; + private readonly ITrialRepository _trialRepository; + private readonly ITrialDictionaryRepository _trialDictionaryRepository; + private readonly IDictionaryRepository _dictionaryRepository; + private readonly ISubjectRepository _subjectRepository; + private readonly ISubjectVisitRepository _subjectVisitRepository; + private readonly IUserInfo _userInfo; + public ReadingService(IWorkloadTPRepository workloadTPRepository, + IWorkloadGlobalRepository workloadGlobalRepository, + IWorkloadADRepository workloadADRepository, + ITrialRepository trialRepository, + ITrialDictionaryRepository trialDictionaryRepository, + IDictionaryRepository dictionaryRepository, + ISubjectRepository subjectRepository, + ISubjectVisitRepository subjectVisitRepository, + IUserInfo userInfo) + { + _workloadTPRepository = workloadTPRepository; + _workloadGlobalRepository = workloadGlobalRepository; + _workloadADRepository = workloadADRepository; + _trialRepository = trialRepository; + _trialDictionaryRepository = trialDictionaryRepository; + _dictionaryRepository = dictionaryRepository; + _subjectRepository = subjectRepository; + _subjectVisitRepository = subjectVisitRepository; + _userInfo = userInfo; + } + public PageOutput GetWorkloadList(WorkloadQueryParam param) + { + + IQueryable query = null; + Expression> subjectLambda = x => true; + if (param.SubjectCode != string.Empty) + { + subjectLambda = subjectLambda.And(o => o.Code.Contains(param.SubjectCode)); + } + Expression> trialLambda = x => true; + if (param.Expedited != null) + { + trialLambda = trialLambda.And(o => o.Expedited == param.Expedited); + } + if (param.TrialId != null && param.TrialId != Guid.Empty) + { + trialLambda = trialLambda.And(o => o.Id == param.TrialId); + } + + + if (param.WorkloadType == 1)// TP + { + Expression> workloadLambda = x => true; + workloadLambda = workloadLambda.And(u => u.ReviewerId == _userInfo.Id); + if (param.Status != null) + { + if (param.Status == 30)//30 的时候,待读和正在读(未提交的) + { + workloadLambda = workloadLambda.And(o => o.Status == 30 || o.Status == 40); + } + else + workloadLambda = workloadLambda.And(o => o.Status == param.Status); + } + query = from tp in _workloadTPRepository.Find(workloadLambda) + join trial in _trialRepository.GetAll().Where(trialLambda) on tp.TrialId equals trial.Id + join subject in _subjectRepository.GetAll().Where(subjectLambda) on tp.SubjectId equals subject.Id + join visit in _subjectVisitRepository.GetAll() on tp.SubjectVisitId equals visit.Id + select new WorkloadReadingDTO + { + Id = tp.Id, + StudyId = tp.StudyId, + WorkloadId = tp.Id, + WorkloadType = 1, + Status = tp.Status, + UpdateTime = tp.UpdateTime, + TrialId = tp.TrialId, + SubjectId = tp.SubjectId, + SubjectCode = subject.Code, + VisitNum = visit.VisitNum, + VisitName = visit.VisitName, + Expedited = trial.Expedited, + TrialCode = trial.Code, + TrialIndication = trial.Indication, + WorkloadCode = tp.TimepointCode + }; + } + else if (param.WorkloadType == 2)//Global + { + Expression> workloadLambda = x => true; + workloadLambda = workloadLambda.And(u => u.ReviewerId == _userInfo.Id); + if (param.Status != null) + { + if (param.Status == 30) + { + workloadLambda = workloadLambda.And(o => o.Status == 30 || o.Status == 40); + } + else + workloadLambda = workloadLambda.And(o => o.Status == param.Status); + } + query = from global in _workloadGlobalRepository.Find(workloadLambda) + join trial in _trialRepository.GetAll().Where(trialLambda) on global.TrialId equals trial.Id + join subject in _subjectRepository.GetAll().Where(subjectLambda) on global.SubjectId equals subject.Id + //join visit in _subjectVisitRepository.GetAll() on global.VisitId equals visit.Id + select new WorkloadReadingDTO + { + Id = global.Id, + WorkloadId = global.Id, + WorkloadType = 1, + Status = global.Status, + UpdateTime = global.UpdateTime, + TrialId = global.TrialId, + SubjectId = global.SubjectId, + SubjectCode = subject.Code, + //VisitNum = visit.VisitNum, + //VisitName = visit.VisitName, + VisitNum = global.VisitNum, + VisitName = global.VisitName, + + Expedited = trial.Expedited, + TrialCode = trial.Code, + TrialIndication = trial.Indication, + WorkloadCode = global.GlobalCode + }; + } + else if (param.WorkloadType == 3)//AD + { + Expression> workloadLambda = x => true; + workloadLambda = workloadLambda.And(u => u.ReviewerId == _userInfo.Id); + if (param.Status != null) + { + if (param.Status == 30)//30 的时候,待读和正在读(未提交的) + { + workloadLambda = workloadLambda.And(o => o.Status == 30 || o.Status == 40); + } + else + workloadLambda = workloadLambda.And(o => o.Status == param.Status); + } + query = from ad in _workloadADRepository.Find(workloadLambda) + join trial in _trialRepository.GetAll().Where(trialLambda) on ad.TrialId equals trial.Id + join subject in _subjectRepository.GetAll().Where(subjectLambda) on ad.SubjectId equals subject.Id + //join visit in _subjectVisitRepository.GetAll() on ad.visi equals visit.Id + select new WorkloadReadingDTO + { + Id = ad.Id, + WorkloadId = ad.Id, + WorkloadType = 1, + Status = ad.Status, + UpdateTime = ad.UpdateTime, + TrialId = ad.TrialId, + SubjectId = ad.SubjectId, + SubjectCode = subject.Code, + //VisitNum = visit.VisitNum, + //VisitName = visit.VisitName, + Expedited = trial.Expedited, + TrialCode = trial.Code, + TrialIndication = trial.Indication, + WorkloadCode = ad.ADCode + }; + } + query.OrderByDescending(u => u.UpdateTime); + var count = query.Count(); + query = query.Skip((param.PageIndex - 1) * param.PageSize).Take(param.PageSize); + return new PageOutput(param.PageIndex, + param.PageSize, count, query.ToList()); + } + } +} diff --git a/IRaCIS.Core.Application/_ExpressionExtend/ExpressionExtend.cs b/IRaCIS.Core.Application/_ExpressionExtend/ExpressionExtend.cs new file mode 100644 index 0000000..740bbfa --- /dev/null +++ b/IRaCIS.Core.Application/_ExpressionExtend/ExpressionExtend.cs @@ -0,0 +1,61 @@ +using System; +using System.Linq.Expressions; + +namespace IRaCIS.Infra.Data.ExpressionExtend +{ + /// + /// 合并表达式 And Or Not扩展 + /// + public static class ExpressionExtend + { + /// + /// 合并表达式 expr1 AND expr2 + /// + /// + /// + /// + /// + public static Expression> And(this Expression> expr1, Expression> expr2) + { + if (expr1 == null) return expr2; + else if (expr2 == null) return expr1; + + //return Expression.Lambda>(Expression.AndAlso(expr1.Body, expr2.Body), expr1.Parameters); + ParameterExpression newParameter = Expression.Parameter(typeof(T), "c"); + NewExpressionVisitor visitor = new NewExpressionVisitor(newParameter); + + var left = visitor.Replace(expr1.Body); + var right = visitor.Replace(expr2.Body); + var body = Expression.And(left, right); + return Expression.Lambda>(body, newParameter); + + } + /// + /// 合并表达式 expr1 or expr2 + /// + /// + /// + /// + /// + public static Expression> Or(this Expression> expr1, Expression> expr2) + { + if (expr1 == null) return expr2; + else if (expr2 == null) return expr1; + + ParameterExpression newParameter = Expression.Parameter(typeof(T), "c"); + NewExpressionVisitor visitor = new NewExpressionVisitor(newParameter); + + var left = visitor.Replace(expr1.Body); + var right = visitor.Replace(expr2.Body); + var body = Expression.Or(left, right); + return Expression.Lambda>(body, newParameter); + } + public static Expression> Not(this Expression> expr) + { + if (expr == null) return null; + var candidateExpr = expr.Parameters[0]; + var body = Expression.Not(expr.Body); + return Expression.Lambda>(body, candidateExpr); + } + } +} diff --git a/IRaCIS.Core.Application/_ExpressionExtend/NewExpressionVisitor.cs b/IRaCIS.Core.Application/_ExpressionExtend/NewExpressionVisitor.cs new file mode 100644 index 0000000..52490b9 --- /dev/null +++ b/IRaCIS.Core.Application/_ExpressionExtend/NewExpressionVisitor.cs @@ -0,0 +1,24 @@ +using System.Linq.Expressions; + +namespace IRaCIS.Infra.Data.ExpressionExtend +{ + /// + /// 建立新表达式 + /// + internal class NewExpressionVisitor : ExpressionVisitor + { + public ParameterExpression _NewParameter { get; private set; } + public NewExpressionVisitor(ParameterExpression param) + { + this._NewParameter = param; + } + public Expression Replace(Expression exp) + { + return this.Visit(exp); + } + protected override Expression VisitParameter(ParameterExpression node) + { + return this._NewParameter; + } + } +} diff --git a/IRaCIS.Core.Application/_ExpressionExtend/QueryableExtension.cs b/IRaCIS.Core.Application/_ExpressionExtend/QueryableExtension.cs new file mode 100644 index 0000000..fc46d36 --- /dev/null +++ b/IRaCIS.Core.Application/_ExpressionExtend/QueryableExtension.cs @@ -0,0 +1,65 @@ +using System; +using System.Linq; +using System.Linq.Expressions; +using System.Reflection; + +namespace IRaCIS.Application.ExpressionExtend +{ + public static class QueryableExtension + { + public static IOrderedQueryable OrderBy(this IQueryable query, string propertyName) + { + Type type = typeof(T); + + PropertyInfo property = type.GetProperty(propertyName); + if (property == null) + throw new ArgumentException(propertyName, "Not Exist"); + + return OrderBy(query, propertyName, false); + } + + public static IOrderedQueryable OrderByDescending(this IQueryable query, string propertyName) + { + Type type = typeof(T); + + PropertyInfo property = type.GetProperty(propertyName); + if (property == null) + throw new ArgumentException(propertyName, "Not Exist"); + + return OrderBy(query, propertyName, true); + } + + static IOrderedQueryable OrderBy(IQueryable query, string propertyName, bool isDesc) + { + string methodName = (isDesc) ? "OrderByDescendingInternal" : "OrderByInternal"; + + var memberProp = typeof(T).GetProperty(propertyName); + + var method = typeof(QueryableExtension).GetMethod(methodName) + + .MakeGenericMethod(typeof(T), memberProp.PropertyType); + + return (IOrderedQueryable)method.Invoke(null, new object[] { query, memberProp }); + } + + public static IOrderedQueryable OrderByInternal(IQueryable query, System.Reflection.PropertyInfo memberProperty) + { + return query.OrderBy(_GetLamba(memberProperty)); + } + + public static IOrderedQueryable OrderByDescendingInternal(IQueryable query, System.Reflection.PropertyInfo memberProperty) + { + return query.OrderByDescending(_GetLamba(memberProperty)); + } + + static Expression> _GetLamba(System.Reflection.PropertyInfo memberProperty) + { + if (memberProperty.PropertyType != typeof(TProp)) throw new Exception(); + + var thisArg = Expression.Parameter(typeof(T)); + var lamba = Expression.Lambda>(Expression.Property(thisArg, memberProperty), thisArg); + return lamba; + } + + } +} \ No newline at end of file diff --git a/IRaCIS.Core.Common/Cache/CacheType.cs b/IRaCIS.Core.Common/Cache/CacheType.cs new file mode 100644 index 0000000..5f64f0c --- /dev/null +++ b/IRaCIS.Core.Common/Cache/CacheType.cs @@ -0,0 +1,18 @@ + +namespace IRaCIS.Core.Infra.Common.Cache +{ + /// + /// 缓存类型 + /// + public enum CacheType + { + /// + /// 内存缓存 + /// + Memory, + /// + /// Redis缓存 + /// + Redis + } +} diff --git a/IRaCIS.Core.Common/Cache/ICache.cs b/IRaCIS.Core.Common/Cache/ICache.cs new file mode 100644 index 0000000..defd2dd --- /dev/null +++ b/IRaCIS.Core.Common/Cache/ICache.cs @@ -0,0 +1,107 @@ +using System; +using System.Threading.Tasks; + +namespace IRaCIS.Core.Infra.Common.Cache +{ + /// + /// 缓存接口 + /// + public interface ICache + { + /// + /// 用于在 key 存在时删除 key + /// + /// 键 + long Del(params string[] key); + + /// + /// 用于在 key 存在时删除 key + /// + /// 键 + /// + Task DelAsync(params string[] key); + + /// + /// 用于在 key 模板存在时删除 + /// + /// key模板 + /// + Task DelByPatternAsync(string pattern); + + /// + /// 检查给定 key 是否存在 + /// + /// 键 + /// + bool Exists(string key); + + /// + /// 检查给定 key 是否存在 + /// + /// 键 + /// + Task ExistsAsync(string key); + + /// + /// 获取指定 key 的值 + /// + /// 键 + /// + string Get(string key); + + /// + /// 获取指定 key 的值 + /// + /// byte[] 或其他类型 + /// 键 + /// + T Get(string key); + + /// + /// 获取指定 key 的值 + /// + /// 键 + /// + Task GetAsync(string key); + + /// + /// 获取指定 key 的值 + /// + /// byte[] 或其他类型 + /// 键 + /// + Task GetAsync(string key); + + /// + /// 设置指定 key 的值,所有写入参数object都支持string | byte[] | 数值 | 对象 + /// + /// 键 + /// 值 + bool Set(string key, object value); + + /// + /// 设置指定 key 的值,所有写入参数object都支持string | byte[] | 数值 | 对象 + /// + /// 键 + /// 值 + /// 有效期 + bool Set(string key, object value, TimeSpan expire); + + /// + /// 设置指定 key 的值,所有写入参数object都支持string | byte[] | 数值 | 对象 + /// + /// 键 + /// 值 + /// + Task SetAsync(string key, object value); + + /// + /// 设置指定 key 的值,所有写入参数object都支持string | byte[] | 数值 | 对象 + /// + /// 键 + /// 值 + /// 有效期 + /// + Task SetAsync(string key, object value, TimeSpan expire); + } +} diff --git a/IRaCIS.Core.Common/Cache/MemoryCache.cs b/IRaCIS.Core.Common/Cache/MemoryCache.cs new file mode 100644 index 0000000..16ffd57 --- /dev/null +++ b/IRaCIS.Core.Common/Cache/MemoryCache.cs @@ -0,0 +1,127 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Text.RegularExpressions; +using System.Threading.Tasks; +using Microsoft.Extensions.Caching.Memory; + +namespace IRaCIS.Core.Infra.Common.Cache +{ + /// + /// 内存缓存 + /// + public class MemoryCache : ICache + { + private readonly IMemoryCache _memoryCache; + public MemoryCache(IMemoryCache memoryCache) + { + _memoryCache = memoryCache; + } + + public long Del(params string[] key) + { + foreach(var k in key) + { + _memoryCache.Remove(k); + } + return key.Length; + } + + public Task DelAsync(params string[] key) + { + foreach (var k in key) + { + _memoryCache.Remove(k); + } + + return Task.FromResult((long)key.Length); + } + + public async Task DelByPatternAsync(string pattern) + { + if (string.IsNullOrEmpty(pattern)) + return default; + + pattern = Regex.Replace(pattern, @"\{.*\}", "(.*)"); + + var keys = GetAllKeys().Where(k => Regex.IsMatch(k, pattern)); + + if(keys != null && keys.Count() > 0) + { + return await DelAsync(keys.ToArray()); + } + + return default; + } + + public bool Exists(string key) + { + return _memoryCache.TryGetValue(key, out _); + } + + public Task ExistsAsync(string key) + { + return Task.FromResult(_memoryCache.TryGetValue(key, out _)); + } + + public string Get(string key) + { + return _memoryCache.Get(key)?.ToString(); + } + + public T Get(string key) + { + return _memoryCache.Get(key); + } + + public Task GetAsync(string key) + { + return Task.FromResult(Get(key)); + } + + public Task GetAsync(string key) + { + return Task.FromResult(Get(key)); + } + + public bool Set(string key, object value) + { + _memoryCache.Set(key, value); + return true; + } + + public bool Set(string key, object value, TimeSpan expire) + { + _memoryCache.Set(key, value, expire); + return true; + } + + public Task SetAsync(string key, object value) + { + Set(key, value); + return Task.FromResult(true); + } + + public Task SetAsync(string key, object value, TimeSpan expire) + { + Set(key, value, expire); + return Task.FromResult(true); + } + + private List GetAllKeys() + { + const BindingFlags flags = BindingFlags.Instance | BindingFlags.NonPublic; + var entries = _memoryCache.GetType().GetField("_entries", flags).GetValue(_memoryCache); + var cacheItems = entries as IDictionary; + var keys = new List(); + if (cacheItems == null) return keys; + foreach (DictionaryEntry cacheItem in cacheItems) + { + keys.Add(cacheItem.Key.ToString()); + } + return keys; + } + } +} diff --git a/IRaCIS.Core.Common/Cache/RedisCache.cs b/IRaCIS.Core.Common/Cache/RedisCache.cs new file mode 100644 index 0000000..1c54017 --- /dev/null +++ b/IRaCIS.Core.Common/Cache/RedisCache.cs @@ -0,0 +1,88 @@ +using System; +using System.Text.RegularExpressions; +using System.Threading.Tasks; + +namespace IRaCIS.Core.Infra.Common.Cache +{ + /// + /// Redis缓存 + /// + public class RedisCache : ICache + { + public long Del(params string[] key) + { + return RedisHelper.Del(key); + } + + public Task DelAsync(params string[] key) + { + return RedisHelper.DelAsync(key); + } + + public async Task DelByPatternAsync(string pattern) + { + if (string.IsNullOrEmpty(pattern)) + return default; + + pattern = Regex.Replace(pattern, @"\{.*\}", "*"); + + var keys = (await RedisHelper.KeysAsync(pattern)); + if(keys != null && keys.Length > 0) + { + return await RedisHelper.DelAsync(keys); + } + + return default; + } + + public bool Exists(string key) + { + return RedisHelper.Exists(key); + } + + public Task ExistsAsync(string key) + { + return RedisHelper.ExistsAsync(key); + } + + public string Get(string key) + { + return RedisHelper.Get(key); + } + + public T Get(string key) + { + return RedisHelper.Get(key); + } + + public Task GetAsync(string key) + { + return RedisHelper.GetAsync(key); + } + + public Task GetAsync(string key) + { + return RedisHelper.GetAsync(key); + } + + public bool Set(string key, object value) + { + return RedisHelper.Set(key, value); + } + + public bool Set(string key, object value, TimeSpan expire) + { + return RedisHelper.Set(key, value, expire); + } + + public Task SetAsync(string key, object value) + { + return RedisHelper.SetAsync(key, value); + } + + public Task SetAsync(string key, object value, TimeSpan expire) + { + return RedisHelper.SetAsync(key, value, expire); + } + } +} diff --git a/IRaCIS.Core.Common/Extention/IQueryablePageListExtensions.cs b/IRaCIS.Core.Common/Extention/IQueryablePageListExtensions.cs new file mode 100644 index 0000000..5347e3e --- /dev/null +++ b/IRaCIS.Core.Common/Extention/IQueryablePageListExtensions.cs @@ -0,0 +1,107 @@ +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; + + +namespace IRaCIS.Core.Infrastructure.Extention +{ + public static class QueryablePageListExtensions + { + //单字段排序 + public static PageOutput ToPagedList(this IQueryable source, int pageIndex, int pageSize, string defaultSortFiled = "Id", bool isAsc = true) + { + if (pageIndex <= 0) + { + pageIndex = 1; + } + if (pageSize <= 0) + { + pageSize = 10; + } + var count = source.Count(); + + if (count == 0) + { + return new PageOutput() { CurrentPageData=new T[0] }; + } + + + var propName = string.IsNullOrWhiteSpace(defaultSortFiled) ? "Id" : defaultSortFiled; + + + + source = source.Skip((pageIndex - 1) * pageSize); + + var items = source + .Take(pageSize) + .ToArray(); + + var pagedList = new PageOutput() + { + PageIndex = pageIndex, + PageSize = pageSize, + TotalCount = count, + CurrentPageData = items + }; + + return pagedList; + } + + + } + + /// + /// 分页信息输出 泛型 + /// + public class PageOutput + { + /// + /// 当前页索引 + /// + public int PageIndex { get; set; } + + /// + /// 每页的记录条数 + /// + public int PageSize { get; set; } + + /// + /// 数据总数 + /// + public long TotalCount { get; set; } = 0; + + /// + /// 数据 + /// + public IList CurrentPageData { get; set; } + + + /// + /// 分页数据 可能额外返回其他类型的查询数据 必须一些配置 + /// + public object OtherData { get; set; } + + public PageOutput() + { + } + + public PageOutput(int pageIndex, int pageSize, long totalCount, IList data) + { + PageIndex = pageIndex; + PageSize = pageSize; + TotalCount = totalCount; + CurrentPageData = data; + } + + public PageOutput(int pageIndex, int pageSize, IQueryable list) + { + PageIndex = pageIndex; + PageSize = pageSize; + TotalCount = list.Count(); + CurrentPageData = list.Skip((pageIndex - 1) * pageSize).Take(pageSize).ToList(); + } + + + } +} diff --git a/IRaCIS.Core.Common/IPHelper.cs b/IRaCIS.Core.Common/IPHelper.cs new file mode 100644 index 0000000..c8827ea --- /dev/null +++ b/IRaCIS.Core.Common/IPHelper.cs @@ -0,0 +1,43 @@ +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.Common/IRaCIS.Core.Infrastructure.csproj b/IRaCIS.Core.Common/IRaCIS.Core.Infrastructure.csproj new file mode 100644 index 0000000..58d68bb --- /dev/null +++ b/IRaCIS.Core.Common/IRaCIS.Core.Infrastructure.csproj @@ -0,0 +1,18 @@ + + + + netstandard2.0 + + + + ..\bin + + + + + + + + + + diff --git a/IRaCIS.Core.Common/MD5Helper.cs b/IRaCIS.Core.Common/MD5Helper.cs new file mode 100644 index 0000000..aa3105f --- /dev/null +++ b/IRaCIS.Core.Common/MD5Helper.cs @@ -0,0 +1,20 @@ +using System.Security.Cryptography; +using System.Text; + +namespace IRaCIS.Core.Infrastructure +{ + public class MD5Helper + { + public static string Md5(string target) + { + using (MD5 md5 = MD5.Create()) + { // MD5非线程安全 + byte[] bytes = md5.ComputeHash(Encoding.UTF8.GetBytes(target)); + StringBuilder sb = new StringBuilder(32); + for (int i = 0; i < bytes.Length; ++i) + sb.Append(bytes[i].ToString("x2")); + return sb.ToString(); + } + } + } +} diff --git a/IRaCIS.Core.Common/ZipHelper.cs b/IRaCIS.Core.Common/ZipHelper.cs new file mode 100644 index 0000000..b6bdec0 --- /dev/null +++ b/IRaCIS.Core.Common/ZipHelper.cs @@ -0,0 +1,58 @@ +using System; +using System.IO; + +using ICSharpCode.SharpZipLib.Checksum; +using ICSharpCode.SharpZipLib.Zip; + +namespace IRaCIS.Core.Infrastructure +{ + public class ZipHelper + { + public static void CreateZip(string sourceFilePath, string destinationZipFilePath) + { + if (sourceFilePath[sourceFilePath.Length - 1] != Path.DirectorySeparatorChar) + sourceFilePath += Path.DirectorySeparatorChar; + try + { + ZipOutputStream zipStream = new ZipOutputStream(File.Create(destinationZipFilePath)); + zipStream.SetLevel(6); // 压缩级别 0-9 + CreateZipFiles(sourceFilePath, zipStream); + zipStream.Finish(); + zipStream.Close(); + } + catch (Exception ex) + { + throw; + } + } + + private static void CreateZipFiles(string sourceFilePath, ZipOutputStream zipStream) + { + Crc32 crc = new Crc32(); + string[] filesArray = Directory.GetFileSystemEntries(sourceFilePath); + foreach (string file in filesArray) + { + if (Directory.Exists(file)) //如果当前是文件夹,递归 + { + CreateZipFiles(file, zipStream); + } + else //如果是文件,开始压缩 + { + FileStream fileStream = File.OpenRead(file); + byte[] buffer = new byte[fileStream.Length]; + fileStream.Read(buffer, 0, buffer.Length); + string tempFile = file.Substring(sourceFilePath.LastIndexOf("\\") + 1); + ZipEntry entry = new ZipEntry(tempFile); + entry.DateTime = DateTime.Now; + entry.Size = fileStream.Length; + fileStream.Close(); + crc.Reset(); + crc.Update(buffer); + entry.Crc = crc.Value; + zipStream.PutNextEntry(entry); + zipStream.Write(buffer, 0, buffer.Length); + } + } + } + } +} diff --git a/IRaCIS.Core.Domain.Share/AuthUser/IUserInfo.cs b/IRaCIS.Core.Domain.Share/AuthUser/IUserInfo.cs new file mode 100644 index 0000000..79bccb9 --- /dev/null +++ b/IRaCIS.Core.Domain.Share/AuthUser/IUserInfo.cs @@ -0,0 +1,26 @@ +using System; + +namespace IRaCIS.Core.Domain.Share.AuthUser +{ + /// + /// 用户信息接口 + /// + public interface IUserInfo + { + /// + /// 主键 + /// + Guid Id { get; } + + /// + /// 用户名 + /// + string UserName { get; } + + /// + /// 昵称 + /// + string RealName { get; } + string ReviewerCode { get; } + } +} diff --git a/IRaCIS.Core.Domain.Share/AuthUser/UserInfo.cs b/IRaCIS.Core.Domain.Share/AuthUser/UserInfo.cs new file mode 100644 index 0000000..089fb27 --- /dev/null +++ b/IRaCIS.Core.Domain.Share/AuthUser/UserInfo.cs @@ -0,0 +1,78 @@ +using System; +using Microsoft.AspNetCore.Http; + +namespace IRaCIS.Core.Domain.Share.AuthUser +{ + /// + /// 用户信息 + /// + public class UserInfo : IUserInfo + { + private readonly IHttpContextAccessor _accessor; + + public UserInfo(IHttpContextAccessor accessor) + { + _accessor = accessor; + } + + /// + /// 用户Id + /// + public Guid Id + { + get { + var id = _accessor?.HttpContext?.User?.FindFirst(ClaimAttributes.UserId); + if (id != null && !string.IsNullOrEmpty(id.Value)) + { + return Guid.Parse(id.Value); + } + return Guid.Empty; + } + } + + /// + /// 用户名 + /// + public string UserName + { + get { + var name = _accessor?.HttpContext?.User?.FindFirst(ClaimAttributes.UserName); + + if (name != null && !string.IsNullOrEmpty(name.Value)) + { + return name.Value; + } + + return ""; + } + } + + + public string RealName + { + get { + var name = _accessor?.HttpContext?.User?.FindFirst(ClaimAttributes.RealName); + + if (name != null && !string.IsNullOrEmpty(name.Value)) + { + return name.Value; + } + + return ""; + } + } + + public string ReviewerCode + { + get { + var reviewerCode = _accessor?.HttpContext?.User?.FindFirst(ClaimAttributes.ReviewerCode); + + if (reviewerCode != null && !string.IsNullOrEmpty(reviewerCode.Value)) + { + return reviewerCode.Value; + } + return string.Empty; + } + } + } +} diff --git a/IRaCIS.Core.Domain.Share/DoctorStatus.cs b/IRaCIS.Core.Domain.Share/DoctorStatus.cs new file mode 100644 index 0000000..6c89c7a --- /dev/null +++ b/IRaCIS.Core.Domain.Share/DoctorStatus.cs @@ -0,0 +1,59 @@ +namespace IRaCIS.Core.Domain.Share +{ + public enum ContractorStatus + { + None = 0,//搜索时不条件查询--未添加信息时数据库的默认值 + Cooperation = 1, + Noncooperation = 2 + } + + public enum ReviewerInformationConfirmStatus + { + None = 0, + ConfirmPass = 1, + ConfirmRefuse = 2 + } + + + public enum ReviewerEnrollStatus + { + Yes = 1, + No = 0 + } + public enum ResumeStatus + { + None = 0, + Pass = 1, + Failed = 2 + } + + + public enum DoctorTrialState + { + NotApply = 0, + + //已申请 + HasAppliedDownLoad = 1, + + //审核通过 + AuditPass = 2, + + AuditFailed = 3, + + //已下载 + ResumeHasDownLoad = 4, + + //已邀请--已确认该名单 + Inviting = 5, + + //同意入组 + InviteConfirmed = 6, + + //拒绝入组 + InviteRefused = 7, + + HasUploadAgreement = 8 + + } + +} \ No newline at end of file diff --git a/IRaCIS.Core.Domain.Share/EnrollStatus.cs b/IRaCIS.Core.Domain.Share/EnrollStatus.cs new file mode 100644 index 0000000..67fd265 --- /dev/null +++ b/IRaCIS.Core.Domain.Share/EnrollStatus.cs @@ -0,0 +1,36 @@ +namespace IRaCIS.Core.Domain.Share +{ + public enum EnrollStatus + { + None = 0, + + HasApplyDownloadResume = 1,//下载简历 申请 + + AuditRefuseDownload = 2,//下载简历审核 不同意 + + HasAuditPassDownload = 3,//下载简历审核 同意 + + HasDownloadResume = 4, // 下载简历 完成 + + HasCommittedToCRO = 5, //已提交CRO + + RefuseCommitCRO = 6, //已提交CRO + + RefuseInviteIntoGroup = 7,// 不邀请入组 + + InviteIntoGroup = 8, //名单被确认 邀请入组 + + RefuseIntoGroup = 9, // 拒绝入组 + + ConfirmIntoGroup = 10, // 确认入组 + + //HasUploadAgreement = 11, // 已上传协议 + + DoctorTrained = 12, // 参加培训 + + DoctorReading = 13, //正在读 + + End = 14 // 结束,锁库 + + } +} diff --git a/IRaCIS.Core.Domain.Share/IRaCIS.Core.Domain.Share.csproj b/IRaCIS.Core.Domain.Share/IRaCIS.Core.Domain.Share.csproj new file mode 100644 index 0000000..a4db717 --- /dev/null +++ b/IRaCIS.Core.Domain.Share/IRaCIS.Core.Domain.Share.csproj @@ -0,0 +1,18 @@ + + + + netstandard2.0 + + + + ..\bin + + + + + + + + + + diff --git a/IRaCIS.Core.Domain.Share/NetResource.cs b/IRaCIS.Core.Domain.Share/NetResource.cs new file mode 100644 index 0000000..7b3e4b7 --- /dev/null +++ b/IRaCIS.Core.Domain.Share/NetResource.cs @@ -0,0 +1,51 @@ +using System.IO; +using System.Runtime.InteropServices; + +namespace IRaCIS.Core.Domain.Share +{ + [StructLayout(LayoutKind.Sequential)] + public class NetResource + { + public int dwScope; + public int dwType; + public int dwDisplayType; + public int dwUsage; + public string lpLocalName; + public string lpRemoteName; + public string lpComment; + public string lpProvider; + } + + + public class WNetAddConnectionHelper + { + [DllImport("mpr.dll", EntryPoint = "WNetAddConnection2")] + private static extern uint WNetAddConnection2(NetResource lpNetResource, string lpPassword, string lpUsername, uint dwFlags); + + [DllImport("mpr.dll")] + public static extern int WNetCancelConnection2A(string sharename, int dwFlags, int fForce); + + public static void Connect() + { + + var remoteName = @"\\192.168.1.119\Potomac_01"; + NetResource netResource = new NetResource(); + netResource.dwScope = 1; + netResource.dwType = 1; + netResource.dwDisplayType = 3; + netResource.dwUsage = 1; + netResource.lpLocalName = "W:"; + netResource.lpRemoteName = remoteName.TrimEnd('\\'); + + var s = WNetAddConnection2(netResource, "Everest@suzhou406", "share", 1); + + } + + public static int Disconnect() + { + return WNetCancelConnection2A("W:", 1, 1); + } + + } +} + diff --git a/IRaCIS.Core.Domain.Share/ProjectStatusEnum.cs b/IRaCIS.Core.Domain.Share/ProjectStatusEnum.cs new file mode 100644 index 0000000..5d7a3e3 --- /dev/null +++ b/IRaCIS.Core.Domain.Share/ProjectStatusEnum.cs @@ -0,0 +1,16 @@ +namespace IRaCIS.Core.Domain.Share +{ + public enum ProjectStatusEnum + { + Created = 0, //创建项目 + ChooseDoctor = 1, //晒选医生 + ApplyDownLoadResume = 2, //申请下载简历 + DownloadApproved = 3,//下载审核已通过 + Downloaded = 4,//已下载 + ConfirmDoctorNames = 5,//确认医生名单 + DoctorConfirm = 6,//医生确认完毕 + EndInGroup = 7, //结束入组 + Going = 8,//进行中 + End = 9 // 结束,锁库 + } +} diff --git a/IRaCIS.Core.Domain.Share/ResumeAuditStatus.cs b/IRaCIS.Core.Domain.Share/ResumeAuditStatus.cs new file mode 100644 index 0000000..fcd802e --- /dev/null +++ b/IRaCIS.Core.Domain.Share/ResumeAuditStatus.cs @@ -0,0 +1,14 @@ +using System; + +namespace IRaCIS.Core.Domain.Share +{ + [Obsolete] + public enum ResumeApplyAuditStatus + { + None=0, + + Pass=1, + + Failed = 2 + } +} \ No newline at end of file diff --git a/IRaCIS.Core.Domain.Share/StudyStatus.cs b/IRaCIS.Core.Domain.Share/StudyStatus.cs new file mode 100644 index 0000000..b520d4c --- /dev/null +++ b/IRaCIS.Core.Domain.Share/StudyStatus.cs @@ -0,0 +1,38 @@ +namespace IRaCIS.Core.Domain.Share +{ + public enum StudyStatus + { + + + Uploaded = 5,//已上传 + + QAing = 10,//QA中-->(QA完成就到 , 需要重传就到) + + NeedReupload = 15,//需要重传15 + + Abandon = 16,//废弃16 + + QAReuploaded = 20,//QA没通过后重新上传完成 + + QAFinish = 25,//QA完成25,合格 + + QAFInishNotPass = 26, //QA结束,不合格 + + + Anonymize = 28,//匿名化完成 + + Distributed = 30,//已分配读片任务 + //Distributed2 = 32, + + Reading = 40,//都片中,未提交读片报告之前 + + NeedAd = 45, + AdDistributed = 50, + AdReading = 60, + + + Review = 80,//待审核 + + Archived = 100,//流程结束,归档锁库 + } +} diff --git a/IRaCIS.Core.Domain.Share/TrialEnrollStatus.cs b/IRaCIS.Core.Domain.Share/TrialEnrollStatus.cs new file mode 100644 index 0000000..6d85724 --- /dev/null +++ b/IRaCIS.Core.Domain.Share/TrialEnrollStatus.cs @@ -0,0 +1,25 @@ +namespace IRaCIS.Core.Domain.Share +{ + public enum TrialEnrollStatus + { + //Created = 0, //创建项目 + + ChooseDoctor = 1, //筛选医生 + + HasApplyDownLoadResume = 2, //已申请下载简历 + + HasApprovedDownload = 3, //已审核通过 + + //HasDownloaded = 4, //已下载 --进入医生挑选阶段 + + HasCommitCRO = 5, //已提交CRO + + HasConfirmedDoctorNames = 6, //已确认医生名单 + + EndInGroup = 9, //结束入组--参与项目的医生都确认了 + + ProjectGoing = 10, //进行中 + + Finished = 11 // 结束,锁库 + } +} diff --git a/IRaCIS.Core.Domain.Share/TrialExpedited.cs b/IRaCIS.Core.Domain.Share/TrialExpedited.cs new file mode 100644 index 0000000..808fc08 --- /dev/null +++ b/IRaCIS.Core.Domain.Share/TrialExpedited.cs @@ -0,0 +1,14 @@ +namespace IRaCIS.Core.Domain.Share +{ + public enum TrialExpedited + { + + All=-1, + + None=0, + + ExpeditedIn24H = 1, + + ExpeditedIn48H = 2 + } +} \ No newline at end of file diff --git a/IRaCIS.Core.Domain.Share/TrialExpeditedStatus.cs b/IRaCIS.Core.Domain.Share/TrialExpeditedStatus.cs new file mode 100644 index 0000000..9e4b939 --- /dev/null +++ b/IRaCIS.Core.Domain.Share/TrialExpeditedStatus.cs @@ -0,0 +1,9 @@ +namespace IRaCIS.Core.Domain.Share +{ + public enum TrialExpeditedStatus + { + Normal = 0, //不加急 + In24HourExpedited = 1,//24小时 加急 + In48HourExpedited = 2,//48小时 加急 + } +} diff --git a/IRaCIS.Core.Domain.Share/UserType.cs b/IRaCIS.Core.Domain.Share/UserType.cs new file mode 100644 index 0000000..edcb9dc --- /dev/null +++ b/IRaCIS.Core.Domain.Share/UserType.cs @@ -0,0 +1,9 @@ +namespace IRaCIS.Core.Domain.Share +{ + public enum UserType + { + AdminUser=0, + + DoctorUser=1 + } +} \ No newline at end of file diff --git a/IRaCIS.Core.Domain.Share/WorkLoadFromStatus.cs b/IRaCIS.Core.Domain.Share/WorkLoadFromStatus.cs new file mode 100644 index 0000000..e8e8ed7 --- /dev/null +++ b/IRaCIS.Core.Domain.Share/WorkLoadFromStatus.cs @@ -0,0 +1,10 @@ +namespace IRaCIS.Core.Domain.Share +{ + public enum WorkLoadFromStatus + { + Doctor = 0, + CRO = 1, + FinalConfirm = 2, + All = 3 + } +} \ No newline at end of file diff --git a/IRaCIS.Core.Domain.Share/WorkLoadStatus.cs b/IRaCIS.Core.Domain.Share/WorkLoadStatus.cs new file mode 100644 index 0000000..0edddb8 --- /dev/null +++ b/IRaCIS.Core.Domain.Share/WorkLoadStatus.cs @@ -0,0 +1,15 @@ +namespace IRaCIS.Core.Domain.Share +{ + public enum WorkloadStatus + { + ToBeAllocated=0,//待分配 + + Distributed = 30,//已分配 + + Reading = 40,//都片中,未提交读片报告之前 + + ReviewFinish = 80,//读片完成 + + //Archived=100,//流程结束,归档锁库 + } +} diff --git a/IRaCIS.Core.Domain.Share/_StaticData.cs b/IRaCIS.Core.Domain.Share/_StaticData.cs new file mode 100644 index 0000000..0e474e5 --- /dev/null +++ b/IRaCIS.Core.Domain.Share/_StaticData.cs @@ -0,0 +1,67 @@ +namespace IRaCIS.Core.Domain.Share +{ + public static class StaticData + { + /// + /// 用户默认密码 + /// + public static readonly string DefaultPassword = "123456"; + + #region 字典表项固定值 + public static readonly string Title = "Title"; + public static readonly string ReadingType = "ReadingType"; + public static readonly string Subspeciality = "Subspeciality"; + public static readonly string Modality = "Modality"; + #endregion + + #region Reviewer Degree + public const string Bachelor = "Bachelor"; + public const string Master = "Master"; + public const string Doctorate = "Doctorate"; + #endregion + + #region UserType + public static readonly string Admin = "Admin"; + public static readonly string DataAdmin = "Reviewer Admin"; + public static readonly string CRC = "CRC"; + public static readonly string QC = "QC"; + public static readonly string PM = "PM"; + public static readonly string CROCoordinator = "CROCoordinator"; + #endregion + + public static readonly string MainCompany = "ZHIZHUN"; + public static readonly string AdminUserName = "admin"; + + public static readonly string GCP = "GCP"; + + + #region 系统返回提示信息 + + public static readonly string AddFailed = "Data add failed"; + public static readonly string DeleteFailed = "Data delete failed"; + public static readonly string UpdateFailed = "Data update failed"; + + public static readonly string DataBaseOperationFailed = "Database operation failed"; + + #endregion + } + + public static class ClaimAttributes + { + /// + /// 用户Id + /// + public const string UserId = "id"; + + /// + /// 用户名 + /// + public const string UserName = "name"; + + /// + /// 姓名 + /// + public const string RealName = "realName"; + public const string ReviewerCode = "reviewerCode"; + } +} \ No newline at end of file diff --git a/IRaCIS.Core.Domain.Share/_SystemConfig.cs b/IRaCIS.Core.Domain.Share/_SystemConfig.cs new file mode 100644 index 0000000..708c1cf --- /dev/null +++ b/IRaCIS.Core.Domain.Share/_SystemConfig.cs @@ -0,0 +1,80 @@ +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Configuration.Json; +using System; +using System.Collections.Generic; + +namespace IRaCIS.Core.Domain.Share +{ + public class SystemConfig + { + public static string RootUrl { get; set; } + public static string CodePrefix { get; set; } + public static string UserCodePrefix { get; set; } + public static string VisitPlanNumPrefix { get; set; } + + public static int CodeLength { get; private set; } + public static List ExcludeCodeList { get; private set; } + public static List AnonymizeTagList = new List(); + public static int LoginExpiredTimeSpan { get; private set; } = 15; + public static bool OpenLog { get; set; } = true; + public static bool AddClinicalInfo { get; set; } = true; + public static bool Share { get; set; } = true; + static SystemConfig() + { + var configuration = new ConfigurationBuilder() + .Add(new JsonConfigurationSource + { + Path = "appsettings.json", + ReloadOnChange = true + }) + .Add(new JsonConfigurationSource + { + Path = "AnonymizeTagSetting.json", + ReloadOnChange = true + }) + .Build(); + + RootUrl = configuration.GetSection("RootUrl").Value; + + CodePrefix = configuration.GetSection("CodePrefix").Value; + + UserCodePrefix = configuration.GetSection("UserCodePrefix").Value; + + VisitPlanNumPrefix = configuration.GetSection("VisitPlanNumPrefix").Value; + try + { + int tempLoginExpiredTimeSpan = 15; + if (int.TryParse(configuration.GetSection("LoginExpiredTimeSpan").Value, out tempLoginExpiredTimeSpan)) + { + LoginExpiredTimeSpan = tempLoginExpiredTimeSpan; + } + OpenLog = Convert.ToBoolean(configuration.GetSection("OpenLog").Value); + AddClinicalInfo = Convert.ToBoolean(configuration.GetSection("AddClinicalInfo").Value); + configuration.GetSection("needAnonymizeTag").Bind(AnonymizeTagList); + Share = Convert.ToBoolean(configuration.GetSection("OpenLog").Value); + } + catch (Exception) + { + + } + + } + + } + + public class AnonymizeTag + { + public string Group { get; set; } + public string Element { get; set; } + public string ReplaceValue { get; set; } + public bool Enable { get; set; } + public AnonymizeTag() { } + public AnonymizeTag(string group, string element, string value, bool enable) + { + Group = group; + Element = element; + ReplaceValue = value; + Enable = enable; + } + } +} \ No newline at end of file diff --git a/IRaCIS.Core.Domain/BaseModel/Entity.cs b/IRaCIS.Core.Domain/BaseModel/Entity.cs new file mode 100644 index 0000000..1d6eb3f --- /dev/null +++ b/IRaCIS.Core.Domain/BaseModel/Entity.cs @@ -0,0 +1,32 @@ +using System; +using System.ComponentModel.DataAnnotations; + +namespace IRaCIS.Core.Domain.Models +{ + public abstract class Entity: Entity + { + + //public virtual Guid Id { get; set; } + + //protected Entity() + //{ + // Id = Guid.NewGuid(); + //} + } + + public interface IEntity + { + + } + + + public class Entity : IEntity + { + /// + /// 编号 + /// + [Key] + [Required] + public virtual TKey Id { get; set; } + } +} diff --git a/IRaCIS.Core.Domain/BaseModel/IAuditAdd.cs b/IRaCIS.Core.Domain/BaseModel/IAuditAdd.cs new file mode 100644 index 0000000..76d9b03 --- /dev/null +++ b/IRaCIS.Core.Domain/BaseModel/IAuditAdd.cs @@ -0,0 +1,20 @@ +using System; + +namespace IRaCIS.Core.Domain.Models +{ + public interface IAuditAdd where TKey: struct + { + TKey CreateUserId { get; set; } + + + DateTime CreateTime { get; set; } + + //string CreateUserName { get; set; } + } + + public interface IAuditAdd: IAuditAdd + { + + } + +} diff --git a/IRaCIS.Core.Domain/BaseModel/IAuditUpdate.cs b/IRaCIS.Core.Domain/BaseModel/IAuditUpdate.cs new file mode 100644 index 0000000..ab9de67 --- /dev/null +++ b/IRaCIS.Core.Domain/BaseModel/IAuditUpdate.cs @@ -0,0 +1,16 @@ +using System; + +namespace IRaCIS.Core.Domain.Models +{ + public interface IAuditUpdate where TKey : struct + { + TKey UpdateUserId { get; set; } + //string UpdateUserName { get; set; } + DateTime UpdateTime { get; set; } + } + + public interface IAuditUpdate : IAuditUpdate + { + + } +} diff --git a/IRaCIS.Core.Domain/Common/Dictionary.cs b/IRaCIS.Core.Domain/Common/Dictionary.cs new file mode 100644 index 0000000..3e28c49 --- /dev/null +++ b/IRaCIS.Core.Domain/Common/Dictionary.cs @@ -0,0 +1,38 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace IRaCIS.Core.Domain.Models +{ + [Table("Dictionary")] + public partial class Dictionary : Entity,IAuditUpdate,IAuditAdd + { + public virtual ICollection DoctorDictionaries { get; set; } + + public Dictionary() + { + DoctorDictionaries=new HashSet(); + } + + [StringLength(50)] + public string KeyName { get; set; } = string.Empty; + + + [StringLength(100)] + public string Value { get; set; } = string.Empty; + + + [StringLength(512)] + public string Memo { get; set; } = string.Empty; + + public int ShowOrder { get; set; } + + public string Type { get; set; } + + public Guid UpdateUserId { get; set; } + public DateTime UpdateTime { get; set; } + public Guid CreateUserId { get; set; } + public DateTime CreateTime { get; set; } + } +} diff --git a/IRaCIS.Core.Domain/Common/IRepository/IDictionaryRepository.cs b/IRaCIS.Core.Domain/Common/IRepository/IDictionaryRepository.cs new file mode 100644 index 0000000..dc41a0d --- /dev/null +++ b/IRaCIS.Core.Domain/Common/IRepository/IDictionaryRepository.cs @@ -0,0 +1,8 @@ +using IRaCIS.Core.Domain.Models; + +namespace IRaCIS.Core.Domain.Interfaces +{ + public interface IDictionaryRepository : IRepository + { + } +} diff --git a/IRaCIS.Core.Domain/Common/IRepository/IHospital.cs b/IRaCIS.Core.Domain/Common/IRepository/IHospital.cs new file mode 100644 index 0000000..40d093e --- /dev/null +++ b/IRaCIS.Core.Domain/Common/IRepository/IHospital.cs @@ -0,0 +1,8 @@ +using IRaCIS.Core.Domain.Models; + +namespace IRaCIS.Core.Domain.Interfaces +{ + interface IHospital : IRepository + { + } +} diff --git a/IRaCIS.Core.Domain/Common/IRepository/IMessageRepository.cs b/IRaCIS.Core.Domain/Common/IRepository/IMessageRepository.cs new file mode 100644 index 0000000..b79c4f7 --- /dev/null +++ b/IRaCIS.Core.Domain/Common/IRepository/IMessageRepository.cs @@ -0,0 +1,8 @@ +using IRaCIS.Core.Domain.Models; + +namespace IRaCIS.Core.Domain.Interfaces +{ + public interface IMessageRepository : IRepository + { + } +} diff --git a/IRaCIS.Core.Domain/Common/IRepository/ISystemLogRepository.cs b/IRaCIS.Core.Domain/Common/IRepository/ISystemLogRepository.cs new file mode 100644 index 0000000..2ac0cdb --- /dev/null +++ b/IRaCIS.Core.Domain/Common/IRepository/ISystemLogRepository.cs @@ -0,0 +1,8 @@ +using IRaCIS.Core.Domain.Models; + +namespace IRaCIS.Core.Domain.Interfaces +{ + public interface ISystemLogRepository : IRepository + { + } +} diff --git a/IRaCIS.Core.Domain/Common/IRepository/IUnitWork.cs b/IRaCIS.Core.Domain/Common/IRepository/IUnitWork.cs new file mode 100644 index 0000000..3aa352c --- /dev/null +++ b/IRaCIS.Core.Domain/Common/IRepository/IUnitWork.cs @@ -0,0 +1,58 @@ +using IRaCIS.Core.Domain.Models; +using System; +using System.Linq; +using System.Linq.Expressions; + +namespace IRaCIS.Core.Domain.Interfaces +{ + /// + /// 工作单元接口 + /// 适合在一下情况使用: + /// 1 在同一事务中进行多表操作 + /// 2 需要多表联合查询 + /// 因为架构采用的是EF访问数据库,暂时可以不用考虑采用传统Unit Work的注册机制 + /// + public interface IUnitWork + { + T FindSingle(Expression> exp = null) where T : class; + bool IsExist(Expression> exp) where T : class; + IQueryable Find(Expression> exp = null) where T : class; + + IQueryable Find(int pageindex = 1, int pagesize = 10, string orderby = "", + Expression> exp = null) where T : class; + + int GetCount(Expression> exp = null) where T : class; + + void Add(T entity) where T : Entity; + + void BatchAdd(T[] entities) where T : Entity; + + /// + /// 更新一个实体的所有属性 + /// + void Update(T entity) where T : class; + + void Delete(T entity) where T : class; + + /// + /// 按指定的ID进行批量更新 + /// + void Update(Expression> identityExp, T entity) where T : class; + + /// + /// 实现按需要只更新部分更新 + /// 如:Update(u =>u.Id==1,u =>new User{Name="ok"}) where T:class; + /// + /// 更新条件 + /// 更新后的实体 + void Update(Expression> where, Expression> entity) where T : class; + /// + /// 批量删除 + /// + void Delete(Expression> exp) where T : class; + + void Save(); + + void ExecuteSql(string sql); + } +} diff --git a/IRaCIS.Core.Domain/Common/IRepository/IUserResearchCenterRepostiory.cs b/IRaCIS.Core.Domain/Common/IRepository/IUserResearchCenterRepostiory.cs new file mode 100644 index 0000000..235285a --- /dev/null +++ b/IRaCIS.Core.Domain/Common/IRepository/IUserResearchCenterRepostiory.cs @@ -0,0 +1,7 @@ +namespace IRaCIS.Core.Domain.Interfaces +{ + public interface IUserResearchCenterRepository + { + + } +} \ No newline at end of file diff --git a/IRaCIS.Core.Domain/Common/IRepository/IVerificationCodeRepository.cs b/IRaCIS.Core.Domain/Common/IRepository/IVerificationCodeRepository.cs new file mode 100644 index 0000000..e9816c0 --- /dev/null +++ b/IRaCIS.Core.Domain/Common/IRepository/IVerificationCodeRepository.cs @@ -0,0 +1,9 @@ +using IRaCIS.Core.Domain.Models; + +namespace IRaCIS.Core.Domain.Interfaces +{ + public interface IVerificationCodeRepository : IRepository + { + + } +} \ No newline at end of file diff --git a/IRaCIS.Core.Domain/Common/Message.cs b/IRaCIS.Core.Domain/Common/Message.cs new file mode 100644 index 0000000..51689a9 --- /dev/null +++ b/IRaCIS.Core.Domain/Common/Message.cs @@ -0,0 +1,18 @@ +using System; +using System.ComponentModel.DataAnnotations.Schema; + +namespace IRaCIS.Core.Domain.Models +{ + [Table("Message")] + public class Message : Entity + { + public Guid ToDoctorId { get; set; } + public Guid FromUserId { get; set; } + public string Title { get; set; } = string.Empty; + public string Content { get; set; } = string.Empty; + public DateTime MessageTime { get; set; } + public bool HasRead { get; set; } + public string Memo { get; set; } = string.Empty; + + } +} diff --git a/IRaCIS.Core.Domain/Common/SystemLog.cs b/IRaCIS.Core.Domain/Common/SystemLog.cs new file mode 100644 index 0000000..37e6e24 --- /dev/null +++ b/IRaCIS.Core.Domain/Common/SystemLog.cs @@ -0,0 +1,21 @@ +using System; +using System.ComponentModel.DataAnnotations.Schema; + +namespace IRaCIS.Core.Domain.Models +{ + [Table("SystemLog")] + public partial class SystemLog : Entity + { + public string ApiPath { get; set; } = string.Empty; + public string Params { get; set; } = string.Empty; + public string Result { get; set; } = string.Empty; + public DateTime RequestTime { get; set; } = DateTime.Now; + public long ElapsedMilliseconds { get; set; } = 0; + public Guid OptUserId { get; set; } = Guid.Empty; + public string OptUserName { get; set; } = string.Empty; + public string ClientIP { get; set; } = string.Empty; + public bool Status { get; set; } = true; + public string Message { get; set; } = string.Empty; + public string LogCategory { get; set; } = string.Empty; + } +} diff --git a/IRaCIS.Core.Domain/Common/VerificationCode.cs b/IRaCIS.Core.Domain/Common/VerificationCode.cs new file mode 100644 index 0000000..d9e1717 --- /dev/null +++ b/IRaCIS.Core.Domain/Common/VerificationCode.cs @@ -0,0 +1,21 @@ +using System; +using System.ComponentModel.DataAnnotations.Schema; + +namespace IRaCIS.Core.Domain.Models +{ + [Table("VerificationCode")] + public class VerificationCode:Entity + { + //public Guid Id { get; set; } + + public Guid UserId { get; set; } + + public string Code { get; set; } + + public int CodeType { get; set; } + + public bool HasSend { get; set; } + + public DateTime ExpirationTime { get; set; } + } +} \ No newline at end of file diff --git a/IRaCIS.Core.Domain/Dcotor/Attachment.cs b/IRaCIS.Core.Domain/Dcotor/Attachment.cs new file mode 100644 index 0000000..b28fa4f --- /dev/null +++ b/IRaCIS.Core.Domain/Dcotor/Attachment.cs @@ -0,0 +1,32 @@ +using System; +using System.ComponentModel.DataAnnotations.Schema; + +namespace IRaCIS.Core.Domain.Models +{ + //public enum AttachmentType + //{ + // Avatar=1,//ͷ + // Resume=2,// + // GCP=3,//GCP֤ + // MedicalLicence=4,//ҽʦʸ֤ + // PracticeCertificate=5,//ִҵʸ֤ + // LargeEquipmentWorkingCertificate=6,//еϸ֤ + // HighestDegreeCertificate=7//ѧ֤ + //} + [Table("Attachment")] + public partial class Attachment : Entity, IAuditAdd + { + public Guid? DoctorId { get; set; } + public string Type { get; set; } + public bool IsOfficial { get; set; } = false; + public string Path { get; set; } = string.Empty; + public string Code { get; set; } = string.Empty; + public DateTime? ExpiryDate { get; set; } + public string FileName { get; set; } = string.Empty; + public DateTime CreateTime { get; set; } + public Guid CreateUserId { get; set; } = Guid.Empty; + + //public Guid CreateUserId { get; set; } = Guid.Empty; + //public DateTime? CreateTime { get; set; } + } +} diff --git a/IRaCIS.Core.Domain/Dcotor/Doctor.cs b/IRaCIS.Core.Domain/Dcotor/Doctor.cs new file mode 100644 index 0000000..e350b1a --- /dev/null +++ b/IRaCIS.Core.Domain/Dcotor/Doctor.cs @@ -0,0 +1,138 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace IRaCIS.Core.Domain.Models +{ + [Table("Doctor")] + public partial class Doctor : Entity, IAuditUpdate, IAuditAdd + { + + // + public virtual ICollection DoctorDicList { get; set; } + public virtual ICollection UserDoctors { get; set; } + public Doctor() + { + //ҽ Titleȸֶѡ + DoctorDicList = new HashSet(); + + + UserDoctors = new HashSet(); + } + + + public string Code { get; set; } + + public string ReviewerCode { get; set; } + + + [StringLength(100)] + public string Phone { get; set; } = string.Empty; + + + [StringLength(100)] + public string Password { get; set; } = string.Empty; + + + [StringLength(50)] + public string ChineseName { get; set; } = string.Empty; + + + [StringLength(100)] + public string FirstName { get; set; } = string.Empty; + + + [StringLength(100)] + public string LastName { get; set; } = string.Empty; + + public int Sex { get; set; } + + + [StringLength(100)] + public string EMail { get; set; } = string.Empty; + + + [StringLength(100)] + public string WeChat { get; set; } = string.Empty; + + + [StringLength(1000)] + public string Introduction { get; set; } = string.Empty; + + public Guid DepartmentId { get; set; } = Guid.Empty; + + + [StringLength(100)] + public string DepartmentOther { get; set; } = string.Empty; + + public Guid RankId { get; set; } = Guid.Empty; + + + [StringLength(100)] + public string RankOther { get; set; } = string.Empty; + + public Guid PositionId { get; set; } = Guid.Empty; + + + [StringLength(100)] + public string PositionOther { get; set; } = string.Empty; + + public Guid HospitalId { get; set; } = Guid.Empty; + + + [StringLength(200)] + public string HospitalOther { get; set; } = string.Empty; + + + [StringLength(100)] + public string ReadingTypeOther { get; set; } = string.Empty; + + + [StringLength(100)] + public string SubspecialityOther { get; set; } = string.Empty; + + public int GCP { get; set; } + + public Guid GCPId { get; set; } = Guid.Empty; + + public Guid OrganizationId { get; set; } = Guid.Empty; + + public string OtherClinicalExperience { get; set; } = string.Empty; + + public int CooperateStatus { get; set; } + + public int ResumeStatus { get; set; } + + + [StringLength(512)] + public string PhotoPath { get; set; } = string.Empty; + + [StringLength(512)] + public string ResumePath { get; set; } = string.Empty; + public Guid SpecialityId { get; set; } = Guid.Empty; + + public string SpecialityOther { get; set; } = string.Empty; + + public string AdminComment { get; set; } = string.Empty; + + public int ReviewStatus { get; set; } + public bool AcceptingNewTrial { get; set; } = false; + public bool ActivelyReading { get; set; } = false; + + public Guid CreateUserId { get; set; } + public DateTime CreateTime { get; set; } + + public Guid UpdateUserId { get; set; } + public DateTime UpdateTime { get; set; } + + public DateTime? LastLoginTime { get; set; } + + public Guid AuditUserId { get; set; } = Guid.Empty; + + public DateTime? AuditTime { get; set; } + + public int Nation { get; set; } = 0; // ֧ͣ0-йҽCN1-ҽUS + + } +} diff --git a/IRaCIS.Core.Domain/Dcotor/DoctorDictionary.cs b/IRaCIS.Core.Domain/Dcotor/DoctorDictionary.cs new file mode 100644 index 0000000..e738b25 --- /dev/null +++ b/IRaCIS.Core.Domain/Dcotor/DoctorDictionary.cs @@ -0,0 +1,20 @@ +using System; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace IRaCIS.Core.Domain.Models +{ + [Table("DoctorDictionary")] + public partial class DoctorDictionary : Entity + { + public virtual Doctor Doctor { get; set; } + public virtual Dictionary Dictionary { get; set; } + + [StringLength(50)] + public string KeyName { get; set; } = string.Empty; + + public Guid DoctorId { get; set; } + + public Guid DictionaryId { get; set; } + } +} diff --git a/IRaCIS.Core.Domain/Dcotor/DoctorWorkload.cs b/IRaCIS.Core.Domain/Dcotor/DoctorWorkload.cs new file mode 100644 index 0000000..46186c5 --- /dev/null +++ b/IRaCIS.Core.Domain/Dcotor/DoctorWorkload.cs @@ -0,0 +1,54 @@ +using System; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace IRaCIS.Core.Domain.Models +{ + [Table("DoctorWorkload")] + public partial class Workload : Entity, IAuditUpdate, IAuditAdd + { + [Required] + public Guid TrialId { get; set; } + + public Guid DoctorId { get; set; } + + public int DataFrom { get; set; } + + public DateTime WorkTime { get; set; } + + public int Training { get; set; } + + public int Downtime { get; set; } + + public int Timepoint { get; set; } + + public int TimepointIn24H { get; set; } + + public int TimepointIn48H { get; set; } + + public int Adjudication { get; set; } + + public int AdjudicationIn24H { get; set; } + + public int AdjudicationIn48H { get; set; } + + public int Global { get; set; } + public int RefresherTraining { get; set; } + + public int CreateUserType { get; set; } + + [Required] + public string YearMonth { get; set; } + + public bool IsLock { get; set; } = false; + + + public Guid CreateUserId { get; set; } + + public DateTime CreateTime { get; set; } + + public Guid UpdateUserId { get; set; } + + public DateTime UpdateTime { get; set; } + } +} diff --git a/IRaCIS.Core.Domain/Dcotor/Education.cs b/IRaCIS.Core.Domain/Dcotor/Education.cs new file mode 100644 index 0000000..aead186 --- /dev/null +++ b/IRaCIS.Core.Domain/Dcotor/Education.cs @@ -0,0 +1,47 @@ +using System; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace IRaCIS.Core.Domain.Models +{ + [Table("Education")] + public partial class Education : Entity, IAuditUpdate, IAuditAdd + { + public Guid DoctorId { get; set; } + + [Column(TypeName = "date")] + public DateTime? BeginDate { get; set; } + [Column(TypeName = "date")] + public DateTime? EndDate { get; set; } + [StringLength(50)] + public string Degree { get; set; } = string.Empty; + [StringLength(100)] + public string Major { get; set; } = string.Empty; + + [StringLength(100)] + public string Organization { get; set; } = string.Empty; + + + [StringLength(50)] + public string Country { get; set; } = string.Empty; + + + [StringLength(50)] + public string Province { get; set; } = string.Empty; + + + [StringLength(50)] + public string City { get; set; } = string.Empty; + + + + public int ShowOrder { get; set; } + + public Guid CreateUserId { get; set; } + public DateTime CreateTime { get; set; } = DateTime.Now; + + + public Guid UpdateUserId { get; set; } + public DateTime UpdateTime { get; set; } + } +} diff --git a/IRaCIS.Core.Domain/Dcotor/IRepository/IAttachmentRepository.cs b/IRaCIS.Core.Domain/Dcotor/IRepository/IAttachmentRepository.cs new file mode 100644 index 0000000..31b9416 --- /dev/null +++ b/IRaCIS.Core.Domain/Dcotor/IRepository/IAttachmentRepository.cs @@ -0,0 +1,8 @@ +using IRaCIS.Core.Domain.Models; + +namespace IRaCIS.Core.Domain.Interfaces +{ + public interface IAttachmentRepository : IRepository + { + } +} diff --git a/IRaCIS.Core.Domain/Dcotor/IRepository/IDoctorDictionaryRepository.cs b/IRaCIS.Core.Domain/Dcotor/IRepository/IDoctorDictionaryRepository.cs new file mode 100644 index 0000000..3295427 --- /dev/null +++ b/IRaCIS.Core.Domain/Dcotor/IRepository/IDoctorDictionaryRepository.cs @@ -0,0 +1,9 @@ +using IRaCIS.Core.Domain.Models; + +namespace IRaCIS.Core.Domain.Interfaces +{ + public interface IDoctorDictionaryRepository : IRepository + { + + } +} diff --git a/IRaCIS.Core.Domain/Dcotor/IRepository/IDoctorRepository.cs b/IRaCIS.Core.Domain/Dcotor/IRepository/IDoctorRepository.cs new file mode 100644 index 0000000..0bbebc2 --- /dev/null +++ b/IRaCIS.Core.Domain/Dcotor/IRepository/IDoctorRepository.cs @@ -0,0 +1,8 @@ +using IRaCIS.Core.Domain.Models; + +namespace IRaCIS.Core.Domain.Interfaces +{ + public interface IDoctorRepository : IRepository + { + } +} diff --git a/IRaCIS.Core.Domain/Dcotor/IRepository/IEducationRepository.cs b/IRaCIS.Core.Domain/Dcotor/IRepository/IEducationRepository.cs new file mode 100644 index 0000000..1e1c16d --- /dev/null +++ b/IRaCIS.Core.Domain/Dcotor/IRepository/IEducationRepository.cs @@ -0,0 +1,9 @@ +using IRaCIS.Core.Domain.Models; + +namespace IRaCIS.Core.Domain.Interfaces +{ + public interface IEducationRepository : IRepository + { + + } +} \ No newline at end of file diff --git a/IRaCIS.Core.Domain/Dcotor/IRepository/IPostgraduateRepository.cs b/IRaCIS.Core.Domain/Dcotor/IRepository/IPostgraduateRepository.cs new file mode 100644 index 0000000..1fe48b4 --- /dev/null +++ b/IRaCIS.Core.Domain/Dcotor/IRepository/IPostgraduateRepository.cs @@ -0,0 +1,9 @@ +using IRaCIS.Core.Domain.Models; + +namespace IRaCIS.Core.Domain.Interfaces +{ + public interface IPostgraduateRepository : IRepository + { + + } +} \ No newline at end of file diff --git a/IRaCIS.Core.Domain/Dcotor/IRepository/IResearchPublicationRepository.cs b/IRaCIS.Core.Domain/Dcotor/IRepository/IResearchPublicationRepository.cs new file mode 100644 index 0000000..3682e18 --- /dev/null +++ b/IRaCIS.Core.Domain/Dcotor/IRepository/IResearchPublicationRepository.cs @@ -0,0 +1,9 @@ +using IRaCIS.Core.Domain.Models; + +namespace IRaCIS.Core.Domain.Interfaces +{ + public interface IResearchPublicationRepository : IRepository + { + + } +} \ No newline at end of file diff --git a/IRaCIS.Core.Domain/Dcotor/IRepository/ITrialExperienceRepository.cs b/IRaCIS.Core.Domain/Dcotor/IRepository/ITrialExperienceRepository.cs new file mode 100644 index 0000000..3c47e9d --- /dev/null +++ b/IRaCIS.Core.Domain/Dcotor/IRepository/ITrialExperienceRepository.cs @@ -0,0 +1,9 @@ +using IRaCIS.Core.Domain.Models; + +namespace IRaCIS.Core.Domain.Interfaces +{ + public interface ITrialExperienceRepository : IRepository + { + + } +} \ No newline at end of file diff --git a/IRaCIS.Core.Domain/Dcotor/IRepository/IVacationRepository.cs b/IRaCIS.Core.Domain/Dcotor/IRepository/IVacationRepository.cs new file mode 100644 index 0000000..4d435ba --- /dev/null +++ b/IRaCIS.Core.Domain/Dcotor/IRepository/IVacationRepository.cs @@ -0,0 +1,8 @@ +using IRaCIS.Core.Domain.Models; + +namespace IRaCIS.Core.Domain.Interfaces +{ + public interface IVacationRepository : IRepository + { + } +} diff --git a/IRaCIS.Core.Domain/Dcotor/Postgraduate.cs b/IRaCIS.Core.Domain/Dcotor/Postgraduate.cs new file mode 100644 index 0000000..48c39c0 --- /dev/null +++ b/IRaCIS.Core.Domain/Dcotor/Postgraduate.cs @@ -0,0 +1,46 @@ +using System; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace IRaCIS.Core.Domain.Models +{ + [Table("Postgraduate")] + public partial class Postgraduate : Entity, IAuditUpdate, IAuditAdd + { + // public Guid Id { get; set; } + + public Guid DoctorId { get; set; } + + [Column(TypeName = "date")] + public DateTime? BeginDate { get; set; } + + [Column(TypeName = "date")] + public DateTime? EndDate { get; set; } + + + [StringLength(50)] + public string Training { get; set; } = string.Empty; + + [StringLength(100)] + public string Major { get; set; } = string.Empty; + + [StringLength(100)] + public string Hospital { get; set; } = string.Empty; + + [StringLength(100)] + public string School { get; set; } = string.Empty; + [StringLength(100)] + public string Country { get; set; } = string.Empty; + + [StringLength(100)] + public string Province { get; set; } = string.Empty; + + [StringLength(100)] + public string City { get; set; } = string.Empty; + + public Guid CreateUserId { get; set; } + public DateTime CreateTime { get; set; } = DateTime.Now; + public Guid UpdateUserId { get; set; } + public DateTime UpdateTime { get; set; } + } +} diff --git a/IRaCIS.Core.Domain/Dcotor/ResearchPublication.cs b/IRaCIS.Core.Domain/Dcotor/ResearchPublication.cs new file mode 100644 index 0000000..0985236 --- /dev/null +++ b/IRaCIS.Core.Domain/Dcotor/ResearchPublication.cs @@ -0,0 +1,19 @@ +using System; +using System.ComponentModel.DataAnnotations.Schema; + +namespace IRaCIS.Core.Domain.Models +{ + [Table("ResearchPublication")] + public partial class ResearchPublication : Entity, IAuditUpdate, IAuditAdd + { + public Guid DoctorId { get; set; } + public string Research { get; set; } = string.Empty; + public string Grants { get; set; } = string.Empty; + public string Publications { get; set; } = string.Empty; + public string AwardsHonors { get; set; } = string.Empty; + public Guid UpdateUserId { get; set; } + public DateTime UpdateTime { get; set; } + public Guid CreateUserId { get; set; } + public DateTime CreateTime { get; set; } + } +} diff --git a/IRaCIS.Core.Domain/Dcotor/TrialExperience.cs b/IRaCIS.Core.Domain/Dcotor/TrialExperience.cs new file mode 100644 index 0000000..b818e7f --- /dev/null +++ b/IRaCIS.Core.Domain/Dcotor/TrialExperience.cs @@ -0,0 +1,26 @@ +using System; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace IRaCIS.Core.Domain.Models +{ + [Table("TrialExperience")] + public partial class TrialExperience : Entity, IAuditUpdate, IAuditAdd + { + public Guid DoctorId { get; set; } + + [StringLength(100)] + public string Term { get; set; } + + [StringLength(100)] + public string EvaluationCriteria { get; set; } + + [StringLength(512)] + public string EvaluationContent { get; set; } + + public Guid CreateUserId { get; set; } + public DateTime CreateTime { get; set; } = DateTime.Now; + public Guid UpdateUserId { get; set; } + public DateTime UpdateTime { get; set; } + } +} diff --git a/IRaCIS.Core.Domain/Dcotor/Vacation.cs b/IRaCIS.Core.Domain/Dcotor/Vacation.cs new file mode 100644 index 0000000..ae5670c --- /dev/null +++ b/IRaCIS.Core.Domain/Dcotor/Vacation.cs @@ -0,0 +1,18 @@ +using System; +using System.ComponentModel.DataAnnotations.Schema; + +namespace IRaCIS.Core.Domain.Models +{ + [Table("Vacation")] + public class Vacation : Entity, IAuditUpdate, IAuditAdd + { + public Guid DoctorId { get; set; } + public DateTime StartDate { get; set; } + public DateTime EndDate { get; set; } + public int Status { get; set; } = 1; + public Guid UpdateUserId { get; set; } + public DateTime UpdateTime { get; set; } + public Guid CreateUserId { get; set; } + public DateTime CreateTime { get; set; } + } +} diff --git a/IRaCIS.Core.Domain/Financial/CalculateTask.cs b/IRaCIS.Core.Domain/Financial/CalculateTask.cs new file mode 100644 index 0000000..d46027c --- /dev/null +++ b/IRaCIS.Core.Domain/Financial/CalculateTask.cs @@ -0,0 +1,16 @@ +using System; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace IRaCIS.Core.Domain.Models +{ + [Table("CalculateTask")] + public class CalculateTask : Entity + { + public Guid ReviewerId { get; set; } + + [Required] + public string YearMonth { get; set; } + public bool IsLock { get; set; } + } +} diff --git a/IRaCIS.Core.Domain/Financial/ExchangeRate.cs b/IRaCIS.Core.Domain/Financial/ExchangeRate.cs new file mode 100644 index 0000000..010975f --- /dev/null +++ b/IRaCIS.Core.Domain/Financial/ExchangeRate.cs @@ -0,0 +1,16 @@ +using System; +using System.ComponentModel.DataAnnotations.Schema; + +namespace IRaCIS.Core.Domain.Models +{ + [Table("ExchangeRate")] + public class ExchangeRate : Entity, IAuditUpdate, IAuditAdd + { + public string YearMonth { get; set; } + public decimal Rate { get; set; } + public Guid UpdateUserId { get; set; } + public DateTime UpdateTime { get; set; } + public Guid CreateUserId { get; set; } + public DateTime CreateTime { get; set; } + } +} diff --git a/IRaCIS.Core.Domain/Financial/IRepository/ICalculateTaskRepository.cs b/IRaCIS.Core.Domain/Financial/IRepository/ICalculateTaskRepository.cs new file mode 100644 index 0000000..9d1e94c --- /dev/null +++ b/IRaCIS.Core.Domain/Financial/IRepository/ICalculateTaskRepository.cs @@ -0,0 +1,8 @@ +using IRaCIS.Core.Domain.Models; + +namespace IRaCIS.Core.Domain.Interfaces +{ + public interface ICalculateTaskRepository : IRepository + { + } +} diff --git a/IRaCIS.Core.Domain/Financial/IRepository/IExchangeRateRepository.cs b/IRaCIS.Core.Domain/Financial/IRepository/IExchangeRateRepository.cs new file mode 100644 index 0000000..401df5f --- /dev/null +++ b/IRaCIS.Core.Domain/Financial/IRepository/IExchangeRateRepository.cs @@ -0,0 +1,9 @@ +using IRaCIS.Core.Domain.Models; + +namespace IRaCIS.Core.Domain.Interfaces +{ + public interface IExchangeRateRepository: IRepository + { + + } +} diff --git a/IRaCIS.Core.Domain/Financial/IRepository/IPaymentAdjustmentRepository.cs b/IRaCIS.Core.Domain/Financial/IRepository/IPaymentAdjustmentRepository.cs new file mode 100644 index 0000000..78f8c65 --- /dev/null +++ b/IRaCIS.Core.Domain/Financial/IRepository/IPaymentAdjustmentRepository.cs @@ -0,0 +1,9 @@ +using IRaCIS.Core.Domain.Models; + +namespace IRaCIS.Core.Domain.Interfaces +{ + public interface IPaymentAdjustmentRepository : IRepository + { + + } +} \ No newline at end of file diff --git a/IRaCIS.Core.Domain/Financial/IRepository/IPaymentDetailRepository.cs b/IRaCIS.Core.Domain/Financial/IRepository/IPaymentDetailRepository.cs new file mode 100644 index 0000000..d7495c9 --- /dev/null +++ b/IRaCIS.Core.Domain/Financial/IRepository/IPaymentDetailRepository.cs @@ -0,0 +1,9 @@ +using IRaCIS.Core.Domain.Models; + +namespace IRaCIS.Core.Domain.Interfaces +{ + public interface IPaymentDetailRepository : IRepository + { + + } +} \ No newline at end of file diff --git a/IRaCIS.Core.Domain/Financial/IRepository/IPaymentRepository.cs b/IRaCIS.Core.Domain/Financial/IRepository/IPaymentRepository.cs new file mode 100644 index 0000000..3505e59 --- /dev/null +++ b/IRaCIS.Core.Domain/Financial/IRepository/IPaymentRepository.cs @@ -0,0 +1,9 @@ +using IRaCIS.Core.Domain.Models; + +namespace IRaCIS.Core.Domain.Interfaces +{ + public interface IPaymentRepository:IRepository + { + + } +} \ No newline at end of file diff --git a/IRaCIS.Core.Domain/Financial/IRepository/IRankPriceRepository.cs b/IRaCIS.Core.Domain/Financial/IRepository/IRankPriceRepository.cs new file mode 100644 index 0000000..0d3ed97 --- /dev/null +++ b/IRaCIS.Core.Domain/Financial/IRepository/IRankPriceRepository.cs @@ -0,0 +1,8 @@ +using IRaCIS.Core.Domain.Models; + +namespace IRaCIS.Core.Domain.Interfaces +{ + public interface IRankPriceRepository : IRepository + { + } +} diff --git a/IRaCIS.Core.Domain/Financial/IRepository/IReviewerPayInfoRepository.cs b/IRaCIS.Core.Domain/Financial/IRepository/IReviewerPayInfoRepository.cs new file mode 100644 index 0000000..fd53bba --- /dev/null +++ b/IRaCIS.Core.Domain/Financial/IRepository/IReviewerPayInfoRepository.cs @@ -0,0 +1,8 @@ +using IRaCIS.Core.Domain.Models; + +namespace IRaCIS.Core.Domain.Interfaces +{ + public interface IReviewerPayInfoRepository : IRepository + { + } +} diff --git a/IRaCIS.Core.Domain/Financial/IRepository/ITrialPaymentPriceRepository.cs b/IRaCIS.Core.Domain/Financial/IRepository/ITrialPaymentPriceRepository.cs new file mode 100644 index 0000000..34cca34 --- /dev/null +++ b/IRaCIS.Core.Domain/Financial/IRepository/ITrialPaymentPriceRepository.cs @@ -0,0 +1,8 @@ +using IRaCIS.Core.Domain.Models; + +namespace IRaCIS.Core.Domain.Interfaces +{ + public interface ITrialPaymentPriceRepository : IRepository + { + } +} diff --git a/IRaCIS.Core.Domain/Financial/IRepository/ITrialRevenuesPriceRepository.cs b/IRaCIS.Core.Domain/Financial/IRepository/ITrialRevenuesPriceRepository.cs new file mode 100644 index 0000000..334d202 --- /dev/null +++ b/IRaCIS.Core.Domain/Financial/IRepository/ITrialRevenuesPriceRepository.cs @@ -0,0 +1,8 @@ +using IRaCIS.Core.Domain.Models; + +namespace IRaCIS.Core.Domain.Interfaces +{ + public interface ITrialRevenuesPriceRepository : IRepository + { + } +} diff --git a/IRaCIS.Core.Domain/Financial/IRepository/IVolumeRewardRepository.cs b/IRaCIS.Core.Domain/Financial/IRepository/IVolumeRewardRepository.cs new file mode 100644 index 0000000..0beed11 --- /dev/null +++ b/IRaCIS.Core.Domain/Financial/IRepository/IVolumeRewardRepository.cs @@ -0,0 +1,9 @@ +using IRaCIS.Core.Domain.Models; + +namespace IRaCIS.Core.Domain.Interfaces +{ + public interface IVolumeRewardRepository : IRepository + { + + } +} \ No newline at end of file diff --git a/IRaCIS.Core.Domain/Financial/Payment.cs b/IRaCIS.Core.Domain/Financial/Payment.cs new file mode 100644 index 0000000..c56e419 --- /dev/null +++ b/IRaCIS.Core.Domain/Financial/Payment.cs @@ -0,0 +1,39 @@ +using System; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace IRaCIS.Core.Domain.Models +{ + + [Table("Payment")] + public partial class Payment : Entity, IAuditUpdate, IAuditAdd + { + public Guid DoctorId { get; set; } + public string YearMonth { get; set; } = string.Empty; + public bool IsLock { get; set; } + public DateTime YearMonthDate { get; set; } + public decimal PaymentUSD { get; set; } + public decimal PaymentCNY { get; set; } + public decimal ExchangeRate { get; set; } + + public decimal AdjustmentCNY { get; set; } + public decimal AdjustmentUSD { get; set; } + public DateTime CalculateTime { get; set; } = DateTime.Now; + + [StringLength(100)] + public string CalculateUser { get; set; } = string.Empty; + + [StringLength(500)] + public string Note { get; set; } = string.Empty; + + //public double TaxCNY { get; set; } + //public double ActuallyPaidCNY { get; set; } + //public double BankTransferCNY { get; set; } + + + public Guid UpdateUserId { get; set; } + public DateTime UpdateTime { get; set; } + public Guid CreateUserId { get; set; } + public DateTime CreateTime { get; set; } + } +} diff --git a/IRaCIS.Core.Domain/Financial/PaymentAdjustment.cs b/IRaCIS.Core.Domain/Financial/PaymentAdjustment.cs new file mode 100644 index 0000000..7e7f166 --- /dev/null +++ b/IRaCIS.Core.Domain/Financial/PaymentAdjustment.cs @@ -0,0 +1,27 @@ +using System; +using System.ComponentModel.DataAnnotations.Schema; + +namespace IRaCIS.Core.Domain.Models +{ + [Table("PaymentAdjustment")] + public partial class PaymentAdjustment : Entity, IAuditUpdate, IAuditAdd + { + public Guid ReviewerId { get; set; } + + public DateTime YearMonthDate { get; set; } + public string YearMonth { get; set; } + public decimal AdjustmentUSD { get; set; } + public decimal AdjustmentCNY { get; set; } + + + public Guid TrialId { get; set; } = Guid.Empty; + public decimal ExchangeRate { get; set; } + public bool IsLock { get; set; } = false; + public string Note { get; set; } = string.Empty; + + public Guid CreateUserId { get; set; } = Guid.Empty; + public DateTime CreateTime { get; set; } = DateTime.Now; + public Guid UpdateUserId { get; set; } = Guid.Empty; + public DateTime UpdateTime { get; set; } = DateTime.Now; + } +} diff --git a/IRaCIS.Core.Domain/Financial/PaymentDetail.cs b/IRaCIS.Core.Domain/Financial/PaymentDetail.cs new file mode 100644 index 0000000..c416f7b --- /dev/null +++ b/IRaCIS.Core.Domain/Financial/PaymentDetail.cs @@ -0,0 +1,36 @@ +using System; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace IRaCIS.Core.Domain.Models +{ + [Table("PaymentDetail")] + public partial class PaymentDetail : Entity, IAuditUpdate, IAuditAdd + { + public Guid PaymentId { get; set; } + public Guid DoctorId { get; set; } + public string YearMonth { get; set; } + public Guid TrialId { get; set; } + + [StringLength(50)] + public string TrialCode { get; set; } + + [StringLength(50)] + public string PaymentType { get; set; } + public int Count { get; set; } + public decimal BasePrice { get; set; } + public decimal PersonalAdditional { get; set; } + public decimal TrialAdditional { get; set; } + public decimal ExchangeRate { get; set; } + public decimal PaymentUSD { get; set; } + public decimal PaymentCNY { get; set; } + + public int ShowTypeOrder { get; set; } + public int ShowCodeOrder { get; set; } + + public Guid UpdateUserId { get; set; } + public DateTime UpdateTime { get; set; } + public Guid CreateUserId { get; set; } + public DateTime CreateTime { get; set; } + } +} diff --git a/IRaCIS.Core.Domain/Financial/RankPrice.cs b/IRaCIS.Core.Domain/Financial/RankPrice.cs new file mode 100644 index 0000000..657cefd --- /dev/null +++ b/IRaCIS.Core.Domain/Financial/RankPrice.cs @@ -0,0 +1,29 @@ +using System; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace IRaCIS.Core.Domain.Models +{ + [Table("RankPrice")] + public partial class RankPrice : Entity, IAuditUpdate, IAuditAdd + { + [StringLength(200)] + public string RankName { get; set; } + public decimal Timepoint { get; set; } + public decimal TimepointIn24H { get; set; } + public decimal TimepointIn48H { get; set; } + public decimal Adjudication { get; set; } + public decimal AdjudicationIn24H { get; set; } + public decimal AdjudicationIn48H { get; set; } + public decimal Global { get; set; } + public decimal Training { get; set; } + public decimal Downtime { get; set; } + public decimal RefresherTraining { get; set; } + public int ShowOrder { get; set; } + + public DateTime CreateTime { get; set; } + public Guid CreateUserId { get; set; } = Guid.Empty; + public DateTime UpdateTime { get; set; } + public Guid UpdateUserId { get; set; } = Guid.Empty; + } +} diff --git a/IRaCIS.Core.Domain/Financial/ReviewerPayInformation.cs b/IRaCIS.Core.Domain/Financial/ReviewerPayInformation.cs new file mode 100644 index 0000000..7c63856 --- /dev/null +++ b/IRaCIS.Core.Domain/Financial/ReviewerPayInformation.cs @@ -0,0 +1,30 @@ +using System; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace IRaCIS.Core.Domain.Models +{ + [Table("DoctorPayInformation")] + public partial class ReviewerPayInformation : Entity, IAuditAdd, IAuditUpdate + { + public Guid DoctorId { get; set; } + [StringLength(200)] + public string DoctorNameInBank { get; set; } + + [StringLength(100)] + public string IDCard { get; set; } + + [StringLength(100)] + public string BankCardNumber { get; set; } + + [StringLength(200)] + public string BankName { get; set; } + public Guid RankId { get; set; } + public decimal Additional { get; set; } + + public DateTime CreateTime { get; set; } + public Guid CreateUserId { get; set; } = Guid.Empty; + public DateTime UpdateTime { get; set; } + public Guid UpdateUserId { get; set; } = Guid.Empty; + } +} diff --git a/IRaCIS.Core.Domain/Financial/TrialPaymentPrice.cs b/IRaCIS.Core.Domain/Financial/TrialPaymentPrice.cs new file mode 100644 index 0000000..33096a5 --- /dev/null +++ b/IRaCIS.Core.Domain/Financial/TrialPaymentPrice.cs @@ -0,0 +1,29 @@ +using System; +using System.ComponentModel.DataAnnotations.Schema; + +namespace IRaCIS.Core.Domain.Models +{ + [Table("TrialPaymentPrice")] + public partial class TrialPaymentPrice : Entity, IAuditAdd, IAuditUpdate + { + public Trial Trial { get; set; } + + public Guid TrialId { get; set; } + public decimal TrialAdditional { get; set; } = 0; + + public string SowName { get; set; } = string.Empty; + public string SowPath { get; set; } = string.Empty; + public decimal AdjustmentMultiple { get; set; } = 1; + + + /// + /// Ƿ ΪĿ + /// + public bool? IsNewTrial { get; set; } = false; + + public DateTime CreateTime { get; set; } + public Guid CreateUserId { get; set; } + public DateTime UpdateTime { get; set; } + public Guid UpdateUserId { get; set; } + } +} diff --git a/IRaCIS.Core.Domain/Financial/TrialRevenuesPrice.cs b/IRaCIS.Core.Domain/Financial/TrialRevenuesPrice.cs new file mode 100644 index 0000000..dc1c6ba --- /dev/null +++ b/IRaCIS.Core.Domain/Financial/TrialRevenuesPrice.cs @@ -0,0 +1,26 @@ +using System; +using System.ComponentModel.DataAnnotations.Schema; + +namespace IRaCIS.Core.Domain.Models +{ + [Table("TrialRevenuesPrice")] + public class TrialRevenuesPrice : Entity, IAuditUpdate, IAuditAdd + { + public Guid TrialId { get; set; } + public decimal Timepoint { get; set; } + public decimal TimepointIn24H { get; set; } + public decimal TimepointIn48H { get; set; } + public decimal Adjudication { get; set; } + public decimal AdjudicationIn24H { get; set; } + public decimal AdjudicationIn48H { get; set; } + public decimal Global { get; set; } + public decimal Training { get; set; } + public decimal Downtime { get; set; } + public decimal RefresherTraining { get; set; } + + public Guid UpdateUserId { get; set; } + public DateTime UpdateTime { get; set; } + public Guid CreateUserId { get; set; } + public DateTime CreateTime { get; set; } + } +} diff --git a/IRaCIS.Core.Domain/Financial/TrialRevenuesPriceVerification.cs b/IRaCIS.Core.Domain/Financial/TrialRevenuesPriceVerification.cs new file mode 100644 index 0000000..822c312 --- /dev/null +++ b/IRaCIS.Core.Domain/Financial/TrialRevenuesPriceVerification.cs @@ -0,0 +1,33 @@ +using System; + +namespace IRaCIS.Core.Domain.Models +{ + public class TrialRevenuesPriceVerification : Entity + { + public Guid TrialId { get; set; } + + public Guid ReviewerId { get; set; } + + public string YearMonth { get; set; } + + public bool Training { get; set; } = false; + + public bool Downtime { get; set; } = false; + + public bool Global { get; set; } = false; + + public bool Timepoint { get; set; } = false; + + public bool TimepointIn24H { get; set; } = false; + + public bool TimepointIn48H { get; set; } = false; + + public bool Adjudication { get; set; } = false; + + public bool AdjudicationIn24H { get; set; } = false; + + public bool AdjudicationIn48H { get; set; } = false; + public bool RefresherTraining { get; set; } = false; + public DateTime WorkLoadDate { get; set; } + } +} \ No newline at end of file diff --git a/IRaCIS.Core.Domain/Financial/VolumeReward.cs b/IRaCIS.Core.Domain/Financial/VolumeReward.cs new file mode 100644 index 0000000..73bc155 --- /dev/null +++ b/IRaCIS.Core.Domain/Financial/VolumeReward.cs @@ -0,0 +1,17 @@ +using System; +using System.ComponentModel.DataAnnotations.Schema; + +namespace IRaCIS.Core.Domain.Models +{ + [Table("VolumeReward")] + public partial class VolumeReward : Entity, IAuditUpdate, IAuditAdd + { + public decimal Price { get; set; } + public int Min { get; set; } + public int Max { get; set; } + public Guid UpdateUserId { get; set; } + public DateTime UpdateTime { get; set; } + public Guid CreateUserId { get; set; } + public DateTime CreateTime { get; set; } + } +} diff --git a/IRaCIS.Core.Domain/IRaCIS.Core.Domain.csproj b/IRaCIS.Core.Domain/IRaCIS.Core.Domain.csproj new file mode 100644 index 0000000..23f6ecd --- /dev/null +++ b/IRaCIS.Core.Domain/IRaCIS.Core.Domain.csproj @@ -0,0 +1,11 @@ + + + + netstandard2.0 + + + + + + + diff --git a/IRaCIS.Core.Domain/IRepository.cs b/IRaCIS.Core.Domain/IRepository.cs new file mode 100644 index 0000000..5241997 --- /dev/null +++ b/IRaCIS.Core.Domain/IRepository.cs @@ -0,0 +1,49 @@ +using Microsoft.EntityFrameworkCore.ChangeTracking; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Expressions; +using System.Threading.Tasks; + +namespace IRaCIS.Core.Domain +{ + /// + /// 仓储接口 + /// + /// + public interface IRepository where T : class + { + IQueryable GetAll(); + T Add(T t); + IEnumerable AddRange(IEnumerable t); + void Delete(T t); + bool Delete(Expression> exp); + void Update(T t); + Task AddOrUpdateAsync(T t); + + bool Update(Expression> where, Expression> entity); + bool IsExist(Expression> exp); + int GetCount(Expression> exp=null); + T FindSingleOrDefault(Expression> exp = null); + IQueryable Find(Expression> exp = null); + IQueryable Find(int pageSize, int pageIndex, bool isAsc, Expression> orderByLambda, Expression> whereLambda=null); + + IQueryable Find(int pageSize, int pageIndex, bool isAsc, string propName, + Expression> whereLambda); + bool SaveChanges(); + + ValueTask> AddAsync(T entity); + + Task DeleteAsync(Expression> whereLambda); + Task UpdateAsync(Expression> whereLambda, Expression> entity); + + Task IsExistAsync(Expression> whereLambda); + + Task GetFirstOrDefaultAsync(Expression> whereLambda); + + Task GetCountAsync(Expression> whereLambda = null); + + Task SaveChangesAsync(); + + } +} \ No newline at end of file diff --git a/IRaCIS.Core.Domain/ITestRepository.cs b/IRaCIS.Core.Domain/ITestRepository.cs new file mode 100644 index 0000000..c749a34 --- /dev/null +++ b/IRaCIS.Core.Domain/ITestRepository.cs @@ -0,0 +1,7 @@ +namespace IRaCIS.Core.Domain +{ + public interface ITestRepository : IRepository + { + + } +} \ No newline at end of file diff --git a/IRaCIS.Core.Domain/Image/DicomInstance.cs b/IRaCIS.Core.Domain/Image/DicomInstance.cs new file mode 100644 index 0000000..a6e2974 --- /dev/null +++ b/IRaCIS.Core.Domain/Image/DicomInstance.cs @@ -0,0 +1,43 @@ +using System; +using System.ComponentModel.DataAnnotations.Schema; + +namespace IRaCIS.Core.Domain.Models +{ + [Table("DicomInstance")] + public class DicomInstance : Entity, IAuditAdd, IAuditUpdate + { + public Guid StudyId { get; set; } + public Guid SeriesId { get; set; } + public string StudyInstanceUid { get; set; } + public string SeriesInstanceUid { get; set; } + public string SopInstanceUid { get; set; } + public int InstanceNumber { get; set; } + public DateTime InstanceTime { get; set; } + public bool CPIStatus { get; set; } + public int ImageRows { get; set; } + public int ImageColumns { get; set; } + public int SliceLocation { get; set; } + + + public string SliceThickness { get; set; } + public int NumberOfFrames { get; set; } + public string PixelSpacing { get; set; } + + public string ImagerPixelSpacing { get; set; } + public string FrameOfReferenceUID { get; set; } + public string WindowCenter { get; set; } + public string WindowWidth { get; set; } + + + public Guid TrialId { get; set; } + public Guid SiteId { get; set; } + public Guid SubjectId { get; set; } + public Guid SubjectVisitId { get; set; } + public bool Anonymize { get; set; } + + public Guid CreateUserId { get; set; } + public DateTime CreateTime { get; set; } = DateTime.Now; + public Guid UpdateUserId { get; set; } + public DateTime UpdateTime { get; set; } = DateTime.Now; + } +} diff --git a/IRaCIS.Core.Domain/Image/DicomSeries.cs b/IRaCIS.Core.Domain/Image/DicomSeries.cs new file mode 100644 index 0000000..c7e3fa9 --- /dev/null +++ b/IRaCIS.Core.Domain/Image/DicomSeries.cs @@ -0,0 +1,48 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations.Schema; + +namespace IRaCIS.Core.Domain.Models +{ + [Table("DicomSeries")] + public class DicomSeries : Entity, IAuditAdd, IAuditUpdate + { + public Guid StudyId { get; set; } + public string StudyInstanceUid { get; set; } + public string SeriesInstanceUid { get; set; } + public int SeriesNumber { get; set; } + public DateTime SeriesTime { get; set; } + public string Modality { get; set; } + public string Description { get; set; } + public int InstanceCount { get; set; } + public string SliceThickness { get; set; } + + + + + public string ImagePositionPatient { get; set; } + public string ImageOrientationPatient { get; set; } + public string BodyPartExamined { get; set; } + public string SequenceName { get; set; } + public string ProtocolName { get; set; } + public string ImagerPixelSpacing { get; set; } + + + public string AcquisitionTime { get; set; } = string.Empty; + public string AcquisitionNumber { get; set; } = string.Empty; + public string TriggerTime { get; set; } = string.Empty; + + + + + public Guid TrialId { get; set; } + public Guid SiteId { get; set; } + public Guid SubjectId { get; set; } + public Guid SubjectVisitId { get; set; } + + public Guid CreateUserId { get; set; } + public DateTime CreateTime { get; set; } = DateTime.Now; + public Guid UpdateUserId { get; set; } + public DateTime UpdateTime { get; set; } = DateTime.Now; + } +} diff --git a/IRaCIS.Core.Domain/Image/DicomStudy.cs b/IRaCIS.Core.Domain/Image/DicomStudy.cs new file mode 100644 index 0000000..63e6581 --- /dev/null +++ b/IRaCIS.Core.Domain/Image/DicomStudy.cs @@ -0,0 +1,59 @@ +using System; +using System.ComponentModel.DataAnnotations.Schema; + +namespace IRaCIS.Core.Domain.Models +{ + [Table("DicomStudy")] + public class DicomStudy : Entity, IAuditUpdate, IAuditAdd + { + + public Guid TrialId { get; set; } + public Guid SiteId { get; set; } + + public Guid SubjectId { get; set; } + public Guid SubjectVisitId { get; set; } + + public string StudyCode { get; set; } = string.Empty; + + public int Status { get; set; } = 1; + + public string StudyInstanceUid { get; set; } = string.Empty; + public DateTime? StudyTime { get; set; } + public string Modalities { get; set; } = string.Empty; + + public string Description { get; set; } = string.Empty; + public int SeriesCount { get; set; } = 0; + public int InstanceCount { get; set; } = 0; + + //public bool SoftDelete { get; set; } = false; + + public string InstitutionName { get; set; } = string.Empty; + public string PatientId { get; set; } = string.Empty; + public string PatientName { get; set; } = string.Empty; + public string PatientAge { get; set; } = string.Empty; + public string PatientSex { get; set; } = string.Empty; + + public string StudyId { get; set; } = string.Empty; + public string AccessionNumber { get; set; } = string.Empty; + public string PatientBirthDate { get; set; } = string.Empty; + + public string AcquisitionTime { get; set; } = string.Empty; + public string AcquisitionNumber { get; set; } = string.Empty; + public string TriggerTime { get; set; } = string.Empty; + + + + + + //0 未知 1 单重 2 双重 + public bool IsDoubleReview { get; set; } + + public string Comment { get; set; } = string.Empty;//上传的时候的 + public string QAComment { get; set; } = string.Empty; + public string BodyPartExamined { get; set; } = string.Empty; + public Guid UpdateUserId { get; set; } + public DateTime UpdateTime { get; set; } = DateTime.Now; + public Guid CreateUserId { get; set; } + public DateTime CreateTime { get; set; } = DateTime.Now; + } +} diff --git a/IRaCIS.Core.Domain/Image/IRepository/IDicomInstanceRepository.cs b/IRaCIS.Core.Domain/Image/IRepository/IDicomInstanceRepository.cs new file mode 100644 index 0000000..df55545 --- /dev/null +++ b/IRaCIS.Core.Domain/Image/IRepository/IDicomInstanceRepository.cs @@ -0,0 +1,9 @@ +using IRaCIS.Core.Domain.Models; + +namespace IRaCIS.Core.Domain.Interfaces +{ + public interface IDicomInstanceRepository : IRepository + { + + } +} \ No newline at end of file diff --git a/IRaCIS.Core.Domain/Image/IRepository/IDicomSeriesRepository.cs b/IRaCIS.Core.Domain/Image/IRepository/IDicomSeriesRepository.cs new file mode 100644 index 0000000..126502c --- /dev/null +++ b/IRaCIS.Core.Domain/Image/IRepository/IDicomSeriesRepository.cs @@ -0,0 +1,9 @@ +using IRaCIS.Core.Domain.Models; + +namespace IRaCIS.Core.Domain.Interfaces +{ + public interface IDicomSeriesRepository : IRepository + { + + } +} \ No newline at end of file diff --git a/IRaCIS.Core.Domain/Image/IRepository/IDicomStudyRepository.cs b/IRaCIS.Core.Domain/Image/IRepository/IDicomStudyRepository.cs new file mode 100644 index 0000000..c8f737f --- /dev/null +++ b/IRaCIS.Core.Domain/Image/IRepository/IDicomStudyRepository.cs @@ -0,0 +1,8 @@ +using IRaCIS.Core.Domain.Models; + +namespace IRaCIS.Core.Domain.Interfaces +{ + public interface IDicomStudyRepository : IRepository + { + } +} diff --git a/IRaCIS.Core.Domain/Image/IRepository/IImageLabelRepository.cs b/IRaCIS.Core.Domain/Image/IRepository/IImageLabelRepository.cs new file mode 100644 index 0000000..83fad9c --- /dev/null +++ b/IRaCIS.Core.Domain/Image/IRepository/IImageLabelRepository.cs @@ -0,0 +1,11 @@ +using IRaCIS.Core.Domain.Models; +using System; +using System.Collections.Generic; +using System.Text; + +namespace IRaCIS.Core.Domain.Interfaces +{ + public interface IImageLabelRepository : IRepository + { + } +} diff --git a/IRaCIS.Core.Domain/Image/IRepository/IImageQARepository.cs b/IRaCIS.Core.Domain/Image/IRepository/IImageQARepository.cs new file mode 100644 index 0000000..e59012a --- /dev/null +++ b/IRaCIS.Core.Domain/Image/IRepository/IImageQARepository.cs @@ -0,0 +1,9 @@ +using IRaCIS.Core.Domain.Models; + +namespace IRaCIS.Core.Domain.Interfaces +{ + public interface IImageQARepository : IRepository + { + + } +} \ No newline at end of file diff --git a/IRaCIS.Core.Domain/Image/IRepository/IKeyInstanceRepository.cs b/IRaCIS.Core.Domain/Image/IRepository/IKeyInstanceRepository.cs new file mode 100644 index 0000000..a43034c --- /dev/null +++ b/IRaCIS.Core.Domain/Image/IRepository/IKeyInstanceRepository.cs @@ -0,0 +1,8 @@ +using IRaCIS.Core.Domain.Models; + +namespace IRaCIS.Core.Domain.Interfaces +{ + public interface IKeyInstanceRepository : IRepository + { + } +} \ No newline at end of file diff --git a/IRaCIS.Core.Domain/Image/IRepository/IStudyReviewerRepository.cs b/IRaCIS.Core.Domain/Image/IRepository/IStudyReviewerRepository.cs new file mode 100644 index 0000000..28d5cae --- /dev/null +++ b/IRaCIS.Core.Domain/Image/IRepository/IStudyReviewerRepository.cs @@ -0,0 +1,8 @@ +using IRaCIS.Core.Domain.Models; + +namespace IRaCIS.Core.Domain.Interfaces +{ + public interface IStudyReviewerRepository : IRepository + { + } +} diff --git a/IRaCIS.Core.Domain/Image/IRepository/IStudyStatusDetailRepository.cs b/IRaCIS.Core.Domain/Image/IRepository/IStudyStatusDetailRepository.cs new file mode 100644 index 0000000..1a9bef0 --- /dev/null +++ b/IRaCIS.Core.Domain/Image/IRepository/IStudyStatusDetailRepository.cs @@ -0,0 +1,8 @@ +using IRaCIS.Core.Domain.Models; + +namespace IRaCIS.Core.Domain.Interfaces +{ + public interface IStudyStatusDetailRepository : IRepository + { + } +} diff --git a/IRaCIS.Core.Domain/Image/ImageLabel.cs b/IRaCIS.Core.Domain/Image/ImageLabel.cs new file mode 100644 index 0000000..2b98540 --- /dev/null +++ b/IRaCIS.Core.Domain/Image/ImageLabel.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations.Schema; +using System.Text; + +namespace IRaCIS.Core.Domain.Models +{ + [Table("ImageLabel")] + public class ImageLabel : Entity + { + public string TpCode { get; set; } = string.Empty; + public Guid StudyId { get; set; } = Guid.Empty; + public Guid SeriesId { get; set; } = Guid.Empty; + public Guid InstanceId { get; set; } = Guid.Empty; + public string LabelValue { get; set; } = string.Empty; + } +} diff --git a/IRaCIS.Core.Domain/Image/ImageQA.cs b/IRaCIS.Core.Domain/Image/ImageQA.cs new file mode 100644 index 0000000..a24d2f9 --- /dev/null +++ b/IRaCIS.Core.Domain/Image/ImageQA.cs @@ -0,0 +1,16 @@ +using System; + +namespace IRaCIS.Core.Domain.Models +{ + public class ImageQA : Entity, IAuditAdd + { + public Guid TrialId { get; set; } + public Guid SiteId { get; set; } + public Guid StudyId { get; set; } + public Guid ParentId { get; set; } + public string CommunicationRecord { get; set; } + public Guid CreateUserId { get; set; } + public DateTime CreateTime { get; set; } = DateTime.Now; + + } +} \ No newline at end of file diff --git a/IRaCIS.Core.Domain/Image/KeyInstance.cs b/IRaCIS.Core.Domain/Image/KeyInstance.cs new file mode 100644 index 0000000..bea65ae --- /dev/null +++ b/IRaCIS.Core.Domain/Image/KeyInstance.cs @@ -0,0 +1,18 @@ +using System; +using System.ComponentModel.DataAnnotations.Schema; + +namespace IRaCIS.Core.Domain.Models +{ + [Table("KeyInstance")] + public class KeyInstance : Entity, IAuditAdd, IAuditUpdate + { + + public string TpCode { get; set; } + public Guid SeriesId { get; set; } + public Guid InstanceId { get; set; } + public Guid CreateUserId { get; set; } + public DateTime CreateTime { get; set; } = DateTime.Now; + public Guid UpdateUserId { get; set; } + public DateTime UpdateTime { get; set; } = DateTime.Now; + } +} diff --git a/IRaCIS.Core.Domain/Image/StudyReviewer.cs b/IRaCIS.Core.Domain/Image/StudyReviewer.cs new file mode 100644 index 0000000..8dc5192 --- /dev/null +++ b/IRaCIS.Core.Domain/Image/StudyReviewer.cs @@ -0,0 +1,20 @@ +using System; +using System.ComponentModel.DataAnnotations.Schema; + +namespace IRaCIS.Core.Domain.Models +{ + [Table("StudyReviewer")] + public class StudyReviewer : Entity, IAuditAdd + { + public Guid StudyId { get; set; } + public Guid ReviewerId { get; set; } + + public Guid TrialId { get; set; } + + // 2是 ad 1是tp + public int WorkloadType { get; set; } = 0; + public int Status { get; set; } = 30; + public Guid CreateUserId { get; set; } + public DateTime CreateTime { get; set; } = DateTime.Now; + } +} diff --git a/IRaCIS.Core.Domain/Image/StudyStatusDetail.cs b/IRaCIS.Core.Domain/Image/StudyStatusDetail.cs new file mode 100644 index 0000000..825d380 --- /dev/null +++ b/IRaCIS.Core.Domain/Image/StudyStatusDetail.cs @@ -0,0 +1,15 @@ +using System; +using System.ComponentModel.DataAnnotations.Schema; + +namespace IRaCIS.Core.Domain.Models +{ + [Table("StudyStatusDetail")] + public class StudyStatusDetail : Entity + { + public Guid StudyId { get; set; } + public int Status { get; set; } = 0; + public string OptUserName { get; set; } = string.Empty; + public DateTime OptTime { get; set; } = DateTime.Now; + public string Note { get; set; } = string.Empty; + } +} diff --git a/IRaCIS.Core.Domain/Institution/CRO.cs b/IRaCIS.Core.Domain/Institution/CRO.cs new file mode 100644 index 0000000..654b29f --- /dev/null +++ b/IRaCIS.Core.Domain/Institution/CRO.cs @@ -0,0 +1,17 @@ +using System; +using System.ComponentModel.DataAnnotations.Schema; + +namespace IRaCIS.Core.Domain.Models +{ + [Table("CROCompany")] + public partial class CRO : Entity, IAuditUpdate, IAuditAdd + { + public string CROName { get; set; } = string.Empty; + public string CROCode { get; set; } + + public DateTime CreateTime { get; set; } + public Guid CreateUserId { get; set; } + public Guid UpdateUserId { get; set; } + public DateTime UpdateTime { get; set; } + } +} diff --git a/IRaCIS.Core.Domain/Institution/Hospital.cs b/IRaCIS.Core.Domain/Institution/Hospital.cs new file mode 100644 index 0000000..0762fd6 --- /dev/null +++ b/IRaCIS.Core.Domain/Institution/Hospital.cs @@ -0,0 +1,23 @@ +using System; +using System.ComponentModel.DataAnnotations.Schema; + +namespace IRaCIS.Core.Domain.Models +{ + [Table("Hospital")] + public class Hospital : Entity, IAuditUpdate, IAuditAdd + { + public string HospitalName { get; set; } = string.Empty; + public string UniversityAffiliated { get; set; } = string.Empty; + public string Country { get; set; } = string.Empty; + public string Province { get; set; } = string.Empty; + public string City { get; set; } = string.Empty; + + + public DateTime CreateTime { get; set; } + public Guid CreateUserId { get; set; } = Guid.Empty; + + public DateTime UpdateTime { get; set; } = DateTime.Now; + public Guid UpdateUserId { get; set; } = Guid.Empty; + + } +} diff --git a/IRaCIS.Core.Domain/Institution/IRepository/ICRORepository.cs b/IRaCIS.Core.Domain/Institution/IRepository/ICRORepository.cs new file mode 100644 index 0000000..3a5b6d3 --- /dev/null +++ b/IRaCIS.Core.Domain/Institution/IRepository/ICRORepository.cs @@ -0,0 +1,9 @@ +using IRaCIS.Core.Domain.Models; + +namespace IRaCIS.Core.Domain.Interfaces +{ + public interface ICRORepository : IRepository + { + + } +} \ No newline at end of file diff --git a/IRaCIS.Core.Domain/Institution/IRepository/IHospitalRepository.cs b/IRaCIS.Core.Domain/Institution/IRepository/IHospitalRepository.cs new file mode 100644 index 0000000..099d41e --- /dev/null +++ b/IRaCIS.Core.Domain/Institution/IRepository/IHospitalRepository.cs @@ -0,0 +1,8 @@ +using IRaCIS.Core.Domain.Models; + +namespace IRaCIS.Core.Domain.Interfaces +{ + public interface IHospitalRepository : IRepository + { + } +} diff --git a/IRaCIS.Core.Domain/Institution/IRepository/ISiteRepository.cs b/IRaCIS.Core.Domain/Institution/IRepository/ISiteRepository.cs new file mode 100644 index 0000000..9ea8e20 --- /dev/null +++ b/IRaCIS.Core.Domain/Institution/IRepository/ISiteRepository.cs @@ -0,0 +1,9 @@ +using IRaCIS.Core.Domain.Models; + +namespace IRaCIS.Core.Domain.Interfaces +{ + public interface ISiteRepository : IRepository + { + + } +} \ No newline at end of file diff --git a/IRaCIS.Core.Domain/Institution/IRepository/ISponsorRepository.cs b/IRaCIS.Core.Domain/Institution/IRepository/ISponsorRepository.cs new file mode 100644 index 0000000..9387c24 --- /dev/null +++ b/IRaCIS.Core.Domain/Institution/IRepository/ISponsorRepository.cs @@ -0,0 +1,9 @@ +using IRaCIS.Core.Domain.Models; + +namespace IRaCIS.Core.Domain.Interfaces +{ + public interface ISponsorRepository : IRepository + { + + } +} \ No newline at end of file diff --git a/IRaCIS.Core.Domain/Institution/Site.cs b/IRaCIS.Core.Domain/Institution/Site.cs new file mode 100644 index 0000000..c76dc1b --- /dev/null +++ b/IRaCIS.Core.Domain/Institution/Site.cs @@ -0,0 +1,27 @@ +using System; +using System.ComponentModel.DataAnnotations.Schema; + +namespace IRaCIS.Core.Domain.Models +{ + [Table("Site")] + public partial class Site : Entity, IAuditUpdate, IAuditAdd + { + public string SiteName { get; set; } + public string SiteCode { get; set; } + + public string City { get; set; } + public string Country { get; set; } + public Guid HospitalId { get; set; } = Guid.Empty; + public string DirectorName { get; set; } = string.Empty; + public string DirectorPhone { get; set; } = string.Empty; + public string ContactName { get; set; } = string.Empty; + public string ContactPhone { get; set; } = string.Empty; + + public int State { get; set; } + + public Guid CreateUserId { get; set; } = Guid.Empty; + public DateTime CreateTime { get; set; } = DateTime.Now; + public Guid UpdateUserId { get; set; } = Guid.Empty; + public DateTime UpdateTime { get; set; } = DateTime.Now; + } +} diff --git a/IRaCIS.Core.Domain/Institution/Sponsor.cs b/IRaCIS.Core.Domain/Institution/Sponsor.cs new file mode 100644 index 0000000..c91cdb3 --- /dev/null +++ b/IRaCIS.Core.Domain/Institution/Sponsor.cs @@ -0,0 +1,16 @@ +using System; +using System.ComponentModel.DataAnnotations.Schema; + +namespace IRaCIS.Core.Domain.Models +{ + [Table("Sponsor")] + public partial class Sponsor : Entity, IAuditUpdate, IAuditAdd + { + public string SponsorName { get; set; } = String.Empty; + + public DateTime CreateTime { get; set; } = DateTime.Now; + public Guid CreateUserId { get; set; } = Guid.Empty; + public DateTime UpdateTime { get; set; } = DateTime.Now; + public Guid UpdateUserId { get; set; } = Guid.Empty; + } +} diff --git a/IRaCIS.Core.Domain/Management/IRepository/IMenuFunctionRepository.cs b/IRaCIS.Core.Domain/Management/IRepository/IMenuFunctionRepository.cs new file mode 100644 index 0000000..3c58b71 --- /dev/null +++ b/IRaCIS.Core.Domain/Management/IRepository/IMenuFunctionRepository.cs @@ -0,0 +1,8 @@ +using IRaCIS.Core.Domain.Models; + +namespace IRaCIS.Core.Domain.Interfaces +{ + public interface IMenuFunctionRepository : IRepository + { + } +} diff --git a/IRaCIS.Core.Domain/Management/IRepository/IRoleMenuFunctionRepository.cs b/IRaCIS.Core.Domain/Management/IRepository/IRoleMenuFunctionRepository.cs new file mode 100644 index 0000000..1d679ac --- /dev/null +++ b/IRaCIS.Core.Domain/Management/IRepository/IRoleMenuFunctionRepository.cs @@ -0,0 +1,8 @@ +using IRaCIS.Core.Domain.Models; + +namespace IRaCIS.Core.Domain.Interfaces +{ + public interface IRoleMenuFunctionRepository : IRepository + { + } +} diff --git a/IRaCIS.Core.Domain/Management/IRepository/IRoleRepository.cs b/IRaCIS.Core.Domain/Management/IRepository/IRoleRepository.cs new file mode 100644 index 0000000..e49d11f --- /dev/null +++ b/IRaCIS.Core.Domain/Management/IRepository/IRoleRepository.cs @@ -0,0 +1,9 @@ +using IRaCIS.Core.Domain.Models; + +namespace IRaCIS.Core.Domain.Interfaces +{ + public interface IRoleRepository : IRepository + { + + } +} diff --git a/IRaCIS.Core.Domain/Management/IRepository/IUserRepository.cs b/IRaCIS.Core.Domain/Management/IRepository/IUserRepository.cs new file mode 100644 index 0000000..6a1c5c5 --- /dev/null +++ b/IRaCIS.Core.Domain/Management/IRepository/IUserRepository.cs @@ -0,0 +1,9 @@ +using IRaCIS.Core.Domain.Models; + +namespace IRaCIS.Core.Domain.Interfaces +{ + public interface IUserRepository : IRepository + { + + } +} diff --git a/IRaCIS.Core.Domain/Management/IRepository/IUserRoleRepository.cs b/IRaCIS.Core.Domain/Management/IRepository/IUserRoleRepository.cs new file mode 100644 index 0000000..2a3b061 --- /dev/null +++ b/IRaCIS.Core.Domain/Management/IRepository/IUserRoleRepository.cs @@ -0,0 +1,9 @@ +using IRaCIS.Core.Domain.Models; + +namespace IRaCIS.Core.Domain.Interfaces +{ + public interface IUserRoleRepository : IRepository + { + + } +} diff --git a/IRaCIS.Core.Domain/Management/MenuFunction.cs b/IRaCIS.Core.Domain/Management/MenuFunction.cs new file mode 100644 index 0000000..8bcf991 --- /dev/null +++ b/IRaCIS.Core.Domain/Management/MenuFunction.cs @@ -0,0 +1,33 @@ +using System; +using System.ComponentModel.DataAnnotations.Schema; + +namespace IRaCIS.Core.Domain.Models +{ + [Table("MenuFunction")] + public class MenuFunction : Entity, IAuditUpdate, IAuditAdd + { + public Guid ParentId { get; set; } = Guid.Empty; + public string MenuName { get; set; } = string.Empty; + public string RouteName { get; set; } = string.Empty; + public string Component { get; set; } = string.Empty; + public string Redirect { get; set; } = string.Empty; + public string Path { get; set; } = string.Empty; + public string MetaTitle { get; set; } = string.Empty; + public bool MetaBreadcrumb { get; set; } = false; + public string MetaIcon { get; set; } = string.Empty; + public string MetaActiveMenu { get; set; } = string.Empty; + public string FunctionName { get; set; } = string.Empty; + public bool IsFunction { get; set; } = false; + public string Note { get; set; } = string.Empty; + public int ShowOrder { get; set; } = 0; + public int Status { get; set; } = 1; + public bool Hidden { get; set; } + public bool SuperAdmin { get; set; } = true; + + public DateTime CreateTime { get; set; } = DateTime.Now; + public Guid CreateUserId { get; set; } = Guid.Empty; + public DateTime UpdateTime { get; set; } = DateTime.Now; + public Guid UpdateUserId { get; set; } = Guid.Empty; + + } +} diff --git a/IRaCIS.Core.Domain/Management/Role.cs b/IRaCIS.Core.Domain/Management/Role.cs new file mode 100644 index 0000000..2834f51 --- /dev/null +++ b/IRaCIS.Core.Domain/Management/Role.cs @@ -0,0 +1,21 @@ +using System; +using System.ComponentModel.DataAnnotations.Schema; + +namespace IRaCIS.Core.Domain.Models +{ + [Table("Role")] + public partial class Role : Entity, IAuditUpdate, IAuditAdd + { + public string RoleName { get; set; } = string.Empty; + + public string RoleDescription { get; set; } = string.Empty; + + public int Status { get; set; } + public int PrivilegeLevel { get; set; } //Ȩ޼ + + public DateTime CreateTime { get; set; } = DateTime.Now; + public Guid CreateUserId { get; set; } = Guid.Empty; + public DateTime UpdateTime { get; set; } = DateTime.Now; + public Guid UpdateUserId { get; set; } = Guid.Empty; + } +} diff --git a/IRaCIS.Core.Domain/Management/RoleMenuFunction.cs b/IRaCIS.Core.Domain/Management/RoleMenuFunction.cs new file mode 100644 index 0000000..93daf1a --- /dev/null +++ b/IRaCIS.Core.Domain/Management/RoleMenuFunction.cs @@ -0,0 +1,13 @@ +using System; +using System.ComponentModel.DataAnnotations.Schema; + +namespace IRaCIS.Core.Domain.Models +{ + [Table("RoleMenuFunction")] + public partial class RoleMenuFunction : Entity + { + public Guid RoleId { get; set; } + public Guid MenuFunctionId { get; set; } + public bool IsFunction { get; set; } + } +} diff --git a/IRaCIS.Core.Domain/Management/User.cs b/IRaCIS.Core.Domain/Management/User.cs new file mode 100644 index 0000000..2e8f3c4 --- /dev/null +++ b/IRaCIS.Core.Domain/Management/User.cs @@ -0,0 +1,59 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace IRaCIS.Core.Domain.Models +{ + [Table("User")] + public partial class User : Entity, IAuditAdd, IAuditUpdate + { + public User() + { + UserRoleList = new HashSet(); + UserDoctors = new HashSet(); + } + + public virtual ICollection UserDoctors { get; set; } + public virtual ICollection UserRoleList { get; set; } + + + [StringLength(255)] + public string UserName { get; set; } + + [StringLength(255)] + public string Password { get; set; } + [StringLength(255)] + public string RealName { get; set; } + public string Phone { get; set; } = string.Empty; + public string EMail { get; set; } = string.Empty; + public int Sex { get; set; } + + public int Status { get; set; } = 1; + + + + public DateTime? LastLoginTime { get; set; } + + public bool SuperAdmin { get; set; } = false; + public Guid UserTypeId { get; set; } = Guid.Empty; + public string Code { get; set; } = string.Empty; + public bool IsZhiZhun { get; set; } + + public string UserType { get; set; } = string.Empty; + public string OrganizationName { get; set; } + public Guid OrganizationId { get; set; } = Guid.Empty; + + public Guid OrganizationTypeId { get; set; } = Guid.Empty; + public string OrganizationType { get; set; } = String.Empty; + + public string DepartmentName { get; set; } = String.Empty; + + public string PositionName { get; set; } = String.Empty; + + public Guid CreateUserId { get; set; } + public DateTime CreateTime { get; set; } + public Guid UpdateUserId { get; set; } + public DateTime UpdateTime { get; set; } + } +} diff --git a/IRaCIS.Core.Domain/Management/UserRole.cs b/IRaCIS.Core.Domain/Management/UserRole.cs new file mode 100644 index 0000000..b295325 --- /dev/null +++ b/IRaCIS.Core.Domain/Management/UserRole.cs @@ -0,0 +1,14 @@ +using System; +using System.ComponentModel.DataAnnotations.Schema; + +namespace IRaCIS.Core.Domain.Models +{ + [Table("UserRole")] + public partial class UserRole : Entity + { + public Role Role { get; set; } + public User User { get; set; } + public Guid UserId { get; set; } + public Guid RoleId { get; set; } + } +} diff --git a/IRaCIS.Core.Domain/QA/IRepository/IQADialogRepository.cs b/IRaCIS.Core.Domain/QA/IRepository/IQADialogRepository.cs new file mode 100644 index 0000000..558ba0b --- /dev/null +++ b/IRaCIS.Core.Domain/QA/IRepository/IQADialogRepository.cs @@ -0,0 +1,9 @@ +using IRaCIS.Core.Domain.Models; + +namespace IRaCIS.Core.Domain.Interfaces +{ + public interface IQADialogRepository : IRepository + { + + } +} \ No newline at end of file diff --git a/IRaCIS.Core.Domain/QA/IRepository/IQADictionaryRepository.cs b/IRaCIS.Core.Domain/QA/IRepository/IQADictionaryRepository.cs new file mode 100644 index 0000000..432e0a9 --- /dev/null +++ b/IRaCIS.Core.Domain/QA/IRepository/IQADictionaryRepository.cs @@ -0,0 +1,9 @@ +using IRaCIS.Core.Domain.Models; + +namespace IRaCIS.Core.Domain.Interfaces +{ + public interface IQADictionaryRepository : IRepository + { + + } +} \ No newline at end of file diff --git a/IRaCIS.Core.Domain/QA/IRepository/IQARecordRepository.cs b/IRaCIS.Core.Domain/QA/IRepository/IQARecordRepository.cs new file mode 100644 index 0000000..3671f71 --- /dev/null +++ b/IRaCIS.Core.Domain/QA/IRepository/IQARecordRepository.cs @@ -0,0 +1,9 @@ +using IRaCIS.Core.Domain.Models; + +namespace IRaCIS.Core.Domain.Interfaces +{ + public interface IQARecordRepository : IRepository + { + + } +} \ No newline at end of file diff --git a/IRaCIS.Core.Domain/QA/IRepository/IQATemplateDictionaryRepository.cs b/IRaCIS.Core.Domain/QA/IRepository/IQATemplateDictionaryRepository.cs new file mode 100644 index 0000000..28c6ff1 --- /dev/null +++ b/IRaCIS.Core.Domain/QA/IRepository/IQATemplateDictionaryRepository.cs @@ -0,0 +1,9 @@ +using IRaCIS.Core.Domain.Models; + +namespace IRaCIS.Core.Domain.Interfaces +{ + public interface IQATemplateDictionaryRepository : IRepository + { + + } +} \ No newline at end of file diff --git a/IRaCIS.Core.Domain/QA/IRepository/IQATemplateRepository.cs b/IRaCIS.Core.Domain/QA/IRepository/IQATemplateRepository.cs new file mode 100644 index 0000000..72a990b --- /dev/null +++ b/IRaCIS.Core.Domain/QA/IRepository/IQATemplateRepository.cs @@ -0,0 +1,9 @@ +using IRaCIS.Core.Domain.Models; + +namespace IRaCIS.Core.Domain.Interfaces +{ + public interface IQATemplateRepository : IRepository + { + + } +} \ No newline at end of file diff --git a/IRaCIS.Core.Domain/QA/QADialog.cs b/IRaCIS.Core.Domain/QA/QADialog.cs new file mode 100644 index 0000000..3112c96 --- /dev/null +++ b/IRaCIS.Core.Domain/QA/QADialog.cs @@ -0,0 +1,16 @@ +using System; + +namespace IRaCIS.Core.Domain.Models +{ + public class QADialog : Entity, IAuditAdd + { + public string TalkContent { get; set; } = string.Empty; + + public Guid QARecordId { get; set; } + + public Guid ParentId { get; set; } + + public DateTime CreateTime { get; set; } = DateTime.Now; + public Guid CreateUserId { get; set; } = Guid.Empty; + } +} \ No newline at end of file diff --git a/IRaCIS.Core.Domain/QA/QADictionary.cs b/IRaCIS.Core.Domain/QA/QADictionary.cs new file mode 100644 index 0000000..bd2e707 --- /dev/null +++ b/IRaCIS.Core.Domain/QA/QADictionary.cs @@ -0,0 +1,17 @@ +using System; + +namespace IRaCIS.Core.Domain.Models +{ + public class QADictionary : Entity + { + public Guid QARecordId { get; set; } + + public string Note { get; set; } + + public Guid DictionaryId { get; set; } + + public Guid TrialId { get; set; } + + public Guid SiteId { get; set; } + } +} \ No newline at end of file diff --git a/IRaCIS.Core.Domain/QA/QARecord.cs b/IRaCIS.Core.Domain/QA/QARecord.cs new file mode 100644 index 0000000..c417590 --- /dev/null +++ b/IRaCIS.Core.Domain/QA/QARecord.cs @@ -0,0 +1,31 @@ +using System; +using System.Collections.Generic; + +namespace IRaCIS.Core.Domain.Models +{ + public class QARecord : Entity, IAuditAdd + { + public Guid StudyId { get; set; } + + public Guid QATemplateId { get; set; } + + public DateTime? DeadlineTime { get; set; } + + public string Note { get; set; } = string.Empty; + + public DateTime CreateTime { get; set; } = DateTime.Now; + + public Guid CreateUserId { get; set; } = Guid.Empty; + + public virtual ICollection QaDictionaryList { get; set; } + + public QARecord() + { + //存放医生关联 Title、等各种多选项 + QaDictionaryList = new HashSet(); + } + + + + } +} \ No newline at end of file diff --git a/IRaCIS.Core.Domain/QA/QATemplate.cs b/IRaCIS.Core.Domain/QA/QATemplate.cs new file mode 100644 index 0000000..23b086f --- /dev/null +++ b/IRaCIS.Core.Domain/QA/QATemplate.cs @@ -0,0 +1,15 @@ +using System; + +namespace IRaCIS.Core.Domain.Models +{ + public class QATemplate : Entity, IAuditUpdate, IAuditAdd + { + public string Name { get; set; } = string.Empty; + public string Description { get; set; } = string.Empty; + + public DateTime CreateTime { get; set; } = DateTime.Now; + public Guid CreateUserId { get; set; } = Guid.Empty; + public DateTime UpdateTime { get; set; } = DateTime.Now; + public Guid UpdateUserId { get; set; } = Guid.Empty; + } +} \ No newline at end of file diff --git a/IRaCIS.Core.Domain/QA/QATemplateDictionary.cs b/IRaCIS.Core.Domain/QA/QATemplateDictionary.cs new file mode 100644 index 0000000..44aa4d7 --- /dev/null +++ b/IRaCIS.Core.Domain/QA/QATemplateDictionary.cs @@ -0,0 +1,11 @@ +using System; + +namespace IRaCIS.Core.Domain.Models +{ + public class QATemplateDictionary : Entity + { + public Guid DictionaryId { get; set; } + + public Guid QATemplateId { get; set; } + } +} \ No newline at end of file diff --git a/IRaCIS.Core.Domain/Relation/IRepository/IUserDoctorRepository.cs b/IRaCIS.Core.Domain/Relation/IRepository/IUserDoctorRepository.cs new file mode 100644 index 0000000..02371d6 --- /dev/null +++ b/IRaCIS.Core.Domain/Relation/IRepository/IUserDoctorRepository.cs @@ -0,0 +1,9 @@ +using IRaCIS.Core.Domain.Models; + +namespace IRaCIS.Core.Domain.Interfaces +{ + public interface IUserDoctorRepository : IRepository + { + + } +} \ No newline at end of file diff --git a/IRaCIS.Core.Domain/Relation/IRepository/IUserTrialRepository.cs b/IRaCIS.Core.Domain/Relation/IRepository/IUserTrialRepository.cs new file mode 100644 index 0000000..7fd0f88 --- /dev/null +++ b/IRaCIS.Core.Domain/Relation/IRepository/IUserTrialRepository.cs @@ -0,0 +1,9 @@ +using IRaCIS.Core.Domain.Models; + +namespace IRaCIS.Core.Domain.Interfaces +{ + public interface IUserTrialRepository : IRepository + { + + } +} \ No newline at end of file diff --git a/IRaCIS.Core.Domain/Relation/UserDoctor.cs b/IRaCIS.Core.Domain/Relation/UserDoctor.cs new file mode 100644 index 0000000..0f93551 --- /dev/null +++ b/IRaCIS.Core.Domain/Relation/UserDoctor.cs @@ -0,0 +1,22 @@ +using System; +using System.ComponentModel.DataAnnotations.Schema; + +namespace IRaCIS.Core.Domain.Models +{ + /// + /// ûҽϵ - ʵ + /// + [Table("UserDoctor")] + public partial class UserDoctor : Entity + { + [ForeignKey("User")] + public Guid UserId { get; set; } + + [ForeignKey("Doctor")] + public Guid DoctorId { get; set; } + + public Doctor Doctor { get; set; } + + public User User { get; set; } + } +} diff --git a/IRaCIS.Core.Domain/Relation/UserTrial.cs b/IRaCIS.Core.Domain/Relation/UserTrial.cs new file mode 100644 index 0000000..5b23430 --- /dev/null +++ b/IRaCIS.Core.Domain/Relation/UserTrial.cs @@ -0,0 +1,32 @@ +using System; +using System.ComponentModel.DataAnnotations.Schema; + +namespace IRaCIS.Core.Domain.Models +{ + /// + /// άԱĿϵ - ʵ + /// + [Table("UserTrial")] + public partial class UserTrial : Entity, IAuditUpdate, IAuditAdd + { + public Guid UserId { get; set; } + public Guid TrialId { get; set; } + + + public Guid UserTypeId { get; set; } + public string UserType { get; set; } + public Guid OrganizationTypeId { get; set; } = Guid.Empty; + public string OrganizationType { get; set; } = string.Empty; + public string OrganizationName { get; set; } = string.Empty; + public Guid OrganizationId { get; set; } + + public string UserRealName { get; set; } + + public Guid SiteId { get; set; } = Guid.Empty; + + public Guid UpdateUserId { get; set; } + public DateTime UpdateTime { get; set; } + public Guid CreateUserId { get; set; } + public DateTime CreateTime { get; set; } + } +} diff --git a/IRaCIS.Core.Domain/Report/GlobalRS.cs b/IRaCIS.Core.Domain/Report/GlobalRS.cs new file mode 100644 index 0000000..a5eb5ca --- /dev/null +++ b/IRaCIS.Core.Domain/Report/GlobalRS.cs @@ -0,0 +1,15 @@ +using System; + +namespace IRaCIS.Core.Domain.Models +{ + public class GlobalRS : Entity + { + public Guid GlobalId { get; set; } + public string TpCode { get; set; } + public decimal VisitNum { get; set; } + public bool Agree { get; set; } + public string NewRS { get; set; } + public string Note { get; set; } + + } +} \ No newline at end of file diff --git a/IRaCIS.Core.Domain/Report/GlobalResult.cs b/IRaCIS.Core.Domain/Report/GlobalResult.cs new file mode 100644 index 0000000..1e6a2d7 --- /dev/null +++ b/IRaCIS.Core.Domain/Report/GlobalResult.cs @@ -0,0 +1,16 @@ +using System; + +namespace IRaCIS.Core.Domain.Models +{ + public class GlobalResult:Entity + { + public Guid GlobalId { get; set; } + public Guid SubjectId { get; set; } + public string SubjectCode { get; set; } + + public decimal VisitNum { get; set; } + public string SubjectNote { get; set; }=String.Empty; + public string Result { get; set; } = String.Empty; + + } +} \ No newline at end of file diff --git a/IRaCIS.Core.Domain/Report/IRepository/IGlobalRSRepository.cs b/IRaCIS.Core.Domain/Report/IRepository/IGlobalRSRepository.cs new file mode 100644 index 0000000..c9be7e4 --- /dev/null +++ b/IRaCIS.Core.Domain/Report/IRepository/IGlobalRSRepository.cs @@ -0,0 +1,9 @@ +using IRaCIS.Core.Domain.Models; + +namespace IRaCIS.Core.Domain.Interfaces +{ + public interface IGlobalRSRepository : IRepository + { + + } +} \ No newline at end of file diff --git a/IRaCIS.Core.Domain/Report/IRepository/IGlobalResultRepository.cs b/IRaCIS.Core.Domain/Report/IRepository/IGlobalResultRepository.cs new file mode 100644 index 0000000..a46a19e --- /dev/null +++ b/IRaCIS.Core.Domain/Report/IRepository/IGlobalResultRepository.cs @@ -0,0 +1,9 @@ +using IRaCIS.Core.Domain.Models; + +namespace IRaCIS.Core.Domain.Interfaces +{ + public interface IGlobalResultRepository : IRepository + { + + } +} \ No newline at end of file diff --git a/IRaCIS.Core.Domain/Report/IRepository/IReportRepository.cs b/IRaCIS.Core.Domain/Report/IRepository/IReportRepository.cs new file mode 100644 index 0000000..bc59066 --- /dev/null +++ b/IRaCIS.Core.Domain/Report/IRepository/IReportRepository.cs @@ -0,0 +1,11 @@ +using IRaCIS.Core.Domain.Models; +using System; +using System.Collections.Generic; +using System.Text; + +namespace IRaCIS.Core.Domain.Interfaces +{ + public interface IReportRepository : IRepository + { + } +} diff --git a/IRaCIS.Core.Domain/Report/IRepository/TU_TR_RSRepository.cs b/IRaCIS.Core.Domain/Report/IRepository/TU_TR_RSRepository.cs new file mode 100644 index 0000000..9e17193 --- /dev/null +++ b/IRaCIS.Core.Domain/Report/IRepository/TU_TR_RSRepository.cs @@ -0,0 +1,17 @@ +using IRaCIS.Core.Domain.Models; +using System; +using System.Collections.Generic; +using System.Text; + +namespace IRaCIS.Core.Domain.Interfaces +{ + public interface ITURepository : IRepository + { + } + public interface ITRRepository : IRepository + { + } + public interface IRSRepository : IRepository + { + } +} diff --git a/IRaCIS.Core.Domain/Report/Report.cs b/IRaCIS.Core.Domain/Report/Report.cs new file mode 100644 index 0000000..8e59d14 --- /dev/null +++ b/IRaCIS.Core.Domain/Report/Report.cs @@ -0,0 +1,27 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations.Schema; +using System.Text; + +namespace IRaCIS.Core.Domain.Models +{ + [Table("Report")] + public class Report : Entity + { + public bool Qualified { get; set; } = true; + public string DiseaseProgression { get; set; } = string.Empty; + public string NotEvaluable { get; set; } = string.Empty; + public string Timepoint { get; set; } = string.Empty; + public string TrialCode { get; set; } = string.Empty; + public string SubjectCode { get; set; } = string.Empty; + public decimal? VisitNum { get; set; } + public string VisitName { get; set; } = string.Empty; + public int? DiseaseSituation { get; set; } + public string Comment { get; set; } + public Guid? TPId { get; set; } + public Guid? DicomStudyId { get; set; } + public string TpCode { get; set; } = string.Empty; + public bool AffectRead { get; set; } = false;//是否影响读片 + public string AffectReadNote { get; set; } = string.Empty;//备注说明 + } +} diff --git a/IRaCIS.Core.Domain/Report/TU_TR_RS.cs b/IRaCIS.Core.Domain/Report/TU_TR_RS.cs new file mode 100644 index 0000000..f074612 --- /dev/null +++ b/IRaCIS.Core.Domain/Report/TU_TR_RS.cs @@ -0,0 +1,129 @@ +using System; +using System.ComponentModel.DataAnnotations.Schema; + +namespace IRaCIS.Core.Domain.Models +{ + [Table("TU")] + public class TU : Entity + { + //病灶类型 1-非淋巴结靶病灶,2-淋巴结靶病灶,3-非靶病灶,,4-疑似新病灶,5-明确新病灶 + public int LesionType { get; set; } + public string STUDYID { get; set; } + public string DOMAIN { get; set; } = "TU"; + public string USUBJID { get; set; } + public int TUSEQ { get; set; } + public string TUGRPID { get; set; } = string.Empty; + public string TUREFID { get; set; } = string.Empty;//内部或外部的肿瘤/病灶标识。 例如:医学影像 ID + public string TUSPID { get; set; } = string.Empty; + public string TULNKID { get; set; } = string.Empty; + public string TUTESTCD { get; set; } = string.Empty; + public string TUTEST { get; set; } = string.Empty; + + //肿瘤标识的结果。 肿瘤标识的结果是对标识肿瘤的分类。 + //例如,当 TUTESTCD=TUMIDENT (肿瘤/病灶标识)时, + //TUORRES的值可能是 TARGET, NON-TARGET, NEW或者 BENIGN ABNORMALITY + public string TUORRES { get; set; } = string.Empty; + public string TUSTRESC { get; set; } = string.Empty; + public string TUNAM { get; set; } = string.Empty; + public string TULOC { get; set; } = string.Empty; + public string TULAT { get; set; } = string.Empty; + public string TUDIR { get; set; } = string.Empty; + public string TUPORTOT { get; set; } = string.Empty; + public string TUMETHOD { get; set; } = string.Empty; + public string TUEVAL { get; set; } = string.Empty; + public string TUEVALID { get; set; } = string.Empty; + public string TUACPTFL { get; set; } = string.Empty; + public decimal VISITNUM { get; set; } = 0; + public string VISIT { get; set; } = string.Empty; + public int VISITDY { get; set; } + public string EPOCH { get; set; } = string.Empty; + public string TUDTC { get; set; } = string.Empty; + public int TUDY { get; set; } = 0; + public string LocDescription { get; set; } = string.Empty; + + public string TpCode { get; set; } = string.Empty; + } + + [Table("TR")] + public class TR : Entity + { + public string STUDYID { get; set; } = string.Empty; + public string DOMAIN { get; set; } = "TR"; + public string USUBJID { get; set; } = string.Empty; + public int TRSEQ { get; set; } + public string TRGRPID { get; set; } = string.Empty; + public string TRREFID { get; set; } = string.Empty; + public string TRSPID { get; set; } = string.Empty; + public string TRLNKID { get; set; } = string.Empty; + public string TRLNKGRP { get; set; } = string.Empty; + public string TRTESTCD { get; set; } = string.Empty; + public string TRTEST { get; set; } = string.Empty; + public string TRORRES { get; set; } = string.Empty; + public double TRORRES_Double + { + get { + double temp = 0; + double.TryParse(TRORRES, out temp); + return temp; + } + } + public string TRORRESU { get; set; } = string.Empty; + public string TRSTRESC { get; set; } = string.Empty; + public double TRSTRESN { get; set; } = 0; + public string TRSTRESU { get; set; } = string.Empty; + public string TRSTAT { get; set; } = string.Empty; + public string TRREASND { get; set; } = string.Empty; + public string TRNAM { get; set; } = string.Empty; + public string TRMETHOD { get; set; } = string.Empty; + public string TREVAL { get; set; } = string.Empty; + public string TREVALID { get; set; } = string.Empty; + public string TRACPTFL { get; set; } = string.Empty; + public decimal VISITNUM { get; set; } = 0; + public string VISIT { get; set; } = string.Empty; + public int VISITDY { get; set; } = 0; + public string EPOCH { get; set; } = string.Empty; + public string TRDTC { get; set; } = string.Empty; + public int TRDY { get; set; } = 0; + public string Note { get; set; } // 备注 + public bool CoveredLesion { get; set; } = true;//本次扫描是否覆盖该病灶 + public string TpCode { get; set; } = string.Empty; + } + + [Table("RS")] + public class RS : Entity + { + public string STUDYID { get; set; } = string.Empty; + public string DOMAIN { get; set; } = "RS"; + public string USUBJID { get; set; } = string.Empty; + public int RSSEQ { get; set; } + public string RSGRPID { get; set; } = string.Empty; + public string RSREFID { get; set; } = string.Empty; + public string RSSPID { get; set; } = string.Empty; + public string RSLNKID { get; set; } = string.Empty; + public string RSLNKGRP { get; set; } = string.Empty; + public string RSTESTCD { get; set; } = string.Empty; + public string RSTEST { get; set; } = string.Empty; + public string RSCAT { get; set; } = string.Empty; + public string RSORRES { get; set; } = string.Empty; + public string RSSTRESC { get; set; } = string.Empty; + public string RSSTAT { get; set; } = string.Empty; + public string RSREASND { get; set; } = string.Empty; + public string RSNAM { get; set; } = string.Empty; + + public string RSEVAL { get; set; } = string.Empty; + public string RSEVALID { get; set; } = string.Empty; + public string RSACPTFL { get; set; } = string.Empty; + public decimal VISITNUM { get; set; } = 0; + public string VISIT { get; set; } = string.Empty; + public int VISITDY { get; set; } = 0; + public string EPOCH { get; set; } = string.Empty; + public string RSDTC { get; set; } = string.Empty; + public int RSDY { get; set; } = 0; + public string TpCode { get; set; } = string.Empty; + public Guid StudyGuid { get; set; } = Guid.Empty; + public Guid TrialGuid { get; set; } = Guid.Empty; + public Guid SubjectGuid { get; set; } = Guid.Empty; + public string Note { get; set; } = string.Empty; + + } +} diff --git a/IRaCIS.Core.Domain/Test.cs b/IRaCIS.Core.Domain/Test.cs new file mode 100644 index 0000000..bce40fd --- /dev/null +++ b/IRaCIS.Core.Domain/Test.cs @@ -0,0 +1,15 @@ +using System; +using System.ComponentModel.DataAnnotations.Schema; +using IRaCIS.Core.Domain.Models; + +namespace IRaCIS.Core.Domain +{ + public class Test:Entity + { + [DatabaseGenerated(DatabaseGeneratedOption.Identity)] + public int AutoIncrease { get; set; } + + public string Str { get; set; } + + } +} \ No newline at end of file diff --git a/IRaCIS.Core.Domain/Trial/Enroll.cs b/IRaCIS.Core.Domain/Trial/Enroll.cs new file mode 100644 index 0000000..545fbab --- /dev/null +++ b/IRaCIS.Core.Domain/Trial/Enroll.cs @@ -0,0 +1,57 @@ +using System; +using System.ComponentModel.DataAnnotations.Schema; + +namespace IRaCIS.Core.Domain.Models +{ + [Table("Enroll")] + public partial class Enroll : Entity, IAuditUpdate, IAuditAdd + { + + public virtual Trial Trial { get; set; } + + + public virtual Doctor Doctor { get; set; } + + //public TrialPaymentPrice TrialPaymentPrice { get; set; } + + public Guid DoctorId { get; set; } + public Guid TrialId { get; set; } + public Guid AttachmentId { get; set; } = Guid.Empty; + public int EnrollStatus { get; set; } + + public decimal? AdjustmentMultiple { get; set; } + public DateTime? EnrollTime { get; set; } + public DateTime? OutEnrollTime { get; set; } + + public string Memo { get; set; } = string.Empty; + + public int ReviewerReadingType { get; set; } = 0; + + public Guid UpdateUserId { get; set; } + public DateTime UpdateTime { get; set; } = DateTime.Now; + public Guid CreateUserId { get; set; } + public DateTime CreateTime { get; set; } + + public int? Training { get; set; } + + public int? RefresherTraining { get; set; } + + public int? Timepoint { get; set; } + + public int? Timepoint48H { get; set; } + + public int? Timepoint24H { get; set; } + + public int? Adjudication { get; set; } + + public int? Adjudication48H { get; set; } + + public int? Adjudication24H { get; set; } + + public int? Global { get; set; } + + + public int? Downtime { get; set; } + + } +} diff --git a/IRaCIS.Core.Domain/Trial/EnrollDetail.cs b/IRaCIS.Core.Domain/Trial/EnrollDetail.cs new file mode 100644 index 0000000..8298956 --- /dev/null +++ b/IRaCIS.Core.Domain/Trial/EnrollDetail.cs @@ -0,0 +1,26 @@ +using System; +using System.ComponentModel.DataAnnotations.Schema; + +namespace IRaCIS.Core.Domain.Models +{ + [Table("EnrollDetail")] + public partial class EnrollDetail : Entity, IAuditAdd + { + public virtual TrialStatusDetail TrialDetail { get; set; } + + public Guid DoctorId { get; set; } + public Guid TrialId { get; set; } + public int EnrollStatus { get; set; } + public Guid? EnrollId { get; set; } + public string Memo { get; set; } = string.Empty; + public Guid CreateUserId { get; set; } + public int OptUserType { get; set; } + public DateTime CreateTime { get; set; } + + [ForeignKey("TrialDetail")] + public Guid TrialDetailId { get; set; } + + //public Guid CreateUserId { get; set; } + //public DateTime CreateTime { get; set; } + } +} diff --git a/IRaCIS.Core.Domain/Trial/IRepository/IAcquisitionSpecificationRepository.cs b/IRaCIS.Core.Domain/Trial/IRepository/IAcquisitionSpecificationRepository.cs new file mode 100644 index 0000000..83ffae5 --- /dev/null +++ b/IRaCIS.Core.Domain/Trial/IRepository/IAcquisitionSpecificationRepository.cs @@ -0,0 +1,8 @@ +using IRaCIS.Core.Domain.Models; + +namespace IRaCIS.Core.Domain.Interfaces +{ + public interface IAcquisitionSpecificationRepository : IRepository + { + } +} diff --git a/IRaCIS.Core.Domain/Trial/IRepository/IEnrollDetailRepository.cs b/IRaCIS.Core.Domain/Trial/IRepository/IEnrollDetailRepository.cs new file mode 100644 index 0000000..11c0bee --- /dev/null +++ b/IRaCIS.Core.Domain/Trial/IRepository/IEnrollDetailRepository.cs @@ -0,0 +1,9 @@ +using IRaCIS.Core.Domain.Models; + +namespace IRaCIS.Core.Domain.Interfaces +{ + public interface IEnrollDetailRepository : IRepository + { + + } +} \ No newline at end of file diff --git a/IRaCIS.Core.Domain/Trial/IRepository/IEnrollRepository.cs b/IRaCIS.Core.Domain/Trial/IRepository/IEnrollRepository.cs new file mode 100644 index 0000000..6793bd4 --- /dev/null +++ b/IRaCIS.Core.Domain/Trial/IRepository/IEnrollRepository.cs @@ -0,0 +1,9 @@ +using IRaCIS.Core.Domain.Models; + +namespace IRaCIS.Core.Domain.Interfaces +{ + public interface IEnrollRepository : IRepository + { + + } +} \ No newline at end of file diff --git a/IRaCIS.Core.Domain/Trial/IRepository/ISubjectRepository.cs b/IRaCIS.Core.Domain/Trial/IRepository/ISubjectRepository.cs new file mode 100644 index 0000000..284c86d --- /dev/null +++ b/IRaCIS.Core.Domain/Trial/IRepository/ISubjectRepository.cs @@ -0,0 +1,8 @@ +using IRaCIS.Core.Domain.Models; + +namespace IRaCIS.Core.Domain.Interfaces +{ + public interface ISubjectRepository : IRepository + { + } +} diff --git a/IRaCIS.Core.Domain/Trial/IRepository/ISubjectVisitRepository.cs b/IRaCIS.Core.Domain/Trial/IRepository/ISubjectVisitRepository.cs new file mode 100644 index 0000000..4008b16 --- /dev/null +++ b/IRaCIS.Core.Domain/Trial/IRepository/ISubjectVisitRepository.cs @@ -0,0 +1,8 @@ +using IRaCIS.Core.Domain.Models; + +namespace IRaCIS.Core.Domain.Interfaces +{ + public interface ISubjectVisitRepository : IRepository + { + } +} diff --git a/IRaCIS.Core.Domain/Trial/IRepository/ITrialDetailRepository.cs b/IRaCIS.Core.Domain/Trial/IRepository/ITrialDetailRepository.cs new file mode 100644 index 0000000..5868ae5 --- /dev/null +++ b/IRaCIS.Core.Domain/Trial/IRepository/ITrialDetailRepository.cs @@ -0,0 +1,9 @@ +using IRaCIS.Core.Domain.Models; + +namespace IRaCIS.Core.Domain.Interfaces +{ + public interface ITrialDetailRepository : IRepository + { + + } +} \ No newline at end of file diff --git a/IRaCIS.Core.Domain/Trial/IRepository/ITrialDictionaryRepository.cs b/IRaCIS.Core.Domain/Trial/IRepository/ITrialDictionaryRepository.cs new file mode 100644 index 0000000..a75125d --- /dev/null +++ b/IRaCIS.Core.Domain/Trial/IRepository/ITrialDictionaryRepository.cs @@ -0,0 +1,9 @@ +using IRaCIS.Core.Domain.Models; + +namespace IRaCIS.Core.Domain.Interfaces +{ + public interface ITrialDictionaryRepository: IRepository + { + + } +} \ No newline at end of file diff --git a/IRaCIS.Core.Domain/Trial/IRepository/ITrialInterviewRepository.cs b/IRaCIS.Core.Domain/Trial/IRepository/ITrialInterviewRepository.cs new file mode 100644 index 0000000..ae3a8ef --- /dev/null +++ b/IRaCIS.Core.Domain/Trial/IRepository/ITrialInterviewRepository.cs @@ -0,0 +1,8 @@ +using IRaCIS.Core.Domain.Models; + +namespace IRaCIS.Core.Domain.Interfaces +{ + public interface ITrialInterviewRepository : IRepository + { + } +} diff --git a/IRaCIS.Core.Domain/Trial/IRepository/ITrialRepository.cs b/IRaCIS.Core.Domain/Trial/IRepository/ITrialRepository.cs new file mode 100644 index 0000000..1b8ec53 --- /dev/null +++ b/IRaCIS.Core.Domain/Trial/IRepository/ITrialRepository.cs @@ -0,0 +1,9 @@ +using IRaCIS.Core.Domain.Models; + +namespace IRaCIS.Core.Domain.Interfaces +{ + public interface ITrialRepository : IRepository + { + //IEnumerable GetDoctorWorkLoadStatistics(int projectId); + } +} \ No newline at end of file diff --git a/IRaCIS.Core.Domain/Trial/IRepository/ITrialRevenuesPriceVerificationRepository.cs b/IRaCIS.Core.Domain/Trial/IRepository/ITrialRevenuesPriceVerificationRepository.cs new file mode 100644 index 0000000..3000734 --- /dev/null +++ b/IRaCIS.Core.Domain/Trial/IRepository/ITrialRevenuesPriceVerificationRepository.cs @@ -0,0 +1,9 @@ +using IRaCIS.Core.Domain.Models; + +namespace IRaCIS.Core.Domain.Interfaces +{ + public interface ITrialRevenuesPriceVerificationRepository : IRepository + { + + } +} \ No newline at end of file diff --git a/IRaCIS.Core.Domain/Trial/IRepository/IVisitStageRepository.cs b/IRaCIS.Core.Domain/Trial/IRepository/IVisitStageRepository.cs new file mode 100644 index 0000000..dbc0f9b --- /dev/null +++ b/IRaCIS.Core.Domain/Trial/IRepository/IVisitStageRepository.cs @@ -0,0 +1,8 @@ +using IRaCIS.Core.Domain.Models; + +namespace IRaCIS.Core.Domain.Interfaces +{ + public interface IVisitStageRepository : IRepository + { + } +} diff --git a/IRaCIS.Core.Domain/Trial/IRepository/IWorkloadDistributionRepository.cs b/IRaCIS.Core.Domain/Trial/IRepository/IWorkloadDistributionRepository.cs new file mode 100644 index 0000000..7eb9457 --- /dev/null +++ b/IRaCIS.Core.Domain/Trial/IRepository/IWorkloadDistributionRepository.cs @@ -0,0 +1,18 @@ +using IRaCIS.Core.Domain.Models; + +namespace IRaCIS.Core.Domain.Interfaces +{ + public interface IWorkloadTPRepository : IRepository + { + } + public interface IWorkloadGlobalRepository : IRepository + { + } + public interface IWorkloadADRepository : IRepository + { + } + + public interface IWorkloadDetailRepository : IRepository + { + } +} diff --git a/IRaCIS.Core.Domain/Trial/IRepository/IWorkloadRepository.cs b/IRaCIS.Core.Domain/Trial/IRepository/IWorkloadRepository.cs new file mode 100644 index 0000000..c12d84e --- /dev/null +++ b/IRaCIS.Core.Domain/Trial/IRepository/IWorkloadRepository.cs @@ -0,0 +1,9 @@ +using IRaCIS.Core.Domain.Models; + +namespace IRaCIS.Core.Domain.Interfaces +{ + public interface IWorkloadRepository : IRepository + { + + } +} \ No newline at end of file diff --git a/IRaCIS.Core.Domain/Trial/Subject.cs b/IRaCIS.Core.Domain/Trial/Subject.cs new file mode 100644 index 0000000..6ffa3e3 --- /dev/null +++ b/IRaCIS.Core.Domain/Trial/Subject.cs @@ -0,0 +1,30 @@ +using System; +using System.ComponentModel.DataAnnotations.Schema; + +namespace IRaCIS.Core.Domain.Models +{ + /// + /// 受试者 + /// + [Table("Subject")] + public class Subject : Entity, IAuditAdd, IAuditUpdate + { + public string Code { get; set; } + public string Name { get; set; } = string.Empty; + public int Age { get; set; } + public string Sex { get; set; } = string.Empty; + public Guid SiteId { get; set; } = Guid.Empty; + public Guid SubjectVisitId { get; set; } = Guid.Empty; + public Guid TrialId { get; set; } = Guid.Empty; + public string MedicalNo { get; set; } = string.Empty; + public int StudyCount { get; set; } = 0; + public string Modalities { get; set; } = string.Empty; + public int Status { get; set; } = 1;//1 访视中,2 出组 + public string Reason { get; set; } = string.Empty; + + public DateTime CreateTime { get; set; } + public Guid CreateUserId { get; set; } + public DateTime UpdateTime { get; set; } + public Guid UpdateUserId { get; set; } + } +} diff --git a/IRaCIS.Core.Domain/Trial/SubjectVisit.cs b/IRaCIS.Core.Domain/Trial/SubjectVisit.cs new file mode 100644 index 0000000..7725cd2 --- /dev/null +++ b/IRaCIS.Core.Domain/Trial/SubjectVisit.cs @@ -0,0 +1,32 @@ +using System; +using System.ComponentModel.DataAnnotations.Schema; + +namespace IRaCIS.Core.Domain.Models +{ + [Table("SubjectVisit")] + public class SubjectVisit : Entity, IAuditUpdate, IAuditAdd + { + public Guid TrialId { get; set; } + public Guid SubjectId { get; set; } + public Guid SiteId { get; set; } + public decimal VisitNum { get; set; } + public string VisitName { get; set; } = string.Empty; + public int VisitDay { get; set; } + public string SVUPDES { get; set; } = string.Empty; + public DateTime? SVSTDTC { get; set; } + public DateTime? SVENDTC { get; set; } + + + public bool InPlan { get; set; } = true; + + public bool StudyUploaded { get; set; } = false; + + + + + public Guid CreateUserId { get; set; } + public DateTime CreateTime { get; set; } + public Guid UpdateUserId { get; set; } + public DateTime UpdateTime { get; set; } + } +} diff --git a/IRaCIS.Core.Domain/Trial/Trial.cs b/IRaCIS.Core.Domain/Trial/Trial.cs new file mode 100644 index 0000000..d14c0a0 --- /dev/null +++ b/IRaCIS.Core.Domain/Trial/Trial.cs @@ -0,0 +1,87 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace IRaCIS.Core.Domain.Models +{ + [Table("Trial")] + public partial class Trial : Entity, IAuditUpdate, IAuditAdd + { + public Trial() + { + ClinicalTrialProjectDetails = new HashSet(); + TrialDicList = new List(); + } + + public virtual ICollection ClinicalTrialProjectDetails { get; set; } + public virtual ICollection TrialDicList { get; set; } + + [StringLength(100)] + public string Code { get; set; } = string.Empty; + + [StringLength(512)] + public string Indication { get; set; } = string.Empty; + + public int TrialStatus { get; set; } + + [StringLength(500)] + public string TrialStatusStr { get; set; } = string.Empty; + + [StringLength(50)] + + [ForeignKey("CROId")] + public CRO CRO { get; set; } + public string Phase { get; set; } = string.Empty; + + public List EnrollList { get; set; } + + [ForeignKey("ReviewModeId")] + public Dictionary ReviewMode { get; set; } + + public Guid ReviewTypeId { get; set; } = Guid.Empty; + + public Guid CriterionId { get; set; } = Guid.Empty; + + public Guid CROId { get; set; } = Guid.Empty; + + public Guid SponsorId { get; set; } = Guid.Empty; + + [StringLength(500)] + public string TurnaroundTime { get; set; } = string.Empty; + + public Guid ReviewModeId { get; set; } = Guid.Empty; + + public int ExpectedPatients { get; set; } + + public int TimePointsPerPatient { get; set; } + + public int GRRReviewers { get; set; } + + public int TotalReviewers { get; set; } + + [StringLength(500)] + public string ReviewProtocol { get; set; } = string.Empty; + + [StringLength(500)] + public string MessageFromClient { get; set; } = string.Empty; + + public string Note { get; set; } = string.Empty; + + + public string ReviewProtocolName { get; set; } = string.Empty; + public string MessageFromClientName { get; set; } = string.Empty; + public int Expedited { get; set; } + + public DateTime CreateTime { get; set; } + + public Guid CreateUserId { get; set; } + + public DateTime UpdateTime { get; set; } + + public Guid UpdateUserId { get; set; } + public int AttendedReviewerType { get; set; } = 0;//0ȫйҽ 1ҽ 2йҽҲҽ + + public bool VisitPlanConfirmed { get; set; } + } +} diff --git a/IRaCIS.Core.Domain/Trial/TrialAttachment.cs b/IRaCIS.Core.Domain/Trial/TrialAttachment.cs new file mode 100644 index 0000000..f5f8dc8 --- /dev/null +++ b/IRaCIS.Core.Domain/Trial/TrialAttachment.cs @@ -0,0 +1,18 @@ +using System; +using System.ComponentModel.DataAnnotations.Schema; + +namespace IRaCIS.Core.Domain.Models +{ + [Table("TrialAttachment")] + public class TrialAttachment : Entity, IAuditUpdate, IAuditAdd + { + public Guid TrialId { get; set; } + public string Type { get; set; } = String.Empty; + public string DocumentName { get; set; } = String.Empty; + public string DocumentPath { get; set; } = String.Empty; + public DateTime CreateTime { get; set; } + public Guid CreateUserId { get; set; } + public DateTime UpdateTime { get; set; } + public Guid UpdateUserId { get; set; } + } +} diff --git a/IRaCIS.Core.Domain/Trial/TrialDictionary.cs b/IRaCIS.Core.Domain/Trial/TrialDictionary.cs new file mode 100644 index 0000000..02df547 --- /dev/null +++ b/IRaCIS.Core.Domain/Trial/TrialDictionary.cs @@ -0,0 +1,22 @@ +using System; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace IRaCIS.Core.Domain.Models +{ + [Table("TrialDictionary")] + public partial class TrialDictionary : Entity + { + //public Guid Id { get; set; } + + public virtual Trial Trial { get; set; } + public virtual Dictionary Dictionary { get; set; } + + [StringLength(50)] + public string KeyName { get; set; } = string.Empty; + + public Guid TrialId { get; set; } + + public Guid DictionaryId { get; set; } + } +} diff --git a/IRaCIS.Core.Domain/Trial/TrialInterView.cs b/IRaCIS.Core.Domain/Trial/TrialInterView.cs new file mode 100644 index 0000000..ef1a415 --- /dev/null +++ b/IRaCIS.Core.Domain/Trial/TrialInterView.cs @@ -0,0 +1,15 @@ +using System; +using System.ComponentModel.DataAnnotations.Schema; + +namespace IRaCIS.Core.Domain.Models +{ + [Table("TrialInterview")] + public class TrialInterview : Entity + { + public Guid TrialId { get; set; } + public string Stage { get; set; } + public string InterViewTime { get; set; } + public string Description { get; set; } + public DateTime CreateTime { get; set; } + } +} diff --git a/IRaCIS.Core.Domain/Trial/TrialStatusDetail.cs b/IRaCIS.Core.Domain/Trial/TrialStatusDetail.cs new file mode 100644 index 0000000..49aca07 --- /dev/null +++ b/IRaCIS.Core.Domain/Trial/TrialStatusDetail.cs @@ -0,0 +1,37 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace IRaCIS.Core.Domain.Models +{ + [Table("TrialStatus")] + public partial class TrialStatusDetail : Entity, IAuditAdd + { + public virtual ICollection IntoGroupDetails { get; set; } + public TrialStatusDetail() + { + IntoGroupDetails = new HashSet(); + } + + public Trial Trial { get; set; } + + [ForeignKey("Trial")] + public Guid TrialId { get; set; } + + + + public int TrialStatus { get; set; } + + [StringLength(100)] + public string Memo { get; set; } = string.Empty; + + public int OptUserType { get; set; } + + public Guid CreateUserId { get; set; } + + public DateTime CreateTime { get; set; } + + + } +} diff --git a/IRaCIS.Core.Domain/Trial/VisitStage.cs b/IRaCIS.Core.Domain/Trial/VisitStage.cs new file mode 100644 index 0000000..7ee6b27 --- /dev/null +++ b/IRaCIS.Core.Domain/Trial/VisitStage.cs @@ -0,0 +1,23 @@ +using System; +using System.ComponentModel.DataAnnotations.Schema; + +namespace IRaCIS.Core.Domain.Models +{ + [Table("VisitStage")] + public class VisitStage : Entity, IAuditUpdate, IAuditAdd + { + public Guid TrialId { get; set; } + + public decimal VisitNum { get; set; } + public string VisitName { get; set; } = string.Empty; + public int VisitDay { get; set; } + public string Description { get; set; } = string.Empty; + + public bool NeedGlobal { get; set; } = false; + + public Guid CreateUserId { get; set; } + public DateTime CreateTime { get; set; } + public Guid UpdateUserId { get; set; } + public DateTime UpdateTime { get; set; } + } +} diff --git a/IRaCIS.Core.Domain/Trial/WorkloadDistribution.cs b/IRaCIS.Core.Domain/Trial/WorkloadDistribution.cs new file mode 100644 index 0000000..d5972cc --- /dev/null +++ b/IRaCIS.Core.Domain/Trial/WorkloadDistribution.cs @@ -0,0 +1,67 @@ +using System; +using System.ComponentModel.DataAnnotations.Schema; + +namespace IRaCIS.Core.Domain.Models +{ + [Table("WorkloadTP")] + public class WorkloadTP : Entity + { + public Guid TrialId { get; set; } + public Guid SiteId { get; set; } + public Guid SubjectId { get; set; } + public Guid SubjectVisitId { get; set; } + public Guid StudyId { get; set; } + public string TimepointCode { get; set; } + public Guid ReviewerId { get; set; } + public int Status { get; set; } + public DateTime UpdateTime { get; set; } + } + + [Table("WorkloadGlobal")] + public class WorkloadGlobal : Entity + { + public Guid SiteId { get; set; } + public Guid VisitId { get; set; } + public string VisitName { get; set; } + + + // 项目Id,受试者Id,num 共同决定 Global 关联的所有study, + // 暂定设计成这样,后期如有需要,爱用中间表 关联。 + public Guid TrialId { get; set; } + public Guid SubjectId { get; set; } + public decimal VisitNum { get; set; } + + public string GlobalCode { get; set; } + public Guid ReviewerId { get; set; } + public int Status { get; set; } + public DateTime UpdateTime { get; set; } + } + + [Table("WorkloadAD")] + public class WorkloadAD : Entity + { + public Guid TrialId { get; set; } + public Guid SiteId { get; set; } + public Guid SubjectId { get; set; } + public string ADCode { get; set; } + public Guid ReviewerId { get; set; } + public int Status { get; set; } + public DateTime UpdateTime { get; set; } + public Guid Global1Id { get; set; } + public Guid Global2Id { get; set; } + + public Guid? SelectGlobalId { get; set; } + + public string AdNote { get; set; } + } + + [Table("WorkloadDetail")] + public class WorkloadDetail : Entity + { + public Guid WorkloadId { get; set; } + public string OptUserName { get; set; } + public DateTime OptTime { get; set; } = DateTime.Now; + public int Status { get; set; } + public Guid ReviewerId { get; set; } = Guid.Empty; + } +} diff --git a/IRaCIS.Core.Infra.EF/BaseRepository.cs b/IRaCIS.Core.Infra.EF/BaseRepository.cs new file mode 100644 index 0000000..ea8cfa2 --- /dev/null +++ b/IRaCIS.Core.Infra.EF/BaseRepository.cs @@ -0,0 +1,252 @@ +using IRaCIS.Core.Domain; +using IRaCIS.Core.Domain.Models; +//切换.net core 切换注释 +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.ChangeTracking; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Expressions; +using System.Threading.Tasks; +using Z.EntityFramework.Plus; + +namespace IRaCIS.Core.Infra.EFCore +{ + public class BaseRepository : IRepository where T : Entity + { + protected readonly IRaCISDBContext _dbContext; + + private readonly DbSet _dbSet; + + public BaseRepository(IRaCISDBContext db) + { + this._dbContext = db; + _dbSet = db.Set(); + } + + #region 添加 + + public async ValueTask> AddAsync(T entity) + { + return await _dbSet.AddAsync(entity); + } + + public T Add(T t) + { + //t.Id = Guid.NewGuid(); + _dbSet.Add(t); + return t; + } + + public async Task AddOrUpdateAsync(T t) + { + var exist = await GetAll().FirstOrDefaultAsync(s => s.Id == t.Id); + if (exist == null) + { + Add(t); + } + else + { + Update(t); + + } + await SaveChangesAsync(); + + #region 解决方式一 保存以后的实体会默认自动跟踪 在此detach 以免第二次 更新时 同一个实体被跟踪两次 + + _dbContext.Entry(t).State = EntityState.Detached; + + #endregion + + + } + + public IEnumerable AddRange(IEnumerable t) + { + //foreach (var entity in t) + //{ + // entity.Id = Guid.NewGuid(); + //} + _dbSet.AddRange(t); + return t; + } + + #endregion + + #region 删除 + public async Task DeleteAsync(Expression> whereLambda) + { + return await _dbSet.Where(whereLambda).DeleteAsync(); + } + + public void Delete(T t) + { + _dbSet.Attach(t); + _dbSet.Remove(t); + } + + public bool Delete(Expression> exp) + { + return _dbSet.Where(exp).DeleteFromQuery() > 0; + } + + #endregion + + #region 更新 + + public async Task UpdateAsync(Expression> whereLambda, Expression> entity) + { + return await _dbSet.Where(whereLambda).UpdateAsync(entity); + } + + public void Update(T t) + { + //var a = _dbContext.ChangeTracker.Entries().ToList(); + var entry = this._dbContext.Entry(t); + + entry.State = EntityState.Modified; + } + + /// + /// 实现按需要只更新部分更新 + /// 如:Update(u =>u.Id==1,u =>new User{Name="ok"}); + /// + /// The where. + /// The entity. + public bool Update(Expression> where, Expression> entity) + { + return _dbSet.Where(where).UpdateFromQuery(entity) > 0; + //return _dbSet.Where(where).Update(entity); + } + + + #endregion + + + #region 是否存在 + + public async Task IsExistAsync(Expression> whereLambda) + { + return await _dbSet.AnyAsync(whereLambda); + } + + + public bool IsExist(Expression> exp) + { + return _dbSet.Any(exp); + } + + #endregion + + #region 查找单个对象 + + public async Task GetFirstOrDefaultAsync(Expression> whereLambda) + { + return await _dbSet.AsNoTracking().FirstOrDefaultAsync(whereLambda); + } + + /// + /// 查找单个,且不被上下文所跟踪 + /// + public T FindSingleOrDefault(Expression> exp = null) + { + return GetAll().FirstOrDefault(exp); + } + + /// + /// 跟踪 + /// + /// + /// + public T FindSingleOrDefaultTrack(Expression> exp = null) + { + return _dbSet.FirstOrDefault(exp); + } + + #endregion + + + + #region 获取总数 + + public Task GetCountAsync(Expression> whereLambda = null) + { + return whereLambda == null ? _dbSet.CountAsync() : _dbSet.CountAsync(whereLambda); + } + + public int GetCount(Expression> whereLambda = null) + { + return whereLambda == null ? _dbSet.Count() : _dbSet.Count(whereLambda); + } + + + #endregion + + + + public IQueryable Find(Expression> exp = null) + { + if (exp != null) + + return _dbSet.AsNoTracking().Where(exp); + else + { + return _dbSet.AsNoTracking(); + + } + } + + public IQueryable Find(int pageSize, int pageIndex, bool isAsc, + Expression> orderByLambda, Expression> whereLambda) + { + if (orderByLambda == null) + { + return Find(whereLambda).Skip((pageIndex - 1) * pageSize).Take(pageSize); + } + else + { + //是否升序 + if (isAsc) + { + + return Find(whereLambda).OrderBy(orderByLambda).Skip((pageIndex - 1) * pageSize).Take(pageSize); + } + else + { + return Find(whereLambda).OrderByDescending(orderByLambda).Skip((pageIndex - 1) * pageSize).Take(pageSize); + } + } + } + + + public IQueryable Find(int pageSize, int pageIndex, bool isAsc, string propName, Expression> whereLambda) + { + //是否升序 + if (isAsc) + { + + return GetAll().Where(whereLambda).OrderBy(propName).Skip((pageIndex - 1) * pageSize).Take(pageSize); + } + + return GetAll().Where(whereLambda).OrderByDescending(propName).Skip((pageIndex - 1) * pageSize).Take(pageSize); + + } + + + public bool SaveChanges() + { + return _dbContext.SaveChanges() > 0; + } + + + public async Task SaveChangesAsync() + { + return await _dbContext.SaveChangesAsync(); + } + + public IQueryable GetAll() + { + return _dbSet.AsNoTracking(); + } + } +} \ No newline at end of file diff --git a/IRaCIS.Core.Infra.EF/Common/AttachmentRepository.cs b/IRaCIS.Core.Infra.EF/Common/AttachmentRepository.cs new file mode 100644 index 0000000..df4e440 --- /dev/null +++ b/IRaCIS.Core.Infra.EF/Common/AttachmentRepository.cs @@ -0,0 +1,14 @@ +using IRaCIS.Core.Domain.Interfaces; +using IRaCIS.Core.Domain.Models; + +namespace IRaCIS.Core.Infra.EFCore.Repository +{ + public class AttachmentRepository : BaseRepository, IAttachmentRepository + { + public AttachmentRepository( IRaCISDBContext db) + : base( db) + { + + } + } +} diff --git a/IRaCIS.Core.Infra.EF/Common/DictionaryRepository.cs b/IRaCIS.Core.Infra.EF/Common/DictionaryRepository.cs new file mode 100644 index 0000000..cdab5a7 --- /dev/null +++ b/IRaCIS.Core.Infra.EF/Common/DictionaryRepository.cs @@ -0,0 +1,13 @@ +using IRaCIS.Core.Domain.Interfaces; +using IRaCIS.Core.Domain.Models; + +namespace IRaCIS.Core.Infra.EFCore.Repository +{ + public class DictionaryRepository : BaseRepository, IDictionaryRepository + { + public DictionaryRepository( IRaCISDBContext db) + : base( db) + { + } + } +} diff --git a/IRaCIS.Core.Infra.EF/Common/LogRepository.cs b/IRaCIS.Core.Infra.EF/Common/LogRepository.cs new file mode 100644 index 0000000..cef6663 --- /dev/null +++ b/IRaCIS.Core.Infra.EF/Common/LogRepository.cs @@ -0,0 +1,14 @@ +using IRaCIS.Core.Domain.Interfaces; +using IRaCIS.Core.Domain.Models; + +namespace IRaCIS.Core.Infra.EFCore.Repository +{ + public class LogRepository : BaseRepository, ISystemLogRepository + { + public LogRepository( IRaCISDBContext db) + : base( db) + { + + } + } +} diff --git a/IRaCIS.Core.Infra.EF/Common/MessageRepository.cs b/IRaCIS.Core.Infra.EF/Common/MessageRepository.cs new file mode 100644 index 0000000..d1fadd9 --- /dev/null +++ b/IRaCIS.Core.Infra.EF/Common/MessageRepository.cs @@ -0,0 +1,13 @@ +using IRaCIS.Core.Domain.Interfaces; +using IRaCIS.Core.Domain.Models; + +namespace IRaCIS.Core.Infra.EFCore.Repository +{ + public class MessageRepository : BaseRepository, IMessageRepository + { + public MessageRepository(IRaCISDBContext db) + : base(db) + { + } + } +} \ No newline at end of file diff --git a/IRaCIS.Core.Infra.EF/Common/VerificationCodeRepository.cs b/IRaCIS.Core.Infra.EF/Common/VerificationCodeRepository.cs new file mode 100644 index 0000000..c17b1eb --- /dev/null +++ b/IRaCIS.Core.Infra.EF/Common/VerificationCodeRepository.cs @@ -0,0 +1,13 @@ +using IRaCIS.Core.Domain.Interfaces; +using IRaCIS.Core.Domain.Models; + +namespace IRaCIS.Core.Infra.EFCore.Repository +{ + public class VerificationCodeRepository : BaseRepository, IVerificationCodeRepository + { + public VerificationCodeRepository( IRaCISDBContext db) + : base( db) + { + } + } +} \ No newline at end of file diff --git a/IRaCIS.Core.Infra.EF/Doctor/DoctorDictionaryRepository.cs b/IRaCIS.Core.Infra.EF/Doctor/DoctorDictionaryRepository.cs new file mode 100644 index 0000000..c8f98d7 --- /dev/null +++ b/IRaCIS.Core.Infra.EF/Doctor/DoctorDictionaryRepository.cs @@ -0,0 +1,13 @@ +using IRaCIS.Core.Domain.Interfaces; +using IRaCIS.Core.Domain.Models; + +namespace IRaCIS.Core.Infra.EFCore.Repository +{ + public class DoctorDictionaryRepository : BaseRepository, IDoctorDictionaryRepository + { + public DoctorDictionaryRepository( IRaCISDBContext db) : base( db) + { + + } + } +} \ No newline at end of file diff --git a/IRaCIS.Core.Infra.EF/Doctor/DoctorRepository.cs b/IRaCIS.Core.Infra.EF/Doctor/DoctorRepository.cs new file mode 100644 index 0000000..00632d8 --- /dev/null +++ b/IRaCIS.Core.Infra.EF/Doctor/DoctorRepository.cs @@ -0,0 +1,13 @@ +using IRaCIS.Core.Domain.Interfaces; +using IRaCIS.Core.Domain.Models; + +namespace IRaCIS.Core.Infra.EFCore.Repository +{ + public class DoctorRepository : BaseRepository, IDoctorRepository + { + public DoctorRepository( IRaCISDBContext db) + : base( db) + { + } + } +} diff --git a/IRaCIS.Core.Infra.EF/Doctor/EducationRepository.cs b/IRaCIS.Core.Infra.EF/Doctor/EducationRepository.cs new file mode 100644 index 0000000..2a4dc59 --- /dev/null +++ b/IRaCIS.Core.Infra.EF/Doctor/EducationRepository.cs @@ -0,0 +1,12 @@ +using IRaCIS.Core.Domain.Interfaces; +using IRaCIS.Core.Domain.Models; + +namespace IRaCIS.Core.Infra.EFCore.Repository +{ + public class EducationRepository : BaseRepository, IEducationRepository + { + public EducationRepository( IRaCISDBContext db) : base( db) + { + } + } +} \ No newline at end of file diff --git a/IRaCIS.Core.Infra.EF/Doctor/HolidayRepository.cs b/IRaCIS.Core.Infra.EF/Doctor/HolidayRepository.cs new file mode 100644 index 0000000..cd9ffed --- /dev/null +++ b/IRaCIS.Core.Infra.EF/Doctor/HolidayRepository.cs @@ -0,0 +1,12 @@ +using IRaCIS.Core.Domain.Interfaces; +using IRaCIS.Core.Domain.Models; + +namespace IRaCIS.Core.Infra.EFCore.Repository +{ + public class HolidayRepository : BaseRepository, IVacationRepository + { + public HolidayRepository( IRaCISDBContext db) : base( db) + { + } + } +} diff --git a/IRaCIS.Core.Infra.EF/Doctor/PostgraduateRepository.cs b/IRaCIS.Core.Infra.EF/Doctor/PostgraduateRepository.cs new file mode 100644 index 0000000..52f90a0 --- /dev/null +++ b/IRaCIS.Core.Infra.EF/Doctor/PostgraduateRepository.cs @@ -0,0 +1,12 @@ +using IRaCIS.Core.Domain.Interfaces; +using IRaCIS.Core.Domain.Models; + +namespace IRaCIS.Core.Infra.EFCore.Repository +{ + public class PostgraduateRepository : BaseRepository, IPostgraduateRepository + { + public PostgraduateRepository( IRaCISDBContext db) : base( db) + { + } + } +} \ No newline at end of file diff --git a/IRaCIS.Core.Infra.EF/Doctor/ResearchPublicationRepository.cs b/IRaCIS.Core.Infra.EF/Doctor/ResearchPublicationRepository.cs new file mode 100644 index 0000000..7af3889 --- /dev/null +++ b/IRaCIS.Core.Infra.EF/Doctor/ResearchPublicationRepository.cs @@ -0,0 +1,13 @@ +using IRaCIS.Core.Domain.Interfaces; +using IRaCIS.Core.Domain.Models; + +namespace IRaCIS.Core.Infra.EFCore.Repository +{ + public class ResearchPublicationRepository : BaseRepository, IResearchPublicationRepository + { + public ResearchPublicationRepository( IRaCISDBContext db) : base( db) + { + + } + } +} \ No newline at end of file diff --git a/IRaCIS.Core.Infra.EF/Doctor/TrialExperienceRepository.cs b/IRaCIS.Core.Infra.EF/Doctor/TrialExperienceRepository.cs new file mode 100644 index 0000000..d6900f2 --- /dev/null +++ b/IRaCIS.Core.Infra.EF/Doctor/TrialExperienceRepository.cs @@ -0,0 +1,12 @@ +using IRaCIS.Core.Domain.Interfaces; +using IRaCIS.Core.Domain.Models; + +namespace IRaCIS.Core.Infra.EFCore.Repository +{ + public class TrialExperienceRepository : BaseRepository, ITrialExperienceRepository + { + public TrialExperienceRepository( IRaCISDBContext db) : base( db) + { + } + } +} \ No newline at end of file diff --git a/IRaCIS.Core.Infra.EF/Financial/ExchangeRateRepository.cs b/IRaCIS.Core.Infra.EF/Financial/ExchangeRateRepository.cs new file mode 100644 index 0000000..ab80cdb --- /dev/null +++ b/IRaCIS.Core.Infra.EF/Financial/ExchangeRateRepository.cs @@ -0,0 +1,13 @@ +using IRaCIS.Core.Domain.Interfaces; +using IRaCIS.Core.Domain.Models; + +namespace IRaCIS.Core.Infra.EFCore.Repository +{ + public class ExchangeRateRepository : BaseRepository, IExchangeRateRepository + { + public ExchangeRateRepository( IRaCISDBContext db) : base( db) + { + + } + } +} diff --git a/IRaCIS.Core.Infra.EF/Financial/PaymentAdjustmentRepository.cs b/IRaCIS.Core.Infra.EF/Financial/PaymentAdjustmentRepository.cs new file mode 100644 index 0000000..8ccc193 --- /dev/null +++ b/IRaCIS.Core.Infra.EF/Financial/PaymentAdjustmentRepository.cs @@ -0,0 +1,14 @@ +using IRaCIS.Core.Domain.Interfaces; +using IRaCIS.Core.Domain.Models; + +namespace IRaCIS.Core.Infra.EFCore.Repository +{ + public class PaymentAdjustmentRepository : BaseRepository, IPaymentAdjustmentRepository + { + public PaymentAdjustmentRepository( IRaCISDBContext db) : base( db) + { + + } + } + +} \ No newline at end of file diff --git a/IRaCIS.Core.Infra.EF/Financial/PaymentDetailRepository.cs b/IRaCIS.Core.Infra.EF/Financial/PaymentDetailRepository.cs new file mode 100644 index 0000000..25536de --- /dev/null +++ b/IRaCIS.Core.Infra.EF/Financial/PaymentDetailRepository.cs @@ -0,0 +1,14 @@ +using IRaCIS.Core.Domain.Interfaces; +using IRaCIS.Core.Domain.Models; + +namespace IRaCIS.Core.Infra.EFCore.Repository +{ + public class PaymentDetailRepository : BaseRepository, IPaymentDetailRepository + + { + public PaymentDetailRepository( IRaCISDBContext db) : base( db) + { + + } + } +} \ No newline at end of file diff --git a/IRaCIS.Core.Infra.EF/Financial/PaymentRepository.cs b/IRaCIS.Core.Infra.EF/Financial/PaymentRepository.cs new file mode 100644 index 0000000..c3f4f8a --- /dev/null +++ b/IRaCIS.Core.Infra.EF/Financial/PaymentRepository.cs @@ -0,0 +1,13 @@ +using IRaCIS.Core.Domain.Interfaces; +using IRaCIS.Core.Domain.Models; + +namespace IRaCIS.Core.Infra.EFCore.Repository +{ + public class CostStatisticsRepository:BaseRepository,IPaymentRepository + { + public CostStatisticsRepository( IRaCISDBContext db) : base( db) + { + + } + } +} \ No newline at end of file diff --git a/IRaCIS.Core.Infra.EF/Financial/RankPriceRepository.cs b/IRaCIS.Core.Infra.EF/Financial/RankPriceRepository.cs new file mode 100644 index 0000000..a72af06 --- /dev/null +++ b/IRaCIS.Core.Infra.EF/Financial/RankPriceRepository.cs @@ -0,0 +1,13 @@ +using IRaCIS.Core.Domain.Interfaces; +using IRaCIS.Core.Domain.Models; + +namespace IRaCIS.Core.Infra.EFCore.Repository +{ + public class RankPriceRepository : BaseRepository, IRankPriceRepository + { + public RankPriceRepository( IRaCISDBContext db) : base( db) + { + + } + } +} diff --git a/IRaCIS.Core.Infra.EF/Financial/ReviewerPayInfoRepository.cs b/IRaCIS.Core.Infra.EF/Financial/ReviewerPayInfoRepository.cs new file mode 100644 index 0000000..924d42b --- /dev/null +++ b/IRaCIS.Core.Infra.EF/Financial/ReviewerPayInfoRepository.cs @@ -0,0 +1,13 @@ +using IRaCIS.Core.Domain.Interfaces; +using IRaCIS.Core.Domain.Models; + +namespace IRaCIS.Core.Infra.EFCore.Repository +{ + public class ReviewerPayInfoRepository : BaseRepository, IReviewerPayInfoRepository + { + public ReviewerPayInfoRepository( IRaCISDBContext db) : base( db) + { + + } + } +} diff --git a/IRaCIS.Core.Infra.EF/Financial/TrialPaymentPriceRepository.cs b/IRaCIS.Core.Infra.EF/Financial/TrialPaymentPriceRepository.cs new file mode 100644 index 0000000..96441cb --- /dev/null +++ b/IRaCIS.Core.Infra.EF/Financial/TrialPaymentPriceRepository.cs @@ -0,0 +1,13 @@ +using IRaCIS.Core.Domain.Interfaces; +using IRaCIS.Core.Domain.Models; + +namespace IRaCIS.Core.Infra.EFCore.Repository +{ + public class TrialPaymentPriceRepository : BaseRepository, ITrialPaymentPriceRepository + { + public TrialPaymentPriceRepository( IRaCISDBContext db) : base( db) + { + + } + } +} diff --git a/IRaCIS.Core.Infra.EF/Financial/TrialRevenuesPriceRepository.cs b/IRaCIS.Core.Infra.EF/Financial/TrialRevenuesPriceRepository.cs new file mode 100644 index 0000000..c9c40ca --- /dev/null +++ b/IRaCIS.Core.Infra.EF/Financial/TrialRevenuesPriceRepository.cs @@ -0,0 +1,13 @@ +using IRaCIS.Core.Domain.Interfaces; +using IRaCIS.Core.Domain.Models; + +namespace IRaCIS.Core.Infra.EFCore.Repository +{ + public class TrialRevenuesPriceRepository : BaseRepository, ITrialRevenuesPriceRepository + { + public TrialRevenuesPriceRepository( IRaCISDBContext db) : base( db) + { + + } + } +} diff --git a/IRaCIS.Core.Infra.EF/Financial/VolumeRewardRepository.cs b/IRaCIS.Core.Infra.EF/Financial/VolumeRewardRepository.cs new file mode 100644 index 0000000..8be9742 --- /dev/null +++ b/IRaCIS.Core.Infra.EF/Financial/VolumeRewardRepository.cs @@ -0,0 +1,13 @@ +using IRaCIS.Core.Domain.Interfaces; +using IRaCIS.Core.Domain.Models; + +namespace IRaCIS.Core.Infra.EFCore.Repository +{ + public class AwardPriceRepository: BaseRepository, IVolumeRewardRepository + { + public AwardPriceRepository( IRaCISDBContext db) : base( db) + { + + } + } +} \ No newline at end of file diff --git a/IRaCIS.Core.Infra.EF/IRaCIS.Core.Infra.EFCore.csproj b/IRaCIS.Core.Infra.EF/IRaCIS.Core.Infra.EFCore.csproj new file mode 100644 index 0000000..9a40ed8 --- /dev/null +++ b/IRaCIS.Core.Infra.EF/IRaCIS.Core.Infra.EFCore.csproj @@ -0,0 +1,36 @@ + + + + netstandard2.0 + + + + ..\bin + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/IRaCIS.Core.Infra.EF/IRaCISDBContext.cs b/IRaCIS.Core.Infra.EF/IRaCISDBContext.cs new file mode 100644 index 0000000..7f232d6 --- /dev/null +++ b/IRaCIS.Core.Infra.EF/IRaCISDBContext.cs @@ -0,0 +1,224 @@ +using IRaCIS.Core.Domain.Models; +using IRaCIS.Core.Domain.Share.AuthUser; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.Logging; +using System; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using IRaCIS.Core.Domain; + +//using System.Data.Entity; +//using IRaCIS.Infra.Data.Mapping; + +namespace IRaCIS.Core.Infra.EFCore +{ + public class IRaCISDBContext : DbContext + { + private readonly IUserInfo _userInfo; + + ///记录控制台日志: + ///1. Microsoft.Extensions.Logging + ///Microsoft.Extensions.Logging.Console + ///2. 定义日志工厂 + ///3. OnConfiguring配置使用日志工厂 + /// + /// 指定静态ILoggerFactory + /// + //在控制台 + //public static readonly ILoggerFactory MyLoggerFactory + // = LoggerFactory.Create(builder => { builder.AddConsole(); }); + //调试窗口 + public static readonly ILoggerFactory + MyLoggerFactory = LoggerFactory.Create(builder => { builder.AddDebug(); }); + + public IRaCISDBContext(DbContextOptions options, IUserInfo userInfo) : base(options) + { + _userInfo = userInfo; + Console.WriteLine("This is IRaCISDBContext DbContextOptions"); + } + protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) + { + + optionsBuilder.UseLoggerFactory(MyLoggerFactory); + } + + public virtual DbSet Dictionary { get; set; } + public virtual DbSet Doctor { get; set; } + public virtual DbSet DoctorDictionary { get; set; } + + public virtual DbSet Attachment { get; set; } + public virtual DbSet DoctorWorkload { get; set; } + public virtual DbSet EnrollDetails { get; set; } + public virtual DbSet Postgraduate { get; set; } + public virtual DbSet ProjectDictionary { get; set; } + public virtual DbSet Trial { get; set; } + public virtual DbSet TrialDetail { get; set; } + public virtual DbSet TrialExperience { get; set; } + public virtual DbSet Education { get; set; } + public virtual DbSet IntoGroup { get; set; } + public virtual DbSet ResearchPublications { get; set; } + public virtual DbSet SysMessages { get; set; } + + public virtual DbSet MenuFunctions { get; set; } + public virtual DbSet Roles { get; set; } + public virtual DbSet RoleMenus { get; set; } + public virtual DbSet Users { get; set; } + public virtual DbSet UserRoles { get; set; } + + + public virtual DbSet ResearchCenter { get; set; } + public virtual DbSet UserDoctor { get; set; } + + public virtual DbSet UserTrial { get; set; } + + public virtual DbSet Hospitals { get; set; } + + public virtual DbSet CROCompany { get; set; } + public virtual DbSet Sponsor { get; set; } + public virtual DbSet Vacation { get; set; } + + public virtual DbSet ReviewerPayInformation { get; set; } + public virtual DbSet RankPrice { get; set; } + public virtual DbSet TrialPaymentPrice { get; set; } + + public virtual DbSet AwardPrice { get; set; } + + public virtual DbSet Payment { get; set; } + + public virtual DbSet PaymentDetail { get; set; } + public virtual DbSet ExchangeRate { get; set; } + public virtual DbSet ImageAcquisitionSpecification { get; set; } + public virtual DbSet ClinicalStudySubjects { get; set; } + public virtual DbSet VisitPlans { get; set; } + public virtual DbSet DicomStudys { get; set; } + public virtual DbSet DicomSeries { get; set; } + public virtual DbSet DicomInstances { get; set; } + + public virtual DbSet StudyStatusDetails { get; set; } + //public virtual DbSet Images { get; set; } + public virtual DbSet TrialRevenuesPrice { get; set; } + + public virtual DbSet PaymentAdjustment { get; set; } + public virtual DbSet SystemLogs { get; set; } + + public virtual DbSet VerificationCodes { get; set; } + + public virtual DbSet TrialRevenuesPriceVerification { get; set; } + + public virtual DbSet Test { get; set; } + + + #region QA + public virtual DbSet QADictionary { get; set; } + public virtual DbSet QATemplate { get; set; } + public virtual DbSet QADialog { get; set; } + + public virtual DbSet QATemplateDictionary { get; set; } + + public virtual DbSet QARecord { get; set; } + + public virtual DbSet SubjectVisit { get; set; } + + + #endregion + public virtual DbSet StudyReviewer { get; set; } + + #region 工作量分配 + public virtual DbSet WorkloadTPs { get; set; } + public virtual DbSet WorkloadGlobals { get; set; } + public virtual DbSet WorkloadADs { get; set; } + public virtual DbSet WorkloadDetails { get; set; } + #endregion + + public virtual DbSet TU { get; set; } + public virtual DbSet TR { get; set; } + public virtual DbSet RS { get; set; } + public virtual DbSet Reports { get; set; } + + + public virtual DbSet GlobalRS { get; set; } + public virtual DbSet GlobalResult { get; set; } + + public virtual DbSet ImageLabels { get; set; } + public virtual DbSet KeyInstances { get; set; } + + public override int SaveChanges() + { + ChangeTracker.DetectChanges(); // Important! + var addList = ChangeTracker.Entries().Where(p => p.State == EntityState.Added).Select(t => t.Entity).ToList(); + var updateList = ChangeTracker.Entries().Where(p => p.State == EntityState.Modified).Select(t => t.Entity).ToList(); + try + { + foreach (var entity in addList) + { + if (entity is IAuditAdd baseEntity) + { + baseEntity.CreateTime = DateTime.Now; + baseEntity.CreateUserId = _userInfo.Id; + } + if (entity is IAuditUpdate updateEntity) + { + updateEntity.UpdateTime = DateTime.Now; + updateEntity.UpdateUserId = _userInfo.Id; + } + } + + foreach (var entity in updateList) + { + if (entity is IAuditUpdate baseEntity) + { + baseEntity.UpdateTime = DateTime.Now; + baseEntity.UpdateUserId = _userInfo.Id; + } + } + } + catch (Exception e) + { + Console.WriteLine(e); + throw; + } + return base.SaveChanges(); + } + + public override Task SaveChangesAsync(CancellationToken cancellationToken = new CancellationToken()) + { + ChangeTracker.DetectChanges(); // Important! + var addList = ChangeTracker.Entries().Where(p => p.State == EntityState.Added).Select(t => t.Entity).ToList(); + var updateList = ChangeTracker.Entries().Where(p => p.State == EntityState.Modified).Select(t => t.Entity).ToList(); + try + { + foreach (var entity in addList) + { + if (entity is IAuditAdd baseEntity) + { + baseEntity.CreateTime = DateTime.Now; + baseEntity.CreateUserId = _userInfo.Id; + } + if (entity is IAuditUpdate updateEntity) + { + updateEntity.UpdateTime = DateTime.Now; + updateEntity.UpdateUserId = _userInfo.Id; + } + } + + foreach (var entity in updateList) + { + if (entity is IAuditUpdate baseEntity) + { + baseEntity.UpdateTime = DateTime.Now; + baseEntity.UpdateUserId = _userInfo.Id; + } + } + } + catch (Exception e) + { + Console.WriteLine(e); + throw; + } + + + return base.SaveChangesAsync(cancellationToken); + } + } +} \ No newline at end of file diff --git a/IRaCIS.Core.Infra.EF/Image/DicomInstanceRepository.cs b/IRaCIS.Core.Infra.EF/Image/DicomInstanceRepository.cs new file mode 100644 index 0000000..814faa3 --- /dev/null +++ b/IRaCIS.Core.Infra.EF/Image/DicomInstanceRepository.cs @@ -0,0 +1,28 @@ +using IRaCIS.Core.Domain.Interfaces; +using IRaCIS.Core.Domain.Models; + +namespace IRaCIS.Core.Infra.EFCore.Repository +{ + public class DicomInstanceRepository : BaseRepository, IDicomInstanceRepository + { + public DicomInstanceRepository(IRaCISDBContext db) : base(db) + { + + } + //public new async Task AddOrUpdateAsync(DicomInstance t) + //{ + // var exist = GetAll().AsNoTracking().FirstOrDefault(s => s.Id == t.Id); + // if (exist == null) + // { + + // Add(t); + + // } + // else + // { + // Update(exist); + // } + // await _dbContext.SaveChangesAsync(); + //} + } +} \ No newline at end of file diff --git a/IRaCIS.Core.Infra.EF/Image/DicomSeriesRepository.cs b/IRaCIS.Core.Infra.EF/Image/DicomSeriesRepository.cs new file mode 100644 index 0000000..b87cc9a --- /dev/null +++ b/IRaCIS.Core.Infra.EF/Image/DicomSeriesRepository.cs @@ -0,0 +1,26 @@ +using IRaCIS.Core.Domain.Interfaces; +using IRaCIS.Core.Domain.Models; + +namespace IRaCIS.Core.Infra.EFCore.Repository +{ + public class DicomSeriesRepository : BaseRepository, IDicomSeriesRepository + { + public DicomSeriesRepository(IRaCISDBContext db) : base(db) + { + + } + //public new async Task AddOrUpdateAsync(DicomSeries t) + //{ + // var exist = GetAll().AsNoTracking().FirstOrDefault(s => s.Id == t.Id); + // if (exist == null) + // { + // Add(t); + // } + // else + // { + // Update(exist); + // } + // await _dbContext.SaveChangesAsync(); + //} + } +} \ No newline at end of file diff --git a/IRaCIS.Core.Infra.EF/Image/DicomStudyRepository.cs b/IRaCIS.Core.Infra.EF/Image/DicomStudyRepository.cs new file mode 100644 index 0000000..9baa802 --- /dev/null +++ b/IRaCIS.Core.Infra.EF/Image/DicomStudyRepository.cs @@ -0,0 +1,13 @@ +using IRaCIS.Core.Domain.Interfaces; +using IRaCIS.Core.Domain.Models; + +namespace IRaCIS.Core.Infra.EFCore.Repository +{ + public class DicomStudyRepository : BaseRepository, IDicomStudyRepository + { + public DicomStudyRepository( IRaCISDBContext db) : base( db) + { + + } + } +} diff --git a/IRaCIS.Core.Infra.EF/Image/ImageLabelRepository.cs b/IRaCIS.Core.Infra.EF/Image/ImageLabelRepository.cs new file mode 100644 index 0000000..6452743 --- /dev/null +++ b/IRaCIS.Core.Infra.EF/Image/ImageLabelRepository.cs @@ -0,0 +1,16 @@ +using IRaCIS.Core.Domain.Interfaces; +using IRaCIS.Core.Domain.Models; +using System; +using System.Collections.Generic; +using System.Text; + +namespace IRaCIS.Core.Infra.EFCore.Repository +{ + public class ImageLabelRepository : BaseRepository, IImageLabelRepository + { + public ImageLabelRepository(IRaCISDBContext db) : base(db) + { + + } + } +} diff --git a/IRaCIS.Core.Infra.EF/Image/ImageQARepository.cs b/IRaCIS.Core.Infra.EF/Image/ImageQARepository.cs new file mode 100644 index 0000000..20c2203 --- /dev/null +++ b/IRaCIS.Core.Infra.EF/Image/ImageQARepository.cs @@ -0,0 +1,13 @@ +using IRaCIS.Core.Domain.Interfaces; +using IRaCIS.Core.Domain.Models; + +namespace IRaCIS.Core.Infra.EFCore.Repository +{ + public class ImageQARepository : BaseRepository,IImageQARepository + { + public ImageQARepository(IRaCISDBContext db) : base(db) + { + + } + } +} \ No newline at end of file diff --git a/IRaCIS.Core.Infra.EF/Image/KeyInstanceRepository.cs b/IRaCIS.Core.Infra.EF/Image/KeyInstanceRepository.cs new file mode 100644 index 0000000..725b567 --- /dev/null +++ b/IRaCIS.Core.Infra.EF/Image/KeyInstanceRepository.cs @@ -0,0 +1,13 @@ +using IRaCIS.Core.Domain.Interfaces; +using IRaCIS.Core.Domain.Models; + +namespace IRaCIS.Core.Infra.EFCore.Repository +{ + public class KeyInstanceRepository : BaseRepository, IKeyInstanceRepository + { + public KeyInstanceRepository(IRaCISDBContext db) : base(db) + { + + } + } +} \ No newline at end of file diff --git a/IRaCIS.Core.Infra.EF/Image/StudyReviewerRepository.cs b/IRaCIS.Core.Infra.EF/Image/StudyReviewerRepository.cs new file mode 100644 index 0000000..99e5fa6 --- /dev/null +++ b/IRaCIS.Core.Infra.EF/Image/StudyReviewerRepository.cs @@ -0,0 +1,15 @@ +using IRaCIS.Core.Domain.Interfaces; +using IRaCIS.Core.Domain.Models; + +namespace IRaCIS.Core.Infra.EFCore.Repository +{ + + public class StudyReviewerRepository : BaseRepository, IStudyReviewerRepository + { + public StudyReviewerRepository(IRaCISDBContext db) + : base(db) + { + + } + } +} diff --git a/IRaCIS.Core.Infra.EF/Image/StudyStatusDetailRepository.cs b/IRaCIS.Core.Infra.EF/Image/StudyStatusDetailRepository.cs new file mode 100644 index 0000000..ba0b10d --- /dev/null +++ b/IRaCIS.Core.Infra.EF/Image/StudyStatusDetailRepository.cs @@ -0,0 +1,13 @@ +using IRaCIS.Core.Domain.Interfaces; +using IRaCIS.Core.Domain.Models; + +namespace IRaCIS.Core.Infra.EFCore.Repository +{ + public class StudyStatusDetailRepository : BaseRepository, IStudyStatusDetailRepository + { + public StudyStatusDetailRepository(IRaCISDBContext db) : base(db) + { + + } + } +} \ No newline at end of file diff --git a/IRaCIS.Core.Infra.EF/Institution/CRORepository.cs b/IRaCIS.Core.Infra.EF/Institution/CRORepository.cs new file mode 100644 index 0000000..ae036fb --- /dev/null +++ b/IRaCIS.Core.Infra.EF/Institution/CRORepository.cs @@ -0,0 +1,14 @@ +using IRaCIS.Core.Domain.Interfaces; +using IRaCIS.Core.Domain.Models; + +namespace IRaCIS.Core.Infra.EFCore.Repository +{ + public class CRORepository:BaseRepository,ICRORepository + { + public CRORepository( IRaCISDBContext db) + : base( db) + { + + } + } +} \ No newline at end of file diff --git a/IRaCIS.Core.Infra.EF/Institution/HospitalRepository.cs b/IRaCIS.Core.Infra.EF/Institution/HospitalRepository.cs new file mode 100644 index 0000000..f5e9504 --- /dev/null +++ b/IRaCIS.Core.Infra.EF/Institution/HospitalRepository.cs @@ -0,0 +1,13 @@ +using IRaCIS.Core.Domain.Interfaces; +using IRaCIS.Core.Domain.Models; + +namespace IRaCIS.Core.Infra.EFCore.Repository +{ + public class HospitalRepository : BaseRepository, IHospitalRepository + { + public HospitalRepository( IRaCISDBContext db) + : base( db) + { + } + } +} diff --git a/IRaCIS.Core.Infra.EF/Institution/SiteRepository.cs b/IRaCIS.Core.Infra.EF/Institution/SiteRepository.cs new file mode 100644 index 0000000..fae5817 --- /dev/null +++ b/IRaCIS.Core.Infra.EF/Institution/SiteRepository.cs @@ -0,0 +1,13 @@ +using IRaCIS.Core.Domain.Interfaces; +using IRaCIS.Core.Domain.Models; + +namespace IRaCIS.Core.Infra.EFCore.Repository +{ + public class SiteRepository : BaseRepository, ISiteRepository + { + public SiteRepository( IRaCISDBContext db) : base( db) + { + + } + } +} \ No newline at end of file diff --git a/IRaCIS.Core.Infra.EF/Institution/SponsorRepository.cs b/IRaCIS.Core.Infra.EF/Institution/SponsorRepository.cs new file mode 100644 index 0000000..bac33e3 --- /dev/null +++ b/IRaCIS.Core.Infra.EF/Institution/SponsorRepository.cs @@ -0,0 +1,14 @@ +using IRaCIS.Core.Domain.Interfaces; +using IRaCIS.Core.Domain.Models; + +namespace IRaCIS.Core.Infra.EFCore.Repository +{ + public class SponsorRepository : BaseRepository, ISponsorRepository + { + public SponsorRepository(IRaCISDBContext db) + : base(db) + { + + } + } +} \ No newline at end of file diff --git a/IRaCIS.Core.Infra.EF/Management/MenuRepository.cs b/IRaCIS.Core.Infra.EF/Management/MenuRepository.cs new file mode 100644 index 0000000..3c73e99 --- /dev/null +++ b/IRaCIS.Core.Infra.EF/Management/MenuRepository.cs @@ -0,0 +1,13 @@ +using IRaCIS.Core.Domain.Interfaces; +using IRaCIS.Core.Domain.Models; + +namespace IRaCIS.Core.Infra.EFCore.Repository +{ + public class MenuFunctionRepository : BaseRepository, IMenuFunctionRepository + { + public MenuFunctionRepository( IRaCISDBContext db) + : base( db) + { + } + } +} diff --git a/IRaCIS.Core.Infra.EF/Management/RoleMenuRepository.cs b/IRaCIS.Core.Infra.EF/Management/RoleMenuRepository.cs new file mode 100644 index 0000000..d8853a7 --- /dev/null +++ b/IRaCIS.Core.Infra.EF/Management/RoleMenuRepository.cs @@ -0,0 +1,14 @@ +using IRaCIS.Core.Domain.Interfaces; +using IRaCIS.Core.Domain.Models; + +namespace IRaCIS.Core.Infra.EFCore.Repository +{ + public class RoleMenuRepository : BaseRepository, IRoleMenuFunctionRepository + { + public RoleMenuRepository( IRaCISDBContext db) + : base( db) + { + + } + } +} diff --git a/IRaCIS.Core.Infra.EF/Management/RoleRepository.cs b/IRaCIS.Core.Infra.EF/Management/RoleRepository.cs new file mode 100644 index 0000000..1a0581e --- /dev/null +++ b/IRaCIS.Core.Infra.EF/Management/RoleRepository.cs @@ -0,0 +1,13 @@ +using IRaCIS.Core.Domain.Interfaces; +using IRaCIS.Core.Domain.Models; + +namespace IRaCIS.Core.Infra.EFCore.Repository +{ + public class RoleRepository : BaseRepository, IRoleRepository + { + public RoleRepository( IRaCISDBContext db) : base( db) + { + + } + } +} diff --git a/IRaCIS.Core.Infra.EF/Management/UserRepository.cs b/IRaCIS.Core.Infra.EF/Management/UserRepository.cs new file mode 100644 index 0000000..26799e9 --- /dev/null +++ b/IRaCIS.Core.Infra.EF/Management/UserRepository.cs @@ -0,0 +1,13 @@ +using IRaCIS.Core.Domain.Interfaces; +using IRaCIS.Core.Domain.Models; + +namespace IRaCIS.Core.Infra.EFCore.Repository +{ + public class UserRepository : BaseRepository, IUserRepository + { + public UserRepository( IRaCISDBContext db) + : base( db) + { + } + } +} diff --git a/IRaCIS.Core.Infra.EF/Management/UserRoleRepository.cs b/IRaCIS.Core.Infra.EF/Management/UserRoleRepository.cs new file mode 100644 index 0000000..3a15e30 --- /dev/null +++ b/IRaCIS.Core.Infra.EF/Management/UserRoleRepository.cs @@ -0,0 +1,13 @@ +using IRaCIS.Core.Domain.Interfaces; +using IRaCIS.Core.Domain.Models; + +namespace IRaCIS.Core.Infra.EFCore.Repository +{ + public class UserRoleRepository : BaseRepository, IUserRoleRepository + { + public UserRoleRepository( IRaCISDBContext db) + : base( db) + { + } + } +} diff --git a/IRaCIS.Core.Infra.EF/QA/QADialogRepository.cs b/IRaCIS.Core.Infra.EF/QA/QADialogRepository.cs new file mode 100644 index 0000000..693ac3b --- /dev/null +++ b/IRaCIS.Core.Infra.EF/QA/QADialogRepository.cs @@ -0,0 +1,13 @@ +using IRaCIS.Core.Domain.Interfaces; +using IRaCIS.Core.Domain.Models; + +namespace IRaCIS.Core.Infra.EFCore.Repository +{ + public class QADialogRepository : BaseRepository, IQADialogRepository + { + public QADialogRepository(IRaCISDBContext db) + : base(db) + { + } + } +} \ No newline at end of file diff --git a/IRaCIS.Core.Infra.EF/QA/QADictionaryRepository.cs b/IRaCIS.Core.Infra.EF/QA/QADictionaryRepository.cs new file mode 100644 index 0000000..cecc35e --- /dev/null +++ b/IRaCIS.Core.Infra.EF/QA/QADictionaryRepository.cs @@ -0,0 +1,13 @@ +using IRaCIS.Core.Domain.Interfaces; +using IRaCIS.Core.Domain.Models; + +namespace IRaCIS.Core.Infra.EFCore.Repository +{ + public class QADictionaryRepository : BaseRepository, IQADictionaryRepository + { + public QADictionaryRepository(IRaCISDBContext db) + : base(db) + { + } + } +} \ No newline at end of file diff --git a/IRaCIS.Core.Infra.EF/QA/QARecordRepository.cs b/IRaCIS.Core.Infra.EF/QA/QARecordRepository.cs new file mode 100644 index 0000000..3b348be --- /dev/null +++ b/IRaCIS.Core.Infra.EF/QA/QARecordRepository.cs @@ -0,0 +1,13 @@ +using IRaCIS.Core.Domain.Interfaces; +using IRaCIS.Core.Domain.Models; + +namespace IRaCIS.Core.Infra.EFCore.Repository +{ + public class QARecordRepository : BaseRepository, IQARecordRepository + { + public QARecordRepository(IRaCISDBContext db) + : base(db) + { + } + } +} \ No newline at end of file diff --git a/IRaCIS.Core.Infra.EF/QA/QATemplateDictionaryRepository.cs b/IRaCIS.Core.Infra.EF/QA/QATemplateDictionaryRepository.cs new file mode 100644 index 0000000..bdd6628 --- /dev/null +++ b/IRaCIS.Core.Infra.EF/QA/QATemplateDictionaryRepository.cs @@ -0,0 +1,13 @@ +using IRaCIS.Core.Domain.Interfaces; +using IRaCIS.Core.Domain.Models; + +namespace IRaCIS.Core.Infra.EFCore.Repository +{ + public class QATemplateDictionaryRepository : BaseRepository, IQATemplateDictionaryRepository + { + public QATemplateDictionaryRepository(IRaCISDBContext db) + : base(db) + { + } + } +} \ No newline at end of file diff --git a/IRaCIS.Core.Infra.EF/QA/QATemplateRepository.cs b/IRaCIS.Core.Infra.EF/QA/QATemplateRepository.cs new file mode 100644 index 0000000..f21aef8 --- /dev/null +++ b/IRaCIS.Core.Infra.EF/QA/QATemplateRepository.cs @@ -0,0 +1,13 @@ +using IRaCIS.Core.Domain.Interfaces; +using IRaCIS.Core.Domain.Models; + +namespace IRaCIS.Core.Infra.EFCore.Repository +{ + public class QATemplateRepository : BaseRepository, IQATemplateRepository + { + public QATemplateRepository(IRaCISDBContext db) + : base(db) + { + } + } +} \ No newline at end of file diff --git a/IRaCIS.Core.Infra.EF/QueryableExtension.cs b/IRaCIS.Core.Infra.EF/QueryableExtension.cs new file mode 100644 index 0000000..666d52a --- /dev/null +++ b/IRaCIS.Core.Infra.EF/QueryableExtension.cs @@ -0,0 +1,68 @@ +using System; +using System.Linq; +using System.Linq.Expressions; +using System.Reflection; + +namespace IRaCIS.Core.Infra.EFCore +{ + public static class QueryableExtension + { + public static IOrderedQueryable OrderBy(this IQueryable query, string propertyName) + { + Type type = typeof(T); + + PropertyInfo property = type.GetProperty(propertyName); + if (property == null) + throw new ArgumentException("propertyName", "Not Exist"); + + return OrderBy(query, propertyName, false); + } + + + public static IOrderedQueryable OrderByDescending(this IQueryable query, string propertyName) + { + Type type = typeof(T); + + PropertyInfo property = type.GetProperty(propertyName); + if (property == null) + throw new ArgumentException("propertyName", "Not Exist"); + + return OrderBy(query, propertyName, true); + } + + + static IOrderedQueryable OrderBy(IQueryable query, string propertyName, bool isDesc) + { + string methodName = (isDesc) ? "OrderByDescendingInternal" : "OrderByInternal"; + + var memberProp = typeof(T).GetProperty(propertyName); + + var method = typeof(QueryableExtension).GetMethod(methodName) + + .MakeGenericMethod(typeof(T), memberProp.PropertyType); + + return (IOrderedQueryable)method.Invoke(null, new object[] { query, memberProp }); + } + + public static IOrderedQueryable OrderByInternal(IQueryable query, System.Reflection.PropertyInfo memberProperty) + { + return query.OrderBy(_GetLamba(memberProperty)); + } + + public static IOrderedQueryable OrderByDescendingInternal(IQueryable query, System.Reflection.PropertyInfo memberProperty) + { + return query.OrderByDescending(_GetLamba(memberProperty)); + } + + static Expression> _GetLamba(System.Reflection.PropertyInfo memberProperty) + { + if (memberProperty.PropertyType != typeof(TProp)) throw new Exception(); + + var thisArg = Expression.Parameter(typeof(T)); + var lamba = Expression.Lambda>(Expression.Property(thisArg, memberProperty), thisArg); + + return lamba; + } + + } +} \ No newline at end of file diff --git a/IRaCIS.Core.Infra.EF/Relation/UserDoctorRepository.cs b/IRaCIS.Core.Infra.EF/Relation/UserDoctorRepository.cs new file mode 100644 index 0000000..0b1b69a --- /dev/null +++ b/IRaCIS.Core.Infra.EF/Relation/UserDoctorRepository.cs @@ -0,0 +1,13 @@ +using IRaCIS.Core.Domain.Interfaces; +using IRaCIS.Core.Domain.Models; + +namespace IRaCIS.Core.Infra.EFCore.Repository +{ + public class UserDoctorRepository : BaseRepository, IUserDoctorRepository + { + public UserDoctorRepository( IRaCISDBContext db) + : base( db) + { + } + } +} \ No newline at end of file diff --git a/IRaCIS.Core.Infra.EF/Relation/UserTrialRepository.cs b/IRaCIS.Core.Infra.EF/Relation/UserTrialRepository.cs new file mode 100644 index 0000000..2156180 --- /dev/null +++ b/IRaCIS.Core.Infra.EF/Relation/UserTrialRepository.cs @@ -0,0 +1,13 @@ +using IRaCIS.Core.Domain.Interfaces; +using IRaCIS.Core.Domain.Models; + +namespace IRaCIS.Core.Infra.EFCore.Repository +{ + public class UserTrialRepository : BaseRepository, IUserTrialRepository + { + public UserTrialRepository( IRaCISDBContext db) + : base( db) + { + } + } +} \ No newline at end of file diff --git a/IRaCIS.Core.Infra.EF/Report/GlobalRSRepository.cs b/IRaCIS.Core.Infra.EF/Report/GlobalRSRepository.cs new file mode 100644 index 0000000..1e7841f --- /dev/null +++ b/IRaCIS.Core.Infra.EF/Report/GlobalRSRepository.cs @@ -0,0 +1,13 @@ +using IRaCIS.Core.Domain.Interfaces; +using IRaCIS.Core.Domain.Models; + +namespace IRaCIS.Core.Infra.EFCore.Repository +{ + public class GlobalRSRepository : BaseRepository, IGlobalRSRepository + { + public GlobalRSRepository(IRaCISDBContext db) : base(db) + { + + } + } +} \ No newline at end of file diff --git a/IRaCIS.Core.Infra.EF/Report/GlobalResultRepository.cs b/IRaCIS.Core.Infra.EF/Report/GlobalResultRepository.cs new file mode 100644 index 0000000..a24b94f --- /dev/null +++ b/IRaCIS.Core.Infra.EF/Report/GlobalResultRepository.cs @@ -0,0 +1,13 @@ +using IRaCIS.Core.Domain.Interfaces; +using IRaCIS.Core.Domain.Models; + +namespace IRaCIS.Core.Infra.EFCore.Repository +{ + public class GlobalResultRepository : BaseRepository, IGlobalResultRepository + { + public GlobalResultRepository(IRaCISDBContext db) : base(db) + { + + } + } +} \ No newline at end of file diff --git a/IRaCIS.Core.Infra.EF/Report/ReportRepository.cs b/IRaCIS.Core.Infra.EF/Report/ReportRepository.cs new file mode 100644 index 0000000..a55561c --- /dev/null +++ b/IRaCIS.Core.Infra.EF/Report/ReportRepository.cs @@ -0,0 +1,13 @@ +using IRaCIS.Core.Domain.Interfaces; +using IRaCIS.Core.Domain.Models; + +namespace IRaCIS.Core.Infra.EFCore.Repository +{ + public class ReportRepository : BaseRepository, IReportRepository + { + public ReportRepository(IRaCISDBContext db) : base(db) + { + + } + } +} diff --git a/IRaCIS.Core.Infra.EF/Report/TU_TR_RSRepository.cs b/IRaCIS.Core.Infra.EF/Report/TU_TR_RSRepository.cs new file mode 100644 index 0000000..e2a56c3 --- /dev/null +++ b/IRaCIS.Core.Infra.EF/Report/TU_TR_RSRepository.cs @@ -0,0 +1,27 @@ +using IRaCIS.Core.Domain.Interfaces; +using IRaCIS.Core.Domain.Models; + +namespace IRaCIS.Core.Infra.EFCore.Repository +{ + public class TURepository : BaseRepository, ITURepository + { + public TURepository(IRaCISDBContext db) : base(db) + { + + } + } + public class TRRepository : BaseRepository, ITRRepository + { + public TRRepository(IRaCISDBContext db) : base(db) + { + + } + } + public class RSRepository : BaseRepository, IRSRepository + { + public RSRepository(IRaCISDBContext db) : base(db) + { + + } + } +} diff --git a/IRaCIS.Core.Infra.EF/TestRepository.cs b/IRaCIS.Core.Infra.EF/TestRepository.cs new file mode 100644 index 0000000..989b9f9 --- /dev/null +++ b/IRaCIS.Core.Infra.EF/TestRepository.cs @@ -0,0 +1,12 @@ +using IRaCIS.Core.Domain; + +namespace IRaCIS.Core.Infra.EFCore +{ + public class TestRepository : BaseRepository, ITestRepository + { + public TestRepository(IRaCISDBContext db) : base(db) + { + + } + } +} \ No newline at end of file diff --git a/IRaCIS.Core.Infra.EF/Trial/ClinicalStudySubjectsRepository.cs b/IRaCIS.Core.Infra.EF/Trial/ClinicalStudySubjectsRepository.cs new file mode 100644 index 0000000..937457d --- /dev/null +++ b/IRaCIS.Core.Infra.EF/Trial/ClinicalStudySubjectsRepository.cs @@ -0,0 +1,14 @@ +using IRaCIS.Core.Domain.Interfaces; +using IRaCIS.Core.Domain.Models; + +namespace IRaCIS.Core.Infra.EFCore.Repository +{ + public class ClinicalStudySubjectsRepository : BaseRepository, ISubjectRepository + { + public ClinicalStudySubjectsRepository( IRaCISDBContext db) + : base( db) + { + + } + } +} diff --git a/IRaCIS.Core.Infra.EF/Trial/EnrollDetailRepository.cs b/IRaCIS.Core.Infra.EF/Trial/EnrollDetailRepository.cs new file mode 100644 index 0000000..693fa98 --- /dev/null +++ b/IRaCIS.Core.Infra.EF/Trial/EnrollDetailRepository.cs @@ -0,0 +1,13 @@ +using IRaCIS.Core.Domain.Interfaces; +using IRaCIS.Core.Domain.Models; + +namespace IRaCIS.Core.Infra.EFCore.Repository +{ + public class EnrollDetailRepository : BaseRepository, IEnrollDetailRepository + { + public EnrollDetailRepository( IRaCISDBContext db) : base( db) + { + + } + } +} \ No newline at end of file diff --git a/IRaCIS.Core.Infra.EF/Trial/EnrollRepository.cs b/IRaCIS.Core.Infra.EF/Trial/EnrollRepository.cs new file mode 100644 index 0000000..2e39267 --- /dev/null +++ b/IRaCIS.Core.Infra.EF/Trial/EnrollRepository.cs @@ -0,0 +1,13 @@ +using IRaCIS.Core.Domain.Interfaces; +using IRaCIS.Core.Domain.Models; + +namespace IRaCIS.Core.Infra.EFCore.Repository +{ + public class EnrollRepository : BaseRepository, IEnrollRepository + { + public EnrollRepository( IRaCISDBContext db) : base( db) + { + + } + } +} \ No newline at end of file diff --git a/IRaCIS.Core.Infra.EF/Trial/SubjectVisitRepository.cs b/IRaCIS.Core.Infra.EF/Trial/SubjectVisitRepository.cs new file mode 100644 index 0000000..6554428 --- /dev/null +++ b/IRaCIS.Core.Infra.EF/Trial/SubjectVisitRepository.cs @@ -0,0 +1,13 @@ +using IRaCIS.Core.Domain.Interfaces; +using IRaCIS.Core.Domain.Models; + +namespace IRaCIS.Core.Infra.EFCore.Repository +{ + public class SubjectVisitRepository : BaseRepository, ISubjectVisitRepository + { + public SubjectVisitRepository(IRaCISDBContext db) : base(db) + { + + } + } +} \ No newline at end of file diff --git a/IRaCIS.Core.Infra.EF/Trial/TrialAttachmentRepository.cs b/IRaCIS.Core.Infra.EF/Trial/TrialAttachmentRepository.cs new file mode 100644 index 0000000..1e02a59 --- /dev/null +++ b/IRaCIS.Core.Infra.EF/Trial/TrialAttachmentRepository.cs @@ -0,0 +1,13 @@ +using IRaCIS.Core.Domain.Interfaces; +using IRaCIS.Core.Domain.Models; + +namespace IRaCIS.Core.Infra.EFCore.Repository +{ + public class TrialAttachmentRepository : BaseRepository, IAcquisitionSpecificationRepository + { + public TrialAttachmentRepository( IRaCISDBContext db) : base( db) + { + + } + } +} \ No newline at end of file diff --git a/IRaCIS.Core.Infra.EF/Trial/TrialDetailRepository.cs b/IRaCIS.Core.Infra.EF/Trial/TrialDetailRepository.cs new file mode 100644 index 0000000..01e48c1 --- /dev/null +++ b/IRaCIS.Core.Infra.EF/Trial/TrialDetailRepository.cs @@ -0,0 +1,12 @@ +using IRaCIS.Core.Domain.Interfaces; +using IRaCIS.Core.Domain.Models; + +namespace IRaCIS.Core.Infra.EFCore.Repository +{ + public class TrialDetailRepository : BaseRepository, ITrialDetailRepository + { + public TrialDetailRepository( IRaCISDBContext db) : base( db) + { + } + } +} \ No newline at end of file diff --git a/IRaCIS.Core.Infra.EF/Trial/TrialDictionaryRepository.cs b/IRaCIS.Core.Infra.EF/Trial/TrialDictionaryRepository.cs new file mode 100644 index 0000000..fb48686 --- /dev/null +++ b/IRaCIS.Core.Infra.EF/Trial/TrialDictionaryRepository.cs @@ -0,0 +1,13 @@ +using IRaCIS.Core.Domain.Interfaces; +using IRaCIS.Core.Domain.Models; + +namespace IRaCIS.Core.Infra.EFCore.Repository +{ + public class TrialDictionaryRepository : BaseRepository, ITrialDictionaryRepository + { + public TrialDictionaryRepository( IRaCISDBContext db) : base( db) + { + + } + } +} \ No newline at end of file diff --git a/IRaCIS.Core.Infra.EF/Trial/TrialRepository.cs b/IRaCIS.Core.Infra.EF/Trial/TrialRepository.cs new file mode 100644 index 0000000..70e09b9 --- /dev/null +++ b/IRaCIS.Core.Infra.EF/Trial/TrialRepository.cs @@ -0,0 +1,18 @@ +using IRaCIS.Core.Domain.Interfaces; +using IRaCIS.Core.Domain.Models; +namespace IRaCIS.Core.Infra.EFCore.Repository +{ + public class TrialRepository : BaseRepository, ITrialRepository + { + public TrialRepository( IRaCISDBContext db) : base( db) + { + + } + + //public IEnumerable GetDoctorWorkLoadStatistics(int projectId) + //{ + // return db.Database.SqlQuery($"EXEC [dbo].[doctorWorkLoadProcedure] @ProjectId = {projectId}").ToList(); + //} + + } +} \ No newline at end of file diff --git a/IRaCIS.Core.Infra.EF/Trial/TrialRevenuesPriceVerificationRepository.cs b/IRaCIS.Core.Infra.EF/Trial/TrialRevenuesPriceVerificationRepository.cs new file mode 100644 index 0000000..49a9776 --- /dev/null +++ b/IRaCIS.Core.Infra.EF/Trial/TrialRevenuesPriceVerificationRepository.cs @@ -0,0 +1,13 @@ +using IRaCIS.Core.Domain.Interfaces; +using IRaCIS.Core.Domain.Models; + +namespace IRaCIS.Core.Infra.EFCore.Repository +{ + public class TrialRevenuesPriceVerificationRepository: BaseRepository, ITrialRevenuesPriceVerificationRepository + { + public TrialRevenuesPriceVerificationRepository(IRaCISDBContext db) : base(db) + { + + } + } +} \ No newline at end of file diff --git a/IRaCIS.Core.Infra.EF/Trial/VisitStageRepository.cs b/IRaCIS.Core.Infra.EF/Trial/VisitStageRepository.cs new file mode 100644 index 0000000..10548d6 --- /dev/null +++ b/IRaCIS.Core.Infra.EF/Trial/VisitStageRepository.cs @@ -0,0 +1,13 @@ +using IRaCIS.Core.Domain.Interfaces; +using IRaCIS.Core.Domain.Models; + +namespace IRaCIS.Core.Infra.EFCore.Repository +{ + public class VisitStageRepository : BaseRepository, IVisitStageRepository + { + public VisitStageRepository( IRaCISDBContext db) : base( db) + { + + } + } +} diff --git a/IRaCIS.Core.Infra.EF/Trial/WorkloadDistributionRepository.cs b/IRaCIS.Core.Infra.EF/Trial/WorkloadDistributionRepository.cs new file mode 100644 index 0000000..710922e --- /dev/null +++ b/IRaCIS.Core.Infra.EF/Trial/WorkloadDistributionRepository.cs @@ -0,0 +1,35 @@ +using IRaCIS.Core.Domain.Interfaces; +using IRaCIS.Core.Domain.Models; + +namespace IRaCIS.Core.Infra.EFCore.Repository +{ + public class WorkloadTPRepository : BaseRepository, IWorkloadTPRepository + { + public WorkloadTPRepository(IRaCISDBContext db) : base(db) + { + + } + } + public class WorkloadGlobalRepository : BaseRepository, IWorkloadGlobalRepository + { + public WorkloadGlobalRepository(IRaCISDBContext db) : base(db) + { + + } + } + public class WorkloadADRepository : BaseRepository, IWorkloadADRepository + { + public WorkloadADRepository(IRaCISDBContext db) : base(db) + { + + } + } + + public class WorkloadDetailRepository : BaseRepository, IWorkloadDetailRepository + { + public WorkloadDetailRepository(IRaCISDBContext db) : base(db) + { + + } + } +} diff --git a/IRaCIS.Core.Infra.EF/Trial/WorkloadRepository.cs b/IRaCIS.Core.Infra.EF/Trial/WorkloadRepository.cs new file mode 100644 index 0000000..7341b84 --- /dev/null +++ b/IRaCIS.Core.Infra.EF/Trial/WorkloadRepository.cs @@ -0,0 +1,13 @@ +using IRaCIS.Core.Domain.Interfaces; +using IRaCIS.Core.Domain.Models; + +namespace IRaCIS.Core.Infra.EFCore.Repository +{ + public class WorkloadRepository : BaseRepository, IWorkloadRepository + { + public WorkloadRepository( IRaCISDBContext db) : base( db) + { + + } + } +} \ No newline at end of file