Procházet zdrojové kódy

1、多库租户实现及优化 2、其他优化

zuohuaijun před 3 roky
rodič
revize
3184585e29
28 změnil soubory, kde provedl 529 přidání a 461 odebrání
  1. 2 2
      Admin.NET/Admin.NET.Application/AppConfig.json
  2. 1 1
      Admin.NET/Admin.NET.Application/Const/ApplicationConst.cs
  3. 52 56
      Admin.NET/Admin.NET.Core/Admin.NET.Core.xml
  4. 6 1
      Admin.NET/Admin.NET.Core/Const/CacheConst.cs
  5. 6 1
      Admin.NET/Admin.NET.Core/Const/SqlSugarConst.cs
  6. 3 0
      Admin.NET/Admin.NET.Core/Job/OnlineUserJob.cs
  7. 0 2
      Admin.NET/Admin.NET.Core/SeedData/SysDictTypeSeedData.cs
  8. 1 3
      Admin.NET/Admin.NET.Core/SeedData/SysOrgSeedData.cs
  9. 0 16
      Admin.NET/Admin.NET.Core/SeedData/SysPosSeedData.cs
  10. 0 60
      Admin.NET/Admin.NET.Core/SeedData/SysRoleMenuSeedData.cs
  11. 0 6
      Admin.NET/Admin.NET.Core/SeedData/SysRoleSeedData.cs
  12. 1 2
      Admin.NET/Admin.NET.Core/SeedData/SysTenantSeedData.cs
  13. 0 2
      Admin.NET/Admin.NET.Core/SeedData/SysUserRoleSeedData.cs
  14. 0 2
      Admin.NET/Admin.NET.Core/SeedData/SysUserSeedData.cs
  15. 7 7
      Admin.NET/Admin.NET.Core/Service/Auth/SysAuthService.cs
  16. 5 108
      Admin.NET/Admin.NET.Core/Service/Cache/SysCacheService.cs
  17. 10 7
      Admin.NET/Admin.NET.Core/Service/File/SysFileService.cs
  18. 6 4
      Admin.NET/Admin.NET.Core/Service/Menu/SysMenuService.cs
  19. 3 3
      Admin.NET/Admin.NET.Core/Service/Org/SysOrgService.cs
  20. 58 2
      Admin.NET/Admin.NET.Core/Service/Tenant/SysTenantService.cs
  21. 18 26
      Admin.NET/Admin.NET.Core/Service/User/UserManager.cs
  22. 23 2
      Admin.NET/Admin.NET.Core/SqlSugar/SqlSugarRepository.cs
  23. 200 113
      Admin.NET/Admin.NET.Core/SqlSugar/SqlSugarSetup.cs
  24. 2 1
      Admin.NET/Admin.NET.Web.Core/Startup.cs
  25. 32 32
      Web/src/api-services/apis/sys-cache-api.ts
  26. 76 0
      Web/src/api-services/apis/sys-tenant-api.ts
  27. 1 1
      Web/src/views/system/cache/index.vue
  28. 16 1
      Web/src/views/system/tenant/index.vue

+ 2 - 2
Admin.NET/Admin.NET.Application/AppConfig.json

@@ -5,7 +5,7 @@
         "ConnectionConfigs": [
             // 默认第一个为主库
             {
-                "ConfigId": "Dilon",
+                "ConfigId": "default",
                 "DbType": "Sqlite", // MySql、SqlServer、Sqlite、Oracle、PostgreSQL、Dm、Kdbndp、Oscar、MySqlConnector、Access
                 "ConnectionString": "DataSource=./Admin.NET.db",
                 "EnableInitDb": true, // 启用库表初始化
@@ -13,7 +13,7 @@
             },
             // 其他业务库
             {
-                "ConfigId": "Test",
+                "ConfigId": "test",
                 "DbType": "Sqlite",
                 "ConnectionString": "DataSource=./Test.db",
                 "EnableInitDb": false, // 启用库表初始化

+ 1 - 1
Admin.NET/Admin.NET.Application/Const/ApplicationConst.cs

@@ -13,5 +13,5 @@ public class ApplicationConst
     /// <summary>
     /// 数据库标识
     /// </summary>
-    public const string ConfigId = "Test";
+    public const string ConfigId = "test";
 }

+ 52 - 56
Admin.NET/Admin.NET.Core/Admin.NET.Core.xml

@@ -64,7 +64,7 @@
         </member>
         <member name="F:Admin.NET.Core.CacheConst.KeyPermission">
             <summary>
-            权限缓存
+            权限缓存(按钮集合)
             </summary>
         </member>
         <member name="F:Admin.NET.Core.CacheConst.KeyOrgIdList">
@@ -107,6 +107,11 @@
             swagger登录缓存
             </summary>
         </member>
+        <member name="F:Admin.NET.Core.CacheConst.KeyTenant">
+            <summary>
+            租户缓存
+            </summary>
+        </member>
         <member name="T:Admin.NET.Core.ClaimConst">
             <summary>
             Claim相关常量
@@ -252,6 +257,11 @@
             默认表主键
             </summary>
         </member>
+        <member name="F:Admin.NET.Core.SqlSugarConst.TenantId">
+            <summary>
+            默认租户Id
+            </summary>
+        </member>
         <member name="T:Admin.NET.Core.EntityBaseId">
             <summary>
             框架实体基类Id
@@ -4014,56 +4024,11 @@
             <param name="prefixKey">键名前缀</param>
             <returns></returns>
         </member>
-        <member name="M:Admin.NET.Core.Service.SysCacheService.GetOrgIdList(System.Int64)">
-            <summary>
-            获取机构Id集合
-            </summary>
-            <param name="userId"></param>
-            <returns></returns>
-        </member>
-        <member name="M:Admin.NET.Core.Service.SysCacheService.SetOrgIdList(System.Int64,System.Collections.Generic.List{System.Int64})">
-            <summary>
-            缓存机构Id集合
-            </summary>
-            <param name="userId"></param>
-            <param name="orgIdList"></param>
-            <returns></returns>
-        </member>
-        <member name="M:Admin.NET.Core.Service.SysCacheService.GetPermission(System.Int64)">
-            <summary>
-            获取权限集合(按钮)
-            </summary>
-            <param name="userId"></param>
-            <returns></returns>
-        </member>
-        <member name="M:Admin.NET.Core.Service.SysCacheService.SetPermission(System.Int64,System.Collections.Generic.List{System.String})">
-            <summary>
-            缓存权限集合(按钮)
-            </summary>
-            <param name="userId"></param>
-            <param name="permissions"></param>
-            <returns></returns>
-        </member>
-        <member name="M:Admin.NET.Core.Service.SysCacheService.GetMaxDataScopeType(System.Int64)">
-            <summary>
-            获取最大角色数据范围
-            </summary>
-            <param name="userId"></param>
-            <returns></returns>
-        </member>
-        <member name="M:Admin.NET.Core.Service.SysCacheService.SetMaxDataScopeType(System.Int64,System.Int32)">
-            <summary>
-            缓存最大角色数据范围
-            </summary>
-            <param name="userId"></param>
-            <param name="dataScopeType"></param>
-            <returns></returns>
-        </member>
-        <member name="M:Admin.NET.Core.Service.SysCacheService.CacheDetail(System.String)">
+        <member name="M:Admin.NET.Core.Service.SysCacheService.GetCacheValue(System.String)">
             <summary>
-            获取缓存
+            获取缓存值
             </summary>
-            <param name="cacheKey"></param>
+            <param name="key"></param>
             <returns></returns>
         </member>
         <member name="P:Admin.NET.Core.Service.CustomViewEngine.ConfigId">
@@ -6173,6 +6138,13 @@
             <param name="input"></param>
             <returns></returns>
         </member>
+        <member name="M:Admin.NET.Core.Service.SysTenantService.GetTenant(System.Int64)">
+            <summary>
+            获取租户
+            </summary>
+            <param name="tenantId"></param>
+            <returns></returns>
+        </member>
         <member name="M:Admin.NET.Core.Service.SysTenantService.GetTenantAdminUser(System.Int64)">
             <summary>
             获取租户管理员用户
@@ -6180,6 +6152,19 @@
             <param name="tenantId"></param>
             <returns></returns>
         </member>
+        <member name="M:Admin.NET.Core.Service.SysTenantService.UpdateTenantCache">
+            <summary>
+            缓存所有租户
+            </summary>
+            <returns></returns>
+        </member>
+        <member name="M:Admin.NET.Core.Service.SysTenantService.CreateTenantDb(Admin.NET.Core.Service.TenantInput)">
+            <summary>
+            创建租户数据库(根据默认库结构)
+            </summary>
+            <param name="input"></param>
+            <returns></returns>
+        </member>
         <member name="P:Admin.NET.Core.Service.PageTimerInput.TimerName">
             <summary>
             任务名称
@@ -6759,13 +6744,6 @@
             当前登录用户
             </summary>
         </member>
-        <member name="M:Admin.NET.Core.UserManager.CheckUserAsync(System.Int64)">
-            <summary>
-            获取用户信息
-            </summary>
-            <param name="userId"></param>
-            <returns></returns>
-        </member>
         <member name="T:Admin.NET.Core.IEntityFilter">
             <summary>
             自定义实体过滤器接口
@@ -6865,11 +6843,29 @@
             </summary>
             <param name="services"></param>
         </member>
+        <member name="M:Admin.NET.Core.SqlSugarSetup.SetDbConfig(Admin.NET.Core.DbConnectionConfig)">
+            <summary>
+            配置连接属性
+            </summary>
+            <param name="config"></param>
+        </member>
+        <member name="M:Admin.NET.Core.SqlSugarSetup.SetDbAop(SqlSugar.SqlSugarScopeProvider,Admin.NET.Core.DbConnectionConfig)">
+            <summary>
+            配置Aop
+            </summary>
+            <param name="db"></param>
+            <param name="config"></param>
+        </member>
         <member name="M:Admin.NET.Core.SqlSugarSetup.InitDataBase(SqlSugar.SqlSugarScope,Admin.NET.Core.DbConnectionOptions)">
             <summary>
             初始化数据库结构
             </summary>
         </member>
+        <member name="M:Admin.NET.Core.SqlSugarSetup.CreateDataBase(SqlSugar.ISqlSugarClient,Admin.NET.Core.DbConnectionConfig,System.Int64)">
+            <summary>
+            初始化数据库结构
+            </summary>
+        </member>
         <member name="M:Admin.NET.Core.SqlSugarSetup.SetDeletedEntityFilter(SqlSugar.SqlSugarScopeProvider)">
             <summary>
             配置实体假删除过滤器

+ 6 - 1
Admin.NET/Admin.NET.Core/Const/CacheConst.cs

@@ -16,7 +16,7 @@ public class CacheConst
     public const string KeyMenu = "menu:";
 
     /// <summary>
-    /// 权限缓存
+    /// 权限缓存(按钮集合)
     /// </summary>
     public const string KeyPermission = "permission:";
 
@@ -59,4 +59,9 @@ public class CacheConst
     /// swagger登录缓存
     /// </summary>
     public const string SwaggerLogin = "swaggerLogin:";
+
+    /// <summary>
+    /// 租户缓存
+    /// </summary>
+    public const string KeyTenant = "tenant:";
 }

+ 6 - 1
Admin.NET/Admin.NET.Core/Const/SqlSugarConst.cs

@@ -8,10 +8,15 @@ public class SqlSugarConst
     /// <summary>
     /// 默认数据库标识
     /// </summary>
-    public const string ConfigId = "Dilon";
+    public const string ConfigId = "default";
 
     /// <summary>
     /// 默认表主键
     /// </summary>
     public const string PrimaryKey = "Id";
+
+    /// <summary>
+    /// 默认租户Id
+    /// </summary>
+    public const string TenantId = "TenantId";
 }

+ 3 - 0
Admin.NET/Admin.NET.Core/Job/OnlineUserJob.cs

@@ -19,6 +19,9 @@ public class OnlineUserJob : ISpareTimeWorker
 
             Console.ForegroundColor = ConsoleColor.Red;
             Console.WriteLine("【" + DateTime.Now + "】服务重启清空在线用户");
+
+            // 缓存多租户
+            await services.GetService<SysTenantService>().UpdateTenantCache();
         });
     }
 }

+ 0 - 2
Admin.NET/Admin.NET.Core/SeedData/SysDictTypeSeedData.cs

@@ -17,8 +17,6 @@ public class SysDictTypeSeedData : ISqlSugarEntitySeedData<SysDictType>
             new SysDictType{ Id=269037954100002, Name="代码生成查询类型", Code="code_gen_query_type", Order=100, Remark="代码生成查询类型", Status=StatusEnum.Enable, CreateTime=DateTime.Parse("2022-02-10 00:00:00") },
             new SysDictType{ Id=269037954100003, Name="代码生成.NET类型", Code="code_gen_net_type", Order=100, Remark="代码生成.NET类型", Status=StatusEnum.Enable, CreateTime=DateTime.Parse("2022-02-10 00:00:00") },
             new SysDictType{ Id=269037954100004, Name="代码生成方式", Code="code_gen_create_type", Order=100, Remark="代码生成方式", Status=StatusEnum.Enable, CreateTime=DateTime.Parse("2022-02-10 00:00:00") },
-
-            new SysDictType{ Id=269037954200001, Name="机构级别", Code="org_level", Order=100, Remark="机构级别", Status=StatusEnum.Enable, CreateTime=DateTime.Parse("2022-02-10 00:00:00") },
         };
     }
 }

+ 1 - 3
Admin.NET/Admin.NET.Core/SeedData/SysOrgSeedData.cs

@@ -13,7 +13,7 @@ public class SysOrgSeedData : ISqlSugarEntitySeedData<SysOrg>
     {
         return new[]
         {
-            new SysOrg{ Id=252885263003720, Pid=0, Name="大名科技有限公司", Code="1001", CreateTime=DateTime.Parse("2022-02-10 00:00:00"), Remark="大名科技", TenantId=142307070918780 },
+            new SysOrg{ Id=252885263003720, Pid=0, Name="大名科技", Code="1001", CreateTime=DateTime.Parse("2022-02-10 00:00:00"), Remark="大名科技", TenantId=142307070918780 },
             new SysOrg{ Id=252885263003721, Pid=252885263003720, Name="市场部", Code="100101", CreateTime=DateTime.Parse("2022-02-10 00:00:00"), Remark="市场部", TenantId=142307070918780 },
             new SysOrg{ Id=252885263003722, Pid=252885263003720, Name="研发部", Code="100102", CreateTime=DateTime.Parse("2022-02-10 00:00:00"), Remark="研发部", TenantId=142307070918780 },
             new SysOrg{ Id=252885263003723, Pid=252885263003720, Name="财务部", Code="100103", CreateTime=DateTime.Parse("2022-02-10 00:00:00"), Remark="财务部", TenantId=142307070918780 },
@@ -29,8 +29,6 @@ public class SysOrgSeedData : ISqlSugarEntitySeedData<SysOrg>
             new SysOrg{ Id=252885263003741, Pid=252885263003740, Name="市场部", Code="100301", CreateTime=DateTime.Parse("2022-02-10 00:00:00"), Remark="市场部", TenantId=142307070918780 },
             new SysOrg{ Id=252885263003742, Pid=252885263003740, Name="研发部", Code="100302", CreateTime=DateTime.Parse("2022-02-10 00:00:00"), Remark="市场部", TenantId=142307070918780 },
             new SysOrg{ Id=252885263003743, Pid=252885263003740, Name="财务部", Code="100303", CreateTime=DateTime.Parse("2022-02-10 00:00:00"), Remark="市场部", TenantId=142307070918780 },
-
-            new SysOrg{ Id=252885263004720, Pid=0, Name="租户1公司", Code="2001", CreateTime=DateTime.Parse("2022-02-10 00:00:00"), Remark="租户1公司" , TenantId=142307070918781 },
         };
     }
 }

+ 0 - 16
Admin.NET/Admin.NET.Core/SeedData/SysPosSeedData.cs

@@ -28,22 +28,6 @@ public class SysPosSeedData : ISqlSugarEntitySeedData<SysPos>
             new SysPos{ Id=252885263003732, Name="副科长", Code="fkz", CreateTime=DateTime.Parse("2022-02-10 00:00:00"), Remark="副科长", TenantId=142307070918780 },
             new SysPos{ Id=252885263003733, Name="职员", Code="zy", CreateTime=DateTime.Parse("2022-02-10 00:00:00"), Remark="职员", TenantId=142307070918780 },
             new SysPos{ Id=252885263003734, Name="其他", Code="qt", CreateTime=DateTime.Parse("2022-02-10 00:00:00"), Remark="其他", TenantId=142307070918780 },
-
-            new SysPos{ Id=252885263004720, Name="党委书记", Code="dwsj", CreateTime=DateTime.Parse("2022-02-10 00:00:00"), Remark="党委书记", TenantId=142307070918781 },
-            new SysPos{ Id=252885263004721, Name="董事长", Code="dsz", CreateTime=DateTime.Parse("2022-02-10 00:00:00"), Remark="董事长", TenantId=142307070918781 },
-            new SysPos{ Id=252885263004722, Name="副董事长", Code="fdsz", CreateTime=DateTime.Parse("2022-02-10 00:00:00"), Remark="副董事长", TenantId=142307070918781 },
-            new SysPos{ Id=252885263004723, Name="总经理", Code="zjl", CreateTime=DateTime.Parse("2022-02-10 00:00:00"), Remark="总经理", TenantId=142307070918781 },
-            new SysPos{ Id=252885263004724, Name="副总经理", Code="fzjl", CreateTime=DateTime.Parse("2022-02-10 00:00:00"), Remark="副总经理", Status=StatusEnum.Disable, TenantId=142307070918781 },
-            new SysPos{ Id=252885263004725, Name="部门经理", Code="bmjl", CreateTime=DateTime.Parse("2022-02-10 00:00:00"), Remark="部门经理", TenantId=142307070918781 },
-            new SysPos{ Id=252885263004726, Name="部门副经理", Code="bmfjl", CreateTime=DateTime.Parse("2022-02-10 00:00:00"), Remark="部门副经理", TenantId=142307070918781 },
-            new SysPos{ Id=252885263004727, Name="主任", Code="zr", CreateTime=DateTime.Parse("2022-02-10 00:00:00"), Remark="主任", TenantId=142307070918781 },
-            new SysPos{ Id=252885263004728, Name="副主任", Code="fzr", CreateTime=DateTime.Parse("2022-02-10 00:00:00"), Remark="副主任", TenantId=142307070918781 },
-            new SysPos{ Id=252885263004729, Name="局长", Code="jz", CreateTime=DateTime.Parse("2022-02-10 00:00:00"), Remark="局长", TenantId=142307070918781 },
-            new SysPos{ Id=252885263004730, Name="副局长", Code="fjz", CreateTime=DateTime.Parse("2022-02-10 00:00:00"), Remark="副局长", TenantId=142307070918781 },
-            new SysPos{ Id=252885263004731, Name="科长", Code="kz", CreateTime=DateTime.Parse("2022-02-10 00:00:00"), Remark="科长", TenantId=142307070918781 },
-            new SysPos{ Id=252885263004732, Name="副科长", Code="fkz", CreateTime=DateTime.Parse("2022-02-10 00:00:00"), Remark="副科长", TenantId=142307070918781 },
-            new SysPos{ Id=252885263004733, Name="职员", Code="zy", CreateTime=DateTime.Parse("2022-02-10 00:00:00"), Remark="职员", TenantId=142307070918781 },
-            new SysPos{ Id=252885263004734, Name="其他", Code="qt", CreateTime=DateTime.Parse("2022-02-10 00:00:00"), Remark="其他", TenantId=142307070918781 },
         };
     }
 }

+ 0 - 60
Admin.NET/Admin.NET.Core/SeedData/SysRoleMenuSeedData.cs

@@ -146,66 +146,6 @@ public class SysRoleMenuSeedData : ISqlSugarEntitySeedData<SysRoleMenu>
             new SysRoleMenu{ Id=252885263005152, RoleId=252885263003724, MenuId=252885263002261 },
             new SysRoleMenu{ Id=252885263005153, RoleId=252885263003724, MenuId=252885263002262 },
             new SysRoleMenu{ Id=252885263005154, RoleId=252885263003724, MenuId=252885263002263 },
-
-            // 其他租户
-            // 数据面板【admin1/252885263004721】
-            new SysRoleMenu{ Id=252885263101000, RoleId=252885263004721, MenuId=252885263002100 },
-            new SysRoleMenu{ Id=252885263101001, RoleId=252885263004721, MenuId=252885263002110 },
-            new SysRoleMenu{ Id=252885263101002, RoleId=252885263004721, MenuId=252885263002111 },
-            // 系统管理
-            new SysRoleMenu{ Id=252885263101100, RoleId=252885263004721, MenuId=252885263002200 },
-            // 账号管理
-            new SysRoleMenu{ Id=252885263101101, RoleId=252885263004721, MenuId=252885263002210 },
-            new SysRoleMenu{ Id=252885263101102, RoleId=252885263004721, MenuId=252885263002211 },
-            new SysRoleMenu{ Id=252885263101103, RoleId=252885263004721, MenuId=252885263002212 },
-            new SysRoleMenu{ Id=252885263101104, RoleId=252885263004721, MenuId=252885263002213 },
-            new SysRoleMenu{ Id=252885263101105, RoleId=252885263004721, MenuId=252885263002214 },
-            new SysRoleMenu{ Id=252885263101106, RoleId=252885263004721, MenuId=252885263002215 },
-            new SysRoleMenu{ Id=252885263101107, RoleId=252885263004721, MenuId=252885263002216 },
-            new SysRoleMenu{ Id=252885263101108, RoleId=252885263004721, MenuId=252885263002217 },
-            new SysRoleMenu{ Id=252885263101109, RoleId=252885263004721, MenuId=252885263002218 },
-            new SysRoleMenu{ Id=252885263103110, RoleId=252885263004721, MenuId=252885263002219 },
-            new SysRoleMenu{ Id=252885263113111, RoleId=252885263003721, MenuId=252885263012220 },
-            // 角色管理
-            new SysRoleMenu{ Id=252885263103111, RoleId=252885263004721, MenuId=252885263002220 },
-            new SysRoleMenu{ Id=252885263103112, RoleId=252885263004721, MenuId=252885263002221 },
-            new SysRoleMenu{ Id=252885263103113, RoleId=252885263004721, MenuId=252885263002222 },
-            new SysRoleMenu{ Id=252885263103114, RoleId=252885263004721, MenuId=252885263002223 },
-            new SysRoleMenu{ Id=252885263103115, RoleId=252885263004721, MenuId=252885263002224 },
-            new SysRoleMenu{ Id=252885263103116, RoleId=252885263004721, MenuId=252885263002225 },
-            new SysRoleMenu{ Id=252885263103117, RoleId=252885263004721, MenuId=252885263002226 },
-            new SysRoleMenu{ Id=252885263103118, RoleId=252885263004721, MenuId=252885263002227 },
-            // 菜单管理
-            new SysRoleMenu{ Id=252885263103121, RoleId=252885263004721, MenuId=252885263002230 },
-            new SysRoleMenu{ Id=252885263103122, RoleId=252885263004721, MenuId=252885263002231 },
-            new SysRoleMenu{ Id=252885263103123, RoleId=252885263004721, MenuId=252885263002232 },
-            new SysRoleMenu{ Id=252885263103124, RoleId=252885263004721, MenuId=252885263002233 },
-            new SysRoleMenu{ Id=252885263103125, RoleId=252885263004721, MenuId=252885263002234 },
-            // 机构管理
-            new SysRoleMenu{ Id=252885263103131, RoleId=252885263004721, MenuId=252885263002240 },
-            new SysRoleMenu{ Id=252885263103132, RoleId=252885263004721, MenuId=252885263002241 },
-            new SysRoleMenu{ Id=252885263103133, RoleId=252885263004721, MenuId=252885263002242 },
-            new SysRoleMenu{ Id=252885263103134, RoleId=252885263004721, MenuId=252885263002243 },
-            new SysRoleMenu{ Id=252885263103135, RoleId=252885263004721, MenuId=252885263002244 },
-            // 职位管理
-            new SysRoleMenu{ Id=252885263103141, RoleId=252885263004721, MenuId=252885263002250 },
-            new SysRoleMenu{ Id=252885263103142, RoleId=252885263004721, MenuId=252885263002251 },
-            new SysRoleMenu{ Id=252885263103143, RoleId=252885263004721, MenuId=252885263002252 },
-            new SysRoleMenu{ Id=252885263103144, RoleId=252885263004721, MenuId=252885263002253 },
-            new SysRoleMenu{ Id=252885263103145, RoleId=252885263004721, MenuId=252885263002254 },
-            // 个人中心
-            new SysRoleMenu{ Id=252885263103151, RoleId=252885263004721, MenuId=252885263002260 },
-            new SysRoleMenu{ Id=252885263103152, RoleId=252885263004721, MenuId=252885263002261 },
-            new SysRoleMenu{ Id=252885263103153, RoleId=252885263004721, MenuId=252885263002262 },
-            new SysRoleMenu{ Id=252885263103154, RoleId=252885263004721, MenuId=252885263002263 },
-            // 通知公告
-            new SysRoleMenu{ Id=252885263103161, RoleId=252885263004721, MenuId=252885263002270 },
-            new SysRoleMenu{ Id=252885263103162, RoleId=252885263004721, MenuId=252885263002271 },
-            new SysRoleMenu{ Id=252885263103163, RoleId=252885263004721, MenuId=252885263002272 },
-            new SysRoleMenu{ Id=252885263103164, RoleId=252885263004721, MenuId=252885263002273 },
-            new SysRoleMenu{ Id=252885263103165, RoleId=252885263004721, MenuId=252885263002274 },
-            new SysRoleMenu{ Id=252885263103166, RoleId=252885263004721, MenuId=252885263002275 },
-            new SysRoleMenu{ Id=252885263103167, RoleId=252885263004721, MenuId=252885263002276 },
         };
     }
 }

+ 0 - 6
Admin.NET/Admin.NET.Core/SeedData/SysRoleSeedData.cs

@@ -18,12 +18,6 @@ public class SysRoleSeedData : ISqlSugarEntitySeedData<SysRole>
             new SysRole{ Id=252885263003723, Name="本部门数据", DataScope=DataScopeEnum.Dept, Code="sys_dept", CreateTime=DateTime.Parse("2022-02-10 00:00:00"), Remark="本部门数据", TenantId=142307070918780 },
             new SysRole{ Id=252885263003724, Name="仅本人数据", DataScope=DataScopeEnum.Self, Code="sys_self", CreateTime=DateTime.Parse("2022-02-10 00:00:00"), Remark="仅本人数据", TenantId=142307070918780 },
             new SysRole{ Id=252885263003725, Name="自定义数据", DataScope=DataScopeEnum.Define, Code="sys_define", CreateTime=DateTime.Parse("2022-02-10 00:00:00"), Remark="自定义数据", TenantId=142307070918780 },
-
-            new SysRole{ Id=252885263004721, Name="系统管理员", DataScope=DataScopeEnum.All, Code="sys_admin", CreateTime=DateTime.Parse("2022-02-10 00:00:00"), Remark="系统管理员", TenantId=142307070918781 },
-            new SysRole{ Id=252885263004722, Name="本部门及以下数据", DataScope=DataScopeEnum.DeptChild, Code="sys_deptChild", CreateTime=DateTime.Parse("2022-02-10 00:00:00"), Remark="本部门及以下数据", TenantId=142307070918781 },
-            new SysRole{ Id=252885263004723, Name="本部门数据", DataScope=DataScopeEnum.Dept, Code="sys_dept", CreateTime=DateTime.Parse("2022-02-10 00:00:00"), Remark="本部门数据", TenantId=142307070918781 },
-            new SysRole{ Id=252885263004724, Name="仅本人数据", DataScope=DataScopeEnum.Self, Code="sys_self", CreateTime=DateTime.Parse("2022-02-10 00:00:00"), Remark="仅本人数据", TenantId=142307070918781 },
-            new SysRole{ Id=252885263004725, Name="自定义数据", DataScope=DataScopeEnum.Define, Code="sys_define", CreateTime=DateTime.Parse("2022-02-10 00:00:00"), Remark="自定义数据", TenantId=142307070918781 },
         };
     }
 }

+ 1 - 2
Admin.NET/Admin.NET.Core/SeedData/SysTenantSeedData.cs

@@ -13,8 +13,7 @@ public class SysTenantSeedData : ISqlSugarEntitySeedData<SysTenant>
     {
         return new[]
         {
-            new SysTenant{ Id=142307070918780, Name="系统默认", AdminName="Administrator", Host="www.dilon.vip", Email="zuohuaijun@163.com", Phone="18020030720", TenantType=TenantTypeEnum.Db, DbType=SqlSugar.DbType.Sqlite, Connection="DataSource=./Admin.NET.db", ConfigId="Dilon", Remark="系统默认", CreateTime=DateTime.Parse("2022-02-10 00:00:00") },
-            new SysTenant{ Id=142307070918781, Name="测试租户", AdminName="TestAdmin", Host="www.dilon.top", Email="515096995@qq.com", Phone="18020030720", TenantType=TenantTypeEnum.Db, DbType=SqlSugar.DbType.Sqlite, Connection="DataSource=./Test.db", ConfigId="Test", Remark="测试租户", CreateTime=DateTime.Parse("2022-02-10 00:00:00") },
+            new SysTenant{ Id=142307070918780, Name="系统默认", AdminName="Administrator", Host="www.dilon.vip", Email="zuohuaijun@163.com", Phone="18020030720", TenantType=TenantTypeEnum.Db, DbType=SqlSugar.DbType.Sqlite, Connection="DataSource=./Admin.NET.db", ConfigId=SqlSugarConst.ConfigId, Remark="系统默认", CreateTime=DateTime.Parse("2022-02-10 00:00:00") },
         };
     }
 }

+ 0 - 2
Admin.NET/Admin.NET.Core/SeedData/SysUserRoleSeedData.cs

@@ -18,8 +18,6 @@ public class SysUserRoleSeedData : ISqlSugarEntitySeedData<SysUserRole>
             new SysUserRole{ Id=252885263003003, UserId=252885263003723, RoleId=252885263003723 },
             new SysUserRole{ Id=252885263003004, UserId=252885263003724, RoleId=252885263003724 },
             new SysUserRole{ Id=252885263003005, UserId=252885263003725, RoleId=252885263003725 },
-
-            new SysUserRole{ Id=252885263004001, UserId=252885263004721, RoleId=252885263004721 }
         };
     }
 }

+ 0 - 2
Admin.NET/Admin.NET.Core/SeedData/SysUserSeedData.cs

@@ -19,8 +19,6 @@ public class SysUserSeedData : ISqlSugarEntitySeedData<SysUser>
             new SysUser{ Id=252885263003723, Account="user2", Password="e10adc3949ba59abbe56e057f20f883e", NickName="部门职员", RealName="部门职员", Phone="18020030720", Birthday=DateTime.Parse("1986-06-28"), Sex=GenderEnum.Female, AccountType=AccountTypeEnum.User, Remark="部门职员", CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrgId=252885263003722, PosId=252885263003729, TenantId=142307070918780 },
             new SysUser{ Id=252885263003724, Account="user3", Password="e10adc3949ba59abbe56e057f20f883e", NickName="普通用户", RealName="普通用户", Phone="18020030720", Birthday=DateTime.Parse("1986-06-28"), Sex=GenderEnum.Female, AccountType=AccountTypeEnum.User, Remark="普通用户", CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrgId=252885263003723, PosId=252885263003729, TenantId=142307070918780 },
             new SysUser{ Id=252885263003725, Account="user4", Password="e10adc3949ba59abbe56e057f20f883e", NickName="其他", RealName="其他", Phone="18020030720", Birthday=DateTime.Parse("1986-06-28"), Sex=GenderEnum.Female, AccountType=AccountTypeEnum.None, Remark="普通用户", CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrgId=252885263003724, PosId=252885263003729, TenantId=142307070918780 },
-
-            new SysUser{ Id=252885263004721, Account="admin1", Password="e10adc3949ba59abbe56e057f20f883e", NickName="系统管理员", RealName="系统管理员", Phone="18020030720", Birthday=DateTime.Parse("1986-06-28"), Sex=GenderEnum.Male, AccountType=AccountTypeEnum.Admin, Remark="系统管理员", CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrgId=252885263004720, PosId=252885263004721, TenantId=142307070918781 }
         };
     }
 }

+ 7 - 7
Admin.NET/Admin.NET.Core/Service/Auth/SysAuthService.cs

@@ -58,7 +58,8 @@ public class SysAuthService : IDynamicApiController, ITransient
     [SuppressMonitor]
     public async Task<LoginOutput> Login([Required] LoginInput input)
     {
-        // 判断租户
+        // 记录当前租户
+        _userManager.TenantId = input.TenantId;
 
         // 判断验证码
         var captchaEnabled = await GetCaptchaFlag();
@@ -82,7 +83,7 @@ public class SysAuthService : IDynamicApiController, ITransient
         var accessToken = JWTEncryption.Encrypt(new Dictionary<string, object>
         {
             {ClaimConst.UserId, user.Id},
-            {ClaimConst.TenantId, user.TenantId},
+            {ClaimConst.TenantId, input.TenantId},
             {ClaimConst.Account, user.Account},
             {ClaimConst.RealName, user.RealName},
             {ClaimConst.AccountType, user.AccountType },
@@ -112,7 +113,7 @@ public class SysAuthService : IDynamicApiController, ITransient
     [HttpGet("/userInfo")]
     public async Task<LoginUserOutput> GetUserInfo()
     {
-        var user = _userManager.User;
+        var user = _sysUserRep.GetFirst(u => u.Id == _userManager.UserId);
         if (user == null)
             throw Oops.Oh(ErrorCodeEnum.D1011);
 
@@ -171,8 +172,7 @@ public class SysAuthService : IDynamicApiController, ITransient
     [HttpPost("/logout")]
     public async void Logout()
     {
-        var user = _userManager.User;
-        if (user == null)
+        if (string.IsNullOrWhiteSpace(_userManager.Account))
             throw Oops.Oh(ErrorCodeEnum.D1011);
 
         // 设置响应报文头
@@ -185,8 +185,8 @@ public class SysAuthService : IDynamicApiController, ITransient
             Message = "退出",
             VisType = LoginTypeEnum.Logout,
             Ip = _httpContextAccessor.HttpContext.GetRemoteIpAddressToIPv4(),
-            Account = user.Account,
-            RealName = user.RealName
+            Account = _userManager.Account,
+            RealName = _userManager.RealName
         });
     }
 

+ 5 - 108
Admin.NET/Admin.NET.Core/Service/Cache/SysCacheService.cs

@@ -98,116 +98,13 @@ public class SysCacheService : IDynamicApiController, ISingleton
     }
 
     /// <summary>
-    /// 获取机构Id集合
+    /// 获取缓存值
     /// </summary>
-    /// <param name="userId"></param>
-    /// <returns></returns>
-    [NonAction]
-    public List<long> GetOrgIdList(long userId)
-    {
-        var key = CacheConst.KeyOrgIdList + userId;
-        return _cache.Get<List<long>>(key);
-    }
-
-    /// <summary>
-    /// 缓存机构Id集合
-    /// </summary>
-    /// <param name="userId"></param>
-    /// <param name="orgIdList"></param>
-    /// <returns></returns>
-    [NonAction]
-    public bool SetOrgIdList(long userId, List<long> orgIdList)
-    {
-        var key = CacheConst.KeyOrgIdList + userId;
-        return _cache.Set(key, orgIdList);
-    }
-
-    /// <summary>
-    /// 获取权限集合(按钮)
-    /// </summary>
-    /// <param name="userId"></param>
-    /// <returns></returns>
-    [NonAction]
-    public List<string> GetPermission(long userId)
-    {
-        var key = CacheConst.KeyPermission + userId;
-        return _cache.Get<List<string>>(key);
-    }
-
-    /// <summary>
-    /// 缓存权限集合(按钮)
-    /// </summary>
-    /// <param name="userId"></param>
-    /// <param name="permissions"></param>
-    /// <returns></returns>
-    [NonAction]
-    public bool SetPermission(long userId, List<string> permissions)
-    {
-        var key = CacheConst.KeyPermission + userId;
-        return _cache.Set(key, permissions);
-    }
-
-    /// <summary>
-    /// 获取最大角色数据范围
-    /// </summary>
-    /// <param name="userId"></param>
-    /// <returns></returns>
-    [NonAction]
-    public int? GetMaxDataScopeType(long userId)
-    {
-        var key = CacheConst.KeyMaxDataScopeType + userId;
-        return _cache.Get<int>(key);
-    }
-
-    /// <summary>
-    /// 缓存最大角色数据范围
-    /// </summary>
-    /// <param name="userId"></param>
-    /// <param name="dataScopeType"></param>
-    /// <returns></returns>
-    [NonAction]
-    public bool SetMaxDataScopeType(long userId, int dataScopeType)
-    {
-        var key = CacheConst.KeyMaxDataScopeType + userId;
-        return _cache.Set(key, dataScopeType);
-    }
-
-    /// <summary>
-    /// 获取缓存
-    /// </summary>
-    /// <param name="cacheKey"></param>
+    /// <param name="key"></param>
     /// <returns></returns>
-    [HttpGet("/sysCache/detail")]
-    public dynamic CacheDetail(string cacheKey)
+    [HttpGet("/sysCache/value")]
+    public dynamic GetCacheValue(string key)
     {
-        return _cache.Get<dynamic>(cacheKey);
+        return _cache.Get<dynamic>(key);
     }
-
-    ///// <summary>
-    ///// 获取菜单缓存
-    ///// </summary>
-    ///// <param name="userId"></param>
-    ///// <param name="appCode"></param>
-    ///// <returns></returns>
-    //[NonAction]
-    //public async Task<List<AntDesignTreeNode>> GetMenu(long userId, string appCode)
-    //{
-    //    var cacheKey = CacheConst.KeyMenu + $"{userId}-{appCode}";
-    //    var res = await _cache.GetStringAsync(cacheKey);
-    //    return string.IsNullOrWhiteSpace(res) ? null : JSON.Deserialize<List<AntDesignTreeNode>>(res);
-    //}
-
-    ///// <summary>
-    ///// 缓存菜单
-    ///// </summary>
-    ///// <param name="userId"></param>
-    ///// <param name="appCode"></param>
-    ///// <param name="menus"></param>
-    ///// <returns></returns>
-    //[NonAction]
-    //public async Task SetMenu(long userId, string appCode, List<AntDesignTreeNode> menus)
-    //{
-    //    var cacheKey = CommonConst.CACHE_KEY_MENU + $"{userId}-{appCode}";
-    //    await _cache.SetStringAsync(cacheKey, JSON.Serialize(menus));
-    //}
 }

+ 10 - 7
Admin.NET/Admin.NET.Core/Service/File/SysFileService.cs

@@ -9,18 +9,21 @@ namespace Admin.NET.Core.Service;
 [ApiDescriptionSettings(Order = 194)]
 public class SysFileService : IDynamicApiController, ITransient
 {
+    private readonly UserManager _userManager;
     private readonly SqlSugarRepository<SysFile> _sysFileRep;
     private readonly OSSProviderOptions _OSSProviderOptions;
     private readonly UploadOptions _uploadOptions;
     private readonly ICommonService _commonService;
     private readonly IOSSService _OSSService;
 
-    public SysFileService(SqlSugarRepository<SysFile> sysFileRep,
+    public SysFileService(UserManager userManager,
+        SqlSugarRepository<SysFile> sysFileRep,
         IOptions<OSSProviderOptions> oSSProviderOptions,
         IOptions<UploadOptions> uploadOptions,
         ICommonService commonService,
         IOSSServiceFactory ossServiceFactory)
     {
+        _userManager = userManager;
         _sysFileRep = sysFileRep;
         _OSSProviderOptions = oSSProviderOptions.Value;
         _uploadOptions = uploadOptions.Value;
@@ -257,7 +260,8 @@ public class SysFileService : IDynamicApiController, ITransient
     [HttpPost("/sysFile/uploadAvatar")]
     public async Task<FileOutput> UploadAvatar([Required] IFormFile file)
     {
-        var user = App.GetService<UserManager>().User;
+        var sysUserRep = _sysFileRep.ChangeRepository<SqlSugarRepository<SysUser>>();
+        var user = sysUserRep.GetFirst(u => u.Id == _userManager.UserId);
         // 删除当前用户已有头像
         if (!string.IsNullOrWhiteSpace(user.Avatar) && user.Avatar.EndsWith(".png"))
         {
@@ -266,8 +270,7 @@ public class SysFileService : IDynamicApiController, ITransient
         }
 
         var res = await UploadFile(file, "Avatar");
-        await _sysFileRep.ChangeRepository<SqlSugarRepository<SysUser>>()
-            .UpdateAsync(u => new SysUser() { Avatar = res.Url }, u => u.Id == user.Id);
+        await sysUserRep.UpdateAsync(u => new SysUser() { Avatar = res.Url }, u => u.Id == user.Id);
         return res;
     }
 
@@ -279,7 +282,8 @@ public class SysFileService : IDynamicApiController, ITransient
     [HttpPost("/sysFile/uploadSignature")]
     public async Task<FileOutput> UploadSignature([Required] IFormFile file)
     {
-        var user = App.GetService<UserManager>().User;
+        var sysUserRep = _sysFileRep.ChangeRepository<SqlSugarRepository<SysUser>>();
+        var user = sysUserRep.GetFirst(u => u.Id == _userManager.UserId);
         // 删除当前用户已有电子签名
         if (!string.IsNullOrWhiteSpace(user.Signature) && user.Signature.EndsWith(".png"))
         {
@@ -288,8 +292,7 @@ public class SysFileService : IDynamicApiController, ITransient
         }
 
         var res = await UploadFile(file, "Signature");
-        await _sysFileRep.ChangeRepository<SqlSugarRepository<SysUser>>()
-            .UpdateAsync(u => new SysUser() { Signature = res.Url }, u => u.Id == user.Id);
+        await sysUserRep.UpdateAsync(u => new SysUser() { Signature = res.Url }, u => u.Id == user.Id);
         return res;
     }
 }

+ 6 - 4
Admin.NET/Admin.NET.Core/Service/Menu/SysMenuService.cs

@@ -1,3 +1,5 @@
+using static SKIT.FlurlHttpClient.Wechat.Api.Models.CgibinUserInfoBatchGetResponse.Types;
+
 namespace Admin.NET.Core.Service;
 
 /// <summary>
@@ -168,7 +170,7 @@ public class SysMenuService : IDynamicApiController, ITransient
     public async Task<List<string>> GetPermCodeList()
     {
         var userId = _userManager.UserId;
-        var permissions = _sysCacheService.GetPermission(userId); // 取缓存
+        var permissions = _sysCacheService.Get<List<string>>(CacheConst.KeyPermission + userId); // 取缓存
         if (permissions == null || permissions.Count == 0)
         {
             var menuIdList = _userManager.SuperAdmin ? new List<long>() : await GetMenuIdList();
@@ -176,7 +178,7 @@ public class SysMenuService : IDynamicApiController, ITransient
                 .Where(u => u.Type == MenuTypeEnum.Btn)
                 .WhereIF(menuIdList.Count > 0, u => menuIdList.Contains(u.Id))
                 .Select(u => u.Permission).ToListAsync();
-            _sysCacheService.SetPermission(userId, permissions); // 缓存结果
+            _sysCacheService.Set(CacheConst.KeyPermission + userId, permissions); // 缓存结果
         }
         return permissions;
     }
@@ -188,13 +190,13 @@ public class SysMenuService : IDynamicApiController, ITransient
     [NonAction]
     public async Task<List<string>> GetAllPermCodeList()
     {
-        var permissions = _sysCacheService.GetPermission(0); // 先从缓存里面读取
+        var permissions = _sysCacheService.Get<List<string>>(CacheConst.KeyPermission + 0); // 先从缓存里面读取
         if (permissions == null || permissions.Count == 0)
         {
             permissions = await _sysMenuRep.AsQueryable()
                 .Where(u => u.Type == MenuTypeEnum.Btn)
                 .Select(u => u.Permission).ToListAsync();
-            _sysCacheService.SetPermission(0, permissions); // 缓存结果
+            _sysCacheService.Set(CacheConst.KeyPermission + 0, permissions); // 缓存结果
         }
         return permissions;
     }

+ 3 - 3
Admin.NET/Admin.NET.Core/Service/Org/SysOrgService.cs

@@ -174,7 +174,7 @@ public class SysOrgService : IDynamicApiController, ITransient
             return new List<long>();
 
         var userId = _userManager.UserId;
-        var orgIdList = _sysCacheService.GetOrgIdList(userId); // 取缓存
+        var orgIdList = _sysCacheService.Get<List<long>>(CacheConst.KeyOrgIdList + userId); // 取缓存
         if (orgIdList == null || orgIdList.Count < 1)
         {
             // 扩展机构集合
@@ -183,7 +183,7 @@ public class SysOrgService : IDynamicApiController, ITransient
             var orgList2 = await GetUserRoleOrgIdList(userId);
             // 机构并集
             orgIdList = orgList1.Select(u => u.OrgId).Union(orgList2).ToList();
-            _sysCacheService.SetOrgIdList(userId, orgIdList); // 存缓存
+            _sysCacheService.Set(CacheConst.KeyOrgIdList + userId, orgIdList); // 存缓存
         }
         return orgIdList;
     }
@@ -231,7 +231,7 @@ public class SysOrgService : IDynamicApiController, ITransient
         var orgIdList2 = await GetOrgIdListByDataScope(strongerDataScopeType);
 
         // 缓存当前用户最大角色数据范围
-        _sysCacheService.SetMaxDataScopeType(_userManager.UserId, strongerDataScopeType);
+        _sysCacheService.Set(CacheConst.KeyMaxDataScopeType + _userManager.UserId, strongerDataScopeType);
 
         // 并集机构集合
         return orgIdList1.Union(orgIdList2).ToList();

+ 58 - 2
Admin.NET/Admin.NET.Core/Service/Tenant/SysTenantService.cs

@@ -17,6 +17,8 @@ public class SysTenantService : IDynamicApiController, ITransient
     private readonly SysUserRoleService _sysUserRoleService;
     private readonly SysRoleMenuService _sysRoleMenuService;
     private readonly SysConfigService _sysConfigService;
+    private readonly SysCacheService _sysCacheService;
+    private readonly ISqlSugarClient _db;
 
     public SysTenantService(SqlSugarRepository<SysTenant> tenantRep,
         SqlSugarRepository<SysOrg> orgRep,
@@ -28,7 +30,9 @@ public class SysTenantService : IDynamicApiController, ITransient
         SqlSugarRepository<SysUserRole> userRoleRep,
         SysUserRoleService sysUserRoleService,
         SysRoleMenuService sysRoleMenuService,
-        SysConfigService sysConfigService)
+        SysConfigService sysConfigService,
+        SysCacheService sysCacheService,
+        ISqlSugarClient db)
     {
         _tenantRep = tenantRep;
         _orgRep = orgRep;
@@ -41,6 +45,8 @@ public class SysTenantService : IDynamicApiController, ITransient
         _sysUserRoleService = sysUserRoleService;
         _sysRoleMenuService = sysRoleMenuService;
         _sysConfigService = sysConfigService;
+        _sysCacheService = sysCacheService;
+        _db = db;
     }
 
     /// <summary>
@@ -81,6 +87,7 @@ public class SysTenantService : IDynamicApiController, ITransient
 
         var tenant = input.Adapt<SysTenant>();
         await _tenantRep.InsertAsync(tenant);
+        await UpdateTenantCache();
 
         if (tenant.TenantType == TenantTypeEnum.Db) return;
         await InitNewTenant(tenant);
@@ -167,6 +174,7 @@ public class SysTenantService : IDynamicApiController, ITransient
             throw Oops.Oh(ErrorCodeEnum.D1023);
         var entity = await _tenantRep.GetFirstAsync(u => u.Id == input.Id);
         await _tenantRep.DeleteAsync(entity);
+        await UpdateTenantCache();
 
         // 删除与租户相关的表数据
         var userIds = users.Select(u => u.Id).ToList();
@@ -202,6 +210,7 @@ public class SysTenantService : IDynamicApiController, ITransient
         if (tenantAdminUser == null) return;
         tenantAdminUser.Account = entity.AdminName;
         await _userRep.Context.Updateable(tenantAdminUser).UpdateColumns(u => new { u.Account }).ExecuteCommandAsync();
+        await UpdateTenantCache();
     }
 
     /// <summary>
@@ -262,6 +271,17 @@ public class SysTenantService : IDynamicApiController, ITransient
         await _userRep.UpdateAsync(tenantAdminUser);
     }
 
+    /// <summary>
+    /// 获取租户
+    /// </summary>
+    /// <param name="tenantId"></param>
+    /// <returns></returns>
+    [NonAction]
+    public async Task<SysTenant> GetTenant(long tenantId)
+    {
+        return await _tenantRep.GetFirstAsync(u => u.Id == tenantId);
+    }
+
     /// <summary>
     /// 获取租户管理员用户
     /// </summary>
@@ -269,6 +289,42 @@ public class SysTenantService : IDynamicApiController, ITransient
     /// <returns></returns>
     private async Task<SysUser> GetTenantAdminUser(long tenantId)
     {
-        return await _userRep.AsQueryable().Filter(null, true).Where(u => u.TenantId == tenantId && u.AccountType == AccountTypeEnum.Admin).FirstAsync();
+        return await _userRep.GetFirstAsync(u => u.TenantId == tenantId && u.AccountType == AccountTypeEnum.Admin);
+    }
+
+    /// <summary>
+    /// 缓存所有租户
+    /// </summary>
+    /// <returns></returns>
+    [NonAction]
+    public async Task UpdateTenantCache()
+    {
+        _sysCacheService.Remove(CacheConst.KeyTenant);
+
+        var tenantList = await _tenantRep.GetListAsync();
+        _sysCacheService.Set(CacheConst.KeyTenant, tenantList);
+    }
+
+    /// <summary>
+    /// 创建租户数据库(根据默认库结构)
+    /// </summary>
+    /// <param name="input"></param>
+    /// <returns></returns>
+    [HttpPost("/sysTenant/createDb")]
+    public async Task CreateTenantDb(TenantInput input)
+    {
+        var tenant = await _tenantRep.GetFirstAsync(u => u.Id == input.Id);
+        if (tenant == null) return;
+
+        var dbConnection = new DbConnectionConfig
+        {
+            EnableInitDb = true,
+            DbType = tenant.DbType,
+            ConfigId = tenant.ConfigId,
+            ConnectionString = tenant.Connection,
+            IsAutoCloseConnection = true,
+        };
+
+        SqlSugarSetup.CreateDataBase(_db, dbConnection, tenant.Id);
     }
 }

+ 18 - 26
Admin.NET/Admin.NET.Core/Service/User/UserManager.cs

@@ -5,59 +5,51 @@
 /// </summary>
 public class UserManager : IScoped
 {
-    private readonly SqlSugarRepository<SysUser> _sysUserRep;
     private readonly IHttpContextAccessor _httpContextAccessor;
+    private long _tenantId;
 
     public long UserId
     {
-        get => long.Parse(_httpContextAccessor.HttpContext.User.FindFirst(ClaimConst.UserId)?.Value);
+        get => long.Parse(_httpContextAccessor.HttpContext?.User.FindFirst(ClaimConst.UserId)?.Value);
+    }
+
+    public long TenantId
+    {
+        get
+        {
+            var tId = _httpContextAccessor.HttpContext?.User.FindFirst(ClaimConst.TenantId);
+            return tId == null ? _tenantId : long.Parse(tId.Value);
+        }
+        set => _tenantId = value;
     }
 
     public string Account
     {
-        get => _httpContextAccessor.HttpContext.User.FindFirst(ClaimConst.Account)?.Value;
+        get => _httpContextAccessor.HttpContext?.User.FindFirst(ClaimConst.Account)?.Value;
     }
 
     public string RealName
     {
-        get => _httpContextAccessor.HttpContext.User.FindFirst(ClaimConst.RealName)?.Value;
+        get => _httpContextAccessor.HttpContext?.User.FindFirst(ClaimConst.RealName)?.Value;
     }
 
     public bool SuperAdmin
     {
-        get => _httpContextAccessor.HttpContext.User.FindFirst(ClaimConst.AccountType)?.Value == ((int)AccountTypeEnum.SuperAdmin).ToString();
+        get => _httpContextAccessor.HttpContext?.User.FindFirst(ClaimConst.AccountType)?.Value == ((int)AccountTypeEnum.SuperAdmin).ToString();
     }
 
     public long OrgId
     {
-        get => long.Parse(_httpContextAccessor.HttpContext.User.FindFirst(ClaimConst.OrgId)?.Value);
+        get => long.Parse(_httpContextAccessor.HttpContext?.User.FindFirst(ClaimConst.OrgId)?.Value);
     }
 
     public string OpenId
     {
-        get => _httpContextAccessor.HttpContext.User.FindFirst(ClaimConst.OpenId)?.Value;
+        get => _httpContextAccessor.HttpContext?.User.FindFirst(ClaimConst.OpenId)?.Value;
     }
 
-    public SysUser User
+    public UserManager(IHttpContextAccessor httpContextAccessor)
     {
-        get => _sysUserRep.GetFirst(u => u.Id == UserId);
-    }
-
-    public UserManager(SqlSugarRepository<SysUser> sysUserRep,
-        IHttpContextAccessor httpContextAccessor)
-    {
-        _sysUserRep = sysUserRep;
         _httpContextAccessor = httpContextAccessor;
     }
-
-    /// <summary>
-    /// 获取用户信息
-    /// </summary>
-    /// <param name="userId"></param>
-    /// <returns></returns>
-    public async Task<SysUser> CheckUserAsync(long userId)
-    {
-        var user = await _sysUserRep.GetFirstAsync(u => u.Id == userId);
-        return user ?? throw Oops.Oh(ErrorCodeEnum.D1002);
-    }
 }

+ 23 - 2
Admin.NET/Admin.NET.Core/SqlSugar/SqlSugarRepository.cs

@@ -10,7 +10,28 @@ public class SqlSugarRepository<T> : SimpleClient<T> where T : class, new()
 
     public SqlSugarRepository(ISqlSugarClient context = null) : base(context)
     {
-        iTenant = App.GetService<ISqlSugarClient>().AsTenant();
-        base.Context = iTenant.GetConnectionScopeWithAttr<T>();
+        iTenant = App.GetRequiredService<ISqlSugarClient>().AsTenant();
+
+        // 根据当前租户Id切换数据库
+        var tenantId = App.GetRequiredService<UserManager>().TenantId;
+        if (tenantId > 1)
+        {
+            var tenant = App.GetRequiredService<SysCacheService>().Get<List<SysTenant>>(CacheConst.KeyTenant).FirstOrDefault(u => u.Id == tenantId);
+            if (!iTenant.IsAnyConnection(tenant.ConfigId))
+            {
+                iTenant.AddConnection(new ConnectionConfig()
+                {
+                    ConfigId = tenant.ConfigId,
+                    ConnectionString = tenant.Connection,
+                    DbType = tenant.DbType,
+                    IsAutoCloseConnection = true
+                });
+            }
+            base.Context = iTenant.GetConnectionScope(tenant.ConfigId);
+        }
+        else
+        {
+            base.Context = iTenant.GetConnectionScopeWithAttr<T>();
+        }
     }
 }

+ 200 - 113
Admin.NET/Admin.NET.Core/SqlSugar/SqlSugarSetup.cs

@@ -11,6 +11,34 @@ public static class SqlSugarSetup
     public static void AddSqlSugar(this IServiceCollection services)
     {
         var dbOptions = App.GetOptions<DbConnectionOptions>();
+        dbOptions.ConnectionConfigs.ForEach(config =>
+        {
+            SetDbConfig(config);
+        });
+
+        SqlSugarScope sqlSugar = new(dbOptions.ConnectionConfigs.Adapt<List<ConnectionConfig>>(), client =>
+        {
+            dbOptions.ConnectionConfigs.ForEach(config =>
+            {
+                var db = client.GetConnectionScope((string)config.ConfigId);
+                SetDbAop(db, config);
+            });
+        });
+
+        // 初始化数据库表结构及种子数据
+        InitDataBase(sqlSugar, dbOptions);
+
+        services.AddSingleton<ISqlSugarClient>(sqlSugar); // 单例注册
+        services.AddScoped(typeof(SqlSugarRepository<>)); // 仓储注册
+        services.AddUnitOfWork<SqlSugarUnitOfWork>(); // 注册事务与工作单元
+    }
+
+    /// <summary>
+    /// 配置连接属性
+    /// </summary>
+    /// <param name="config"></param>
+    public static void SetDbConfig(DbConnectionConfig config)
+    {
         var configureExternalServices = new ConfigureExternalServices
         {
             EntityService = (type, column) => // 修改列可空-1、带?问号 2、String类型若没有Required
@@ -21,127 +49,117 @@ public static class SqlSugarSetup
             },
             DataInfoCacheService = new SqlSugarCache(),
         };
-        dbOptions.ConnectionConfigs.ForEach(config =>
+        config.ConfigureExternalServices = configureExternalServices;
+        config.InitKeyType = InitKeyType.Attribute;
+        config.IsAutoCloseConnection = true;
+        config.MoreSettings = new ConnMoreSettings
         {
-            config.ConfigureExternalServices = configureExternalServices;
-            config.InitKeyType = InitKeyType.Attribute;
-            config.IsAutoCloseConnection = true;
-            config.MoreSettings = new ConnMoreSettings
-            {
-                IsAutoRemoveDataCache = true
-            };
-        });
+            IsAutoRemoveDataCache = true
+        };
+    }
 
-        SqlSugarScope sqlSugar = new(dbOptions.ConnectionConfigs.Adapt<List<ConnectionConfig>>(), client =>
-        {
-            dbOptions.ConnectionConfigs.ForEach(config =>
-            {
-                var db = client.GetConnectionScope((string)config.ConfigId);
+    /// <summary>
+    /// 配置Aop
+    /// </summary>
+    /// <param name="db"></param>
+    /// <param name="config"></param>
+    public static void SetDbAop(this SqlSugarScopeProvider db, DbConnectionConfig config)
+    {
+        // 设置超时时间
+        db.Ado.CommandTimeOut = 30;
 
-                // 设置超时时间
-                db.Ado.CommandTimeOut = 30;
+        // 打印SQL语句
+        db.Aop.OnLogExecuting = (sql, pars) =>
+        {
+            if (sql.StartsWith("SELECT", StringComparison.OrdinalIgnoreCase))
+                Console.ForegroundColor = ConsoleColor.Green;
+            if (sql.StartsWith("UPDATE", StringComparison.OrdinalIgnoreCase) || sql.StartsWith("INSERT", StringComparison.OrdinalIgnoreCase))
+                Console.ForegroundColor = ConsoleColor.White;
+            if (sql.StartsWith("DELETE", StringComparison.OrdinalIgnoreCase))
+                Console.ForegroundColor = ConsoleColor.Blue;
+            Console.WriteLine("【" + DateTime.Now + "——执行SQL】\r\n" + UtilMethods.GetSqlString(config.DbType, sql, pars) + "\r\n");
+            App.PrintToMiniProfiler("SqlSugar", "Info", sql + "\r\n" + db.Utilities.SerializeObject(pars.ToDictionary(it => it.ParameterName, it => it.Value)));
+        };
+        db.Aop.OnError = (ex) =>
+        {
+            if (ex.Parametres == null) return;
+            Console.ForegroundColor = ConsoleColor.Red;
+            var pars = db.Utilities.SerializeObject(((SugarParameter[])ex.Parametres).ToDictionary(it => it.ParameterName, it => it.Value));
+            Console.WriteLine("【" + DateTime.Now + "——错误SQL】\r\n" + UtilMethods.GetSqlString(config.DbType, ex.Sql, (SugarParameter[])ex.Parametres) + "\r\n");
+            App.PrintToMiniProfiler("SqlSugar", "Error", $"{ex.Message}{Environment.NewLine}{ex.Sql}{pars}{Environment.NewLine}");
+        };
 
-                // 打印SQL语句
-                db.Aop.OnLogExecuting = (sql, pars) =>
-                {
-                    if (sql.StartsWith("SELECT", StringComparison.OrdinalIgnoreCase))
-                        Console.ForegroundColor = ConsoleColor.Green;
-                    if (sql.StartsWith("UPDATE", StringComparison.OrdinalIgnoreCase) || sql.StartsWith("INSERT", StringComparison.OrdinalIgnoreCase))
-                        Console.ForegroundColor = ConsoleColor.White;
-                    if (sql.StartsWith("DELETE", StringComparison.OrdinalIgnoreCase))
-                        Console.ForegroundColor = ConsoleColor.Blue;
-                    Console.WriteLine("【" + DateTime.Now + "——执行SQL】\r\n" + UtilMethods.GetSqlString(config.DbType, sql, pars) + "\r\n");
-                    App.PrintToMiniProfiler("SqlSugar", "Info", sql + "\r\n" + db.Utilities.SerializeObject(pars.ToDictionary(it => it.ParameterName, it => it.Value)));
-                };
-                db.Aop.OnError = (ex) =>
+        // 数据审计
+        db.Aop.DataExecuting = (oldValue, entityInfo) =>
+        {
+            // 新增操作
+            if (entityInfo.OperationType == DataFilterType.InsertByObject)
+            {
+                // 主键(long类型)且没有值的---赋值雪花Id
+                if (entityInfo.EntityColumnInfo.IsPrimarykey && entityInfo.EntityColumnInfo.PropertyInfo.PropertyType == typeof(long))
                 {
-                    if (ex.Parametres == null) return;
-                    Console.ForegroundColor = ConsoleColor.Red;
-                    var pars = db.Utilities.SerializeObject(((SugarParameter[])ex.Parametres).ToDictionary(it => it.ParameterName, it => it.Value));
-                    Console.WriteLine("【" + DateTime.Now + "——错误SQL】\r\n" + UtilMethods.GetSqlString(config.DbType, ex.Sql, (SugarParameter[])ex.Parametres) + "\r\n");
-                    App.PrintToMiniProfiler("SqlSugar", "Error", $"{ex.Message}{Environment.NewLine}{ex.Sql}{pars}{Environment.NewLine}");
-                };
-
-                // 数据审计
-                db.Aop.DataExecuting = (oldValue, entityInfo) =>
+                    var id = entityInfo.EntityColumnInfo.PropertyInfo.GetValue(entityInfo.EntityValue);
+                    if (id == null || (long)id == 0)
+                        entityInfo.SetValue(Yitter.IdGenerator.YitIdHelper.NextId());
+                }
+                if (entityInfo.PropertyName == "CreateTime")
+                    entityInfo.SetValue(DateTime.Now);
+                if (App.User != null)
                 {
-                    // 新增操作
-                    if (entityInfo.OperationType == DataFilterType.InsertByObject)
+                    if (entityInfo.PropertyName == "TenantId")
                     {
-                        // 主键(long类型)且没有值的---赋值雪花Id
-                        if (entityInfo.EntityColumnInfo.IsPrimarykey && entityInfo.EntityColumnInfo.PropertyInfo.PropertyType == typeof(long))
-                        {
-                            var id = entityInfo.EntityColumnInfo.PropertyInfo.GetValue(entityInfo.EntityValue);
-                            if (id == null || (long)id == 0)
-                                entityInfo.SetValue(Yitter.IdGenerator.YitIdHelper.NextId());
-                        }
-                        if (entityInfo.PropertyName == "CreateTime")
-                            entityInfo.SetValue(DateTime.Now);
-                        if (App.User != null)
-                        {
-                            if (entityInfo.PropertyName == "TenantId")
-                            {
-                                var tenantId = ((dynamic)entityInfo.EntityValue).TenantId;
-                                if (tenantId == null || tenantId == 0)
-                                    entityInfo.SetValue(App.User.FindFirst(ClaimConst.TenantId)?.Value);
-                            }
-                            if (entityInfo.PropertyName == "CreateUserId")
-                                entityInfo.SetValue(App.User.FindFirst(ClaimConst.UserId)?.Value);
-                            if (entityInfo.PropertyName == "CreateOrgId")
-                                entityInfo.SetValue(App.User.FindFirst(ClaimConst.OrgId)?.Value);
-                        }
+                        var tenantId = ((dynamic)entityInfo.EntityValue).TenantId;
+                        if (tenantId == null || tenantId == 0)
+                            entityInfo.SetValue(App.User.FindFirst(ClaimConst.TenantId)?.Value);
                     }
-                    // 更新操作
-                    if (entityInfo.OperationType == DataFilterType.UpdateByObject)
-                    {
-                        if (entityInfo.PropertyName == "UpdateTime")
-                            entityInfo.SetValue(DateTime.Now);
-                        if (entityInfo.PropertyName == "UpdateUserId")
-                            entityInfo.SetValue(App.User?.FindFirst(ClaimConst.UserId)?.Value);
-                    }
-                };
-
-                // 差异日志
-                db.Aop.OnDiffLogEvent = async u =>
-                {
-                    if (!config.EnableDiffLog) return;
-
-                    var LogDiff = new SysLogDiff
-                    {
-                        // 操作后记录(字段描述、列名、值、表名、表描述)
-                        AfterData = JsonConvert.SerializeObject(u.AfterData),
-                        // 操作前记录(字段描述、列名、值、表名、表描述)
-                        BeforeData = JsonConvert.SerializeObject(u.BeforeData),
-                        // 传进来的对象
-                        BusinessData = JsonConvert.SerializeObject(u.BusinessData),
-                        // 枚举(insert、update、delete)
-                        DiffType = u.DiffType.ToString(),
-                        Sql = UtilMethods.GetSqlString(config.DbType, u.Sql, u.Parameters),
-                        Parameters = JsonConvert.SerializeObject(u.Parameters),
-                        Duration = u.Time == null ? 0 : (long)u.Time.Value.TotalMilliseconds
-                    };
-                    await client.GetConnectionScope(SqlSugarConst.ConfigId).Insertable(LogDiff).ExecuteCommandAsync();
-                    Console.ForegroundColor = ConsoleColor.Red;
-                    Console.WriteLine(DateTime.Now + $"\r\n**********差异日志开始**********\r\n{Environment.NewLine}{JsonConvert.SerializeObject(LogDiff)}{Environment.NewLine}**********差异日志结束**********\r\n");
-                };
-
-                // 配置实体假删除过滤器
-                SetDeletedEntityFilter(db);
-                // 配置租户过滤器
-                SetTenantEntityFilter(db);
-                // 配置用户机构范围过滤器
-                SetOrgEntityFilter(db);
-                // 配置自定义过滤器
-                SetCustomEntityFilter(db);
-            });
-        });
-
-        // 初始化数据库表结构及种子数据
-        InitDataBase(sqlSugar, dbOptions);
+                    if (entityInfo.PropertyName == "CreateUserId")
+                        entityInfo.SetValue(App.User.FindFirst(ClaimConst.UserId)?.Value);
+                    if (entityInfo.PropertyName == "CreateOrgId")
+                        entityInfo.SetValue(App.User.FindFirst(ClaimConst.OrgId)?.Value);
+                }
+            }
+            // 更新操作
+            if (entityInfo.OperationType == DataFilterType.UpdateByObject)
+            {
+                if (entityInfo.PropertyName == "UpdateTime")
+                    entityInfo.SetValue(DateTime.Now);
+                if (entityInfo.PropertyName == "UpdateUserId")
+                    entityInfo.SetValue(App.User?.FindFirst(ClaimConst.UserId)?.Value);
+            }
+        };
 
-        services.AddSingleton<ISqlSugarClient>(sqlSugar); // 单例注册
-        services.AddScoped(typeof(SqlSugarRepository<>)); // 注册仓储
-        services.AddUnitOfWork<SqlSugarUnitOfWork>(); // 注册事务与工作单元
+        //// 差异日志
+        //db.Aop.OnDiffLogEvent = async u =>
+        //{
+        //    if (!config.EnableDiffLog) return;
+
+        //    var LogDiff = new SysLogDiff
+        //    {
+        //        // 操作后记录(字段描述、列名、值、表名、表描述)
+        //        AfterData = JsonConvert.SerializeObject(u.AfterData),
+        //        // 操作前记录(字段描述、列名、值、表名、表描述)
+        //        BeforeData = JsonConvert.SerializeObject(u.BeforeData),
+        //        // 传进来的对象
+        //        BusinessData = JsonConvert.SerializeObject(u.BusinessData),
+        //        // 枚举(insert、update、delete)
+        //        DiffType = u.DiffType.ToString(),
+        //        Sql = UtilMethods.GetSqlString(config.DbType, u.Sql, u.Parameters),
+        //        Parameters = JsonConvert.SerializeObject(u.Parameters),
+        //        Duration = u.Time == null ? 0 : (long)u.Time.Value.TotalMilliseconds
+        //    };
+        //    await client.GetConnectionScope(SqlSugarConst.ConfigId).Insertable(LogDiff).ExecuteCommandAsync();
+        //    Console.ForegroundColor = ConsoleColor.Red;
+        //    Console.WriteLine(DateTime.Now + $"\r\n**********差异日志开始**********\r\n{Environment.NewLine}{JsonConvert.SerializeObject(LogDiff)}{Environment.NewLine}**********差异日志结束**********\r\n");
+        //};
+
+        // 配置实体假删除过滤器
+        SetDeletedEntityFilter(db);
+        // 配置租户过滤器
+        SetTenantEntityFilter(db);
+        // 配置用户机构范围过滤器
+        SetOrgEntityFilter(db);
+        // 配置自定义过滤器
+        SetCustomEntityFilter(db);
     }
 
     /// <summary>
@@ -208,6 +226,75 @@ public static class SqlSugarSetup
         }
     }
 
+    /// <summary>
+    /// 初始化数据库结构
+    /// </summary>
+    public static void CreateDataBase(ISqlSugarClient db, DbConnectionConfig config, long tenantId)
+    {
+        SetDbConfig(config);
+
+        var itenant = db.AsTenant();
+        // 创建数据库
+        if (!config.EnableInitDb || config.DbType == SqlSugar.DbType.Oracle) return;
+        itenant.AddConnection(config);
+        var dbProvider = itenant.GetConnectionScope(config.ConfigId);
+        SetDbAop(dbProvider, config);
+        dbProvider.DbMaintenance.CreateDatabase();
+
+        // 获取所有实体表-初始化表结构
+        var entityTypes = App.EffectiveTypes.Where(u => !u.IsInterface && !u.IsAbstract && u.IsClass
+            && u.IsDefined(typeof(SugarTable), false) && !u.IsDefined(typeof(NotTableAttribute), false));
+        if (!entityTypes.Any()) return;
+        foreach (var entityType in entityTypes)
+        {
+            var tAtt = entityType.GetCustomAttribute<TenantAttribute>();
+            if (tAtt != null) continue;
+            var db2 = itenant.GetConnectionScope(config.ConfigId);
+            var splitTable = entityType.GetCustomAttribute<SplitTableAttribute>();
+            if (splitTable == null)
+                db2.CodeFirst.InitTables(entityType);
+            else
+                db2.CodeFirst.SplitTables().InitTables(entityType);
+        }
+
+        // 获取所有种子配置-初始化数据
+        var seedDataTypes = App.EffectiveTypes.Where(u => !u.IsInterface && !u.IsAbstract && u.IsClass
+            && u.GetInterfaces().Any(i => i.HasImplementedRawGeneric(typeof(ISqlSugarEntitySeedData<>))));
+        if (!seedDataTypes.Any()) return;
+        foreach (var seedType in seedDataTypes)
+        {
+            var instance = Activator.CreateInstance(seedType);
+
+            var hasDataMethod = seedType.GetMethod("HasData");
+            var seedData = ((IEnumerable)hasDataMethod?.Invoke(instance, null))?.Cast<object>();
+            if (seedData == null) continue;
+
+            var entityType = seedType.GetInterfaces().First().GetGenericArguments().First();
+            var tAtt = entityType.GetCustomAttribute<TenantAttribute>();
+            if (tAtt != null) continue;
+            var db2 = itenant.GetConnectionScope(config.ConfigId);
+            var seedDataTable = seedData.ToList().ToDataTable();
+            seedDataTable.TableName = db.EntityMaintenance.GetEntityInfo(entityType).DbTableName;
+            // 设置租户Id
+            if (seedDataTable.Columns.Contains(SqlSugarConst.TenantId))
+            {
+                foreach (DataRow dr in seedDataTable.Rows)                
+                    dr[SqlSugarConst.TenantId] = tenantId;                
+            }
+            if (seedDataTable.Columns.Contains(SqlSugarConst.PrimaryKey))
+            {
+                var storage = db2.Storageable(seedDataTable).WhereColumns(SqlSugarConst.PrimaryKey).ToStorage();
+                storage.AsInsertable.ExecuteCommand();
+                storage.AsUpdateable.ExecuteCommand();
+            }
+            else // 没有主键或者不是预定义的主键(没主键有重复的可能)
+            {
+                var storage = db2.Storageable(seedDataTable).ToStorage();
+                storage.AsInsertable.ExecuteCommand();
+            }
+        }
+    }
+
     /// <summary>
     /// 配置实体假删除过滤器
     /// </summary>
@@ -305,7 +392,7 @@ public static class SqlSugarSetup
         if (tableFilterItemList == null)
         {
             // 获取用户所属机构
-            var orgIds = App.GetService<SysCacheService>().GetOrgIdList(long.Parse(userId));
+            var orgIds = App.GetService<SysCacheService>().Get<List<long>>(CacheConst.KeyOrgIdList + userId);
             if (orgIds == null || orgIds.Count == 0) return;
 
             // 获取业务实体数据表

+ 2 - 1
Admin.NET/Admin.NET.Web.Core/Startup.cs

@@ -1,4 +1,5 @@
 using Admin.NET.Core;
+using Admin.NET.Core.Service;
 using AspNetCoreRateLimit;
 using Furion;
 using Furion.SpecificationDocument;
@@ -21,7 +22,7 @@ namespace Admin.NET.Web.Core;
 
 public class Startup : AppStartup
 {
-    public void ConfigureServices(IServiceCollection services)
+    public async void ConfigureServices(IServiceCollection services)
     {
         // 配置选项
         services.AddProjectOptions();

+ 32 - 32
Web/src/api-services/apis/sys-cache-api.ts

@@ -207,13 +207,12 @@ export const SysCacheApiAxiosParamCreator = function (configuration?: Configurat
         },
         /**
          * 
-         * @summary 获取缓存
-         * @param {string} [cacheKey] 
+         * @summary 获取所有缓存键名
          * @param {*} [options] Override http request option.
          * @throws {RequiredError}
          */
-        sysCacheDetailGet: async (cacheKey?: string, options: AxiosRequestConfig = {}): Promise<RequestArgs> => {
-            const localVarPath = `/sysCache/detail`;
+        sysCacheKeyListGet: async (options: AxiosRequestConfig = {}): Promise<RequestArgs> => {
+            const localVarPath = `/sysCache/keyList`;
             // use dummy base URL string because the URL constructor only accepts absolute URLs.
             const localVarUrlObj = new URL(localVarPath, 'https://example.com');
             let baseOptions;
@@ -226,10 +225,6 @@ export const SysCacheApiAxiosParamCreator = function (configuration?: Configurat
 
             // authentication Bearer required
 
-            if (cacheKey !== undefined) {
-                localVarQueryParameter['cacheKey'] = cacheKey;
-            }
-
             const query = new URLSearchParams(localVarUrlObj.search);
             for (const key in localVarQueryParameter) {
                 query.set(key, localVarQueryParameter[key]);
@@ -248,12 +243,13 @@ export const SysCacheApiAxiosParamCreator = function (configuration?: Configurat
         },
         /**
          * 
-         * @summary 获取所有缓存键名
+         * @summary 获取缓存值
+         * @param {string} [key] 
          * @param {*} [options] Override http request option.
          * @throws {RequiredError}
          */
-        sysCacheKeyListGet: async (options: AxiosRequestConfig = {}): Promise<RequestArgs> => {
-            const localVarPath = `/sysCache/keyList`;
+        sysCacheValueGet: async (key?: string, options: AxiosRequestConfig = {}): Promise<RequestArgs> => {
+            const localVarPath = `/sysCache/value`;
             // use dummy base URL string because the URL constructor only accepts absolute URLs.
             const localVarUrlObj = new URL(localVarPath, 'https://example.com');
             let baseOptions;
@@ -266,6 +262,10 @@ export const SysCacheApiAxiosParamCreator = function (configuration?: Configurat
 
             // authentication Bearer required
 
+            if (key !== undefined) {
+                localVarQueryParameter['key'] = key;
+            }
+
             const query = new URLSearchParams(localVarUrlObj.search);
             for (const key in localVarQueryParameter) {
                 query.set(key, localVarQueryParameter[key]);
@@ -352,13 +352,12 @@ export const SysCacheApiFp = function(configuration?: Configuration) {
         },
         /**
          * 
-         * @summary 获取缓存
-         * @param {string} [cacheKey] 
+         * @summary 获取所有缓存键名
          * @param {*} [options] Override http request option.
          * @throws {RequiredError}
          */
-        async sysCacheDetailGet(cacheKey?: string, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => Promise<AxiosResponse<AdminResultObject>>> {
-            const localVarAxiosArgs = await SysCacheApiAxiosParamCreator(configuration).sysCacheDetailGet(cacheKey, options);
+        async sysCacheKeyListGet(options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => Promise<AxiosResponse<AdminResultListString>>> {
+            const localVarAxiosArgs = await SysCacheApiAxiosParamCreator(configuration).sysCacheKeyListGet(options);
             return (axios: AxiosInstance = globalAxios, basePath: string = BASE_PATH) => {
                 const axiosRequestArgs :AxiosRequestConfig = {...localVarAxiosArgs.options, url: basePath + localVarAxiosArgs.url};
                 return axios.request(axiosRequestArgs);
@@ -366,12 +365,13 @@ export const SysCacheApiFp = function(configuration?: Configuration) {
         },
         /**
          * 
-         * @summary 获取所有缓存键名
+         * @summary 获取缓存值
+         * @param {string} [key] 
          * @param {*} [options] Override http request option.
          * @throws {RequiredError}
          */
-        async sysCacheKeyListGet(options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => Promise<AxiosResponse<AdminResultListString>>> {
-            const localVarAxiosArgs = await SysCacheApiAxiosParamCreator(configuration).sysCacheKeyListGet(options);
+        async sysCacheValueGet(key?: string, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => Promise<AxiosResponse<AdminResultObject>>> {
+            const localVarAxiosArgs = await SysCacheApiAxiosParamCreator(configuration).sysCacheValueGet(key, options);
             return (axios: AxiosInstance = globalAxios, basePath: string = BASE_PATH) => {
                 const axiosRequestArgs :AxiosRequestConfig = {...localVarAxiosArgs.options, url: basePath + localVarAxiosArgs.url};
                 return axios.request(axiosRequestArgs);
@@ -431,22 +431,22 @@ export const SysCacheApiFactory = function (configuration?: Configuration, baseP
         },
         /**
          * 
-         * @summary 获取缓存
-         * @param {string} [cacheKey] 
+         * @summary 获取所有缓存键名
          * @param {*} [options] Override http request option.
          * @throws {RequiredError}
          */
-        async sysCacheDetailGet(cacheKey?: string, options?: AxiosRequestConfig): Promise<AxiosResponse<AdminResultObject>> {
-            return SysCacheApiFp(configuration).sysCacheDetailGet(cacheKey, options).then((request) => request(axios, basePath));
+        async sysCacheKeyListGet(options?: AxiosRequestConfig): Promise<AxiosResponse<AdminResultListString>> {
+            return SysCacheApiFp(configuration).sysCacheKeyListGet(options).then((request) => request(axios, basePath));
         },
         /**
          * 
-         * @summary 获取所有缓存键名
+         * @summary 获取缓存值
+         * @param {string} [key] 
          * @param {*} [options] Override http request option.
          * @throws {RequiredError}
          */
-        async sysCacheKeyListGet(options?: AxiosRequestConfig): Promise<AxiosResponse<AdminResultListString>> {
-            return SysCacheApiFp(configuration).sysCacheKeyListGet(options).then((request) => request(axios, basePath));
+        async sysCacheValueGet(key?: string, options?: AxiosRequestConfig): Promise<AxiosResponse<AdminResultObject>> {
+            return SysCacheApiFp(configuration).sysCacheValueGet(key, options).then((request) => request(axios, basePath));
         },
     };
 };
@@ -507,23 +507,23 @@ export class SysCacheApi extends BaseAPI {
     }
     /**
      * 
-     * @summary 获取缓存
-     * @param {string} [cacheKey] 
+     * @summary 获取所有缓存键名
      * @param {*} [options] Override http request option.
      * @throws {RequiredError}
      * @memberof SysCacheApi
      */
-    public async sysCacheDetailGet(cacheKey?: string, options?: AxiosRequestConfig) : Promise<AxiosResponse<AdminResultObject>> {
-        return SysCacheApiFp(this.configuration).sysCacheDetailGet(cacheKey, options).then((request) => request(this.axios, this.basePath));
+    public async sysCacheKeyListGet(options?: AxiosRequestConfig) : Promise<AxiosResponse<AdminResultListString>> {
+        return SysCacheApiFp(this.configuration).sysCacheKeyListGet(options).then((request) => request(this.axios, this.basePath));
     }
     /**
      * 
-     * @summary 获取所有缓存键名
+     * @summary 获取缓存值
+     * @param {string} [key] 
      * @param {*} [options] Override http request option.
      * @throws {RequiredError}
      * @memberof SysCacheApi
      */
-    public async sysCacheKeyListGet(options?: AxiosRequestConfig) : Promise<AxiosResponse<AdminResultListString>> {
-        return SysCacheApiFp(this.configuration).sysCacheKeyListGet(options).then((request) => request(this.axios, this.basePath));
+    public async sysCacheValueGet(key?: string, options?: AxiosRequestConfig) : Promise<AxiosResponse<AdminResultObject>> {
+        return SysCacheApiFp(this.configuration).sysCacheValueGet(key, options).then((request) => request(this.axios, this.basePath));
     }
 }

+ 76 - 0
Web/src/api-services/apis/sys-tenant-api.ts

@@ -71,6 +71,47 @@ export const SysTenantApiAxiosParamCreator = function (configuration?: Configura
                 options: localVarRequestOptions,
             };
         },
+        /**
+         * 
+         * @summary 创建租户数据库(根据默认库结构)
+         * @param {TenantInput} [body] 
+         * @param {*} [options] Override http request option.
+         * @throws {RequiredError}
+         */
+        sysTenantCreateDbPost: async (body?: TenantInput, options: AxiosRequestConfig = {}): Promise<RequestArgs> => {
+            const localVarPath = `/sysTenant/createDb`;
+            // use dummy base URL string because the URL constructor only accepts absolute URLs.
+            const localVarUrlObj = new URL(localVarPath, 'https://example.com');
+            let baseOptions;
+            if (configuration) {
+                baseOptions = configuration.baseOptions;
+            }
+            const localVarRequestOptions :AxiosRequestConfig = { method: 'POST', ...baseOptions, ...options};
+            const localVarHeaderParameter = {} as any;
+            const localVarQueryParameter = {} as any;
+
+            // authentication Bearer required
+
+            localVarHeaderParameter['Content-Type'] = 'application/json-patch+json';
+
+            const query = new URLSearchParams(localVarUrlObj.search);
+            for (const key in localVarQueryParameter) {
+                query.set(key, localVarQueryParameter[key]);
+            }
+            for (const key in options.params) {
+                query.set(key, options.params[key]);
+            }
+            localVarUrlObj.search = (new URLSearchParams(query)).toString();
+            let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {};
+            localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers};
+            const needsSerialization = (typeof body !== "string") || localVarRequestOptions.headers['Content-Type'] === 'application/json';
+            localVarRequestOptions.data =  needsSerialization ? JSON.stringify(body !== undefined ? body : {}) : (body || "");
+
+            return {
+                url: localVarUrlObj.pathname + localVarUrlObj.search + localVarUrlObj.hash,
+                options: localVarRequestOptions,
+            };
+        },
         /**
          * 
          * @summary 删除租户
@@ -419,6 +460,20 @@ export const SysTenantApiFp = function(configuration?: Configuration) {
                 return axios.request(axiosRequestArgs);
             };
         },
+        /**
+         * 
+         * @summary 创建租户数据库(根据默认库结构)
+         * @param {TenantInput} [body] 
+         * @param {*} [options] Override http request option.
+         * @throws {RequiredError}
+         */
+        async sysTenantCreateDbPost(body?: TenantInput, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => Promise<AxiosResponse<void>>> {
+            const localVarAxiosArgs = await SysTenantApiAxiosParamCreator(configuration).sysTenantCreateDbPost(body, options);
+            return (axios: AxiosInstance = globalAxios, basePath: string = BASE_PATH) => {
+                const axiosRequestArgs :AxiosRequestConfig = {...localVarAxiosArgs.options, url: basePath + localVarAxiosArgs.url};
+                return axios.request(axiosRequestArgs);
+            };
+        },
         /**
          * 
          * @summary 删除租户
@@ -542,6 +597,16 @@ export const SysTenantApiFactory = function (configuration?: Configuration, base
         async sysTenantAddPost(body?: AddTenantInput, options?: AxiosRequestConfig): Promise<AxiosResponse<void>> {
             return SysTenantApiFp(configuration).sysTenantAddPost(body, options).then((request) => request(axios, basePath));
         },
+        /**
+         * 
+         * @summary 创建租户数据库(根据默认库结构)
+         * @param {TenantInput} [body] 
+         * @param {*} [options] Override http request option.
+         * @throws {RequiredError}
+         */
+        async sysTenantCreateDbPost(body?: TenantInput, options?: AxiosRequestConfig): Promise<AxiosResponse<void>> {
+            return SysTenantApiFp(configuration).sysTenantCreateDbPost(body, options).then((request) => request(axios, basePath));
+        },
         /**
          * 
          * @summary 删除租户
@@ -639,6 +704,17 @@ export class SysTenantApi extends BaseAPI {
     public async sysTenantAddPost(body?: AddTenantInput, options?: AxiosRequestConfig) : Promise<AxiosResponse<void>> {
         return SysTenantApiFp(this.configuration).sysTenantAddPost(body, options).then((request) => request(this.axios, this.basePath));
     }
+    /**
+     * 
+     * @summary 创建租户数据库(根据默认库结构)
+     * @param {TenantInput} [body] 
+     * @param {*} [options] Override http request option.
+     * @throws {RequiredError}
+     * @memberof SysTenantApi
+     */
+    public async sysTenantCreateDbPost(body?: TenantInput, options?: AxiosRequestConfig) : Promise<AxiosResponse<void>> {
+        return SysTenantApiFp(this.configuration).sysTenantCreateDbPost(body, options).then((request) => request(this.axios, this.basePath));
+    }
     /**
      * 
      * @summary 删除租户

+ 1 - 1
Web/src/views/system/cache/index.vue

@@ -119,7 +119,7 @@ export default defineComponent({
 
 			currentNode.value = node;
 			state.loading1 = true;
-			var res = await getAPI(SysCacheApi).sysCacheDetailGet(node.id);
+			var res = await getAPI(SysCacheApi).sysCacheValueGet(node.id);
 			state.cacheValue = res.data.result;
 			state.loading1 = false;
 		};

+ 16 - 1
Web/src/views/system/tenant/index.vue

@@ -57,7 +57,7 @@
 				<el-table-column prop="remark" label="备注" show-overflow-tooltip />
 				<el-table-column label="操作" width="180" fixed="right" align="center" show-overflow-tooltip>
 					<template #default="scope">
-						<el-button icon="ele-Coin" size="small" text type="danger" @click="openEditTenant(scope.row)" v-auth="'sysTenant:createDb'" :disabled="scope.row.tenantType == 0"> 生成库 </el-button>
+						<el-button icon="ele-Coin" size="small" text type="danger" @click="createTenant(scope.row)" v-auth="'sysTenant:createDb'" :disabled="scope.row.tenantType == 0"> 创建库 </el-button>
 						<el-button icon="ele-Edit" size="small" text type="primary" @click="openEditTenant(scope.row)" v-auth="'sysTenant:update'"> 编辑 </el-button>
 						<el-dropdown>
 							<el-button icon="ele-MoreFilled" size="small" text type="primary" style="padding-left: 12px" />
@@ -195,6 +195,20 @@ export default defineComponent({
 			state.tableParams.page = val;
 			handleQuery();
 		};
+		// 创建租户库
+		const createTenant = (row: any) => {
+			ElMessageBox.confirm(`确定创建/更新数据库:【${row.name}】?`, '提示', {
+				confirmButtonText: '确定',
+				cancelButtonText: '取消',
+				type: 'warning',
+			})
+				.then(async () => {
+					await getAPI(SysTenantApi).sysTenantCreateDbPost({ id: row.id });
+					handleQuery();
+					ElMessage.success('创建/更新数据库成功');
+				})
+				.catch(() => {});
+		};
 		return {
 			handleQuery,
 			resetQuery,
@@ -207,6 +221,7 @@ export default defineComponent({
 			delTenant,
 			handleSizeChange,
 			handleCurrentChange,
+			createTenant,
 			...toRefs(state),
 		};
 	},