From 68b747196aac11254d476779c820affcc8677179 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E5=86=9B?= <510423039@qq.com> Date: Fri, 1 Oct 2021 10:42:51 +0800 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20=E6=B7=BB=E5=8A=A0=E7=A7=9F?= =?UTF-8?q?=E6=88=B7=E6=A8=A1=E5=9D=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Aggregates/DataDictionary.cs | 2 +- .../DataDictionaryDataSeedContributor.cs | 25 +- .../Filters/HiddenAbpDefaultApiFilter.cs | 16 +- .../ProjectNameHttpApiHostModule.cs | 15 +- .../Properties/launchSettings.json | 2 +- ...e.ProjectName.Application.Contracts.csproj | 4 + .../Tenants/Dtos/FindTenantByNameInput.cs | 7 + .../Tenants/Dtos/PagingTenantInput.cs | 9 + .../UpdateDefaultConnectionStringInput.cs | 11 + .../Tenants/Dtos/UpdateTenantInput.cs | 12 + .../Roles/RoleAppService.cs | 14 +- .../Users/LoginAppService.cs | 21 +- .../appsettings.json | 2 +- .../Tenants/AbpTenantController.cs | 26 + .../Controllers/Tenants/TenantController.cs | 83 ++ vben271/src/api/sys/model/userModel.ts | 2 + vben271/src/assets/images/header.jpg | Bin 0 -> 16880 bytes vben271/src/enums/cacheEnum.ts | 2 + vben271/src/locales/lang/en/routes/tenant.ts | 6 + vben271/src/locales/lang/en/sys.ts | 4 +- .../src/locales/lang/zh-CN/routes/tenant.ts | 6 + vben271/src/locales/lang/zh-CN/sys.ts | 4 +- vben271/src/router/routes/modules/admin.ts | 2 +- vben271/src/router/routes/modules/tenant.ts | 27 + vben271/src/services/ServiceProxies.ts | 916 ++++++++++++++++++ vben271/src/services/ServiceProxyBase.ts | 14 +- vben271/src/store/modules/user.ts | 17 +- vben271/src/utils/cache/persistent.ts | 2 + .../apiScopes/EditApiScope.vue | 2 +- vben271/src/views/sys/login/Login.vue | 2 + vben271/src/views/sys/login/LoginForm.vue | 17 +- .../src/views/sys/login/LoginFormTitle.vue | 1 + vben271/src/views/sys/login/MobileForm.vue | 8 + .../src/views/sys/login/TenantLoginForm.vue | 106 ++ vben271/src/views/sys/login/useLogin.ts | 12 +- vben271/src/views/tenants/CreateTenant.vue | 63 ++ .../views/tenants/EditConnectionString.vue | 75 ++ vben271/src/views/tenants/EditTenant.vue | 69 ++ vben271/src/views/tenants/Tenant.ts | 125 +++ vben271/src/views/tenants/Tenant.vue | 150 +++ 40 files changed, 1822 insertions(+), 59 deletions(-) create mode 100644 aspnet-core/services/src/CompanyName.ProjectName.Application.Contracts/Tenants/Dtos/FindTenantByNameInput.cs create mode 100644 aspnet-core/services/src/CompanyName.ProjectName.Application.Contracts/Tenants/Dtos/PagingTenantInput.cs create mode 100644 aspnet-core/services/src/CompanyName.ProjectName.Application.Contracts/Tenants/Dtos/UpdateDefaultConnectionStringInput.cs create mode 100644 aspnet-core/services/src/CompanyName.ProjectName.Application.Contracts/Tenants/Dtos/UpdateTenantInput.cs create mode 100644 aspnet-core/services/src/CompanyName.ProjectName.HttpApi/Controllers/Tenants/AbpTenantController.cs create mode 100644 aspnet-core/services/src/CompanyName.ProjectName.HttpApi/Controllers/Tenants/TenantController.cs create mode 100644 vben271/src/assets/images/header.jpg create mode 100644 vben271/src/locales/lang/en/routes/tenant.ts create mode 100644 vben271/src/locales/lang/zh-CN/routes/tenant.ts create mode 100644 vben271/src/router/routes/modules/tenant.ts create mode 100644 vben271/src/views/sys/login/TenantLoginForm.vue create mode 100644 vben271/src/views/tenants/CreateTenant.vue create mode 100644 vben271/src/views/tenants/EditConnectionString.vue create mode 100644 vben271/src/views/tenants/EditTenant.vue create mode 100644 vben271/src/views/tenants/Tenant.ts create mode 100644 vben271/src/views/tenants/Tenant.vue diff --git a/aspnet-core/modules/DataDictionaryManagement/src/CompanyName.ProjectName.DataDictionaryManagement.Domain/DataDictionaries/Aggregates/DataDictionary.cs b/aspnet-core/modules/DataDictionaryManagement/src/CompanyName.ProjectName.DataDictionaryManagement.Domain/DataDictionaries/Aggregates/DataDictionary.cs index 11992271..2ad4aa58 100644 --- a/aspnet-core/modules/DataDictionaryManagement/src/CompanyName.ProjectName.DataDictionaryManagement.Domain/DataDictionaries/Aggregates/DataDictionary.cs +++ b/aspnet-core/modules/DataDictionaryManagement/src/CompanyName.ProjectName.DataDictionaryManagement.Domain/DataDictionaries/Aggregates/DataDictionary.cs @@ -72,7 +72,7 @@ namespace CompanyName.ProjectName.DataDictionaryManagement.DataDictionaries.Aggr public void SetTenantId(Guid? tenantId) { - TenantId = TenantId; + TenantId = tenantId; } public void SetCode(string code) diff --git a/aspnet-core/modules/DataDictionaryManagement/src/CompanyName.ProjectName.DataDictionaryManagement.Domain/DataDictionaries/DataDictionaryDataSeedContributor.cs b/aspnet-core/modules/DataDictionaryManagement/src/CompanyName.ProjectName.DataDictionaryManagement.Domain/DataDictionaries/DataDictionaryDataSeedContributor.cs index 3873bb42..78c81cf0 100644 --- a/aspnet-core/modules/DataDictionaryManagement/src/CompanyName.ProjectName.DataDictionaryManagement.Domain/DataDictionaries/DataDictionaryDataSeedContributor.cs +++ b/aspnet-core/modules/DataDictionaryManagement/src/CompanyName.ProjectName.DataDictionaryManagement.Domain/DataDictionaries/DataDictionaryDataSeedContributor.cs @@ -4,6 +4,7 @@ using CompanyName.ProjectName.DataDictionaryManagement.DataDictionaries.Aggregat using Volo.Abp.Data; using Volo.Abp.DependencyInjection; using Volo.Abp.Guids; +using Volo.Abp.MultiTenancy; namespace CompanyName.ProjectName.DataDictionaryManagement.DataDictionaries { @@ -11,27 +12,31 @@ namespace CompanyName.ProjectName.DataDictionaryManagement.DataDictionaries { private readonly IDataDictionaryRepository _dataDictionaryRepository; private readonly IGuidGenerator _guidGenerator; + private readonly ICurrentTenant _currentTenant; public DataDictionaryDataSeedContributor( IDataDictionaryRepository dataDictionaryRepository, - IGuidGenerator guidGenerator) + IGuidGenerator guidGenerator, ICurrentTenant currentTenant) { _dataDictionaryRepository = dataDictionaryRepository; _guidGenerator = guidGenerator; + _currentTenant = currentTenant; } public async Task SeedAsync(DataSeedContext context) { - var gender = await _dataDictionaryRepository.FindByCodeAsync("Gender"); - if (gender == null) + using (_currentTenant.Change(context?.TenantId)) { - var id = DataDictionaryManagementConsts.SeedDataDictionaryId;//_guidGenerator.Create(); - - var entity = new DataDictionary(id, "Gender", "性别", "单元测试"); - entity.AddDetail(_guidGenerator.Create(), "Man", "男", 1, "单元测试"); - entity.AddDetail(_guidGenerator.Create(), "WoMan", "女", 2, "单元测试"); - entity.AddDetail(_guidGenerator.Create(), "None", "未知", 3, "单元测试", false); - await _dataDictionaryRepository.InsertAsync(entity); + var gender = await _dataDictionaryRepository.FindByCodeAsync("Gender"); + if (gender == null) + { + var id = context is {TenantId: null} ? DataDictionaryManagementConsts.SeedDataDictionaryId : _guidGenerator.Create(); + var entity = new DataDictionary(id, "Gender", "性别", "单元测试", context?.TenantId); + entity.AddDetail(_guidGenerator.Create(), "Man", "男", 1, "单元测试"); + entity.AddDetail(_guidGenerator.Create(), "WoMan", "女", 2, "单元测试"); + entity.AddDetail(_guidGenerator.Create(), "None", "未知", 3, "单元测试", false); + await _dataDictionaryRepository.InsertAsync(entity); + } } } } diff --git a/aspnet-core/services/host/CompanyName.ProjectName.HttpApi.Host/Extensions/Filters/HiddenAbpDefaultApiFilter.cs b/aspnet-core/services/host/CompanyName.ProjectName.HttpApi.Host/Extensions/Filters/HiddenAbpDefaultApiFilter.cs index 6feaaae2..ec023a51 100644 --- a/aspnet-core/services/host/CompanyName.ProjectName.HttpApi.Host/Extensions/Filters/HiddenAbpDefaultApiFilter.cs +++ b/aspnet-core/services/host/CompanyName.ProjectName.HttpApi.Host/Extensions/Filters/HiddenAbpDefaultApiFilter.cs @@ -42,14 +42,14 @@ namespace CompanyName.ProjectName.Extensions.Filters private List GetHiddenAbpDefaultApiList() { return new List() { - // "/api/abp/multi-tenancy/tenants", - // "/api/account", - // "/api/feature-management/features", - // "/api/permission-management/permissions", - // "/api/identity/my-profile", - // "/api/identity", - // "/api/multi-tenancy/tenants", - // "/api/setting-management/emailing" + "/api/abp/multi-tenancy/tenants", + "/api/account", + "/api/feature-management/features", + "/api/permission-management/permissions", + "/api/identity/my-profile", + "/api/identity", + "/api/multi-tenancy/tenants", + "/api/setting-management/emailing" }; } } diff --git a/aspnet-core/services/host/CompanyName.ProjectName.HttpApi.Host/ProjectNameHttpApiHostModule.cs b/aspnet-core/services/host/CompanyName.ProjectName.HttpApi.Host/ProjectNameHttpApiHostModule.cs index e747a15c..d006cbf0 100644 --- a/aspnet-core/services/host/CompanyName.ProjectName.HttpApi.Host/ProjectNameHttpApiHostModule.cs +++ b/aspnet-core/services/host/CompanyName.ProjectName.HttpApi.Host/ProjectNameHttpApiHostModule.cs @@ -36,9 +36,11 @@ using System.Threading.Tasks; using CompanyName.ProjectName.CAP; using CompanyName.ProjectName.Extensions; using CompanyName.ProjectName.Extensions.Customs.Http; +using CompanyName.ProjectName.MultiTenancy; using Savorboard.CAP.InMemoryMessageQueue; using Serilog; using Volo.Abp.AspNetCore.ExceptionHandling; +using Volo.Abp.AspNetCore.MultiTenancy; namespace CompanyName.ProjectName { @@ -54,7 +56,8 @@ namespace CompanyName.ProjectName typeof(AbpAccountWebModule), typeof(AbpAspNetCoreAuthenticationJwtBearerModule), typeof(AbpBackgroundJobsHangfireModule), - typeof(AbpCapModule) + typeof(AbpCapModule), + typeof(AbpAspNetCoreMultiTenancyModule) )] public class ProjectNameHttpApiHostModule : AbpModule { @@ -96,11 +99,11 @@ namespace CompanyName.ProjectName app.UseRouting(); app.UseCors(DefaultCorsPolicyName); app.UseAuthentication(); - // - // if (MultiTenancyConsts.IsEnabled) - // { - // app.UseMultiTenancy(); - // } + + if (MultiTenancyConsts.IsEnabled) + { + app.UseMultiTenancy(); + } app.UseAuthorization(); diff --git a/aspnet-core/services/host/CompanyName.ProjectName.HttpApi.Host/Properties/launchSettings.json b/aspnet-core/services/host/CompanyName.ProjectName.HttpApi.Host/Properties/launchSettings.json index 64892bee..6fce9433 100644 --- a/aspnet-core/services/host/CompanyName.ProjectName.HttpApi.Host/Properties/launchSettings.json +++ b/aspnet-core/services/host/CompanyName.ProjectName.HttpApi.Host/Properties/launchSettings.json @@ -20,7 +20,7 @@ "launchBrowser": true, "applicationUrl": "http://localhost:44315", "environmentVariables": { - "ASPNETCORE_ENVIRONMENT": "Production" + "ASPNETCORE_ENVIRONMENT": "Development" } } } diff --git a/aspnet-core/services/src/CompanyName.ProjectName.Application.Contracts/CompanyName.ProjectName.Application.Contracts.csproj b/aspnet-core/services/src/CompanyName.ProjectName.Application.Contracts/CompanyName.ProjectName.Application.Contracts.csproj index c1a365b2..82bf0b16 100644 --- a/aspnet-core/services/src/CompanyName.ProjectName.Application.Contracts/CompanyName.ProjectName.Application.Contracts.csproj +++ b/aspnet-core/services/src/CompanyName.ProjectName.Application.Contracts/CompanyName.ProjectName.Application.Contracts.csproj @@ -35,4 +35,8 @@ + + + + diff --git a/aspnet-core/services/src/CompanyName.ProjectName.Application.Contracts/Tenants/Dtos/FindTenantByNameInput.cs b/aspnet-core/services/src/CompanyName.ProjectName.Application.Contracts/Tenants/Dtos/FindTenantByNameInput.cs new file mode 100644 index 00000000..05bd8aa6 --- /dev/null +++ b/aspnet-core/services/src/CompanyName.ProjectName.Application.Contracts/Tenants/Dtos/FindTenantByNameInput.cs @@ -0,0 +1,7 @@ +namespace CompanyName.ProjectName.Tenants.Dtos +{ + public class FindTenantByNameInput + { + public string Name { get; set; } + } +} \ No newline at end of file diff --git a/aspnet-core/services/src/CompanyName.ProjectName.Application.Contracts/Tenants/Dtos/PagingTenantInput.cs b/aspnet-core/services/src/CompanyName.ProjectName.Application.Contracts/Tenants/Dtos/PagingTenantInput.cs new file mode 100644 index 00000000..d16612cf --- /dev/null +++ b/aspnet-core/services/src/CompanyName.ProjectName.Application.Contracts/Tenants/Dtos/PagingTenantInput.cs @@ -0,0 +1,9 @@ +using CompanyName.ProjectName.Extensions.Customs; + +namespace CompanyName.ProjectName.Tenants.Dtos +{ + public class PagingTenantInput : PagingBase + { + public string Filter { get; set; } + } +} \ No newline at end of file diff --git a/aspnet-core/services/src/CompanyName.ProjectName.Application.Contracts/Tenants/Dtos/UpdateDefaultConnectionStringInput.cs b/aspnet-core/services/src/CompanyName.ProjectName.Application.Contracts/Tenants/Dtos/UpdateDefaultConnectionStringInput.cs new file mode 100644 index 00000000..13ac523e --- /dev/null +++ b/aspnet-core/services/src/CompanyName.ProjectName.Application.Contracts/Tenants/Dtos/UpdateDefaultConnectionStringInput.cs @@ -0,0 +1,11 @@ +using System; +using System.ComponentModel.DataAnnotations; + +namespace CompanyName.ProjectName.Tenants.Dtos +{ + public class UpdateConnectionStringInput + { + public Guid Id { get; set; } + [Required(ErrorMessage = "连接字符串不能为空")] public string ConnectionString { get; set; } + } +} \ No newline at end of file diff --git a/aspnet-core/services/src/CompanyName.ProjectName.Application.Contracts/Tenants/Dtos/UpdateTenantInput.cs b/aspnet-core/services/src/CompanyName.ProjectName.Application.Contracts/Tenants/Dtos/UpdateTenantInput.cs new file mode 100644 index 00000000..ca699ee2 --- /dev/null +++ b/aspnet-core/services/src/CompanyName.ProjectName.Application.Contracts/Tenants/Dtos/UpdateTenantInput.cs @@ -0,0 +1,12 @@ +using System; +using System.ComponentModel.DataAnnotations; + +namespace CompanyName.ProjectName.Tenants.Dtos +{ + public class UpdateTenantInput + { + public Guid Id { get; set; } + + [Required(ErrorMessage = "租户名称不能为空")] public string Name { get; set; } + } +} \ No newline at end of file diff --git a/aspnet-core/services/src/CompanyName.ProjectName.Application/Roles/RoleAppService.cs b/aspnet-core/services/src/CompanyName.ProjectName.Application/Roles/RoleAppService.cs index 203833d0..f4c04410 100644 --- a/aspnet-core/services/src/CompanyName.ProjectName.Application/Roles/RoleAppService.cs +++ b/aspnet-core/services/src/CompanyName.ProjectName.Application/Roles/RoleAppService.cs @@ -118,13 +118,13 @@ namespace CompanyName.ProjectName.Roles "AbpIdentity.Users.ManagePermissions", "FeatureManagement", "FeatureManagement.ManageHostFeatures", - "AbpTenantManagement", - "AbpTenantManagement.Tenants", - "AbpTenantManagement.Tenants.Create", - "AbpTenantManagement.Tenants.Update", - "AbpTenantManagement.Tenants.Delete", - "AbpTenantManagement.Tenants.ManageFeatures", - "AbpTenantManagement.Tenants.ManageConnectionStrings", + // "AbpTenantManagement", + // "AbpTenantManagement.Tenants", + // "AbpTenantManagement.Tenants.Create", + // "AbpTenantManagement.Tenants.Update", + // "AbpTenantManagement.Tenants.Delete", + "AbpTenantManagement.Tenants.ManageFeatures", + // "AbpTenantManagement.Tenants.ManageConnectionStrings", "SettingManagement", "SettingManagement.Emailing", "SettingUi" diff --git a/aspnet-core/services/src/CompanyName.ProjectName.Application/Users/LoginAppService.cs b/aspnet-core/services/src/CompanyName.ProjectName.Application/Users/LoginAppService.cs index 6994d1e0..80fcc09f 100644 --- a/aspnet-core/services/src/CompanyName.ProjectName.Application/Users/LoginAppService.cs +++ b/aspnet-core/services/src/CompanyName.ProjectName.Application/Users/LoginAppService.cs @@ -15,6 +15,7 @@ using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using Microsoft.IdentityModel.Tokens; using Volo.Abp.Identity; +using Volo.Abp.MultiTenancy; using Volo.Abp.Security.Claims; namespace CompanyName.ProjectName.Users @@ -25,29 +26,37 @@ namespace CompanyName.ProjectName.Users private readonly JwtOptions _jwtOptions; private readonly Microsoft.AspNetCore.Identity.SignInManager _signInManager; private readonly IHttpClientFactory _httpClientFactory; - private readonly ILogger _logger; + private readonly ICurrentTenant _currentTenant; public LoginAppService( IdentityUserManager userManager, IOptionsSnapshot jwtOptions, Microsoft.AspNetCore.Identity.SignInManager signInManager, - IHttpClientFactory httpClientFactory, ILogger logger) + IHttpClientFactory httpClientFactory, ICurrentTenant currentTenant) { _userManager = userManager; _jwtOptions = jwtOptions.Value; _signInManager = signInManager; _httpClientFactory = httpClientFactory; - _logger = logger; + _currentTenant = currentTenant; } public async Task LoginAsync(LoginInput input) { - _logger.LogError("test"); try { var result = await _signInManager.PasswordSignInAsync(input.Name, input.Password, false, true); - if (result.IsLockedOut) throw new Exception("当前用户已被锁定"); - if (!result.Succeeded) throw new Exception("用户名或者密码错误"); + if (result.IsLockedOut) + { + throw new Exception("当前用户已被锁定"); + } + + if (!result.Succeeded) + { + throw new Exception("用户名或者密码错误"); + } + + var s = _currentTenant.Id; var user = await _userManager.FindByNameAsync(input.Name); return await BuildResult(user); } diff --git a/aspnet-core/services/src/CompanyName.ProjectName.DbMigrator/appsettings.json b/aspnet-core/services/src/CompanyName.ProjectName.DbMigrator/appsettings.json index 47063d9a..1f210a15 100644 --- a/aspnet-core/services/src/CompanyName.ProjectName.DbMigrator/appsettings.json +++ b/aspnet-core/services/src/CompanyName.ProjectName.DbMigrator/appsettings.json @@ -1,5 +1,5 @@ { "ConnectionStrings": { - "Default": "Data Source=localhost;Database=CompanyNameProjectName;uid=root;pwd=1q2w3E*;charset=utf8mb4;Allow User Variables=true;AllowLoadLocalInfile=true" + "Default": "Data Source=localhost;Database=CompanyNameProjectNameDB;uid=root;pwd=1q2w3E*;charset=utf8mb4;Allow User Variables=true;AllowLoadLocalInfile=true" } } \ No newline at end of file diff --git a/aspnet-core/services/src/CompanyName.ProjectName.HttpApi/Controllers/Tenants/AbpTenantController.cs b/aspnet-core/services/src/CompanyName.ProjectName.HttpApi/Controllers/Tenants/AbpTenantController.cs new file mode 100644 index 00000000..e3ec939f --- /dev/null +++ b/aspnet-core/services/src/CompanyName.ProjectName.HttpApi/Controllers/Tenants/AbpTenantController.cs @@ -0,0 +1,26 @@ +using System.Threading.Tasks; +using CompanyName.ProjectName.Tenants.Dtos; +using Microsoft.AspNetCore.Mvc; +using Swashbuckle.AspNetCore.Annotations; +using Volo.Abp.AspNetCore.Mvc.MultiTenancy; + +namespace CompanyName.ProjectName.Controllers.Tenants +{ + [Route("Tenants")] + public class AbpTenantController : ProjectNameController + { + private readonly IAbpTenantAppService _abpTenantAppService; + + public AbpTenantController(IAbpTenantAppService abpTenantAppService) + { + _abpTenantAppService = abpTenantAppService; + } + + [HttpPost("find")] + [SwaggerOperation(summary: "通过名称获取租户信息", Tags = new[] {"Tenants"})] + public async Task FindTenantByNameAsync(FindTenantByNameInput input) + { + return await _abpTenantAppService.FindTenantByNameAsync(input.Name); + } + } +} \ No newline at end of file diff --git a/aspnet-core/services/src/CompanyName.ProjectName.HttpApi/Controllers/Tenants/TenantController.cs b/aspnet-core/services/src/CompanyName.ProjectName.HttpApi/Controllers/Tenants/TenantController.cs new file mode 100644 index 00000000..b812c9f9 --- /dev/null +++ b/aspnet-core/services/src/CompanyName.ProjectName.HttpApi/Controllers/Tenants/TenantController.cs @@ -0,0 +1,83 @@ +using System.Threading.Tasks; +using CompanyName.ProjectName.Publics.Dtos; +using CompanyName.ProjectName.Tenants.Dtos; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using Swashbuckle.AspNetCore.Annotations; +using Volo.Abp.Application.Dtos; +using Volo.Abp.TenantManagement; + +namespace CompanyName.ProjectName.Controllers.Tenants +{ + [Route("Tenants")] + [Authorize(TenantManagementPermissions.Tenants.Default)] + public class TenantController : ProjectNameController + { + private readonly ITenantAppService _tenantAppService; + + public TenantController(ITenantAppService tenantAppService) + { + _tenantAppService = tenantAppService; + } + + [HttpPost("page")] + [SwaggerOperation(summary: "分页获取租户信息", Tags = new[] {"Tenants"})] + public Task> ListAsync(PagingTenantInput input) + { + var request = new GetTenantsInput {Filter = input.Filter, SkipCount = input.SkipCount, MaxResultCount = input.PageSize}; + return _tenantAppService.GetListAsync(request); + } + + [HttpPost("create")] + [SwaggerOperation(summary: "创建租户", Tags = new[] {"Tenants"})] + [Authorize(TenantManagementPermissions.Tenants.Create)] + public Task CreateAsync(TenantCreateDto input) + { + return _tenantAppService.CreateAsync(input); + } + + [HttpPost("update")] + [SwaggerOperation(summary: "更新租户", Tags = new[] {"Tenants"})] + [Authorize(TenantManagementPermissions.Tenants.Update)] + public Task UpdateAsync(UpdateTenantInput input) + { + var request = new TenantUpdateDto() + { + Name = input.Name.Trim() + }; + return _tenantAppService.UpdateAsync(input.Id, request); + } + + [HttpPost("delete")] + [SwaggerOperation(summary: "删除租户", Tags = new[] {"Tenants"})] + [Authorize(TenantManagementPermissions.Tenants.Delete)] + public Task DeleteAsync(IdInput input) + { + return _tenantAppService.DeleteAsync(input.Id); + } + + [HttpPost("getConnectionString")] + [SwaggerOperation(summary: "获取租户连接字符串", Tags = new[] {"Tenants"})] + [Authorize(TenantManagementPermissions.Tenants.ManageConnectionStrings)] + public Task GetDefaultConnectionStringAsync(IdInput input) + { + return _tenantAppService.GetDefaultConnectionStringAsync(input.Id); + } + + [HttpPost("updateConnectionString")] + [SwaggerOperation(summary: "更新租户连接字符串", Tags = new[] {"Tenants"})] + [Authorize(TenantManagementPermissions.Tenants.ManageConnectionStrings)] + public Task UpdateDefaultConnectionStringAsync(UpdateConnectionStringInput input) + { + return _tenantAppService.UpdateDefaultConnectionStringAsync(input.Id, input.ConnectionString); + } + + [HttpPost("deleteConnectionString")] + [SwaggerOperation(summary: "删除租户连接字符串", Tags = new[] {"Tenants"})] + [Authorize(TenantManagementPermissions.Tenants.ManageConnectionStrings)] + public Task DeleteDefaultConnectionStringAsync(IdInput input) + { + return _tenantAppService.DeleteDefaultConnectionStringAsync(input.Id); + } + } +} \ No newline at end of file diff --git a/vben271/src/api/sys/model/userModel.ts b/vben271/src/api/sys/model/userModel.ts index 444a7436..5be6ab9c 100644 --- a/vben271/src/api/sys/model/userModel.ts +++ b/vben271/src/api/sys/model/userModel.ts @@ -4,6 +4,7 @@ export interface LoginParams { username: string; password: string; + tenantId: string; } /** @@ -48,6 +49,7 @@ export interface GetUserInfoByUserIdModel { export interface LoginParams { username: string; password: string; + tenantId: string; } export interface RoleInfo { diff --git a/vben271/src/assets/images/header.jpg b/vben271/src/assets/images/header.jpg new file mode 100644 index 0000000000000000000000000000000000000000..977584b6877cf4abc6c3e3a3d51bfbb0d474da74 GIT binary patch literal 16880 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 K^riIu-2VXLS6svZ literal 0 HcmV?d00001 diff --git a/vben271/src/enums/cacheEnum.ts b/vben271/src/enums/cacheEnum.ts index 8eac7b1f..3d71b47b 100644 --- a/vben271/src/enums/cacheEnum.ts +++ b/vben271/src/enums/cacheEnum.ts @@ -27,6 +27,8 @@ export const APP_SESSION_CACHE_KEY = 'COMMON__SESSION__KEY__'; export const ABP_LOCALE_KEY = 'ABP_LOCALE__'; +export const ABP_TETANT_KEY = 'ABP_TETANT__'; + export const AUHT_KEY = 'AUTH__KEY__'; export enum CacheTypeEnum { diff --git a/vben271/src/locales/lang/en/routes/tenant.ts b/vben271/src/locales/lang/en/routes/tenant.ts new file mode 100644 index 00000000..0311f108 --- /dev/null +++ b/vben271/src/locales/lang/en/routes/tenant.ts @@ -0,0 +1,6 @@ +export default { + name: 'Name', + connectionString: 'ConnectionString', + tenantManagement: 'TenantManagement', + tenantList: 'TenantList', +}; diff --git a/vben271/src/locales/lang/en/sys.ts b/vben271/src/locales/lang/en/sys.ts index 3b296007..c94920b2 100644 --- a/vben271/src/locales/lang/en/sys.ts +++ b/vben271/src/locales/lang/en/sys.ts @@ -70,7 +70,7 @@ export default { signInFormTitle: 'Sign in', signUpFormTitle: 'Sign up', forgetFormTitle: 'Reset password', - + tenantFormTitle: 'Tenant sign in', signInTitle: 'Backstage management system', signInDesc: 'Enter your personal details and get started!', policy: 'I agree to the xxx Privacy Policy', @@ -92,6 +92,7 @@ export default { smsPlaceholder: 'Please input sms code', mobilePlaceholder: 'Please input mobile', policyPlaceholder: 'Register after checking', + tenantPlaceholder: 'Please input tenant', diffPwd: 'The two passwords are inconsistent', userName: 'Username', @@ -100,5 +101,6 @@ export default { email: 'Email', smsCode: 'SMS code', mobile: 'Mobile', + tenant: 'Tenant', }, }; diff --git a/vben271/src/locales/lang/zh-CN/routes/tenant.ts b/vben271/src/locales/lang/zh-CN/routes/tenant.ts new file mode 100644 index 00000000..1f8b25ca --- /dev/null +++ b/vben271/src/locales/lang/zh-CN/routes/tenant.ts @@ -0,0 +1,6 @@ +export default { + name: '名称', + connectionString: '连接字符串', + tenantManagement: '租户管理', + tenantList: '租户列表', +}; diff --git a/vben271/src/locales/lang/zh-CN/sys.ts b/vben271/src/locales/lang/zh-CN/sys.ts index 8dad1cf4..05575b7f 100644 --- a/vben271/src/locales/lang/zh-CN/sys.ts +++ b/vben271/src/locales/lang/zh-CN/sys.ts @@ -64,7 +64,7 @@ export default { qrSignInFormTitle: '二维码登录', signUpFormTitle: '注册', forgetFormTitle: '重置密码', - + tenantFormTitle: '租户登录', signInTitle: '开箱即用的中后台管理系统', signInDesc: '输入您的个人详细信息开始使用!', policy: '我同意xxx隐私政策', @@ -86,6 +86,7 @@ export default { smsPlaceholder: '请输入验证码', mobilePlaceholder: '请输入手机号码', policyPlaceholder: '勾选后才能注册', + tenantPlaceholder: '请输入租户', diffPwd: '两次输入密码不一致', userName: '账号', @@ -94,5 +95,6 @@ export default { email: '邮箱', smsCode: '短信验证码', mobile: '手机号码', + tenant: '租户', }, }; diff --git a/vben271/src/router/routes/modules/admin.ts b/vben271/src/router/routes/modules/admin.ts index 4e2c67b2..fd26fd72 100644 --- a/vben271/src/router/routes/modules/admin.ts +++ b/vben271/src/router/routes/modules/admin.ts @@ -63,7 +63,7 @@ const admin: AppRouteModule = { component: () => import('/@/views/admin/elasticSearch/ElasticSearch.vue'), meta: { title: t('routes.admin.esLogs'), - policy: 'System.AuditLog', + policy: 'System.ES', icon: 'ant-design:snippets-twotone', }, }, diff --git a/vben271/src/router/routes/modules/tenant.ts b/vben271/src/router/routes/modules/tenant.ts new file mode 100644 index 00000000..e1494e1b --- /dev/null +++ b/vben271/src/router/routes/modules/tenant.ts @@ -0,0 +1,27 @@ +import type { AppRouteModule } from '/@/router/types'; +import { LAYOUT } from '/@/router/constant'; +import { t } from '/@/hooks/web/useI18n'; +const tenant: AppRouteModule = { + path: '/tenant', + name: 'Tenant', + component: LAYOUT, + meta: { + orderNo: 30, + icon: 'ion:grid-outline', + title: t('routes.tenant.tenantManagement'), + }, + children: [ + { + path: 'Tenant', + name: 'Tenant', + component: () => import('/@/views/tenants/Tenant.vue'), + meta: { + title: t('routes.tenant.tenantList'), + icon: 'ant-design:switcher-filled', + policy: 'AbpTenantManagement.Tenants', + }, + }, + ], +}; + +export default tenant; diff --git a/vben271/src/services/ServiceProxies.ts b/vben271/src/services/ServiceProxies.ts index 92e1c1d0..e88088bc 100644 --- a/vben271/src/services/ServiceProxies.ts +++ b/vben271/src/services/ServiceProxies.ts @@ -217,6 +217,758 @@ export class AbpApplicationConfigurationServiceProxy extends ServiceProxyBase { } } +export class TenantsServiceProxy extends ServiceProxyBase { + private instance: AxiosInstance; + private baseUrl: string; + protected jsonParseReviver: ((key: string, value: any) => any) | undefined = undefined; + + constructor(baseUrl?: string, instance?: AxiosInstance) { + super(); + this.instance = instance ? instance : axios.create(); + this.baseUrl = baseUrl !== undefined && baseUrl !== null ? baseUrl : ""; + } + + /** + * 通过名称获取租户信息 + * @param body (optional) + * @return Success + */ + find(body: FindTenantByNameInput | undefined , cancelToken?: CancelToken | undefined): Promise { + let url_ = this.baseUrl + "/Tenants/find"; + url_ = url_.replace(/[?&]$/, ""); + + const content_ = JSON.stringify(body); + + let options_ = { + data: content_, + method: "POST", + url: url_, + headers: { + "Content-Type": "application/json", + "Accept": "text/plain" + }, + cancelToken + }; + + return this.transformOptions(options_).then(transformedOptions_ => { + return this.instance.request(transformedOptions_); + }).catch((_error: any) => { + if (isAxiosError(_error) && _error.response) { + return _error.response; + } else { + throw _error; + } + }).then((_response: AxiosResponse) => { + return this.transformResult(url_, _response, (_response: AxiosResponse) => this.processFind(_response)); + }); + } + + protected processFind(response: AxiosResponse): Promise { + const status = response.status; + let _headers: any = {}; + if (response.headers && typeof response.headers === "object") { + for (let k in response.headers) { + if (response.headers.hasOwnProperty(k)) { + _headers[k] = response.headers[k]; + } + } + } + if (status === 200) { + const _responseText = response.data; + let result200: any = null; + let resultData200 = _responseText; + result200 = FindTenantResultDto.fromJS(resultData200); + return result200; + } else if (status === 403) { + const _responseText = response.data; + let result403: any = null; + let resultData403 = _responseText; + result403 = RemoteServiceErrorResponse.fromJS(resultData403); + return throwException("Forbidden", status, _responseText, _headers, result403); + } else if (status === 401) { + const _responseText = response.data; + let result401: any = null; + let resultData401 = _responseText; + result401 = RemoteServiceErrorResponse.fromJS(resultData401); + return throwException("Unauthorized", status, _responseText, _headers, result401); + } else if (status === 400) { + const _responseText = response.data; + let result400: any = null; + let resultData400 = _responseText; + result400 = RemoteServiceErrorResponse.fromJS(resultData400); + return throwException("Bad Request", status, _responseText, _headers, result400); + } else if (status === 404) { + const _responseText = response.data; + let result404: any = null; + let resultData404 = _responseText; + result404 = RemoteServiceErrorResponse.fromJS(resultData404); + return throwException("Not Found", status, _responseText, _headers, result404); + } else if (status === 501) { + const _responseText = response.data; + let result501: any = null; + let resultData501 = _responseText; + result501 = RemoteServiceErrorResponse.fromJS(resultData501); + return throwException("Server Error", status, _responseText, _headers, result501); + } else if (status === 500) { + const _responseText = response.data; + let result500: any = null; + let resultData500 = _responseText; + result500 = RemoteServiceErrorResponse.fromJS(resultData500); + return throwException("Server Error", status, _responseText, _headers, result500); + } else if (status !== 200 && status !== 204) { + const _responseText = response.data; + return throwException("An unexpected server error occurred.", status, _responseText, _headers); + } + return Promise.resolve(null); + } + + /** + * 分页获取租户信息 + * @param body (optional) + * @return Success + */ + page(body: PagingTenantInput | undefined , cancelToken?: CancelToken | undefined): Promise { + let url_ = this.baseUrl + "/Tenants/page"; + url_ = url_.replace(/[?&]$/, ""); + + const content_ = JSON.stringify(body); + + let options_ = { + data: content_, + method: "POST", + url: url_, + headers: { + "Content-Type": "application/json", + "Accept": "text/plain" + }, + cancelToken + }; + + return this.transformOptions(options_).then(transformedOptions_ => { + return this.instance.request(transformedOptions_); + }).catch((_error: any) => { + if (isAxiosError(_error) && _error.response) { + return _error.response; + } else { + throw _error; + } + }).then((_response: AxiosResponse) => { + return this.transformResult(url_, _response, (_response: AxiosResponse) => this.processPage(_response)); + }); + } + + protected processPage(response: AxiosResponse): Promise { + const status = response.status; + let _headers: any = {}; + if (response.headers && typeof response.headers === "object") { + for (let k in response.headers) { + if (response.headers.hasOwnProperty(k)) { + _headers[k] = response.headers[k]; + } + } + } + if (status === 200) { + const _responseText = response.data; + let result200: any = null; + let resultData200 = _responseText; + result200 = TenantDtoPagedResultDto.fromJS(resultData200); + return result200; + } else if (status === 403) { + const _responseText = response.data; + let result403: any = null; + let resultData403 = _responseText; + result403 = RemoteServiceErrorResponse.fromJS(resultData403); + return throwException("Forbidden", status, _responseText, _headers, result403); + } else if (status === 401) { + const _responseText = response.data; + let result401: any = null; + let resultData401 = _responseText; + result401 = RemoteServiceErrorResponse.fromJS(resultData401); + return throwException("Unauthorized", status, _responseText, _headers, result401); + } else if (status === 400) { + const _responseText = response.data; + let result400: any = null; + let resultData400 = _responseText; + result400 = RemoteServiceErrorResponse.fromJS(resultData400); + return throwException("Bad Request", status, _responseText, _headers, result400); + } else if (status === 404) { + const _responseText = response.data; + let result404: any = null; + let resultData404 = _responseText; + result404 = RemoteServiceErrorResponse.fromJS(resultData404); + return throwException("Not Found", status, _responseText, _headers, result404); + } else if (status === 501) { + const _responseText = response.data; + let result501: any = null; + let resultData501 = _responseText; + result501 = RemoteServiceErrorResponse.fromJS(resultData501); + return throwException("Server Error", status, _responseText, _headers, result501); + } else if (status === 500) { + const _responseText = response.data; + let result500: any = null; + let resultData500 = _responseText; + result500 = RemoteServiceErrorResponse.fromJS(resultData500); + return throwException("Server Error", status, _responseText, _headers, result500); + } else if (status !== 200 && status !== 204) { + const _responseText = response.data; + return throwException("An unexpected server error occurred.", status, _responseText, _headers); + } + return Promise.resolve(null); + } + + /** + * 创建租户 + * @param body (optional) + * @return Success + */ + create(body: TenantCreateDto | undefined , cancelToken?: CancelToken | undefined): Promise { + let url_ = this.baseUrl + "/Tenants/create"; + url_ = url_.replace(/[?&]$/, ""); + + const content_ = JSON.stringify(body); + + let options_ = { + data: content_, + method: "POST", + url: url_, + headers: { + "Content-Type": "application/json", + "Accept": "text/plain" + }, + cancelToken + }; + + return this.transformOptions(options_).then(transformedOptions_ => { + return this.instance.request(transformedOptions_); + }).catch((_error: any) => { + if (isAxiosError(_error) && _error.response) { + return _error.response; + } else { + throw _error; + } + }).then((_response: AxiosResponse) => { + return this.transformResult(url_, _response, (_response: AxiosResponse) => this.processCreate(_response)); + }); + } + + protected processCreate(response: AxiosResponse): Promise { + const status = response.status; + let _headers: any = {}; + if (response.headers && typeof response.headers === "object") { + for (let k in response.headers) { + if (response.headers.hasOwnProperty(k)) { + _headers[k] = response.headers[k]; + } + } + } + if (status === 200) { + const _responseText = response.data; + let result200: any = null; + let resultData200 = _responseText; + result200 = TenantDto.fromJS(resultData200); + return result200; + } else if (status === 403) { + const _responseText = response.data; + let result403: any = null; + let resultData403 = _responseText; + result403 = RemoteServiceErrorResponse.fromJS(resultData403); + return throwException("Forbidden", status, _responseText, _headers, result403); + } else if (status === 401) { + const _responseText = response.data; + let result401: any = null; + let resultData401 = _responseText; + result401 = RemoteServiceErrorResponse.fromJS(resultData401); + return throwException("Unauthorized", status, _responseText, _headers, result401); + } else if (status === 400) { + const _responseText = response.data; + let result400: any = null; + let resultData400 = _responseText; + result400 = RemoteServiceErrorResponse.fromJS(resultData400); + return throwException("Bad Request", status, _responseText, _headers, result400); + } else if (status === 404) { + const _responseText = response.data; + let result404: any = null; + let resultData404 = _responseText; + result404 = RemoteServiceErrorResponse.fromJS(resultData404); + return throwException("Not Found", status, _responseText, _headers, result404); + } else if (status === 501) { + const _responseText = response.data; + let result501: any = null; + let resultData501 = _responseText; + result501 = RemoteServiceErrorResponse.fromJS(resultData501); + return throwException("Server Error", status, _responseText, _headers, result501); + } else if (status === 500) { + const _responseText = response.data; + let result500: any = null; + let resultData500 = _responseText; + result500 = RemoteServiceErrorResponse.fromJS(resultData500); + return throwException("Server Error", status, _responseText, _headers, result500); + } else if (status !== 200 && status !== 204) { + const _responseText = response.data; + return throwException("An unexpected server error occurred.", status, _responseText, _headers); + } + return Promise.resolve(null); + } + + /** + * 更新租户 + * @param body (optional) + * @return Success + */ + update(body: UpdateTenantInput | undefined , cancelToken?: CancelToken | undefined): Promise { + let url_ = this.baseUrl + "/Tenants/update"; + url_ = url_.replace(/[?&]$/, ""); + + const content_ = JSON.stringify(body); + + let options_ = { + data: content_, + method: "POST", + url: url_, + headers: { + "Content-Type": "application/json", + "Accept": "text/plain" + }, + cancelToken + }; + + return this.transformOptions(options_).then(transformedOptions_ => { + return this.instance.request(transformedOptions_); + }).catch((_error: any) => { + if (isAxiosError(_error) && _error.response) { + return _error.response; + } else { + throw _error; + } + }).then((_response: AxiosResponse) => { + return this.transformResult(url_, _response, (_response: AxiosResponse) => this.processUpdate(_response)); + }); + } + + protected processUpdate(response: AxiosResponse): Promise { + const status = response.status; + let _headers: any = {}; + if (response.headers && typeof response.headers === "object") { + for (let k in response.headers) { + if (response.headers.hasOwnProperty(k)) { + _headers[k] = response.headers[k]; + } + } + } + if (status === 200) { + const _responseText = response.data; + let result200: any = null; + let resultData200 = _responseText; + result200 = TenantDto.fromJS(resultData200); + return result200; + } else if (status === 403) { + const _responseText = response.data; + let result403: any = null; + let resultData403 = _responseText; + result403 = RemoteServiceErrorResponse.fromJS(resultData403); + return throwException("Forbidden", status, _responseText, _headers, result403); + } else if (status === 401) { + const _responseText = response.data; + let result401: any = null; + let resultData401 = _responseText; + result401 = RemoteServiceErrorResponse.fromJS(resultData401); + return throwException("Unauthorized", status, _responseText, _headers, result401); + } else if (status === 400) { + const _responseText = response.data; + let result400: any = null; + let resultData400 = _responseText; + result400 = RemoteServiceErrorResponse.fromJS(resultData400); + return throwException("Bad Request", status, _responseText, _headers, result400); + } else if (status === 404) { + const _responseText = response.data; + let result404: any = null; + let resultData404 = _responseText; + result404 = RemoteServiceErrorResponse.fromJS(resultData404); + return throwException("Not Found", status, _responseText, _headers, result404); + } else if (status === 501) { + const _responseText = response.data; + let result501: any = null; + let resultData501 = _responseText; + result501 = RemoteServiceErrorResponse.fromJS(resultData501); + return throwException("Server Error", status, _responseText, _headers, result501); + } else if (status === 500) { + const _responseText = response.data; + let result500: any = null; + let resultData500 = _responseText; + result500 = RemoteServiceErrorResponse.fromJS(resultData500); + return throwException("Server Error", status, _responseText, _headers, result500); + } else if (status !== 200 && status !== 204) { + const _responseText = response.data; + return throwException("An unexpected server error occurred.", status, _responseText, _headers); + } + return Promise.resolve(null); + } + + /** + * 删除租户 + * @param body (optional) + * @return Success + */ + delete(body: IdInput | undefined , cancelToken?: CancelToken | undefined): Promise { + let url_ = this.baseUrl + "/Tenants/delete"; + url_ = url_.replace(/[?&]$/, ""); + + const content_ = JSON.stringify(body); + + let options_ = { + data: content_, + method: "POST", + url: url_, + headers: { + "Content-Type": "application/json", + }, + cancelToken + }; + + return this.transformOptions(options_).then(transformedOptions_ => { + return this.instance.request(transformedOptions_); + }).catch((_error: any) => { + if (isAxiosError(_error) && _error.response) { + return _error.response; + } else { + throw _error; + } + }).then((_response: AxiosResponse) => { + return this.transformResult(url_, _response, (_response: AxiosResponse) => this.processDelete(_response)); + }); + } + + protected processDelete(response: AxiosResponse): Promise { + const status = response.status; + let _headers: any = {}; + if (response.headers && typeof response.headers === "object") { + for (let k in response.headers) { + if (response.headers.hasOwnProperty(k)) { + _headers[k] = response.headers[k]; + } + } + } + if (status === 200) { + const _responseText = response.data; + return Promise.resolve(null); + } else if (status === 403) { + const _responseText = response.data; + let result403: any = null; + let resultData403 = _responseText; + result403 = RemoteServiceErrorResponse.fromJS(resultData403); + return throwException("Forbidden", status, _responseText, _headers, result403); + } else if (status === 401) { + const _responseText = response.data; + let result401: any = null; + let resultData401 = _responseText; + result401 = RemoteServiceErrorResponse.fromJS(resultData401); + return throwException("Unauthorized", status, _responseText, _headers, result401); + } else if (status === 400) { + const _responseText = response.data; + let result400: any = null; + let resultData400 = _responseText; + result400 = RemoteServiceErrorResponse.fromJS(resultData400); + return throwException("Bad Request", status, _responseText, _headers, result400); + } else if (status === 404) { + const _responseText = response.data; + let result404: any = null; + let resultData404 = _responseText; + result404 = RemoteServiceErrorResponse.fromJS(resultData404); + return throwException("Not Found", status, _responseText, _headers, result404); + } else if (status === 501) { + const _responseText = response.data; + let result501: any = null; + let resultData501 = _responseText; + result501 = RemoteServiceErrorResponse.fromJS(resultData501); + return throwException("Server Error", status, _responseText, _headers, result501); + } else if (status === 500) { + const _responseText = response.data; + let result500: any = null; + let resultData500 = _responseText; + result500 = RemoteServiceErrorResponse.fromJS(resultData500); + return throwException("Server Error", status, _responseText, _headers, result500); + } else if (status !== 200 && status !== 204) { + const _responseText = response.data; + return throwException("An unexpected server error occurred.", status, _responseText, _headers); + } + return Promise.resolve(null); + } + + /** + * 获取租户连接字符串 + * @param body (optional) + * @return Success + */ + getConnectionString(body: IdInput | undefined , cancelToken?: CancelToken | undefined): Promise { + let url_ = this.baseUrl + "/Tenants/getConnectionString"; + url_ = url_.replace(/[?&]$/, ""); + + const content_ = JSON.stringify(body); + + let options_ = { + data: content_, + method: "POST", + url: url_, + headers: { + "Content-Type": "application/json", + "Accept": "text/plain" + }, + cancelToken + }; + + return this.transformOptions(options_).then(transformedOptions_ => { + return this.instance.request(transformedOptions_); + }).catch((_error: any) => { + if (isAxiosError(_error) && _error.response) { + return _error.response; + } else { + throw _error; + } + }).then((_response: AxiosResponse) => { + return this.transformResult(url_, _response, (_response: AxiosResponse) => this.processGetConnectionString(_response)); + }); + } + + protected processGetConnectionString(response: AxiosResponse): Promise { + const status = response.status; + let _headers: any = {}; + if (response.headers && typeof response.headers === "object") { + for (let k in response.headers) { + if (response.headers.hasOwnProperty(k)) { + _headers[k] = response.headers[k]; + } + } + } + if (status === 200) { + const _responseText = response.data; + let result200: any = null; + let resultData200 = _responseText; + result200 = resultData200 !== undefined ? resultData200 : null; + return result200; + } else if (status === 403) { + const _responseText = response.data; + let result403: any = null; + let resultData403 = _responseText; + result403 = RemoteServiceErrorResponse.fromJS(resultData403); + return throwException("Forbidden", status, _responseText, _headers, result403); + } else if (status === 401) { + const _responseText = response.data; + let result401: any = null; + let resultData401 = _responseText; + result401 = RemoteServiceErrorResponse.fromJS(resultData401); + return throwException("Unauthorized", status, _responseText, _headers, result401); + } else if (status === 400) { + const _responseText = response.data; + let result400: any = null; + let resultData400 = _responseText; + result400 = RemoteServiceErrorResponse.fromJS(resultData400); + return throwException("Bad Request", status, _responseText, _headers, result400); + } else if (status === 404) { + const _responseText = response.data; + let result404: any = null; + let resultData404 = _responseText; + result404 = RemoteServiceErrorResponse.fromJS(resultData404); + return throwException("Not Found", status, _responseText, _headers, result404); + } else if (status === 501) { + const _responseText = response.data; + let result501: any = null; + let resultData501 = _responseText; + result501 = RemoteServiceErrorResponse.fromJS(resultData501); + return throwException("Server Error", status, _responseText, _headers, result501); + } else if (status === 500) { + const _responseText = response.data; + let result500: any = null; + let resultData500 = _responseText; + result500 = RemoteServiceErrorResponse.fromJS(resultData500); + return throwException("Server Error", status, _responseText, _headers, result500); + } else if (status !== 200 && status !== 204) { + const _responseText = response.data; + return throwException("An unexpected server error occurred.", status, _responseText, _headers); + } + return Promise.resolve(null); + } + + /** + * 更新租户连接字符串 + * @param body (optional) + * @return Success + */ + updateConnectionString(body: UpdateConnectionStringInput | undefined , cancelToken?: CancelToken | undefined): Promise { + let url_ = this.baseUrl + "/Tenants/updateConnectionString"; + url_ = url_.replace(/[?&]$/, ""); + + const content_ = JSON.stringify(body); + + let options_ = { + data: content_, + method: "POST", + url: url_, + headers: { + "Content-Type": "application/json", + }, + cancelToken + }; + + return this.transformOptions(options_).then(transformedOptions_ => { + return this.instance.request(transformedOptions_); + }).catch((_error: any) => { + if (isAxiosError(_error) && _error.response) { + return _error.response; + } else { + throw _error; + } + }).then((_response: AxiosResponse) => { + return this.transformResult(url_, _response, (_response: AxiosResponse) => this.processUpdateConnectionString(_response)); + }); + } + + protected processUpdateConnectionString(response: AxiosResponse): Promise { + const status = response.status; + let _headers: any = {}; + if (response.headers && typeof response.headers === "object") { + for (let k in response.headers) { + if (response.headers.hasOwnProperty(k)) { + _headers[k] = response.headers[k]; + } + } + } + if (status === 200) { + const _responseText = response.data; + return Promise.resolve(null); + } else if (status === 403) { + const _responseText = response.data; + let result403: any = null; + let resultData403 = _responseText; + result403 = RemoteServiceErrorResponse.fromJS(resultData403); + return throwException("Forbidden", status, _responseText, _headers, result403); + } else if (status === 401) { + const _responseText = response.data; + let result401: any = null; + let resultData401 = _responseText; + result401 = RemoteServiceErrorResponse.fromJS(resultData401); + return throwException("Unauthorized", status, _responseText, _headers, result401); + } else if (status === 400) { + const _responseText = response.data; + let result400: any = null; + let resultData400 = _responseText; + result400 = RemoteServiceErrorResponse.fromJS(resultData400); + return throwException("Bad Request", status, _responseText, _headers, result400); + } else if (status === 404) { + const _responseText = response.data; + let result404: any = null; + let resultData404 = _responseText; + result404 = RemoteServiceErrorResponse.fromJS(resultData404); + return throwException("Not Found", status, _responseText, _headers, result404); + } else if (status === 501) { + const _responseText = response.data; + let result501: any = null; + let resultData501 = _responseText; + result501 = RemoteServiceErrorResponse.fromJS(resultData501); + return throwException("Server Error", status, _responseText, _headers, result501); + } else if (status === 500) { + const _responseText = response.data; + let result500: any = null; + let resultData500 = _responseText; + result500 = RemoteServiceErrorResponse.fromJS(resultData500); + return throwException("Server Error", status, _responseText, _headers, result500); + } else if (status !== 200 && status !== 204) { + const _responseText = response.data; + return throwException("An unexpected server error occurred.", status, _responseText, _headers); + } + return Promise.resolve(null); + } + + /** + * 删除租户连接字符串 + * @param body (optional) + * @return Success + */ + deleteConnectionString(body: IdInput | undefined , cancelToken?: CancelToken | undefined): Promise { + let url_ = this.baseUrl + "/Tenants/deleteConnectionString"; + url_ = url_.replace(/[?&]$/, ""); + + const content_ = JSON.stringify(body); + + let options_ = { + data: content_, + method: "POST", + url: url_, + headers: { + "Content-Type": "application/json", + }, + cancelToken + }; + + return this.transformOptions(options_).then(transformedOptions_ => { + return this.instance.request(transformedOptions_); + }).catch((_error: any) => { + if (isAxiosError(_error) && _error.response) { + return _error.response; + } else { + throw _error; + } + }).then((_response: AxiosResponse) => { + return this.transformResult(url_, _response, (_response: AxiosResponse) => this.processDeleteConnectionString(_response)); + }); + } + + protected processDeleteConnectionString(response: AxiosResponse): Promise { + const status = response.status; + let _headers: any = {}; + if (response.headers && typeof response.headers === "object") { + for (let k in response.headers) { + if (response.headers.hasOwnProperty(k)) { + _headers[k] = response.headers[k]; + } + } + } + if (status === 200) { + const _responseText = response.data; + return Promise.resolve(null); + } else if (status === 403) { + const _responseText = response.data; + let result403: any = null; + let resultData403 = _responseText; + result403 = RemoteServiceErrorResponse.fromJS(resultData403); + return throwException("Forbidden", status, _responseText, _headers, result403); + } else if (status === 401) { + const _responseText = response.data; + let result401: any = null; + let resultData401 = _responseText; + result401 = RemoteServiceErrorResponse.fromJS(resultData401); + return throwException("Unauthorized", status, _responseText, _headers, result401); + } else if (status === 400) { + const _responseText = response.data; + let result400: any = null; + let resultData400 = _responseText; + result400 = RemoteServiceErrorResponse.fromJS(resultData400); + return throwException("Bad Request", status, _responseText, _headers, result400); + } else if (status === 404) { + const _responseText = response.data; + let result404: any = null; + let resultData404 = _responseText; + result404 = RemoteServiceErrorResponse.fromJS(resultData404); + return throwException("Not Found", status, _responseText, _headers, result404); + } else if (status === 501) { + const _responseText = response.data; + let result501: any = null; + let resultData501 = _responseText; + result501 = RemoteServiceErrorResponse.fromJS(resultData501); + return throwException("Server Error", status, _responseText, _headers, result501); + } else if (status === 500) { + const _responseText = response.data; + let result500: any = null; + let resultData500 = _responseText; + result500 = RemoteServiceErrorResponse.fromJS(resultData500); + return throwException("Server Error", status, _responseText, _headers, result500); + } else if (status !== 200 && status !== 204) { + const _responseText = response.data; + return throwException("An unexpected server error occurred.", status, _responseText, _headers); + } + return Promise.resolve(null); + } +} + export class AccountServiceProxy extends ServiceProxyBase { private instance: AxiosInstance; private baseUrl: string; @@ -8535,6 +9287,42 @@ export interface IFeatureProviderDto { key: string | undefined; } +export class FindTenantByNameInput implements IFindTenantByNameInput { + name!: string | undefined; + + constructor(data?: IFindTenantByNameInput) { + if (data) { + for (var property in data) { + if (data.hasOwnProperty(property)) + (this)[property] = (data)[property]; + } + } + } + + init(_data?: any) { + if (_data) { + this.name = _data["name"]; + } + } + + static fromJS(data: any): FindTenantByNameInput { + data = typeof data === 'object' ? data : {}; + let result = new FindTenantByNameInput(); + result.init(data); + return result; + } + + toJSON(data?: any) { + data = typeof data === 'object' ? data : {}; + data["name"] = this.name; + return data; + } +} + +export interface IFindTenantByNameInput { + name: string | undefined; +} + export class FindTenantResultDto implements IFindTenantResultDto { success!: boolean; tenantId!: string | undefined; @@ -11859,6 +12647,54 @@ export interface IPagingRoleListInput { filter: string | undefined; } +export class PagingTenantInput implements IPagingTenantInput { + pageIndex!: number; + pageSize!: number; + readonly skipCount!: number; + filter!: string | undefined; + + constructor(data?: IPagingTenantInput) { + if (data) { + for (var property in data) { + if (data.hasOwnProperty(property)) + (this)[property] = (data)[property]; + } + } + } + + init(_data?: any) { + if (_data) { + this.pageIndex = _data["pageIndex"]; + this.pageSize = _data["pageSize"]; + (this).skipCount = _data["skipCount"]; + this.filter = _data["filter"]; + } + } + + static fromJS(data: any): PagingTenantInput { + data = typeof data === 'object' ? data : {}; + let result = new PagingTenantInput(); + result.init(data); + return result; + } + + toJSON(data?: any) { + data = typeof data === 'object' ? data : {}; + data["pageIndex"] = this.pageIndex; + data["pageSize"] = this.pageSize; + data["skipCount"] = this.skipCount; + data["filter"] = this.filter; + return data; + } +} + +export interface IPagingTenantInput { + pageIndex: number; + pageSize: number; + skipCount: number; + filter: string | undefined; +} + export class PagingUserListInput implements IPagingUserListInput { pageIndex!: number; pageSize!: number; @@ -13731,6 +14567,46 @@ export interface IUpdateApiResourceInput { apiScopes: string[] | undefined; } +export class UpdateConnectionStringInput implements IUpdateConnectionStringInput { + id!: string; + connectionString!: string; + + constructor(data?: IUpdateConnectionStringInput) { + if (data) { + for (var property in data) { + if (data.hasOwnProperty(property)) + (this)[property] = (data)[property]; + } + } + } + + init(_data?: any) { + if (_data) { + this.id = _data["id"]; + this.connectionString = _data["connectionString"]; + } + } + + static fromJS(data: any): UpdateConnectionStringInput { + data = typeof data === 'object' ? data : {}; + let result = new UpdateConnectionStringInput(); + result.init(data); + return result; + } + + toJSON(data?: any) { + data = typeof data === 'object' ? data : {}; + data["id"] = this.id; + data["connectionString"] = this.connectionString; + return data; + } +} + +export interface IUpdateConnectionStringInput { + id: string; + connectionString: string; +} + export class UpdateCreateApiScopeInput implements IUpdateCreateApiScopeInput { enabled!: boolean; name!: string | undefined; @@ -14335,6 +15211,46 @@ export interface IUpdateSettingInput { values: { [key: string]: string; } | undefined; } +export class UpdateTenantInput implements IUpdateTenantInput { + id!: string; + name!: string; + + constructor(data?: IUpdateTenantInput) { + if (data) { + for (var property in data) { + if (data.hasOwnProperty(property)) + (this)[property] = (data)[property]; + } + } + } + + init(_data?: any) { + if (_data) { + this.id = _data["id"]; + this.name = _data["name"]; + } + } + + static fromJS(data: any): UpdateTenantInput { + data = typeof data === 'object' ? data : {}; + let result = new UpdateTenantInput(); + result.init(data); + return result; + } + + toJSON(data?: any) { + data = typeof data === 'object' ? data : {}; + data["id"] = this.id; + data["name"] = this.name; + return data; + } +} + +export interface IUpdateTenantInput { + id: string; + name: string; +} + export class UpdateUserInput implements IUpdateUserInput { userId!: string; userInfo!: IdentityUserUpdateDto; diff --git a/vben271/src/services/ServiceProxyBase.ts b/vben271/src/services/ServiceProxyBase.ts index bdb872bd..4127745e 100644 --- a/vben271/src/services/ServiceProxyBase.ts +++ b/vben271/src/services/ServiceProxyBase.ts @@ -10,9 +10,9 @@ export class ServiceProxyBase { protected transformOptions(options: AxiosRequestConfig) { options.baseURL = import.meta.env.VITE_API_URL as string; const guard: boolean = this.urlGuard(options.url as string); + const userStore = useUserStoreWithOut(); - if (!guard) { - const userStore = useUserStoreWithOut(); + if (guard) { if (userStore.checkUserLoginExpire) { router.replace(PageEnum.BASE_LOGIN); return; @@ -23,6 +23,12 @@ export class ServiceProxyBase { 'accept-language': language, 'Content-Type': 'application/json', Authorization: 'Bearer ' + token, + __tenant: userStore.tenantId, + }; + } else { + options.headers = { + 'Content-Type': 'application/json', + __tenant: userStore.tenantId, }; } @@ -55,8 +61,8 @@ export class ServiceProxyBase { //判决接口是否需要拦截 private urlGuard(url: string): boolean { - // 登录接口不需要拦截 - return (url.indexOf('login') as number) > 0; + let arr = ['/api/app/account/login', '/Tenants/find']; + return !arr.includes(url); } private buildRequestMessage(): any { diff --git a/vben271/src/store/modules/user.ts b/vben271/src/store/modules/user.ts index 6def5298..e56c4bf6 100644 --- a/vben271/src/store/modules/user.ts +++ b/vben271/src/store/modules/user.ts @@ -4,7 +4,13 @@ import { defineStore } from 'pinia'; import { store } from '/@/store'; import { RoleEnum } from '/@/enums/roleEnum'; import { PageEnum } from '/@/enums/pageEnum'; -import { ROLES_KEY, TOKEN_KEY, USER_INFO_KEY, ABP_LOCALE_KEY } from '/@/enums/cacheEnum'; +import { + ROLES_KEY, + TOKEN_KEY, + USER_INFO_KEY, + ABP_LOCALE_KEY, + ABP_TETANT_KEY, +} from '/@/enums/cacheEnum'; import { getAuthCache, setAuthCache } from '/@/utils/auth'; import { GetUserInfoByUserIdModel, LoginParams } from '/@/api/sys/model/userModel'; import { @@ -30,6 +36,7 @@ interface UserState { sessionTimeout?: boolean; lastUpdateTime: number; language: string; + tenantId: string; } export const useUserStore = defineStore({ @@ -46,6 +53,7 @@ export const useUserStore = defineStore({ // Last fetch time lastUpdateTime: 0, language: '', + tenantId: '', }), getters: { getUserInfo(): UserInfo { @@ -66,6 +74,9 @@ export const useUserStore = defineStore({ getLanguage(): string { return this.language || getAuthCache(ABP_LOCALE_KEY); }, + getTenant(): string { + return this.tenantId || getAuthCache(ABP_TETANT_KEY); + }, checkUserLoginExpire(): boolean { try { const userStore = useUserStoreWithOut(); @@ -98,6 +109,10 @@ export const useUserStore = defineStore({ this.lastUpdateTime = new Date().getTime(); setAuthCache(USER_INFO_KEY, info); }, + setTenant(tenantId: string) { + this.tenantId = tenantId; + setAuthCache(ABP_TETANT_KEY, tenantId); + }, setSessionTimeout(flag: boolean) { this.sessionTimeout = flag; }, diff --git a/vben271/src/utils/cache/persistent.ts b/vben271/src/utils/cache/persistent.ts index e02e9a30..cbfc6ffb 100644 --- a/vben271/src/utils/cache/persistent.ts +++ b/vben271/src/utils/cache/persistent.ts @@ -15,6 +15,7 @@ import { MULTIPLE_TABS_KEY, AUHT_KEY, ABP_LOCALE_KEY, + ABP_TETANT_KEY, } from '/@/enums/cacheEnum'; import { DEFAULT_CACHE_TIME } from '/@/settings/encryptionSetting'; import { toRaw } from 'vue'; @@ -29,6 +30,7 @@ interface BasicStore { [MULTIPLE_TABS_KEY]: RouteLocationNormalized[]; [AUHT_KEY]: ApplicationAuthConfigurationDto; [ABP_LOCALE_KEY]: string; + [ABP_TETANT_KEY]: string; } type LocalStore = BasicStore; diff --git a/vben271/src/views/identityServers/apiScopes/EditApiScope.vue b/vben271/src/views/identityServers/apiScopes/EditApiScope.vue index 097b9257..fb99b8c3 100644 --- a/vben271/src/views/identityServers/apiScopes/EditApiScope.vue +++ b/vben271/src/views/identityServers/apiScopes/EditApiScope.vue @@ -52,7 +52,7 @@ await editApiScopeAsync({ request, changeOkLoading, validate, closeModal }); resetFields(); emit('reload'); - } catch (error) { + } finally { changeOkLoading(false); } }; diff --git a/vben271/src/views/sys/login/Login.vue b/vben271/src/views/sys/login/Login.vue index 8c3bd4bb..d6073dda 100644 --- a/vben271/src/views/sys/login/Login.vue +++ b/vben271/src/views/sys/login/Login.vue @@ -55,6 +55,7 @@ + @@ -70,6 +71,7 @@ import RegisterForm from './RegisterForm.vue'; import MobileForm from './MobileForm.vue'; import QrCodeForm from './QrCodeForm.vue'; + import TenantLoginForm from './TenantLoginForm.vue'; import { useGlobSetting } from '/@/hooks/setting'; import { useI18n } from '/@/hooks/web/useI18n'; import { useDesign } from '/@/hooks/web/useDesign'; diff --git a/vben271/src/views/sys/login/LoginForm.vue b/vben271/src/views/sys/login/LoginForm.vue index 582cecf4..debcefcd 100644 --- a/vben271/src/views/sys/login/LoginForm.vue +++ b/vben271/src/views/sys/login/LoginForm.vue @@ -33,7 +33,13 @@ {{ t('sys.login.registerButton') }} --> - + + + + + {{ t('sys.login.otherSignIn') }}
@@ -58,13 +64,7 @@ import { useMessage } from '/@/hooks/web/useMessage'; import { useUserStore } from '/@/store/modules/user'; - import { - LoginStateEnum, - useLoginState, - useFormRules, - useFormValid, - useOidcLogin, - } from './useLogin'; + import { LoginStateEnum, useLoginState, useFormRules, useFormValid } from './useLogin'; import { useDesign } from '/@/hooks/web/useDesign'; //import { onKeyStroke } from '@vueuse/core'; @@ -104,6 +104,7 @@ toRaw({ password: data.password, username: data.account, + tenantId: '', mode: 'none', //不要默认的错误提示 }) ); diff --git a/vben271/src/views/sys/login/LoginFormTitle.vue b/vben271/src/views/sys/login/LoginFormTitle.vue index a673636e..3a70c84b 100644 --- a/vben271/src/views/sys/login/LoginFormTitle.vue +++ b/vben271/src/views/sys/login/LoginFormTitle.vue @@ -19,6 +19,7 @@ [LoginStateEnum.REGISTER]: t('sys.login.signUpFormTitle'), [LoginStateEnum.MOBILE]: t('sys.login.mobileSignInFormTitle'), [LoginStateEnum.QR_CODE]: t('sys.login.qrSignInFormTitle'), + [LoginStateEnum.TENANT]: t('sys.login.tenantFormTitle'), }; return titleObj[unref(getLoginState)]; }); diff --git a/vben271/src/views/sys/login/MobileForm.vue b/vben271/src/views/sys/login/MobileForm.vue index 88b9f82e..27325bae 100644 --- a/vben271/src/views/sys/login/MobileForm.vue +++ b/vben271/src/views/sys/login/MobileForm.vue @@ -2,6 +2,14 @@ + diff --git a/vben271/src/views/sys/login/useLogin.ts b/vben271/src/views/sys/login/useLogin.ts index 89729630..951e8c72 100644 --- a/vben271/src/views/sys/login/useLogin.ts +++ b/vben271/src/views/sys/login/useLogin.ts @@ -9,6 +9,7 @@ export enum LoginStateEnum { RESET_PASSWORD, MOBILE, QR_CODE, + TENANT, } const currentState = ref(LoginStateEnum.LOGIN); @@ -45,7 +46,7 @@ export function useFormRules(formData?: Recordable) { const getPasswordFormRule = computed(() => createRule(t('sys.login.passwordPlaceholder'))); const getSmsFormRule = computed(() => createRule(t('sys.login.smsPlaceholder'))); const getMobileFormRule = computed(() => createRule(t('sys.login.mobilePlaceholder'))); - + const getTenantFormRule = computed(() => createRule(t('sys.login.tenantPlaceholder'))); const validatePolicy = async (_: RuleObject, value: boolean) => { return !value ? Promise.reject(t('sys.login.policyPlaceholder')) : Promise.resolve(); }; @@ -67,11 +68,13 @@ export function useFormRules(formData?: Recordable) { const passwordFormRule = unref(getPasswordFormRule); const smsFormRule = unref(getSmsFormRule); const mobileFormRule = unref(getMobileFormRule); + const tenantFormRule = unref(getTenantFormRule); const mobileRule = { sms: smsFormRule, mobile: mobileFormRule, }; + switch (unref(currentState)) { // register form rules case LoginStateEnum.REGISTER: @@ -95,7 +98,12 @@ export function useFormRules(formData?: Recordable) { // mobile form rules case LoginStateEnum.MOBILE: return mobileRule; - + case LoginStateEnum.TENANT: + return { + account: accountFormRule, + password: passwordFormRule, + tenant: tenantFormRule, + }; // login form rules default: return { diff --git a/vben271/src/views/tenants/CreateTenant.vue b/vben271/src/views/tenants/CreateTenant.vue new file mode 100644 index 00000000..4fb8c740 --- /dev/null +++ b/vben271/src/views/tenants/CreateTenant.vue @@ -0,0 +1,63 @@ + + + + + diff --git a/vben271/src/views/tenants/EditConnectionString.vue b/vben271/src/views/tenants/EditConnectionString.vue new file mode 100644 index 00000000..5446f3fc --- /dev/null +++ b/vben271/src/views/tenants/EditConnectionString.vue @@ -0,0 +1,75 @@ + + + + + diff --git a/vben271/src/views/tenants/EditTenant.vue b/vben271/src/views/tenants/EditTenant.vue new file mode 100644 index 00000000..f2cb7030 --- /dev/null +++ b/vben271/src/views/tenants/EditTenant.vue @@ -0,0 +1,69 @@ + + + + + diff --git a/vben271/src/views/tenants/Tenant.ts b/vben271/src/views/tenants/Tenant.ts new file mode 100644 index 00000000..23783421 --- /dev/null +++ b/vben271/src/views/tenants/Tenant.ts @@ -0,0 +1,125 @@ +import _ from 'lodash'; +import { FormSchema } from '/@/components/Table'; +import { BasicColumn } from '/@/components/Table'; +import { useI18n } from '/@/hooks/web/useI18n'; +const { t } = useI18n(); +import { TenantsServiceProxy, PagingTenantInput, IdInput } from '/@/services/ServiceProxies'; +export const searchFormSchema: FormSchema[] = [ + { + field: 'filter', + component: 'Input', + label: t('common.key'), + labelWidth: 80, + colProps: { + span: 6, + }, + }, +]; +export const tableColumns: BasicColumn[] = [ + { + title: t('routes.tenant.name'), + dataIndex: 'name', + }, +]; + +export const createFormSchema: FormSchema[] = [ + { + field: 'name', + label: 'Name', + component: 'Input', + required: true, + labelWidth: 150, + colProps: { span: 20 }, + }, + { + field: 'adminEmailAddress', + label: 'AdminEmailAddress', + component: 'Input', + required: true, + labelWidth: 150, + colProps: { span: 20 }, + }, + { + field: 'adminPassword', + label: 'AdminPassword', + component: 'InputPassword', + required: true, + labelWidth: 150, + colProps: { span: 20 }, + }, +]; +export const editFormSchema: FormSchema[] = [ + { + field: 'id', + label: 'Id', + component: 'Input', + required: true, + labelWidth: 150, + show: false, + colProps: { span: 20 }, + }, + { + field: 'name', + label: 'Name', + component: 'Input', + required: true, + labelWidth: 150, + colProps: { span: 20 }, + }, +]; +export const updateConnectionStringFormSchema: FormSchema[] = [ + { + field: 'id', + label: 'Id', + component: 'Input', + required: true, + labelWidth: 150, + show: false, + colProps: { span: 20 }, + }, + { + field: 'connectionString', + label: 'ConnectionString', + component: 'Input', + labelWidth: 150, + colProps: { span: 20 }, + }, +]; +export async function getTenantListAsync(request: PagingTenantInput) { + const _tenantsServiceProxy = new TenantsServiceProxy(); + return await _tenantsServiceProxy.page(request); +} +export async function createTenantAsync({ request, changeOkLoading, validate, closeModal }) { + changeOkLoading(true); + await validate(); + const _tenantsServiceProxy = new TenantsServiceProxy(); + await _tenantsServiceProxy.create(request); + changeOkLoading(false); + closeModal(); +} + +export async function updateTenantAsync({ request, changeOkLoading, validate, closeModal }) { + changeOkLoading(true); + await validate(); + const _tenantsServiceProxy = new TenantsServiceProxy(); + await _tenantsServiceProxy.update(request); + changeOkLoading(false); + closeModal(); +} + +export async function deleteTenantAsync({ id }) { + const _tenantsServiceProxy = new TenantsServiceProxy(); + let request = new IdInput(); + request.id = id; + await _tenantsServiceProxy.delete(request); +} +export async function getConnectionStringAsync({ id }) { + const _tenantsServiceProxy = new TenantsServiceProxy(); + let request = new IdInput(); + request.id = id; + return await _tenantsServiceProxy.getConnectionString(request); +} +export async function updateConnectionStringAsync({ request }) { + const _tenantsServiceProxy = new TenantsServiceProxy(); + return await _tenantsServiceProxy.updateConnectionString(request); +} diff --git a/vben271/src/views/tenants/Tenant.vue b/vben271/src/views/tenants/Tenant.vue new file mode 100644 index 00000000..51b57518 --- /dev/null +++ b/vben271/src/views/tenants/Tenant.vue @@ -0,0 +1,150 @@ + + + + +