Browse Source

更新1.5.0

升级 后端目标框架到.Net 5.0,FreeSql到1.10.3,其它Nuget包到当前最新版本。

升级 前端脚手架vue-cli到4.5.8,vue到2.6.12,element-ui到2.14.1,其它npm包到当前最新版本。

新增 租户管理界面

新增 支持多数据库操作

新增 对话框及其遮罩支持内嵌界面

新增 抽屉窗口及其遮罩支持内嵌界面

更新 admin数据包data.json更新并增加租户演示数据

优化 表索引命名自动读取表名称

优化 后端Api权限验证增加HttpMethod校验

修复 使用动态路径(path/:id),菜单标题组无法显示的问题

修复 用户登录成功后获取登录信息为空无提示的问题

修复 axios get请求通过config配置无法生效的问题

修复 用户权限缓存数据获取失败后,无法正常访问的问题

调整 处理请求和响应的配置统一使用config:{api:{}}
xiaoxue 4 năm trước cách đây
mục cha
commit
a10529481a
85 tập tin đã thay đổi với 1701 bổ sung193 xóa
  1. 1 1
      .github/workflows/gitee-sync.yml
  2. 15 14
      Admin.Core.Common/Admin.Core.Common.csproj
  3. 1 1
      Admin.Core.Common/Attributes/TransactionAttribute.cs
  4. 5 0
      Admin.Core.Common/Auth/ClaimAttributes.cs
  5. 5 0
      Admin.Core.Common/Auth/IUser.cs
  6. 16 0
      Admin.Core.Common/Auth/User.cs
  7. 13 4
      Admin.Core.Common/BaseModel/Entity.cs
  8. 2 2
      Admin.Core.Common/BaseModel/EntityAdd.cs
  9. 15 5
      Admin.Core.Common/BaseModel/EntityFull.cs
  10. 2 2
      Admin.Core.Common/BaseModel/EntityUpdate.cs
  11. 1 1
      Admin.Core.Common/BaseModel/IEntityAdd.cs
  12. 1 1
      Admin.Core.Common/BaseModel/IEntityUpdate.cs
  13. 11 0
      Admin.Core.Common/BaseModel/ITenant.cs
  14. 24 0
      Admin.Core.Common/Configs/AppConfig.cs
  15. 26 0
      Admin.Core.Common/Configs/DbConfig.cs
  16. 9 0
      Admin.Core.Common/Dbs/MySqlDb.cs
  17. 0 10
      Admin.Core.Common/Output/OptionOutput.cs
  18. 3 3
      Admin.Core.Model/Admin.Core.Model.csproj
  19. 2 2
      Admin.Core.Model/Admin/ApiEntity.cs
  20. 2 2
      Admin.Core.Model/Admin/DictionaryEntity.cs
  21. 2 2
      Admin.Core.Model/Admin/DocumentEntity.cs
  22. 1 1
      Admin.Core.Model/Admin/DocumentImageEntity.cs
  23. 7 1
      Admin.Core.Model/Admin/LogAbstract.cs
  24. 2 2
      Admin.Core.Model/Admin/PermissionEntity.cs
  25. 2 2
      Admin.Core.Model/Admin/RoleEntity.cs
  26. 1 1
      Admin.Core.Model/Admin/RolePermissionEntity.cs
  27. 57 0
      Admin.Core.Model/Admin/TenantEntity.cs
  28. 8 2
      Admin.Core.Model/Admin/UserEntity.cs
  29. 1 1
      Admin.Core.Model/Admin/UserRoleEntity.cs
  30. 2 2
      Admin.Core.Model/Admin/ViewEntity.cs
  31. 3 3
      Admin.Core.Repository/Admin.Core.Repository.csproj
  32. 2 2
      Admin.Core.Repository/Admin/Api/ApiRepository.cs
  33. 2 3
      Admin.Core.Repository/Admin/Dictionary/DictionaryRepository.cs
  34. 2 3
      Admin.Core.Repository/Admin/Document/DocumentRepository.cs
  35. 2 3
      Admin.Core.Repository/Admin/DocumentImage/DocumentImageRepository.cs
  36. 1 3
      Admin.Core.Repository/Admin/LoginLog/LoginLogRepository.cs
  37. 1 1
      Admin.Core.Repository/Admin/OprationLog/IOprationLogRepository.cs
  38. 1 2
      Admin.Core.Repository/Admin/OprationLog/OprationLogRepository.cs
  39. 2 3
      Admin.Core.Repository/Admin/Permission/PermissionRepository.cs
  40. 1 2
      Admin.Core.Repository/Admin/Role/RoleRepository.cs
  41. 1 2
      Admin.Core.Repository/Admin/RolePermission/RolePermissionRepository.cs
  42. 8 0
      Admin.Core.Repository/Admin/Tenant/ITenantRepository.cs
  43. 12 0
      Admin.Core.Repository/Admin/Tenant/TenantRepository.cs
  44. 1 2
      Admin.Core.Repository/Admin/User/UserRepository.cs
  45. 1 2
      Admin.Core.Repository/Admin/UserRole/UserRoleRepository.cs
  46. 1 2
      Admin.Core.Repository/Admin/View/ViewRepositoryRepository.cs
  47. 14 0
      Admin.Core.Repository/Base/IdleBusExtesions.cs
  48. 14 0
      Admin.Core.Repository/Base/MyUnitOfWorkManager.cs
  49. 5 5
      Admin.Core.Repository/Base/RepositoryBase.cs
  50. 3 3
      Admin.Core.Services/Admin.Core.Service.csproj
  51. 5 1
      Admin.Core.Services/Admin/Auth/AuthService.cs
  52. 5 0
      Admin.Core.Services/Admin/Auth/Output/AuthLoginOutput.cs
  53. 2 2
      Admin.Core.Services/Admin/Dictionary/DictionaryService.cs
  54. 1 0
      Admin.Core.Services/Admin/OprationLog/OprationLogService.cs
  55. 25 0
      Admin.Core.Services/Admin/Tenant/ITenantService.cs
  56. 44 0
      Admin.Core.Services/Admin/Tenant/Input/TenantAddInput.cs
  57. 18 0
      Admin.Core.Services/Admin/Tenant/Input/TenantUpdateInput.cs
  58. 8 0
      Admin.Core.Services/Admin/Tenant/Output/TenantGetOutput.cs
  59. 59 0
      Admin.Core.Services/Admin/Tenant/Output/TenantListOutput.cs
  60. 106 0
      Admin.Core.Services/Admin/Tenant/TenantService.cs
  61. 18 0
      Admin.Core.Services/Admin/Tenant/_MapConfig.cs
  62. 1 1
      Admin.Core.Services/Admin/User/IUserService.cs
  63. 9 0
      Admin.Core.Services/Admin/User/Output/UserPermissionsOutput.cs
  64. 14 9
      Admin.Core.Services/Admin/User/UserService.cs
  65. 3 3
      Admin.Core.Tests/Admin.Core.Tests.csproj
  66. 103 23
      Admin.Core/Admin.Core.Common.xml
  67. 50 0
      Admin.Core/Admin.Core.Model.xml
  68. 115 0
      Admin.Core/Admin.Core.Service.xml
  69. 8 7
      Admin.Core/Admin.Core.csproj
  70. 98 1
      Admin.Core/Admin.Core.xml
  71. 3 3
      Admin.Core/Aop/TransactionInterceptor.cs
  72. 6 5
      Admin.Core/Auth/PermissionHandler.cs
  73. 2 1
      Admin.Core/Controllers/Admin/AuthController.cs
  74. 89 0
      Admin.Core/Controllers/Admin/TenantController.cs
  75. 32 6
      Admin.Core/Db/DBServiceCollectionExtensions.cs
  76. 2 0
      Admin.Core/Db/Data.cs
  77. 0 0
      Admin.Core/Db/Data/data.json
  78. 36 20
      Admin.Core/Db/DbHelper.cs
  79. 116 0
      Admin.Core/Db/TenantDBServiceCollectionExtensions.cs
  80. 381 0
      Admin.Core/Db/TenantDbHelper.cs
  81. 2 2
      Admin.Core/Program.cs
  82. 8 1
      Admin.Core/Startup.cs
  83. 2 0
      Admin.Core/configs/appconfig.json
  84. 2 2
      Admin.Core/configs/cacheconfig.json
  85. 14 3
      Admin.Core/configs/dbconfig.json

+ 1 - 1
.github/workflows/gitee-sync.yml

@@ -11,7 +11,7 @@ jobs:
             - name: Sync to Gitee 💕
               uses: wearerequired/git-mirror-action@master
               env:
-                  SSH_PRIVATE_KEY: ${{ secrets.SSH_PRIVATE_KEY }}
+                  SSH_PRIVATE_KEY: ${{ secrets.SSH_PRIVATE_KEY_HOME }}
               with:
                   source-repo: "git@github.com:zhontai/Admin.Core.git"
                   destination-repo: "git@gitee.com:zhontai/Admin.Core.git"

+ 15 - 14
Admin.Core.Common/Admin.Core.Common.csproj

@@ -1,9 +1,9 @@
 <Project Sdk="Microsoft.NET.Sdk">
 
   <PropertyGroup>
-    <TargetFramework>netcoreapp3.1</TargetFramework>
-    <GeneratePackageOnBuild>true</GeneratePackageOnBuild>
-    <Version>1.4.1</Version>
+    <TargetFramework>net5.0</TargetFramework>
+    <GeneratePackageOnBuild>false</GeneratePackageOnBuild>
+    <Version>1.5.0</Version>
     <Authors>xiaoxue</Authors>
     <Company>xiaoxue</Company>
     <Description>中台Admin后端通用库</Description>
@@ -22,19 +22,20 @@
 
   <ItemGroup>
     <PackageReference Include="CSRedisCore" Version="3.6.5" />
-    <PackageReference Include="FreeSql" Version="1.10.1" />
-    <PackageReference Include="FreeSql.Provider.MySql" Version="1.10.1" />
-    <PackageReference Include="FreeSql.Provider.Oracle" Version="1.10.1" />
-    <PackageReference Include="FreeSql.Provider.PostgreSQL" Version="1.10.1" />
-    <PackageReference Include="FreeSql.Provider.Sqlite" Version="1.10.1" />
-    <PackageReference Include="FreeSql.Provider.SqlServer" Version="1.10.1" />
-    <PackageReference Include="FreeSql.Repository" Version="1.10.1" />
+    <PackageReference Include="FreeSql" Version="1.10.3" />
+    <PackageReference Include="FreeSql.Provider.MySql" Version="1.10.3" />
+    <PackageReference Include="FreeSql.Provider.Oracle" Version="1.10.3" />
+    <PackageReference Include="FreeSql.Provider.PostgreSQL" Version="1.10.3" />
+    <PackageReference Include="FreeSql.Provider.Sqlite" Version="1.10.3" />
+    <PackageReference Include="FreeSql.Provider.SqlServer" Version="1.10.3" />
+    <PackageReference Include="FreeSql.Repository" Version="1.10.3" />
+    <PackageReference Include="IdleBus" Version="1.5.0" />
     <PackageReference Include="Microsoft.AspNetCore.Http.Abstractions" Version="2.2.0" />
-    <PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="3.1.9" />
-    <PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="3.1.9" />
-    <PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="3.1.9" />
+    <PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="5.0.0" />
+    <PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="5.0.0" />
+    <PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="5.0.0" />
     <PackageReference Include="Microsoft.IdentityModel.Tokens" Version="6.8.0" />
-    <PackageReference Include="System.Drawing.Common" Version="4.7.0" />
+    <PackageReference Include="System.Drawing.Common" Version="5.0.0" />
     <PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="6.8.0" />
     <PackageReference Include="UAParser" Version="3.1.44" />
   </ItemGroup>

+ 1 - 1
Admin.Core.Common/Attributes/TransactionAttribute.cs

@@ -13,7 +13,7 @@ namespace Admin.Core.Common.Attributes
         /// <summary>
         /// 事务传播方式
         /// </summary>
-        public Propagation Propagation { get; set; } = Propagation.Requierd;
+        public Propagation Propagation { get; set; } = Propagation.Required;
 
         /// <summary>
         /// 事务隔离级别

+ 5 - 0
Admin.Core.Common/Auth/ClaimAttributes.cs

@@ -29,5 +29,10 @@
         /// 刷新有效期
         /// </summary>
         public const string RefreshExpires = "re";
+
+        /// <summary>
+        /// 租户Id
+        /// </summary>
+        public const string TenantId = "tenantid";
     }
 }

+ 5 - 0
Admin.Core.Common/Auth/IUser.cs

@@ -19,5 +19,10 @@
         /// 昵称
         /// </summary>
         string NickName { get; }
+
+        /// <summary>
+        /// 租户Id
+        /// </summary>
+        long? TenantId { get; }
     }
 }

+ 16 - 0
Admin.Core.Common/Auth/User.cs

@@ -66,5 +66,21 @@ namespace Admin.Core.Common.Auth
                 return "";
             }
         }
+
+        /// <summary>
+        /// 租户Id
+        /// </summary>
+        public virtual long? TenantId
+        {
+            get
+            {
+                var tenantId = _accessor?.HttpContext?.User?.FindFirst(ClaimAttributes.TenantId);
+                if (tenantId != null && tenantId.Value.NotNull())
+                {
+                    return tenantId.Value.ToLong();
+                }
+                return 0;
+            }
+        }
     }
 }

+ 13 - 4
Admin.Core.Common/BaseModel/Entity.cs

@@ -3,16 +3,25 @@ using System.ComponentModel;
 
 namespace Admin.Core.Common.BaseModel
 {
-    public interface IEntity
+    public interface IEntity<TKey>
+    {
+        /// <summary>
+        /// 主键Id
+        /// </summary>
+        TKey Id { get; set; }
+    }
+
+    public interface IEntity : IEntity<long>
     {
     }
 
-    public class Entity<TKey> : IEntity
+
+    public class Entity<TKey> : IEntity<TKey>
     {
         /// <summary>
-        /// 编号
+        /// 主键Id
         /// </summary>
-        [Description("编号")]
+        [Description("主键Id")]
         [Column(Position = 1, IsIdentity = true)]
         public virtual TKey Id { get; set; }
     }

+ 2 - 2
Admin.Core.Common/BaseModel/EntityAdd.cs

@@ -6,7 +6,7 @@ using FreeSql.DataAnnotations;
 namespace Admin.Core.Common.BaseModel
 {
     /// <summary>
-    /// 实体创建审计
+    /// 实体创建
     /// </summary>
     public class EntityAdd<TKey> : Entity<TKey>, IEntityAdd<TKey> where TKey : struct
     {
@@ -15,7 +15,7 @@ namespace Admin.Core.Common.BaseModel
         /// </summary>
         [Description("创建者Id")]
         [Column(Position = -3, CanUpdate = false)]
-        public TKey? CreatedUserId { get; set; }
+        public long? CreatedUserId { get; set; }
 
         /// <summary>
         /// 创建者

+ 15 - 5
Admin.Core.Common/BaseModel/EntityBase.cs → Admin.Core.Common/BaseModel/EntityFull.cs

@@ -6,10 +6,17 @@ using FreeSql.DataAnnotations;
 namespace Admin.Core.Common.BaseModel
 {
     /// <summary>
-    /// 实体审计
+    /// 实体完整类
     /// </summary>
-    public class EntityBase<TKey> : Entity<TKey>, IEntityVersion, IEntitySoftDelete, IEntityAdd<TKey>, IEntityUpdate<TKey> where TKey : struct
+    public class EntityFull<TKey> : Entity<TKey>, ITenant, IEntityVersion, IEntitySoftDelete, IEntityAdd<TKey>, IEntityUpdate<TKey> where TKey : struct
     {
+        /// <summary>
+        /// 租户Id
+        /// </summary>
+        [Description("租户Id")]
+        [Column(Position = -10, CanUpdate = false)]
+        public virtual long? TenantId { get; set; }
+
         /// <summary>
         /// 版本
         /// </summary>
@@ -29,7 +36,7 @@ namespace Admin.Core.Common.BaseModel
         /// </summary>
         [Description("创建者Id")]
         [Column(Position = -7, CanUpdate = false)]
-        public TKey? CreatedUserId { get; set; }
+        public long? CreatedUserId { get; set; }
 
         /// <summary>
         /// 创建者
@@ -50,7 +57,7 @@ namespace Admin.Core.Common.BaseModel
         /// </summary>
         [Description("修改者Id")]
         [Column(Position = -4, CanInsert = false)]
-        public TKey? ModifiedUserId { get; set; }
+        public long? ModifiedUserId { get; set; }
 
         /// <summary>
         /// 修改者
@@ -67,7 +74,10 @@ namespace Admin.Core.Common.BaseModel
         public DateTime? ModifiedTime { get; set; }
     }
 
-    public class EntityBase : EntityBase<long>
+    /// <summary>
+    /// 实体完整类
+    /// </summary>
+    public class EntityFull : EntityFull<long>
     {
 
     }

+ 2 - 2
Admin.Core.Common/BaseModel/EntityUpdate.cs

@@ -6,7 +6,7 @@ using FreeSql.DataAnnotations;
 namespace Admin.Core.Common.BaseModel
 {
     /// <summary>
-    /// 实体修改审计
+    /// 实体修改
     /// </summary>
     public class EntityUpdate<TKey> : Entity<TKey>, IEntityUpdate<TKey> where TKey : struct
     {
@@ -15,7 +15,7 @@ namespace Admin.Core.Common.BaseModel
         /// </summary>
         [Description("修改者Id")]
         [Column(Position = -3, CanInsert = false)]
-        public TKey? ModifiedUserId { get; set; }
+        public long? ModifiedUserId { get; set; }
 
         /// <summary>
         /// 修改者

+ 1 - 1
Admin.Core.Common/BaseModel/IEntityAdd.cs

@@ -4,7 +4,7 @@ namespace Admin.Core.Common.BaseModel
 {
     public interface IEntityAdd<TKey> where TKey: struct
     {
-        TKey? CreatedUserId { get; set; }
+        long? CreatedUserId { get; set; }
         string CreatedUserName { get; set; }
         DateTime? CreatedTime { get; set; }
     }

+ 1 - 1
Admin.Core.Common/BaseModel/IEntityUpdate.cs

@@ -4,7 +4,7 @@ namespace Admin.Core.Common.BaseModel
 {
     public interface IEntityUpdate<TKey> where TKey : struct
     {
-        TKey? ModifiedUserId { get; set; }
+        long? ModifiedUserId { get; set; }
         string ModifiedUserName { get; set; }
         DateTime? ModifiedTime { get; set; }
     }

+ 11 - 0
Admin.Core.Common/BaseModel/ITenant.cs

@@ -0,0 +1,11 @@
+
+namespace Admin.Core.Common.BaseModel
+{
+    public interface ITenant
+    {
+        /// <summary>
+        /// 租户Id
+        /// </summary>
+        long? TenantId { get; set; }
+    }
+}

+ 24 - 0
Admin.Core.Common/Configs/AppConfig.cs

@@ -1,5 +1,24 @@
 namespace Admin.Core.Common.Configs
 {
+    /// <summary>
+    /// 租户类型
+    /// </summary>
+    public enum TenantType
+    {
+        /// <summary>
+        /// 无租户
+        /// </summary>
+        None,
+        /// <summary>
+        /// 共享数据库
+        /// </summary>
+        Share,
+        /// <summary>
+        /// 独立数据库
+        /// </summary>
+        Own
+    }
+
     /// <summary>
     /// 应用配置
     /// </summary>
@@ -15,6 +34,11 @@
         /// </summary>
         public string[] CorUrls { get; set; }// = new[]{ "http://*:9000" };
 
+        /// <summary>
+        /// 租户类型
+        /// </summary>
+        public TenantType TenantType { get; set; } = TenantType.None;
+
         /// <summary>
         /// Swagger文档
         /// </summary>

+ 26 - 0
Admin.Core.Common/Configs/DbConfig.cs

@@ -3,6 +3,27 @@ using DataType = FreeSql.DataType;
 
 namespace Admin.Core.Common.Configs
 {
+    /// <summary>
+    /// 多数据库
+    /// </summary>
+    public class MultiDb
+    {
+        /// <summary>
+        /// 数据库命名
+        /// </summary>
+        public string Name { get; set; }
+
+        /// <summary>
+        /// 数据库类型
+        /// </summary>
+        public DataType Type { get; set; }
+
+        /// <summary>
+        /// 数据库字符串
+        /// </summary>
+        public string ConnectionString { get; set; }
+    }
+
     /// <summary>
     /// 数据库配置
     /// </summary>
@@ -57,5 +78,10 @@ namespace Admin.Core.Common.Configs
         /// 监听Curd操作
         /// </summary>
         public bool Curd { get; set; } = false;
+
+        /// <summary>
+        /// 多数据库
+        /// </summary>
+        public MultiDb[] Dbs { get; set; }
     }
 }

+ 9 - 0
Admin.Core.Common/Dbs/MySqlDb.cs

@@ -0,0 +1,9 @@
+namespace Admin.Core.Common.Dbs
+{
+    /// <summary>
+    /// 多数据库命名
+    /// </summary>
+    public class MySqlDb
+    {
+    }
+}

+ 0 - 10
Admin.Core.Common/Output/OptionOutput.cs

@@ -14,15 +14,5 @@
         /// 值
         /// </summary>
         public object Value { get; set; }
-
-        /// <summary>
-        /// 禁用
-        /// </summary>
-        public bool Disabled { get; set; }
-
-        /// <summary>
-        /// 额外数据
-        /// </summary>
-        public object Data { get; set; }
     }
 }

+ 3 - 3
Admin.Core.Model/Admin.Core.Model.csproj

@@ -1,9 +1,9 @@
 <Project Sdk="Microsoft.NET.Sdk">
 
   <PropertyGroup>
-    <TargetFramework>netcoreapp3.1</TargetFramework>
-    <GeneratePackageOnBuild>true</GeneratePackageOnBuild>
-    <Version>1.4.1</Version>
+    <TargetFramework>net5.0</TargetFramework>
+    <GeneratePackageOnBuild>false</GeneratePackageOnBuild>
+    <Version>1.5.0</Version>
     <Authors>xiaoxue</Authors>
     <Company>xiaoxue</Company>
     <Description>中台Admin后端实体库</Description>

+ 2 - 2
Admin.Core.Model/Admin/ApiEntity.cs

@@ -8,8 +8,8 @@ namespace Admin.Core.Model.Admin
     /// 接口管理
     /// </summary>
 	[Table(Name = "ad_api")]
-    [Index("uk_api_path", nameof(Path), true)]
-    public class ApiEntity : EntityBase
+    [Index("idx_{tablename}_01", nameof(Path), true)]
+    public class ApiEntity : EntityFull
     {
         /// <summary>
         /// 所属模块

+ 2 - 2
Admin.Core.Model/Admin/DictionaryEntity.cs

@@ -7,8 +7,8 @@ namespace Admin.Core.Model.Admin
     /// 数据字典
     /// </summary>
 	[Table(Name = "ad_dictionary")]
-    [Index("uk_dictionary_parentid_name", nameof(ParentId)+","+nameof(Name), true)]
-    public class DictionaryEntity: EntityBase
+    [Index("idx_{tablename}_01", nameof(ParentId)+","+nameof(Name), true)]
+    public class DictionaryEntity: EntityFull
     {
         /// <summary>
         /// 字典父级

+ 2 - 2
Admin.Core.Model/Admin/DocumentEntity.cs

@@ -7,8 +7,8 @@ namespace Admin.Core.Model.Admin
     /// 文档
     /// </summary>
 	[Table(Name = "ad_document")]
-    [Index("uk_document_parentid_label", nameof(ParentId) + "," + nameof(Label), true)]
-    public class DocumentEntity : EntityBase
+    [Index("idx_{tablename}_01", nameof(ParentId) + "," + nameof(Label), true)]
+    public class DocumentEntity : EntityFull
     {
         /// <summary>
         /// 父级节点

+ 1 - 1
Admin.Core.Model/Admin/DocumentImageEntity.cs

@@ -7,7 +7,7 @@ namespace Admin.Core.Model.Admin
     /// 文档图片
     /// </summary>
 	[Table(Name = "ad_document_image")]
-    [Index("uk_document_image_documentid_url", nameof(DocumentId) + "," + nameof(Url), true)]
+    [Index("idx_{tablename}_01", nameof(DocumentId) + "," + nameof(Url), true)]
     public class DocumentImageEntity: EntityAdd
     {
         /// <summary>

+ 7 - 1
Admin.Core.Model/Admin/LogAbstract.cs

@@ -6,8 +6,14 @@ namespace Admin.Core.Model.Admin
     /// <summary>
     /// 日志
     /// </summary>
-    public abstract class LogAbstract : EntityAdd
+    public abstract class LogAbstract : EntityAdd, ITenant
     {
+        /// <summary>
+        /// 租户Id
+        /// </summary>
+        [Column(Position = -10, CanUpdate = false)]
+        public long? TenantId { get; set; }
+
         /// <summary>
         /// 昵称
         /// </summary>

+ 2 - 2
Admin.Core.Model/Admin/PermissionEntity.cs

@@ -7,8 +7,8 @@ namespace Admin.Core.Model.Admin
     /// 权限
     /// </summary>
 	[Table(Name = "ad_permission")]
-    [Index("uk_permission_parentid_label", nameof(ParentId) + "," + nameof(Label), true)]
-    public class PermissionEntity : EntityBase
+    [Index("idx_{tablename}_01", nameof(ParentId) + "," + nameof(Label), true)]
+    public class PermissionEntity : EntityFull
     {
         /// <summary>
         /// 父级节点

+ 2 - 2
Admin.Core.Model/Admin/RoleEntity.cs

@@ -9,8 +9,8 @@ namespace Admin.Core.Model.Admin
     /// 角色
     /// </summary>
 	[Table(Name = "ad_role")]
-    [Index("uk_role_name", nameof(Name), true)]
-    public class RoleEntity: EntityBase
+    [Index("idx_{tablename}_01", nameof(Name), true)]
+    public class RoleEntity: EntityFull
     {
         /// <summary>
         /// 名称

+ 1 - 1
Admin.Core.Model/Admin/RolePermissionEntity.cs

@@ -7,7 +7,7 @@ namespace Admin.Core.Model.Admin
     /// 角色权限
     /// </summary>
 	[Table(Name = "ad_role_permission")]
-    [Index("uk_role_permissioin_roleid_permissionid", nameof(RoleId) + "," + nameof(PermissionId), true)]
+    [Index("idx_{tablename}_01", nameof(RoleId) + "," + nameof(PermissionId), true)]
     public class RolePermissionEntity: EntityAdd
     {
         /// <summary>

+ 57 - 0
Admin.Core.Model/Admin/TenantEntity.cs

@@ -0,0 +1,57 @@
+using System;
+using Admin.Core.Common.BaseModel;
+using FreeSql;
+using FreeSql.DataAnnotations;
+
+namespace Admin.Core.Model.Admin
+{
+    /// <summary>
+    /// 租户
+    /// </summary>
+	[Table(Name = "ad_tenant")]
+    [Index("idx_{tablename}_01", nameof(Name), true)]
+    [Index("idx_{tablename}_02", nameof(Code), true)]
+    public class TenantEntity : EntityFull
+    {
+        /// <summary>
+        /// 编码
+        /// </summary>
+        [Column(StringLength = 50)]
+        public string Code { get; set; }
+
+        /// <summary>
+        /// 名称
+        /// </summary>
+        [Column(StringLength = 50)]
+        public string Name { get; set; }
+
+        /// <summary>
+        /// 数据库
+        /// </summary>
+        [Column(MapType = typeof(int))]
+        public DataType? DbType { get; set; }
+
+        /// <summary>
+        /// 连接字符串
+        /// </summary>
+        [Column(StringLength = 500)]
+        public string ConnectionString { get; set; }
+
+        /// <summary>
+        /// 空闲时间(分)
+        /// </summary>
+        public int? IdleTime { get; set; } = 10;
+
+        /// <summary>
+        /// 启用
+        /// </summary>
+		public bool Enabled { get; set; } = true;
+
+        /// <summary>
+        /// 说明
+        /// </summary>
+        [Column(StringLength = 500)]
+        public string Description { get; set; }
+    }
+
+}

+ 8 - 2
Admin.Core.Model/Admin/UserEntity.cs

@@ -9,9 +9,15 @@ namespace Admin.Core.Model.Admin
     /// 用户
     /// </summary>
 	[Table(Name = "ad_user")]
-    [Index("uk_user_username", nameof(UserName), true)]
-    public class UserEntity: EntityBase
+    [Index("idx_{tablename}_01", nameof(UserName), true)]
+    public class UserEntity: EntityFull, ITenant
     {
+        /// <summary>
+        /// 租户Id
+        /// </summary>
+        [Column(Position = -10, CanUpdate = true)]
+        public override long? TenantId { get; set; }
+
         /// <summary>
         /// 账号
         /// </summary>

+ 1 - 1
Admin.Core.Model/Admin/UserRoleEntity.cs

@@ -7,7 +7,7 @@ namespace Admin.Core.Model.Admin
     /// 用户角色
     /// </summary>
 	[Table(Name = "ad_user_role")]
-    [Index("uk_user_role_userid_roleid", nameof(UserId) + "," + nameof(RoleId), true)]
+    [Index("idx_{tablename}_01", nameof(UserId) + "," + nameof(RoleId), true)]
     public class UserRoleEntity: EntityAdd
     {
         /// <summary>

+ 2 - 2
Admin.Core.Model/Admin/ViewEntity.cs

@@ -8,8 +8,8 @@ namespace Admin.Core.Model.Admin
     /// 视图管理
     /// </summary>
 	[Table(Name = "ad_view")]
-    [Index("uk_view_parentid_label", nameof(ParentId) + "," + nameof(Label), true)]
-    public class ViewEntity : EntityBase
+    [Index("idx_{tablename}_01", nameof(ParentId) + "," + nameof(Label), true)]
+    public class ViewEntity : EntityFull
     {
         /// <summary>
         /// 所属节点

+ 3 - 3
Admin.Core.Repository/Admin.Core.Repository.csproj

@@ -1,8 +1,8 @@
 <Project Sdk="Microsoft.NET.Sdk">
 
   <PropertyGroup>
-    <TargetFramework>netcoreapp3.1</TargetFramework>
-    <Version>1.4.1</Version>
+    <TargetFramework>net5.0</TargetFramework>
+    <Version>1.5.0</Version>
     <Authors>xiaoxue</Authors>
     <Company>xiaoxue</Company>
     <Description>中台Admin后端仓储库</Description>
@@ -11,7 +11,7 @@
     <RepositoryUrl>https://github.com/zhontai/Admin.Core</RepositoryUrl>
     <RepositoryType>git</RepositoryType>
     <PackageTags>ZhonTai Admin;WebApi</PackageTags>
-    <GeneratePackageOnBuild>true</GeneratePackageOnBuild>
+    <GeneratePackageOnBuild>false</GeneratePackageOnBuild>
   </PropertyGroup>
 
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">

+ 2 - 2
Admin.Core.Repository/Admin/Api/ApiRepository.cs

@@ -1,12 +1,12 @@
-using FreeSql;
 using Admin.Core.Model.Admin;
 using Admin.Core.Common.Auth;
 
 namespace Admin.Core.Repository.Admin
 {
+
     public class ApiRepository : RepositoryBase<ApiEntity>, IApiRepository
     {
-        public ApiRepository(UnitOfWorkManager uowm, IUser user) : base(uowm, user)
+        public ApiRepository(MyUnitOfWorkManager muowm, IUser user) : base(muowm, user)
         {
         }
     }

+ 2 - 3
Admin.Core.Repository/Admin/Dictionary/DictionaryRepository.cs

@@ -1,12 +1,11 @@
-using FreeSql;
-using Admin.Core.Model.Admin;
+using Admin.Core.Model.Admin;
 using Admin.Core.Common.Auth;
 
 namespace Admin.Core.Repository.Admin
 {
     public class DictionaryRepository : RepositoryBase<DictionaryEntity>, IDictionaryRepository
     {
-        public DictionaryRepository(UnitOfWorkManager uowm, IUser user) : base(uowm, user)
+        public DictionaryRepository(MyUnitOfWorkManager muowm, IUser user) : base(muowm, user)
         {
         }
     }

+ 2 - 3
Admin.Core.Repository/Admin/Document/DocumentRepository.cs

@@ -1,12 +1,11 @@
-using FreeSql;
-using Admin.Core.Model.Admin;
+using Admin.Core.Model.Admin;
 using Admin.Core.Common.Auth;
 
 namespace Admin.Core.Repository.Admin
 {
     public class DocumentRepository : RepositoryBase<DocumentEntity>, IDocumentRepository
     {
-        public DocumentRepository(UnitOfWorkManager uowm, IUser user) : base(uowm, user)
+        public DocumentRepository(MyUnitOfWorkManager muowm, IUser user) : base(muowm, user)
         {
         }
     }

+ 2 - 3
Admin.Core.Repository/Admin/DocumentImage/DocumentImageRepository.cs

@@ -1,12 +1,11 @@
-using FreeSql;
-using Admin.Core.Model.Admin;
+using Admin.Core.Model.Admin;
 using Admin.Core.Common.Auth;
 
 namespace Admin.Core.Repository.Admin
 {
     public class DocumentImageRepository : RepositoryBase<DocumentImageEntity>, IDocumentImageRepository
     {
-        public DocumentImageRepository(UnitOfWorkManager uowm, IUser user) : base(uowm, user)
+        public DocumentImageRepository(MyUnitOfWorkManager muowm, IUser user) : base(muowm, user)
         {
         }
     }

+ 1 - 3
Admin.Core.Repository/Admin/LoginLog/LoginLogRepository.cs

@@ -1,13 +1,11 @@
-using FreeSql;
 using Admin.Core.Model.Admin;
 using Admin.Core.Common.Auth;
-using System.Threading.Tasks;
 
 namespace Admin.Core.Repository.Admin
 {
     public class LoginLogRepository : RepositoryBase<LoginLogEntity>, ILoginLogRepository
     {
-        public LoginLogRepository(UnitOfWorkManager uowm, IUser user) : base(uowm, user)
+        public LoginLogRepository(MyUnitOfWorkManager muowm, IUser user) : base(muowm, user)
         {
         }
     }

+ 1 - 1
Admin.Core.Repository/Admin/OprationLog/IOprationLogRepository.cs

@@ -2,7 +2,7 @@ using Admin.Core.Model.Admin;
 
 namespace Admin.Core.Repository.Admin
 {
-	public interface IOprationLogRepository : IRepositoryBase<OprationLogEntity>
+    public interface IOprationLogRepository : IRepositoryBase<OprationLogEntity>
     {
     }
 }

+ 1 - 2
Admin.Core.Repository/Admin/OprationLog/OprationLogRepository.cs

@@ -1,4 +1,3 @@
-using FreeSql;
 using Admin.Core.Model.Admin;
 using Admin.Core.Common.Auth;
 
@@ -6,7 +5,7 @@ namespace Admin.Core.Repository.Admin
 {
     public class OprationLogRepository : RepositoryBase<OprationLogEntity>, IOprationLogRepository
     {
-        public OprationLogRepository(UnitOfWorkManager uowm, IUser user) : base(uowm, user)
+        public OprationLogRepository(MyUnitOfWorkManager muowm, IUser user) : base(muowm, user)
         {
         }
     }

+ 2 - 3
Admin.Core.Repository/Admin/Permission/PermissionRepository.cs

@@ -1,12 +1,11 @@
-using FreeSql;
-using Admin.Core.Model.Admin;
+using Admin.Core.Model.Admin;
 using Admin.Core.Common.Auth;
 
 namespace Admin.Core.Repository.Admin
 {
     public class PermissionRepository : RepositoryBase<PermissionEntity>, IPermissionRepository
     {
-        public PermissionRepository(UnitOfWorkManager uowm, IUser user) : base(uowm, user)
+        public PermissionRepository(MyUnitOfWorkManager muowm, IUser user) : base(muowm, user)
         {
         }
     }

+ 1 - 2
Admin.Core.Repository/Admin/Role/RoleRepository.cs

@@ -1,4 +1,3 @@
-using FreeSql;
 using Admin.Core.Model.Admin;
 using Admin.Core.Common.Auth;
 
@@ -6,7 +5,7 @@ namespace Admin.Core.Repository.Admin
 {	
 	public  class RoleRepository : RepositoryBase<RoleEntity>, IRoleRepository
     {
-        public RoleRepository(UnitOfWorkManager uowm, IUser user) : base(uowm, user)
+        public RoleRepository(MyUnitOfWorkManager muowm, IUser user) : base(muowm, user)
         {
         }
     }

+ 1 - 2
Admin.Core.Repository/Admin/RolePermission/RolePermissionRepository.cs

@@ -1,4 +1,3 @@
-using FreeSql;
 using Admin.Core.Model.Admin;
 using Admin.Core.Common.Auth;
 
@@ -6,7 +5,7 @@ namespace Admin.Core.Repository.Admin
 {
     public class RolePermissionRepository : RepositoryBase<RolePermissionEntity>, IRolePermissionRepository
     {
-        public RolePermissionRepository(UnitOfWorkManager uowm, IUser user) : base(uowm, user)
+        public RolePermissionRepository(MyUnitOfWorkManager muowm, IUser user) : base(muowm, user)
         {
         }
     }

+ 8 - 0
Admin.Core.Repository/Admin/Tenant/ITenantRepository.cs

@@ -0,0 +1,8 @@
+using Admin.Core.Model.Admin;
+
+namespace Admin.Core.Repository.Admin
+{	
+	public interface ITenantRepository : IRepositoryBase<TenantEntity>
+    {
+    }
+}

+ 12 - 0
Admin.Core.Repository/Admin/Tenant/TenantRepository.cs

@@ -0,0 +1,12 @@
+using Admin.Core.Model.Admin;
+using Admin.Core.Common.Auth;
+
+namespace Admin.Core.Repository.Admin
+{	
+	public  class TenantRepository : RepositoryBase<TenantEntity>, ITenantRepository
+    {
+        public TenantRepository(MyUnitOfWorkManager muowm, IUser user) : base(muowm, user)
+        {
+        }
+    }
+}

+ 1 - 2
Admin.Core.Repository/Admin/User/UserRepository.cs

@@ -1,4 +1,3 @@
-using FreeSql;
 using Admin.Core.Model.Admin;
 using Admin.Core.Common.Auth;
 
@@ -6,7 +5,7 @@ namespace Admin.Core.Repository.Admin
 {
     public class UserRepository : RepositoryBase<UserEntity>, IUserRepository
     {
-        public UserRepository(UnitOfWorkManager uowm, IUser user) : base(uowm, user)
+        public UserRepository(MyUnitOfWorkManager muowm, IUser user) : base(muowm, user)
         {
         }
     }

+ 1 - 2
Admin.Core.Repository/Admin/UserRole/UserRoleRepository.cs

@@ -1,4 +1,3 @@
-using FreeSql;
 using Admin.Core.Model.Admin;
 using Admin.Core.Common.Auth;
 
@@ -6,7 +5,7 @@ namespace Admin.Core.Repository.Admin
 {	
 	public class UserRoleRepository : RepositoryBase<UserRoleEntity>, IUserRoleRepository
     {
-        public UserRoleRepository(UnitOfWorkManager uowm, IUser user) : base(uowm, user)
+        public UserRoleRepository(MyUnitOfWorkManager muowm, IUser user) : base(muowm, user)
         {
         }
     }

+ 1 - 2
Admin.Core.Repository/Admin/View/ViewRepositoryRepository.cs

@@ -1,4 +1,3 @@
-using FreeSql;
 using Admin.Core.Model.Admin;
 using Admin.Core.Common.Auth;
 
@@ -6,7 +5,7 @@ namespace Admin.Core.Repository.Admin
 {
     public class ViewRepository : RepositoryBase<ViewEntity>, IViewRepository
     {
-        public ViewRepository(UnitOfWorkManager uowm, IUser user) : base(uowm, user)
+        public ViewRepository(MyUnitOfWorkManager muowm, IUser user) : base(muowm, user)
         {
 
         }

+ 14 - 0
Admin.Core.Repository/Base/IdleBusExtesions.cs

@@ -0,0 +1,14 @@
+
+
+
+namespace Admin.Core.Repository
+{
+    public static class IdleBusExtesions
+    {
+        public static IFreeSql Get(this IdleBus<IFreeSql> ib, long tenantId)
+        {
+            var freeSql = ib.Get("tenant_" + tenantId.ToString());
+            return freeSql;
+        }
+    }
+}

+ 14 - 0
Admin.Core.Repository/Base/MyUnitOfWorkManager.cs

@@ -0,0 +1,14 @@
+
+
+using FreeSql;
+using Admin.Core.Common.Auth;
+
+namespace Admin.Core.Repository
+{
+    public class MyUnitOfWorkManager : UnitOfWorkManager
+    {
+        public MyUnitOfWorkManager(IdleBus<IFreeSql> ib, IUser user) : base(ib.Get(user.TenantId.Value))
+        {
+        }
+    }
+}

+ 5 - 5
Admin.Core.Repository/Base/RepositoryBase.cs

@@ -8,15 +8,14 @@ using Admin.Core.Common.Auth;
 
 namespace Admin.Core.Repository
 {
-    public abstract class RepositoryBase<TEntity,TKey> : BaseRepository<TEntity, TKey> where TEntity : class,new()
+    public abstract class RepositoryBase<TEntity, TKey> : BaseRepository<TEntity, TKey>, IRepositoryBase<TEntity, TKey> where TEntity : class,new()
     {
         private readonly IUser _user;
-        protected RepositoryBase(UnitOfWorkManager uowm, IUser user) : base(uowm.Orm, null, null)
+        protected RepositoryBase(IFreeSql freeSql, IUser user) : base(freeSql, null, null)
         {
-            uowm.Binding(this);
             _user = user;
         }
-        
+
         public virtual Task<TDto> GetAsync<TDto>(TKey id)
         {
             return Select.WhereDynamic(id).ToOneAsync<TDto>();
@@ -61,8 +60,9 @@ namespace Admin.Core.Repository
 
     public abstract class RepositoryBase<TEntity> : RepositoryBase<TEntity, long> where TEntity : class, new()
     {
-        protected RepositoryBase(UnitOfWorkManager uowm, IUser user) : base(uowm, user)
+        protected RepositoryBase(MyUnitOfWorkManager muowm, IUser user) : base(muowm.Orm, user)
         {
+            muowm.Binding(this);
         }
     }
 }

+ 3 - 3
Admin.Core.Services/Admin.Core.Service.csproj

@@ -1,9 +1,9 @@
 <Project Sdk="Microsoft.NET.Sdk">
 
   <PropertyGroup>
-    <TargetFramework>netcoreapp3.1</TargetFramework>
-    <GeneratePackageOnBuild>true</GeneratePackageOnBuild>
-    <Version>1.4.1</Version>
+    <TargetFramework>net5.0</TargetFramework>
+    <GeneratePackageOnBuild>false</GeneratePackageOnBuild>
+    <Version>1.5.0</Version>
     <Authors>xiaoxue</Authors>
     <Company>xiaoxue</Company>
     <Description>中台Admin后端服务库</Description>

+ 5 - 1
Admin.Core.Services/Admin/Auth/AuthService.cs

@@ -70,7 +70,11 @@ namespace Admin.Core.Service.Admin.Auth
             }
             #endregion
 
-            var user = (await _userRepository.GetAsync(a => a.UserName == input.UserName));
+            UserEntity user = null;
+
+            user = await _userRepository.Select.DisableGlobalFilter("Tenant").Where(a=> a.UserName == input.UserName).ToOneAsync();
+            //user = (await _userRepository.GetAsync(a => a.UserName == input.UserName));
+
             if (!(user?.Id > 0))
             {
                 return ResponseOutput.NotOk("账号输入有误!", 3);

+ 5 - 0
Admin.Core.Services/Admin/Auth/Output/AuthLoginOutput.cs

@@ -18,5 +18,10 @@ namespace Admin.Core.Service.Admin.Auth.Output
         /// 姓名
         /// </summary>
         public string NickName { get; set; }
+
+        /// <summary>
+        /// 租户Id
+        /// </summary>
+        public long TenantId { get; set; }
     }
 }

+ 2 - 2
Admin.Core.Services/Admin/Dictionary/DictionaryService.cs

@@ -1,4 +1,4 @@
-using System.Threading.Tasks;
+锘縰sing System.Threading.Tasks;
 using AutoMapper;
 using Admin.Core.Common.Output;
 using Admin.Core.Common.Input;
@@ -63,7 +63,7 @@ namespace Admin.Core.Service.Admin.Dictionary
             var entity = await _dictionaryRepository.GetAsync(input.Id);
             if (!(entity?.Id > 0))
             {
-                return ResponseOutput.NotOk("数据字典不存在!");
+                return ResponseOutput.NotOk("鏁版嵁瀛楀吀涓嶅瓨鍦�紒");
             }
 
             _mapper.Map(input, entity);

+ 1 - 0
Admin.Core.Services/Admin/OprationLog/OprationLogService.cs

@@ -9,6 +9,7 @@ using Admin.Core.Repository.Admin;
 using Admin.Core.Service.Admin.OprationLog.Input;
 using Admin.Core.Service.Admin.OprationLog.Output;
 using Admin.Core.Common.Helpers;
+using Admin.Core.Common.Dbs;
 
 namespace Admin.Core.Service.Admin.OprationLog
 {	

+ 25 - 0
Admin.Core.Services/Admin/Tenant/ITenantService.cs

@@ -0,0 +1,25 @@
+using System.Threading.Tasks;
+using Admin.Core.Common.Input;
+using Admin.Core.Common.Output;
+using Admin.Core.Model.Admin;
+using Admin.Core.Service.Admin.Tenant.Input;
+
+namespace Admin.Core.Service.Admin.Tenant
+{	
+    public interface ITenantService
+    {
+        Task<IResponseOutput> GetAsync(long id);
+
+        Task<IResponseOutput> PageAsync(PageInput<TenantEntity> input);
+
+        Task<IResponseOutput> AddAsync(TenantAddInput input);
+
+        Task<IResponseOutput> UpdateAsync(TenantUpdateInput input);
+
+        Task<IResponseOutput> DeleteAsync(long id);
+
+        Task<IResponseOutput> SoftDeleteAsync(long id);
+
+        Task<IResponseOutput> BatchSoftDeleteAsync(long[] ids);
+    }
+}

+ 44 - 0
Admin.Core.Services/Admin/Tenant/Input/TenantAddInput.cs

@@ -0,0 +1,44 @@
+
+namespace Admin.Core.Service.Admin.Tenant.Input
+{
+    /// <summary>
+    /// 添加
+    /// </summary>
+    public class TenantAddInput
+    {
+        /// <summary>
+        /// 编码
+        /// </summary>
+        public string Code { get; set; }
+
+        /// <summary>
+        /// 名称
+        /// </summary>
+        public string Name { get; set; }
+
+        /// <summary>
+        /// 数据库
+        /// </summary>
+        public FreeSql.DataType? DbType { get; set; }
+
+        /// <summary>
+        /// 连接字符串
+        /// </summary>
+        public string ConnectionString { get; set; }
+
+        /// <summary>
+        /// 空闲时间(分)
+        /// </summary>
+        public int? IdleTime { get; set; }
+
+        /// <summary>
+        /// 启用
+        /// </summary>
+		public bool Enabled { get; set; }
+
+        /// <summary>
+        /// 说明
+        /// </summary>
+        public string Description { get; set; }
+    }
+}

+ 18 - 0
Admin.Core.Services/Admin/Tenant/Input/TenantUpdateInput.cs

@@ -0,0 +1,18 @@
+namespace Admin.Core.Service.Admin.Tenant.Input
+{
+    /// <summary>
+    /// 修改
+    /// </summary>
+    public partial class TenantUpdateInput : TenantAddInput
+    {
+        /// <summary>
+        /// 接口Id
+        /// </summary>
+        public int Id { get; set; }
+
+        /// <summary>
+        /// 版本
+        /// </summary>
+        public long Version { get; set; }
+    }
+}

+ 8 - 0
Admin.Core.Services/Admin/Tenant/Output/TenantGetOutput.cs

@@ -0,0 +1,8 @@
+using Admin.Core.Service.Admin.Tenant.Input;
+
+namespace Admin.Core.Service.Admin.Tenant.Output
+{
+    public class TenantGetOutput : TenantUpdateInput
+    {
+    }
+}

+ 59 - 0
Admin.Core.Services/Admin/Tenant/Output/TenantListOutput.cs

@@ -0,0 +1,59 @@
+using Newtonsoft.Json;
+using System;
+
+namespace Admin.Core.Service.Admin.Tenant.Output
+{
+    public class TenantListOutput
+    {
+        /// <summary>
+        /// 主键
+        /// </summary>
+        public long Id { get; set; }
+
+        /// <summary>
+        /// 编码
+        /// </summary>
+        public string Code { get; set; }
+
+        /// <summary>
+        /// 名称
+        /// </summary>
+        public string Name { get; set; }
+
+        /// <summary>
+        /// 数据库
+        /// </summary>
+        [JsonIgnore]
+        public FreeSql.DataType? DbType { get; set; }
+
+        /// <summary>
+        /// 数据库名称
+        /// </summary>
+        public string DbTypeName => DbType.ToDescriptionOrString();
+
+        /// <summary>
+        /// 连接字符串
+        /// </summary>
+        public string ConnectionString { get; set; }
+
+        /// <summary>
+        /// 空闲时间(分)
+        /// </summary>
+        public int? IdleTime { get; set; }
+
+        /// <summary>
+        /// 启用
+        /// </summary>
+		public bool Enabled { get; set; }
+
+        /// <summary>
+        /// 说明
+        /// </summary>
+        public string Description { get; set; }
+
+        /// <summary>
+        /// 创建时间
+        /// </summary>
+        public DateTime? CreatedTime { get; set; }
+    }
+}

+ 106 - 0
Admin.Core.Services/Admin/Tenant/TenantService.cs

@@ -0,0 +1,106 @@
+using System.Threading.Tasks;
+using AutoMapper;
+using Admin.Core.Common.Auth;
+using Admin.Core.Common.Input;
+using Admin.Core.Common.Output;
+using Admin.Core.Model.Admin;
+using Admin.Core.Repository.Admin;
+using Admin.Core.Service.Admin.Tenant.Input;
+using Admin.Core.Service.Admin.Tenant.Output;
+
+namespace Admin.Core.Service.Admin.Tenant
+{	
+	public class TenantService : ITenantService
+    {
+        private readonly IUser _user;
+        private readonly IMapper _mapper;
+        private readonly ITenantRepository _tenantRepository;
+        public TenantService(
+            IUser user,
+            IMapper mapper,
+            ITenantRepository tenantRepository
+        )
+        {
+            _user = user;
+            _mapper = mapper;
+            _tenantRepository = tenantRepository;
+        }
+
+        public async Task<IResponseOutput> GetAsync(long id)
+        {
+            var result = await _tenantRepository.GetAsync<TenantGetOutput>(id);
+            return ResponseOutput.Ok(result);
+        }
+
+        public async Task<IResponseOutput> PageAsync(PageInput<TenantEntity> input)
+        {
+            var key = input.Filter?.Name;
+
+            var list = await _tenantRepository.Select
+            .WhereIf(key.NotNull(), a => a.Name.Contains(key))
+            .Count(out var total)
+            .OrderByDescending(true, c => c.Id)
+            .Page(input.CurrentPage, input.PageSize)
+            .ToListAsync<TenantListOutput>();
+
+            var data = new PageOutput<TenantListOutput>()
+            {
+                List = list,
+                Total = total
+            };
+            
+            return ResponseOutput.Ok(data);
+        }
+
+        public async Task<IResponseOutput> AddAsync(TenantAddInput input)
+        {
+            var entity = _mapper.Map<TenantEntity>(input);
+            var id = (await _tenantRepository.InsertAsync(entity)).Id;
+
+            return ResponseOutput.Result(id > 0);
+        }
+
+        public async Task<IResponseOutput> UpdateAsync(TenantUpdateInput input)
+        {
+            if (!(input?.Id > 0))
+            {
+                return ResponseOutput.NotOk();
+            }
+
+            var entity = await _tenantRepository.GetAsync(input.Id);
+            if (!(entity?.Id > 0))
+            {
+                return ResponseOutput.NotOk("×⻧²»´æÔÚ£¡");
+            }
+
+            _mapper.Map(input, entity);
+            await _tenantRepository.UpdateAsync(entity);
+            return ResponseOutput.Ok();
+        }
+
+        public async Task<IResponseOutput> DeleteAsync(long id)
+        {
+            var result = false;
+            if (id > 0)
+            {
+                result = (await _tenantRepository.DeleteAsync(m => m.Id == id)) > 0;
+            }
+
+            return ResponseOutput.Result(result);
+        }
+
+        public async Task<IResponseOutput> SoftDeleteAsync(long id)
+        {
+            var result = await _tenantRepository.SoftDeleteAsync(id);
+
+            return ResponseOutput.Result(result);
+        }
+
+        public async Task<IResponseOutput> BatchSoftDeleteAsync(long[] ids)
+        {
+            var result = await _tenantRepository.SoftDeleteAsync(ids);
+
+            return ResponseOutput.Result(result);
+        }
+    }
+}

+ 18 - 0
Admin.Core.Services/Admin/Tenant/_MapConfig.cs

@@ -0,0 +1,18 @@
+using AutoMapper;
+using Admin.Core.Model.Admin;
+using Admin.Core.Service.Admin.Tenant.Input;
+
+namespace Admin.Core.Service.Admin.Tenant
+{
+    /// <summary>
+    /// 映射配置
+    /// </summary>
+    public class MapConfig : Profile
+    {
+        public MapConfig()
+        {
+            CreateMap<TenantAddInput, TenantEntity>();
+            CreateMap<TenantUpdateInput, TenantEntity>();
+        }
+    }
+}

+ 1 - 1
Admin.Core.Services/Admin/User/IUserService.cs

@@ -37,6 +37,6 @@ namespace Admin.Core.Service.Admin.User
 
         Task<IResponseOutput> GetBasicAsync();
 
-        Task<IList<string>> GetPermissionsAsync();
+        Task<IList<UserPermissionsOutput>> GetPermissionsAsync();
     }
 }

+ 9 - 0
Admin.Core.Services/Admin/User/Output/UserPermissionsOutput.cs

@@ -0,0 +1,9 @@
+namespace Admin.Core.Service.Admin.User.Output
+{
+    public class UserPermissionsOutput
+    {
+        public string HttpMethods { get; set; }
+
+        public string Path { get; set; }
+    }
+}

+ 14 - 9
Admin.Core.Services/Admin/User/UserService.cs

@@ -76,25 +76,30 @@ namespace Admin.Core.Service.Admin.User
             return ResponseOutput.Ok(data);
         }
 
-        public async Task<IList<string>> GetPermissionsAsync()
+        public async Task<IList<UserPermissionsOutput>> GetPermissionsAsync()
         {
             var key = string.Format(CacheKey.UserPermissions, _user.Id);
             if (await _cache.ExistsAsync(key))
             {
-                return await _cache.GetAsync<IList<string>>(key);
+                try
+                {
+                    return await _cache.GetAsync<IList<UserPermissionsOutput>>(key);
+                }
+                catch
+                {
+                    await _cache.DelByPatternAsync("admin:user:{0}:permissions");
+                }
             }
-            else
-            {
-                var userPermissoins = await _rolePermissionRepository.Select
+
+            var userPermissoins = await _rolePermissionRepository.Select
                 .InnerJoin<UserRoleEntity>((a, b) => a.RoleId == b.RoleId && b.UserId == _user.Id && a.Permission.Type == PermissionType.Api)
                 .Include(a => a.Permission.Api)
                 .Distinct()
-                .ToListAsync(a => a.Permission.Api.Path);
+                .ToListAsync(a => new UserPermissionsOutput { HttpMethods = a.Permission.Api.HttpMethods, Path = a.Permission.Api.Path });
 
-                await _cache.SetAsync(key, userPermissoins);
+            await _cache.SetAsync(key, userPermissoins);
 
-                return userPermissoins;
-            }
+            return userPermissoins;
         }
 
         public async Task<IResponseOutput> PageAsync(PageInput<UserEntity> input)

+ 3 - 3
Admin.Core.Tests/Admin.Core.Tests.csproj

@@ -1,14 +1,14 @@
 <Project Sdk="Microsoft.NET.Sdk">
 
   <PropertyGroup>
-    <TargetFramework>netcoreapp3.1</TargetFramework>
+    <TargetFramework>net5.0</TargetFramework>
 
     <IsPackable>false</IsPackable>
   </PropertyGroup>
 
   <ItemGroup>
-    <PackageReference Include="Microsoft.AspNetCore.TestHost" Version="3.1.9" />
-    <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.7.1" />
+    <PackageReference Include="Microsoft.AspNetCore.TestHost" Version="5.0.0" />
+    <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.8.0" />
     <PackageReference Include="xunit" Version="2.4.1" />
     <PackageReference Include="xunit.runner.visualstudio" Version="2.4.3">
       <PrivateAssets>all</PrivateAssets>

+ 103 - 23
Admin.Core/Admin.Core.Common.xml

@@ -54,6 +54,11 @@
             刷新有效期
             </summary>
         </member>
+        <member name="F:Admin.Core.Common.Auth.ClaimAttributes.TenantId">
+            <summary>
+            租户Id
+            </summary>
+        </member>
         <member name="T:Admin.Core.Common.Auth.IUser">
             <summary>
             用户信息接口
@@ -74,6 +79,11 @@
             昵称
             </summary>
         </member>
+        <member name="P:Admin.Core.Common.Auth.IUser.TenantId">
+            <summary>
+            租户Id
+            </summary>
+        </member>
         <member name="T:Admin.Core.Common.Auth.User">
             <summary>
             用户信息
@@ -94,6 +104,11 @@
             昵称
             </summary>
         </member>
+        <member name="P:Admin.Core.Common.Auth.User.TenantId">
+            <summary>
+            租户Id
+            </summary>
+        </member>
         <member name="T:Admin.Core.Common.Auth.UserIdentiyServer">
             <summary>
             用户信息
@@ -104,14 +119,19 @@
             用户Id
             </summary>
         </member>
+        <member name="P:Admin.Core.Common.BaseModel.IEntity`1.Id">
+            <summary>
+            主键Id
+            </summary>
+        </member>
         <member name="P:Admin.Core.Common.BaseModel.Entity`1.Id">
             <summary>
-            编号
+            主键Id
             </summary>
         </member>
         <member name="T:Admin.Core.Common.BaseModel.EntityAdd`1">
             <summary>
-            实体创建审计
+            实体创建
             </summary>
         </member>
         <member name="P:Admin.Core.Common.BaseModel.EntityAdd`1.CreatedUserId">
@@ -129,51 +149,61 @@
             创建时间
             </summary>
         </member>
-        <member name="T:Admin.Core.Common.BaseModel.EntityBase`1">
+        <member name="T:Admin.Core.Common.BaseModel.EntityFull`1">
             <summary>
-            实体审计
+            实体完整类
             </summary>
         </member>
-        <member name="P:Admin.Core.Common.BaseModel.EntityBase`1.Version">
+        <member name="P:Admin.Core.Common.BaseModel.EntityFull`1.TenantId">
+            <summary>
+            租户Id
+            </summary>
+        </member>
+        <member name="P:Admin.Core.Common.BaseModel.EntityFull`1.Version">
             <summary>
             版本
             </summary>
         </member>
-        <member name="P:Admin.Core.Common.BaseModel.EntityBase`1.IsDeleted">
+        <member name="P:Admin.Core.Common.BaseModel.EntityFull`1.IsDeleted">
             <summary>
             是否删除
             </summary>
         </member>
-        <member name="P:Admin.Core.Common.BaseModel.EntityBase`1.CreatedUserId">
+        <member name="P:Admin.Core.Common.BaseModel.EntityFull`1.CreatedUserId">
             <summary>
             创建者Id
             </summary>
         </member>
-        <member name="P:Admin.Core.Common.BaseModel.EntityBase`1.CreatedUserName">
+        <member name="P:Admin.Core.Common.BaseModel.EntityFull`1.CreatedUserName">
             <summary>
             创建者
             </summary>
         </member>
-        <member name="P:Admin.Core.Common.BaseModel.EntityBase`1.CreatedTime">
+        <member name="P:Admin.Core.Common.BaseModel.EntityFull`1.CreatedTime">
             <summary>
             创建时间
             </summary>
         </member>
-        <member name="P:Admin.Core.Common.BaseModel.EntityBase`1.ModifiedUserId">
+        <member name="P:Admin.Core.Common.BaseModel.EntityFull`1.ModifiedUserId">
             <summary>
             修改者Id
             </summary>
         </member>
-        <member name="P:Admin.Core.Common.BaseModel.EntityBase`1.ModifiedUserName">
+        <member name="P:Admin.Core.Common.BaseModel.EntityFull`1.ModifiedUserName">
             <summary>
             修改者
             </summary>
         </member>
-        <member name="P:Admin.Core.Common.BaseModel.EntityBase`1.ModifiedTime">
+        <member name="P:Admin.Core.Common.BaseModel.EntityFull`1.ModifiedTime">
             <summary>
             修改时间
             </summary>
         </member>
+        <member name="T:Admin.Core.Common.BaseModel.EntityFull">
+            <summary>
+            实体完整类
+            </summary>
+        </member>
         <member name="T:Admin.Core.Common.BaseModel.EntitySoftDelete`1">
             <summary>
             实体软删除
@@ -186,7 +216,7 @@
         </member>
         <member name="T:Admin.Core.Common.BaseModel.EntityUpdate`1">
             <summary>
-            实体修改审计
+            实体修改
             </summary>
         </member>
         <member name="P:Admin.Core.Common.BaseModel.EntityUpdate`1.ModifiedUserId">
@@ -224,6 +254,11 @@
             版本
             </summary>
         </member>
+        <member name="P:Admin.Core.Common.BaseModel.ITenant.TenantId">
+            <summary>
+            租户Id
+            </summary>
+        </member>
         <member name="T:Admin.Core.Common.Cache.CacheKey">
             <summary>
             缓存键
@@ -370,6 +405,26 @@
             Redis缓存
             </summary>
         </member>
+        <member name="T:Admin.Core.Common.Configs.TenantType">
+            <summary>
+            租户类型
+            </summary>
+        </member>
+        <member name="F:Admin.Core.Common.Configs.TenantType.None">
+            <summary>
+            无租户
+            </summary>
+        </member>
+        <member name="F:Admin.Core.Common.Configs.TenantType.Share">
+            <summary>
+            共享数据库
+            </summary>
+        </member>
+        <member name="F:Admin.Core.Common.Configs.TenantType.Own">
+            <summary>
+            独立数据库
+            </summary>
+        </member>
         <member name="T:Admin.Core.Common.Configs.AppConfig">
             <summary>
             应用配置
@@ -385,6 +440,11 @@
             跨域地址,默认 http://*:9000
             </summary>
         </member>
+        <member name="P:Admin.Core.Common.Configs.AppConfig.TenantType">
+            <summary>
+            租户类型
+            </summary>
+        </member>
         <member name="P:Admin.Core.Common.Configs.AppConfig.Swagger">
             <summary>
             Swagger文档
@@ -500,6 +560,26 @@
             限流连接字符串
             </summary>
         </member>
+        <member name="T:Admin.Core.Common.Configs.MultiDb">
+            <summary>
+            多数据库
+            </summary>
+        </member>
+        <member name="P:Admin.Core.Common.Configs.MultiDb.Name">
+            <summary>
+            数据库命名
+            </summary>
+        </member>
+        <member name="P:Admin.Core.Common.Configs.MultiDb.Type">
+            <summary>
+            数据库类型
+            </summary>
+        </member>
+        <member name="P:Admin.Core.Common.Configs.MultiDb.ConnectionString">
+            <summary>
+            数据库字符串
+            </summary>
+        </member>
         <member name="T:Admin.Core.Common.Configs.DbConfig">
             <summary>
             数据库配置
@@ -555,6 +635,11 @@
             监听Curd操作
             </summary>
         </member>
+        <member name="P:Admin.Core.Common.Configs.DbConfig.Dbs">
+            <summary>
+            多数据库
+            </summary>
+        </member>
         <member name="T:Admin.Core.Common.Configs.JwtConfig">
             <summary>
             Jwt配置
@@ -640,6 +725,11 @@
             文件格式
             </summary>
         </member>
+        <member name="T:Admin.Core.Common.Dbs.MySqlDb">
+            <summary>
+            多数据库命名
+            </summary>
+        </member>
         <member name="F:Admin.Core.Common.Extensions.DateTimeExtensions.TimestampStart">
             <summary>
             时间戳起始日期
@@ -1263,16 +1353,6 @@
             </summary>
         </member>
-        <member name="P:Admin.Core.Common.Output.OptionOutput.Disabled">
-            <summary>
-            禁用
-            </summary>
-        </member>
-        <member name="P:Admin.Core.Common.Output.OptionOutput.Data">
-            <summary>
-            额外数据
-            </summary>
-        </member>
         <member name="T:Admin.Core.Common.Output.PageOutput`1">
             <summary>
             分页信息输出

+ 50 - 0
Admin.Core/Admin.Core.Model.xml

@@ -179,6 +179,11 @@
             日志
             </summary>
         </member>
+        <member name="P:Admin.Core.Model.Admin.LogAbstract.TenantId">
+            <summary>
+            租户Id
+            </summary>
+        </member>
         <member name="P:Admin.Core.Model.Admin.LogAbstract.NickName">
             <summary>
             昵称
@@ -419,11 +424,56 @@
             权限
             </summary>
         </member>
+        <member name="T:Admin.Core.Model.Admin.TenantEntity">
+            <summary>
+            租户
+            </summary>
+        </member>
+        <member name="P:Admin.Core.Model.Admin.TenantEntity.Code">
+            <summary>
+            编码
+            </summary>
+        </member>
+        <member name="P:Admin.Core.Model.Admin.TenantEntity.Name">
+            <summary>
+            名称
+            </summary>
+        </member>
+        <member name="P:Admin.Core.Model.Admin.TenantEntity.DbType">
+            <summary>
+            数据库
+            </summary>
+        </member>
+        <member name="P:Admin.Core.Model.Admin.TenantEntity.ConnectionString">
+            <summary>
+            连接字符串
+            </summary>
+        </member>
+        <member name="P:Admin.Core.Model.Admin.TenantEntity.IdleTime">
+            <summary>
+            空闲时间(分)
+            </summary>
+        </member>
+        <member name="P:Admin.Core.Model.Admin.TenantEntity.Enabled">
+            <summary>
+            启用
+            </summary>
+        </member>
+        <member name="P:Admin.Core.Model.Admin.TenantEntity.Description">
+            <summary>
+            说明
+            </summary>
+        </member>
         <member name="T:Admin.Core.Model.Admin.UserEntity">
             <summary>
             用户
             </summary>
         </member>
+        <member name="P:Admin.Core.Model.Admin.UserEntity.TenantId">
+            <summary>
+            租户Id
+            </summary>
+        </member>
         <member name="P:Admin.Core.Model.Admin.UserEntity.UserName">
             <summary>
             账号

+ 115 - 0
Admin.Core/Admin.Core.Service.xml

@@ -257,6 +257,11 @@
             姓名
             </summary>
         </member>
+        <member name="P:Admin.Core.Service.Admin.Auth.Output.AuthLoginOutput.TenantId">
+            <summary>
+            租户Id
+            </summary>
+        </member>
         <member name="T:Admin.Core.Service.Admin.Auth.MapConfig">
             <summary>
             映射配置
@@ -1150,6 +1155,116 @@
             映射配置
             </summary>
         </member>
+        <member name="T:Admin.Core.Service.Admin.Tenant.Input.TenantAddInput">
+            <summary>
+            添加
+            </summary>
+        </member>
+        <member name="P:Admin.Core.Service.Admin.Tenant.Input.TenantAddInput.Code">
+            <summary>
+            编码
+            </summary>
+        </member>
+        <member name="P:Admin.Core.Service.Admin.Tenant.Input.TenantAddInput.Name">
+            <summary>
+            名称
+            </summary>
+        </member>
+        <member name="P:Admin.Core.Service.Admin.Tenant.Input.TenantAddInput.DbType">
+            <summary>
+            数据库
+            </summary>
+        </member>
+        <member name="P:Admin.Core.Service.Admin.Tenant.Input.TenantAddInput.ConnectionString">
+            <summary>
+            连接字符串
+            </summary>
+        </member>
+        <member name="P:Admin.Core.Service.Admin.Tenant.Input.TenantAddInput.IdleTime">
+            <summary>
+            空闲时间(分)
+            </summary>
+        </member>
+        <member name="P:Admin.Core.Service.Admin.Tenant.Input.TenantAddInput.Enabled">
+            <summary>
+            启用
+            </summary>
+        </member>
+        <member name="P:Admin.Core.Service.Admin.Tenant.Input.TenantAddInput.Description">
+            <summary>
+            说明
+            </summary>
+        </member>
+        <member name="T:Admin.Core.Service.Admin.Tenant.Input.TenantUpdateInput">
+            <summary>
+            修改
+            </summary>
+        </member>
+        <member name="P:Admin.Core.Service.Admin.Tenant.Input.TenantUpdateInput.Id">
+            <summary>
+            接口Id
+            </summary>
+        </member>
+        <member name="P:Admin.Core.Service.Admin.Tenant.Input.TenantUpdateInput.Version">
+            <summary>
+            版本
+            </summary>
+        </member>
+        <member name="P:Admin.Core.Service.Admin.Tenant.Output.TenantListOutput.Id">
+            <summary>
+            主键
+            </summary>
+        </member>
+        <member name="P:Admin.Core.Service.Admin.Tenant.Output.TenantListOutput.Code">
+            <summary>
+            编码
+            </summary>
+        </member>
+        <member name="P:Admin.Core.Service.Admin.Tenant.Output.TenantListOutput.Name">
+            <summary>
+            名称
+            </summary>
+        </member>
+        <member name="P:Admin.Core.Service.Admin.Tenant.Output.TenantListOutput.DbType">
+            <summary>
+            数据库
+            </summary>
+        </member>
+        <member name="P:Admin.Core.Service.Admin.Tenant.Output.TenantListOutput.DbTypeName">
+            <summary>
+            数据库名称
+            </summary>
+        </member>
+        <member name="P:Admin.Core.Service.Admin.Tenant.Output.TenantListOutput.ConnectionString">
+            <summary>
+            连接字符串
+            </summary>
+        </member>
+        <member name="P:Admin.Core.Service.Admin.Tenant.Output.TenantListOutput.IdleTime">
+            <summary>
+            空闲时间(分)
+            </summary>
+        </member>
+        <member name="P:Admin.Core.Service.Admin.Tenant.Output.TenantListOutput.Enabled">
+            <summary>
+            启用
+            </summary>
+        </member>
+        <member name="P:Admin.Core.Service.Admin.Tenant.Output.TenantListOutput.Description">
+            <summary>
+            说明
+            </summary>
+        </member>
+        <member name="P:Admin.Core.Service.Admin.Tenant.Output.TenantListOutput.CreatedTime">
+            <summary>
+            创建时间
+            </summary>
+        </member>
+        <member name="T:Admin.Core.Service.Admin.Tenant.MapConfig">
+            <summary>
+            映射配置
+            </summary>
+        </member>
         <member name="T:Admin.Core.Service.Admin.User.Input.UserAddInput">
             <summary>
             添加

+ 8 - 7
Admin.Core/Admin.Core.csproj

@@ -1,11 +1,11 @@
 <Project Sdk="Microsoft.NET.Sdk.Web">
 
   <PropertyGroup>
-    <TargetFramework>netcoreapp3.1</TargetFramework>
+    <TargetFramework>net5.0</TargetFramework>
     <!--<AspNetCoreHostingModel>InProcess</AspNetCoreHostingModel>-->
     <AspNetCoreHostingModel>OutOfProcess</AspNetCoreHostingModel>
     <GeneratePackageOnBuild>false</GeneratePackageOnBuild>
-    <Version>1.4.1</Version>
+    <Version>1.5.0</Version>
     <PackageLicenseExpression>MIT</PackageLicenseExpression>
     <Authors>xiaoxue</Authors>
     <Company>xiaoxue</Company>
@@ -16,6 +16,7 @@
     <PackageTags>ZhonTai Admin;WebApi</PackageTags>
     <PackageId>Admin.Core</PackageId>
     <Product>Admin.Core</Product>
+    <UserSecretsId>729fff27-b925-4753-a8c8-f3e9c0e50a40</UserSecretsId>
   </PropertyGroup>
 
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
@@ -44,14 +45,14 @@
   </ItemGroup>
 
   <ItemGroup>
-    <PackageReference Include="AspNetCoreRateLimit" Version="3.0.5" />
-    <PackageReference Include="Autofac.Extensions.DependencyInjection" Version="7.0.2" />
+    <PackageReference Include="AspNetCoreRateLimit" Version="3.2.1" />
+    <PackageReference Include="Autofac.Extensions.DependencyInjection" Version="7.1.0" />
     <PackageReference Include="Autofac.Extras.DynamicProxy" Version="6.0.0" />
     <PackageReference Include="Caching.CSRedis" Version="3.6.5" />
-    <PackageReference Include="FluentValidation.AspNetCore" Version="9.2.0" />
+    <PackageReference Include="FluentValidation.AspNetCore" Version="9.3.0" />
     <PackageReference Include="IdentityServer4.AccessTokenValidation" Version="3.0.1" />
-    <PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="3.1.9" />
-    <PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="3.1.9" />
+    <PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="5.0.0" />
+    <PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="5.0.0" />
     <PackageReference Include="Microsoft.Extensions.PlatformAbstractions" Version="1.1.0" />
     <PackageReference Include="NLog" Version="4.7.5" />
     <PackageReference Include="NLog.Web.AspNetCore" Version="4.9.3" />

+ 98 - 1
Admin.Core/Admin.Core.xml

@@ -534,6 +534,53 @@
             <param name="ids"></param>
             <returns></returns>
         </member>
+        <member name="T:Admin.Core.Controllers.Admin.TenantController">
+            <summary>
+            租户管理
+            </summary>
+        </member>
+        <member name="M:Admin.Core.Controllers.Admin.TenantController.Get(System.Int64)">
+            <summary>
+            查询单条租户
+            </summary>
+            <param name="id"></param>
+            <returns></returns>
+        </member>
+        <member name="M:Admin.Core.Controllers.Admin.TenantController.GetPage(Admin.Core.Common.Input.PageInput{Admin.Core.Model.Admin.TenantEntity})">
+            <summary>
+            查询分页租户
+            </summary>
+            <param name="model"></param>
+            <returns></returns>
+        </member>
+        <member name="M:Admin.Core.Controllers.Admin.TenantController.Add(Admin.Core.Service.Admin.Tenant.Input.TenantAddInput)">
+            <summary>
+            新增租户
+            </summary>
+            <param name="input"></param>
+            <returns></returns>
+        </member>
+        <member name="M:Admin.Core.Controllers.Admin.TenantController.Update(Admin.Core.Service.Admin.Tenant.Input.TenantUpdateInput)">
+            <summary>
+            修改租户
+            </summary>
+            <param name="input"></param>
+            <returns></returns>
+        </member>
+        <member name="M:Admin.Core.Controllers.Admin.TenantController.SoftDelete(System.Int64)">
+            <summary>
+            删除租户
+            </summary>
+            <param name="id"></param>
+            <returns></returns>
+        </member>
+        <member name="M:Admin.Core.Controllers.Admin.TenantController.BatchSoftDelete(System.Int64[])">
+            <summary>
+            批量删除租户
+            </summary>
+            <param name="ids"></param>
+            <returns></returns>
+        </member>
         <member name="T:Admin.Core.Controllers.Admin.UserController">
             <summary>
             用户管理
@@ -724,13 +771,63 @@
             <param name="db"></param>
             <returns></returns>
         </member>
-        <member name="M:Admin.Core.Db.ServiceCollectionExtensions.AddDb(Microsoft.Extensions.DependencyInjection.IServiceCollection,Microsoft.Extensions.Hosting.IHostEnvironment)">
+        <member name="M:Admin.Core.Db.DBServiceCollectionExtensions.AddDb(Microsoft.Extensions.DependencyInjection.IServiceCollection,Microsoft.Extensions.Hosting.IHostEnvironment)">
             <summary>
             添加数据库
             </summary>
             <param name="services"></param>
             <param name="env"></param>
         </member>
+        <member name="M:Admin.Core.Db.TenantDbHelper.CreateDatabase(Admin.Core.Common.Configs.DbConfig)">
+            <summary>
+            创建数据库
+            </summary>
+            <param name="dbConfig"></param>
+            <returns></returns>
+        </member>
+        <member name="M:Admin.Core.Db.TenantDbHelper.SyncStructure(IFreeSql,System.String,Admin.Core.Common.Configs.DbConfig)">
+            <summary>
+            同步结构
+            </summary>
+        </member>
+        <member name="M:Admin.Core.Db.TenantDbHelper.InitDtData``1(IFreeSql,``0[],System.Data.Common.DbTransaction,Admin.Core.Common.Configs.DbConfig)">
+            <summary>
+            初始化数据表数据
+            </summary>
+            <typeparam name="T"></typeparam>
+            <param name="db"></param>
+            <param name="data"></param>
+            <param name="tran"></param>
+            <param name="dbConfig"></param>
+            <returns></returns>
+        </member>
+        <member name="M:Admin.Core.Db.TenantDbHelper.SyncDataAuditValue(System.Object,FreeSql.Aop.AuditValueEventArgs)">
+            <summary>
+            同步数据审计方法
+            </summary>
+            <param name="s"></param>
+            <param name="e"></param>
+        </member>
+        <member name="M:Admin.Core.Db.TenantDbHelper.SyncData(IFreeSql,Admin.Core.Common.Configs.DbConfig)">
+            <summary>
+            同步数据
+            </summary>
+            <returns></returns>
+        </member>
+        <member name="M:Admin.Core.Db.TenantDbHelper.GenerateSimpleJsonData(IFreeSql)">
+            <summary>
+            生成极简数据
+            </summary>
+            <param name="db"></param>
+            <returns></returns>
+        </member>
+        <member name="M:Admin.Core.Db.TenantDBServiceCollectionExtensions.AddTenantDb(Microsoft.Extensions.DependencyInjection.IServiceCollection,Microsoft.Extensions.Hosting.IHostEnvironment)">
+            <summary>
+            添加租户数据库
+            </summary>
+            <param name="services"></param>
+            <param name="env"></param>
+        </member>
         <member name="T:Admin.Core.Enums.ApiVersion">
             <summary>
             接口版本

+ 3 - 3
Admin.Core/Aop/TransactionInterceptor.cs

@@ -5,16 +5,16 @@ using FreeSql;
 using Admin.Core.Common.Extensions;
 using Admin.Core.Common.Output;
 using Admin.Core.Common.Attributes;
-
+using Admin.Core.Repository;
 
 namespace Admin.Core.Aop
 {
     public class TransactionInterceptor : IInterceptor
     {
         IUnitOfWork _unitOfWork;
-        private readonly UnitOfWorkManager _unitOfWorkManager;
+        private readonly MyUnitOfWorkManager _unitOfWorkManager;
         
-        public TransactionInterceptor(UnitOfWorkManager unitOfWorkManager)
+        public TransactionInterceptor(MyUnitOfWorkManager unitOfWorkManager)
         {
             _unitOfWorkManager = unitOfWorkManager;
         }

+ 6 - 5
Admin.Core/Auth/PermissionHandler.cs

@@ -1,6 +1,5 @@
 using System.Linq;
 using System.Threading.Tasks;
-using Admin.Core.Common.Attributes;
 using Admin.Core.Service.Admin.User;
 
 namespace Admin.Core.Auth
@@ -8,7 +7,6 @@ namespace Admin.Core.Auth
     /// <summary>
     /// 权限处理
     /// </summary>
-   [SingleInstance]
     public class PermissionHandler : IPermissionHandler
     {
         private readonly IUserService _userService;
@@ -28,9 +26,12 @@ namespace Admin.Core.Auth
         {
             var permissions = await _userService.GetPermissionsAsync();
 
-            //var isValid = permissions.Any(m => m.EqualsIgnoreCase($"{httpMethod}/{api}"));
-            var isValid = permissions.Any(m => m != null && m.EqualsIgnoreCase($"/{api}"));
-            return isValid;
+            var valid = permissions.Any(m => 
+                m.Path.NotNull() && m.Path.EqualsIgnoreCase($"/{api}")
+                && m.HttpMethods.NotNull() && m.HttpMethods.Split(',').Any(n => n.NotNull() && n.EqualsIgnoreCase(httpMethod))
+            );
+
+            return valid;
         }
     }
 }

+ 2 - 1
Admin.Core/Controllers/Admin/AuthController.cs

@@ -60,7 +60,8 @@ namespace Admin.Core.Controllers.Admin
             {
                 new Claim(ClaimAttributes.UserId, user.Id.ToString()),
                 new Claim(ClaimAttributes.UserName, user.UserName),
-                new Claim(ClaimAttributes.UserNickName, user.NickName)
+                new Claim(ClaimAttributes.UserNickName, user.NickName),
+                new Claim(ClaimAttributes.TenantId, user.TenantId.ToString())
             });
 
             return ResponseOutput.Ok(new { token });

+ 89 - 0
Admin.Core/Controllers/Admin/TenantController.cs

@@ -0,0 +1,89 @@
+using System.Threading.Tasks;
+using Microsoft.AspNetCore.Mvc;
+using Admin.Core.Common.Input;
+using Admin.Core.Common.Output;
+using Admin.Core.Model.Admin;
+using Admin.Core.Service.Admin.Tenant;
+using Admin.Core.Service.Admin.Tenant.Input;
+
+namespace Admin.Core.Controllers.Admin
+{
+    /// <summary>
+    /// 租户管理
+    /// </summary>
+    public class TenantController : AreaController
+    {
+        private readonly ITenantService _roleServices;
+
+        public TenantController(ITenantService roleServices)
+        {
+            _roleServices = roleServices;
+        }
+
+        /// <summary>
+        /// 查询单条租户
+        /// </summary>
+        /// <param name="id"></param>
+        /// <returns></returns>
+        [HttpGet]
+        public async Task<IResponseOutput> Get(long id)
+        {
+            return await _roleServices.GetAsync(id);
+        }
+
+        /// <summary>
+        /// 查询分页租户
+        /// </summary>
+        /// <param name="model"></param>
+        /// <returns></returns>
+        [HttpPost]
+        public async Task<IResponseOutput> GetPage(PageInput<TenantEntity> model)
+        {
+            return await _roleServices.PageAsync(model);
+        }
+
+        /// <summary>
+        /// 新增租户
+        /// </summary>
+        /// <param name="input"></param>
+        /// <returns></returns>
+        [HttpPost]
+        public async Task<IResponseOutput> Add(TenantAddInput input)
+        {
+            return await _roleServices.AddAsync(input);
+        }
+
+        /// <summary>
+        /// 修改租户
+        /// </summary>
+        /// <param name="input"></param>
+        /// <returns></returns>
+        [HttpPut]
+        public async Task<IResponseOutput> Update(TenantUpdateInput input)
+        {
+            return await _roleServices.UpdateAsync(input);
+        }
+
+        /// <summary>
+        /// 删除租户
+        /// </summary>
+        /// <param name="id"></param>
+        /// <returns></returns>
+        [HttpDelete]
+        public async Task<IResponseOutput> SoftDelete(long id)
+        {
+            return await _roleServices.SoftDeleteAsync(id);
+        }
+
+        /// <summary>
+        /// 批量删除租户
+        /// </summary>
+        /// <param name="ids"></param>
+        /// <returns></returns>
+        [HttpPut]
+        public async Task<IResponseOutput> BatchSoftDelete(long[] ids)
+        {
+            return await _roleServices.BatchSoftDeleteAsync(ids);
+        }
+    }
+}

+ 32 - 6
Admin.Core/Db/ServiceCollectionExtensions.cs → Admin.Core/Db/DBServiceCollectionExtensions.cs

@@ -6,11 +6,11 @@ using FreeSql;
 using Admin.Core.Common.Configs;
 using Admin.Core.Common.Helpers;
 using Admin.Core.Common.Auth;
-using Admin.Core.Common.BaseModel;
+using Admin.Core.Common.Dbs;
 
 namespace Admin.Core.Db
 {
-    public static class ServiceCollectionExtensions
+    public static class DBServiceCollectionExtensions
     {
         /// <summary>
         /// 添加数据库
@@ -46,10 +46,6 @@ namespace Admin.Core.Db
             #endregion
 
             var fsql = freeSqlBuilder.Build();
-            //fsql.GlobalFilter.Apply<IEntitySoftDelete>("SoftDelete", a => a.IsDeleted == false);
-            services.AddFreeRepository(filter => filter.Apply<IEntitySoftDelete>("SoftDelete", a => a.IsDeleted == false));
-            services.AddScoped<UnitOfWorkManager>();
-            services.AddSingleton(fsql);
 
             #region 初始化数据库
             //同步结构
@@ -103,6 +99,9 @@ namespace Admin.Core.Db
                         case "CreatedUserName":
                             e.Value = user.Name;
                             break;
+                        case "TenantId":
+                            e.Value = user.TenantId;
+                            break;
                             //case "CreatedTime":
                             //    e.Value = DateTime.Now.Subtract(timeOffset);
                             //    break;
@@ -126,6 +125,33 @@ namespace Admin.Core.Db
             };
             #endregion
             #endregion
+
+            //导入多数据库
+            if(null != dbConfig.Dbs)
+            {
+                foreach (var multiDb in dbConfig.Dbs)
+                {
+
+                    switch (multiDb.Name)
+                    {
+                        case nameof(MySqlDb):
+                            var mdb = CreateMultiDbBuilder(multiDb).Build<MySqlDb>();
+                            services.AddSingleton(mdb);
+                            break;
+                        default:
+                            break;
+                    }
+                }
+            }
+        }
+
+        private static FreeSqlBuilder CreateMultiDbBuilder(MultiDb multiDb)
+        {
+            return new FreeSqlBuilder()
+            .UseConnectionString(multiDb.Type, multiDb.ConnectionString)
+            .UseAutoSyncStructure(false)
+            .UseLazyLoading(false)
+            .UseNoneCommandParameter(true);
         }
     }
 }

+ 2 - 0
Admin.Core/Db/Data.cs

@@ -1,4 +1,5 @@
 using Admin.Core.Model.Admin;
+
 namespace Admin.Core.Db
 {
     /// <summary>
@@ -14,5 +15,6 @@ namespace Admin.Core.Db
         public RoleEntity[] Roles { get; set; }
         public UserRoleEntity[] UserRoles { get; set; }
         public RolePermissionEntity[] RolePermissions { get; set; }
+        public TenantEntity[] Tenants { get; set; }
     }
 }

Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 0 - 0
Admin.Core/Db/Data/data.json


+ 36 - 20
Admin.Core/Db/DbHelper.cs

@@ -33,13 +33,13 @@ namespace Admin.Core.Db
 
             try
             {
-                Console.WriteLine("\r\ncreate database started");
+                Console.WriteLine("\r\n create database started");
                 await db.Ado.ExecuteNonQueryAsync(dbConfig.CreateDbSql);
-                Console.WriteLine("create database succeed\r\n");
+                Console.WriteLine(" create database succeed");
             }
             catch (Exception e)
             {
-                Console.WriteLine($"create database failed.\n{e.Message}\r\n");
+                Console.WriteLine($" create database failed.\n {e.Message}");
             }
         }
 
@@ -50,20 +50,20 @@ namespace Admin.Core.Db
         {
             //打印结构比对脚本
             //var dDL = db.CodeFirst.GetComparisonDDLStatements<PermissionEntity>();
-            //Console.WriteLine("\r\n" + dDL);
+            //Console.WriteLine("\r\n " + dDL);
 
             //打印结构同步脚本
             //db.Aop.SyncStructureAfter += (s, e) =>
             //{
             //    if (e.Sql.NotNull())
             //    {
-            //        Console.WriteLine("sync structure sql:\n" + e.Sql);
+            //        Console.WriteLine(" sync structure sql:\n" + e.Sql);
             //    }
             //};
 
             // 同步结构
             var dbType = dbConfig.Type.ToString();
-            Console.WriteLine($"{(msg.NotNull() ? msg : $"sync {dbType} structure")} started");
+            Console.WriteLine($"\r\n {(msg.NotNull() ? msg : $"sync {dbType} structure")} started");
             if(dbConfig.Type == DataType.Oracle)
             {
                 db.CodeFirst.IsSyncStructureToUpper = true;
@@ -81,9 +81,10 @@ namespace Admin.Core.Db
                 typeof(OprationLogEntity),
                 typeof(LoginLogEntity),
                 typeof(DocumentEntity),
-                typeof(DocumentImageEntity)
+                typeof(DocumentImageEntity),
+                typeof(TenantEntity)
             });
-            Console.WriteLine($"{(msg.NotNull() ? msg : $"sync {dbType} structure")} succeed\r\n");
+            Console.WriteLine($" {(msg.NotNull() ? msg : $"sync {dbType} structure")} succeed");
         }
 
         /// <summary>
@@ -128,21 +129,21 @@ namespace Admin.Core.Db
                             await insert.AppendData(data).InsertIdentity().ExecuteAffrowsAsync();
                         }
                         
-                        Console.WriteLine($"table: {tableName} sync data succeed");
+                        Console.WriteLine($" table: {tableName} sync data succeed");
                     }
                     else
                     {
-                        Console.WriteLine($"table: {tableName} import data []");
+                        Console.WriteLine($" table: {tableName} import data []");
                     }
                 }
                 else
                 {
-                    Console.WriteLine($"table: {tableName} record already exists");
+                    Console.WriteLine($" table: {tableName} record already exists");
                 }
             }
             catch (Exception ex)
             {
-                Console.WriteLine($"table: {tableName} sync data failed.\n{ex.Message}");
+                Console.WriteLine($" table: {tableName} sync data failed.\n{ex.Message}");
             }
         }
 
@@ -192,7 +193,7 @@ namespace Admin.Core.Db
                 //    Console.WriteLine($"{e.Sql}\r\n");
                 //};
 
-                Console.WriteLine("sync data started");
+                Console.WriteLine("\r\n sync data started");
 
                 db.Aop.AuditValue += SyncDataAuditValue;
                
@@ -211,17 +212,18 @@ namespace Admin.Core.Db
                     await InitDtData(db, data.Roles, tran, dbConfig);
                     await InitDtData(db, data.UserRoles, tran, dbConfig);
                     await InitDtData(db, data.RolePermissions, tran, dbConfig);
+                    await InitDtData(db, data.Tenants, tran, dbConfig);
 
                     uow.Commit();
                 }
 
                 db.Aop.AuditValue -= SyncDataAuditValue;
 
-                Console.WriteLine("sync data succeed\r\n");
+                Console.WriteLine(" sync data succeed");
             }
             catch (Exception ex)
             {
-                throw new Exception($"sync data failed.\n{ex.Message}\r\n");
+                throw new Exception($" sync data failed.\n{ex.Message}");
             }
         }
 
@@ -234,7 +236,7 @@ namespace Admin.Core.Db
         {
             try
             {
-                Console.WriteLine("\r\ngenerate data started");
+                Console.WriteLine("\r\n generate data started");
 
                 #region 数据表
 
@@ -340,9 +342,22 @@ namespace Admin.Core.Db
                 });
                 #endregion
 
+                #region 租户
+                var tenants = await db.Queryable<TenantEntity>().ToListAsync(a => new
+                {
+                    a.Id,
+                    a.Name,
+                    a.Code,
+                    a.DbType,
+                    a.ConnectionString,
+                    a.IdleTime,
+                    a.Description
+                });
+                #endregion
+
                 #endregion
 
-                if(!(users?.Count > 0))
+                if (!(users?.Count > 0))
                 {
                     return;
                 }
@@ -361,7 +376,8 @@ namespace Admin.Core.Db
                     users,
                     roles,
                     userRoles,
-                    rolePermissions
+                    rolePermissions,
+                    tenants
                 },
                 //Formatting.Indented, 
                 settings
@@ -370,11 +386,11 @@ namespace Admin.Core.Db
                 FileHelper.WriteFile(filePath, jsonData);
                 #endregion
 
-                Console.WriteLine("generate data succeed\r\n");
+                Console.WriteLine(" generate data succeed\r\n");
             }
             catch (Exception ex)
             {
-                throw new Exception($"generate data failed。\n{ex.Message}\r\n");
+                throw new Exception($" generate data failed。\n{ex.Message}\r\n");
             }
         }
     }

+ 116 - 0
Admin.Core/Db/TenantDBServiceCollectionExtensions.cs

@@ -0,0 +1,116 @@
+using System;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Hosting;
+using FreeSql;
+using Admin.Core.Common.Configs;
+using Admin.Core.Common.Helpers;
+using Admin.Core.Common.Auth;
+using Admin.Core.Common.BaseModel;
+using Admin.Core.Repository;
+
+namespace Admin.Core.Db
+{
+    //public class MyIdleBus : IdleBus<DbName, IFreeSql>
+    //{
+    //    public MyIdleBus() : base(TimeSpan.FromMinutes(30)) { }
+    //}
+
+    public static class TenantDBServiceCollectionExtensions
+    {
+        /// <summary>
+        /// 添加租户数据库
+        /// </summary>
+        /// <param name="services"></param>
+        /// <param name="env"></param>
+        public static void AddTenantDb(this IServiceCollection services, IHostEnvironment env)
+        {
+            services.AddScoped<MyUnitOfWorkManager>();
+            
+            var dbConfig = new ConfigHelper().Get<DbConfig>("dbconfig", env.EnvironmentName);
+            var appConfig = new ConfigHelper().Get<AppConfig>("appconfig", env.EnvironmentName);
+            var user = services.BuildServiceProvider().GetService<IUser>();
+            
+            IdleBus<IFreeSql> ib = new IdleBus<IFreeSql>(TimeSpan.FromMinutes(1));
+
+            ib.TryRegister("tenant_" + user.TenantId.ToString(), () =>
+            {
+                #region FreeSql
+                var freeSqlBuilder = new FreeSqlBuilder()
+                        .UseConnectionString(dbConfig.Type, dbConfig.ConnectionString)
+                        .UseLazyLoading(false)
+                        .UseNoneCommandParameter(true);
+
+                #region 监听所有命令
+                if (dbConfig.MonitorCommand)
+                {
+                    freeSqlBuilder.UseMonitorCommand(cmd => { }, (cmd, traceLog) =>
+                    {
+                        Console.WriteLine($"{cmd.CommandText}\r\n");
+                    });
+                }
+                #endregion
+
+                var fsql = freeSqlBuilder.Build();
+                fsql.GlobalFilter.Apply<IEntitySoftDelete>("SoftDelete", a => a.IsDeleted == false);
+                //共享数据库
+                if(appConfig.TenantType == TenantType.Share)
+                {
+                    fsql.GlobalFilter.ApplyIf<ITenant>("Tenant", () => user.TenantId > 0, a => a.TenantId == user.TenantId);
+                }
+
+                #region 监听Curd操作
+                if (dbConfig.Curd)
+                {
+                    fsql.Aop.CurdBefore += (s, e) =>
+                    {
+                        Console.WriteLine($"{e.Sql}\r\n");
+                    };
+                }
+                #endregion
+
+                #region 审计数据
+                fsql.Aop.AuditValue += (s, e) =>
+                {
+                    if (user == null || user.Id <= 0)
+                    {
+                        return;
+                    }
+
+                    if (e.AuditValueType == FreeSql.Aop.AuditValueType.Insert)
+                    {
+                        switch (e.Property.Name)
+                        {
+                            case "CreatedUserId":
+                                e.Value = user.Id;
+                                break;
+                            case "CreatedUserName":
+                                e.Value = user.Name;
+                                break;
+                            case "TenantId":
+                                e.Value = user.TenantId;
+                                break;
+                        }
+                    }
+                    else if (e.AuditValueType == FreeSql.Aop.AuditValueType.Update)
+                    {
+                        switch (e.Property.Name)
+                        {
+                            case "ModifiedUserId":
+                                e.Value = user.Id;
+                                break;
+                            case "ModifiedUserName":
+                                e.Value = user.Name;
+                                break;
+                        }
+                    }
+                };
+                #endregion
+                #endregion
+
+                return fsql;
+            });
+
+            services.AddSingleton(ib);
+        }
+    }
+}

+ 381 - 0
Admin.Core/Db/TenantDbHelper.cs

@@ -0,0 +1,381 @@
+using System;
+using System.IO;
+using System.Linq;
+using System.Threading.Tasks;
+using Newtonsoft.Json;
+using Newtonsoft.Json.Serialization;
+using FreeSql;
+using FreeSql.Aop;
+using FreeSql.DataAnnotations;
+using Admin.Core.Common.Configs;
+using Admin.Core.Common.Helpers;
+using Admin.Core.Model.Admin;
+
+namespace Admin.Core.Db
+{
+    public class TenantDbHelper
+    {
+        /// <summary>
+        /// 创建数据库
+        /// </summary>
+        /// <param name="dbConfig"></param>
+        /// <returns></returns>
+        public async static Task CreateDatabase(DbConfig dbConfig)
+        {
+            if (!dbConfig.CreateDb || dbConfig.Type == DataType.Sqlite)
+            {
+                return;
+            }
+
+            var db = new FreeSqlBuilder()
+                    .UseConnectionString(dbConfig.Type, dbConfig.CreateDbConnectionString)
+                    .Build();
+
+            try
+            {
+                Console.WriteLine("\r\ncreate database started");
+                await db.Ado.ExecuteNonQueryAsync(dbConfig.CreateDbSql);
+                Console.WriteLine("create database succeed\r\n");
+            }
+            catch (Exception e)
+            {
+                Console.WriteLine($"create database failed.\n{e.Message}\r\n");
+            }
+        }
+
+        /// <summary>
+        /// 同步结构
+        /// </summary>
+        public static void SyncStructure(IFreeSql db, string msg = null, DbConfig dbConfig = null)
+        {
+            //打印结构比对脚本
+            //var dDL = db.CodeFirst.GetComparisonDDLStatements<PermissionEntity>();
+            //Console.WriteLine("\r\n" + dDL);
+
+            //打印结构同步脚本
+            //db.Aop.SyncStructureAfter += (s, e) =>
+            //{
+            //    if (e.Sql.NotNull())
+            //    {
+            //        Console.WriteLine("sync structure sql:\n" + e.Sql);
+            //    }
+            //};
+
+            // 同步结构
+            var dbType = dbConfig.Type.ToString();
+            Console.WriteLine($"{(msg.NotNull() ? msg : $"sync {dbType} structure")} started");
+            if(dbConfig.Type == DataType.Oracle)
+            {
+                db.CodeFirst.IsSyncStructureToUpper = true;
+            }
+            db.CodeFirst.SyncStructure(new Type[]
+            {
+                typeof(DictionaryEntity),
+                typeof(ApiEntity),
+                typeof(ViewEntity),
+                typeof(PermissionEntity),
+                typeof(UserEntity),
+                typeof(RoleEntity),
+                typeof(UserRoleEntity),
+                typeof(RolePermissionEntity),
+                typeof(OprationLogEntity),
+                typeof(LoginLogEntity),
+                typeof(DocumentEntity),
+                typeof(DocumentImageEntity)
+            });
+            Console.WriteLine($"{(msg.NotNull() ? msg : $"sync {dbType} structure")} succeed\r\n");
+        }
+
+        /// <summary>
+        /// 初始化数据表数据
+        /// </summary>
+        /// <typeparam name="T"></typeparam>
+        /// <param name="db"></param>
+        /// <param name="data"></param>
+        /// <param name="tran"></param>
+        /// <param name="dbConfig"></param>
+        /// <returns></returns>
+        private static async Task InitDtData<T>(
+            IFreeSql db, 
+            T[] data, 
+            System.Data.Common.DbTransaction tran, 
+            DbConfig dbConfig = null
+        ) where T : class
+        {
+            var table = typeof(T).GetCustomAttributes(typeof(TableAttribute),false).FirstOrDefault() as TableAttribute;
+            var tableName = table.Name;
+
+            try
+            {
+                if (!await db.Queryable<T>().AnyAsync())
+                {
+                    if (data?.Length > 0)
+                    {
+                        var insert = db.Insert<T>();
+
+                        if(tran != null)
+                        {
+                            insert = insert.WithTransaction(tran);
+                        }
+
+                        if(dbConfig.Type == DataType.SqlServer)
+                        {
+                            var insrtSql = insert.AppendData(data).InsertIdentity().ToSql();
+                            await db.Ado.ExecuteNonQueryAsync($"SET IDENTITY_INSERT {tableName} ON\n {insrtSql} \nSET IDENTITY_INSERT {tableName} OFF");
+                        }
+                        else
+                        {
+                            await insert.AppendData(data).InsertIdentity().ExecuteAffrowsAsync();
+                        }
+                        
+                        Console.WriteLine($"table: {tableName} sync data succeed");
+                    }
+                    else
+                    {
+                        Console.WriteLine($"table: {tableName} import data []");
+                    }
+                }
+                else
+                {
+                    Console.WriteLine($"table: {tableName} record already exists");
+                }
+            }
+            catch (Exception ex)
+            {
+                Console.WriteLine($"table: {tableName} sync data failed.\n{ex.Message}");
+            }
+        }
+
+        /// <summary>
+        /// 同步数据审计方法
+        /// </summary>
+        /// <param name="s"></param>
+        /// <param name="e"></param>
+        private static void SyncDataAuditValue(object s, AuditValueEventArgs e)
+        {
+            if (e.AuditValueType == AuditValueType.Insert)
+            {
+                switch (e.Property.Name)
+                {
+                    case "CreatedUserId":
+                        e.Value = 2;
+                        break;
+                    case "CreatedUserName":
+                        e.Value = "admin";
+                        break;
+                }
+            }
+            else if (e.AuditValueType == AuditValueType.Update)
+            {
+                switch (e.Property.Name)
+                {
+                    case "ModifiedUserId":
+                        e.Value = 2;
+                        break;
+                    case "ModifiedUserName":
+                        e.Value = "admin";
+                        break;
+                }
+            }
+        }
+
+        /// <summary>
+        /// 同步数据
+        /// </summary>
+        /// <returns></returns>
+        public static async Task SyncData(IFreeSql db, DbConfig dbConfig = null)
+        {
+            try
+            {
+                //db.Aop.CurdBefore += (s, e) =>
+                //{
+                //    Console.WriteLine($"{e.Sql}\r\n");
+                //};
+
+                Console.WriteLine("sync data started");
+
+                db.Aop.AuditValue += SyncDataAuditValue;
+               
+                var filePath = Path.Combine(AppContext.BaseDirectory, "Db/Data/data.json").ToPath();
+                var jsonData = FileHelper.ReadFile(filePath);
+                var data = JsonConvert.DeserializeObject<Data>(jsonData);
+
+                using (var uow = db.CreateUnitOfWork())
+                using (var tran = uow.GetOrBeginTransaction())
+                {
+                    await InitDtData(db, data.Dictionaries, tran, dbConfig);
+                    await InitDtData(db, data.Apis, tran, dbConfig);
+                    await InitDtData(db, data.Views, tran, dbConfig);
+                    await InitDtData(db, data.Permissions, tran, dbConfig);
+                    await InitDtData(db, data.Users, tran, dbConfig);
+                    await InitDtData(db, data.Roles, tran, dbConfig);
+                    await InitDtData(db, data.UserRoles, tran, dbConfig);
+                    await InitDtData(db, data.RolePermissions, tran, dbConfig);
+
+                    uow.Commit();
+                }
+
+                db.Aop.AuditValue -= SyncDataAuditValue;
+
+                Console.WriteLine("sync data succeed\r\n");
+            }
+            catch (Exception ex)
+            {
+                throw new Exception($"sync data failed.\n{ex.Message}\r\n");
+            }
+        }
+
+        /// <summary>
+        /// 生成极简数据
+        /// </summary>
+        /// <param name="db"></param>
+        /// <returns></returns>
+        public static async Task GenerateSimpleJsonData(IFreeSql db)
+        {
+            try
+            {
+                Console.WriteLine("\r\ngenerate data started");
+
+                #region 数据表
+
+                #region 数据字典
+                var dictionaries = await db.Queryable<DictionaryEntity>().ToListAsync(a => new
+                {
+                    a.Id,
+                    a.ParentId,
+                    a.Name,
+                    a.Code,
+                    a.Value,
+                    a.Description,
+                    a.Sort
+                });
+                #endregion
+
+                #region 接口
+                var apis = await db.Queryable<ApiEntity>().ToListAsync(a => new
+                {
+                    a.Id,
+                    a.ParentId,
+                    a.Name,
+                    a.Label,
+                    a.Path,
+                    a.HttpMethods,
+                    a.Description,
+                    a.Sort
+                });
+                #endregion
+
+                #region 视图
+                var views = await db.Queryable<ViewEntity>().ToListAsync(a => new
+                {
+                    a.Id,
+                    a.ParentId,
+                    a.Name,
+                    a.Label,
+                    a.Path,
+                    a.Description,
+                    a.Sort
+                });
+                #endregion
+
+                #region 权限
+                var permissions = await db.Queryable<PermissionEntity>().ToListAsync(a => new
+                {
+                    a.Id,
+                    a.ParentId,
+                    a.Label,
+                    a.Code,
+                    a.Type,
+                    a.ViewId,
+                    a.ApiId,
+                    a.Path,
+                    a.Icon,
+                    a.Closable,
+                    a.Opened,
+                    a.NewWindow,
+                    a.External,
+                    a.Sort,
+                    a.Description
+                });
+                #endregion
+
+                #region 用户
+                var users = await db.Queryable<UserEntity>().ToListAsync(a => new
+                {
+                    a.Id,
+                    a.UserName,
+                    a.Password,
+                    a.NickName,
+                    a.Avatar,
+                    a.Status,
+                    a.Remark
+                });
+                #endregion
+
+                #region 角色
+                var roles = await db.Queryable<RoleEntity>().ToListAsync(a => new
+                {
+                    a.Id,
+                    a.Name,
+                    a.Sort,
+                    a.Description
+                });
+                #endregion
+
+                #region 用户角色
+                var userRoles = await db.Queryable<UserRoleEntity>().ToListAsync(a => new
+                {
+                    a.Id,
+                    a.UserId,
+                    a.RoleId
+                });
+                #endregion
+
+                #region 角色权限
+                var rolePermissions = await db.Queryable<RolePermissionEntity>().ToListAsync(a => new
+                {
+                    a.Id,
+                    a.RoleId,
+                    a.PermissionId
+                });
+                #endregion
+
+                #endregion
+
+                if(!(users?.Count > 0))
+                {
+                    return;
+                }
+
+                #region 生成数据
+                var settings = new JsonSerializerSettings();
+                settings.ContractResolver = new CamelCasePropertyNamesContractResolver();
+                settings.NullValueHandling = NullValueHandling.Ignore;
+                settings.DefaultValueHandling = DefaultValueHandling.Ignore;
+                var jsonData = JsonConvert.SerializeObject(new
+                {
+                    dictionaries,
+                    apis,
+                    views,
+                    permissions,
+                    users,
+                    roles,
+                    userRoles,
+                    rolePermissions
+                },
+                //Formatting.Indented, 
+                settings
+                );
+                var filePath = Path.Combine(Directory.GetCurrentDirectory(), "Db/Data/data.json").ToPath();
+                FileHelper.WriteFile(filePath, jsonData);
+                #endregion
+
+                Console.WriteLine("generate data succeed\r\n");
+            }
+            catch (Exception ex)
+            {
+                throw new Exception($"generate data failed。\n{ex.Message}\r\n");
+            }
+        }
+    }
+}

+ 2 - 2
Admin.Core/Program.cs

@@ -22,9 +22,9 @@ namespace Admin.Core
             var logger = LogManager.GetCurrentClassLogger();
             try
             {
-                Console.WriteLine("launching...");
+                Console.WriteLine(" launching...");
                 var host = CreateHostBuilder(args).Build();
-                Console.WriteLine($"{string.Join("\r\n", appConfig.Urls)}\r\n");
+                Console.WriteLine($"\r\n {string.Join("\r\n ", appConfig.Urls)}\r\n");
                 await host.RunAsync();
                 return 0;
             }

+ 8 - 1
Admin.Core/Startup.cs

@@ -36,6 +36,8 @@ using Admin.Core.Common.Attributes;
 using Admin.Core.Common.Auth;
 using AspNetCoreRateLimit;
 using IdentityServer4.AccessTokenValidation;
+using Admin.Core.Repository.Admin;
+using Admin.Core.Repository;
 
 namespace Admin.Core
 {
@@ -57,6 +59,8 @@ namespace Admin.Core
 
         public void ConfigureServices(IServiceCollection services)
         {
+            services.AddScoped<IPermissionHandler, PermissionHandler>();
+
             //用户信息
             services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
             if (_appConfig.IdentityServer.Enable)
@@ -72,6 +76,8 @@ namespace Admin.Core
 
             //数据库
             services.AddDb(_env).Wait();
+            //租户分库
+            services.AddTenantDb(_env);
 
             //应用配置
             services.AddSingleton(_appConfig);
@@ -260,7 +266,8 @@ namespace Admin.Core
             #region 操作日志
             if (_appConfig.Log.Operation)
             {
-                services.AddSingleton<ILogHandler, LogHandler>();
+                //services.AddSingleton<ILogHandler, LogHandler>();
+                services.AddScoped<ILogHandler, LogHandler>();
             }
             #endregion
 

+ 2 - 0
Admin.Core/configs/appconfig.json

@@ -3,6 +3,8 @@
   "urls": [ "http://*:8000" ],
   //跨域地址
   "corUrls": [ "http://*:9000" ],
+  //租户类型:None无租户, Share共享数据库, Own独立数据库
+  "tenantType": "None",
   //Swagger文档
   "swagger": false,
   //统一认证授权服务器

+ 2 - 2
Admin.Core/configs/cacheconfig.json

@@ -1,8 +1,8 @@
 {
   //缓存类型 Memory = 0,Redis = 1
-  "type": 0,
+  "type": "Memory",
   //限流缓存类型 Memory = 0,Redis = 1
-  "typeRateLimit": 0,
+  "typeRateLimit": "Memory",
   //Redis配置
   "redis": {
     //连接字符串

+ 14 - 3
Admin.Core/configs/dbconfig.json

@@ -29,12 +29,23 @@
   "generateData": false,
 
   //数据库配置 https://github.com/dotnetcore/FreeSql/wiki/入门
-  //数据库类型 MySql = 0, SqlServer = 1, PostgreSQL = 2, Oracle = 3, Sqlite = 4, OdbcOracle = 5, OdbcSqlServer = 6, OdbcMySql = 7, OdbcPostgreSQL = 8, Odbc = 9, OdbcDameng = 10, MsAccess = 11
-  "type": 4,
+  //数据库类型 MySql = 0, SqlServer = 1, PostgreSQL = 2, Oracle = 3, Sqlite = 4, OdbcOracle = 5, OdbcSqlServer = 6, OdbcMySql = 7, OdbcPostgreSQL = 8, Odbc = 9, OdbcDameng = 10, MsAccess = 11, Dameng = 12, OdbcKingbaseES = 13, ShenTong = 14, KingbaseES = 15, Firebird = 16
+  "type": "Sqlite",
   //连接字符串
   //MySql "Server=localhost; Port=3306; Database=admindb; Uid=root; Pwd=pwd; Charset=utf8mb4;"
   //SqlServer "Data Source=.;Integrated Security=True;Initial Catalog=admindb;Pooling=true;Min Pool Size=1"
   //PostgreSQL "Host=localhost;Port=5432;Username=postgres;Password=; Database=admindb;Pooling=true;Minimum Pool Size=1"
   //Sqlite "Data Source=|DataDirectory|\\admindb.db; Pooling=true;Min Pool Size=1"
-  "connectionString": "Data Source=|DataDirectory|\\admindb.db; Pooling=true;Min Pool Size=1"
+  "connectionString": "Data Source=|DataDirectory|\\admindb.db; Pooling=true;Min Pool Size=1",
+
+  //多数据库
+  //1、Common.Dbs中定义MySqlDb类
+  //2、IFreeSql<MySqlDb> _mySqlDb;
+  "dbs": [
+    //{
+    //  "name": "MySqlDb",
+    //  "type": "MySql",
+    //  "connectionString": "Server=localhost; Port=3306; Database=admindb; Uid=root; Pwd=pwd; Charset=utf8mb4;"
+    //}
+  ]
 }

Một số tệp đã không được hiển thị bởi vì quá nhiều tập tin thay đổi trong này khác