diff --git a/.gitignore b/.gitignore
new file mode 100644
index 00000000..89174ffc
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,45 @@
+# Build and Release Folders
+bin-debug/
+bin-release/
+[Oo]bj/
+[Bb]in/
+
+# Other files and folders
+.settings/
+
+# Executables
+*.swf
+*.air
+*.ipa
+*.apk
+
+# Project files, i.e. `.project`, `.actionScriptProperties` and `.flexProperties`
+# should NOT be excluded as they contain compiler settings and other important
+# information for Eclipse / Flash Builder.
+/Admin.NET/.vs
+/Admin.NET/packages
+/Admin.NET/Admin.NET.Web.Entry/wwwroot/Upload
+/Admin.NET/Admin.NET.Web.Entry/wwwroot/Avatar
+/Admin.NET/Admin.NET.Web.Entry/wwwroot/Signature
+/Admin.NET/Admin.NET.Web.Entry/wwwroot/CodeGen
+/Admin.NET/Admin.NET.Web.Entry/wwwroot/is-cache
+/Admin.NET/Admin.NET.Web.Core/Admin.NET.Web.Core.csproj.user
+/Admin.NET/Admin.NET.Web.Entry/Admin.NET.Web.Entry.csproj.user
+/Admin.NET/Admin.NET.Web.Entry/Properties/PublishProfiles
+/Admin.NET/Admin.NET.Web.Entry/publish
+/Admin.NET/Admin.NET.Web.Entry/logs
+/Admin.NET/Admin.NET.Web.Entry/Admin.NET.db
+
+# folders
+dist/
+node_modules/
+/Web/package-lock.json
+/Web/public/config.js
+/Web/stats.html
+/Web/npminstall-debug.log
+.vs
+.idea
+.DS_Store
+/Admin.NET/.vs
+/Admin.NET.App/unpackage
+/App/unpackage
diff --git a/Admin.NET/.dockerignore b/Admin.NET/.dockerignore
new file mode 100644
index 00000000..3729ff0c
--- /dev/null
+++ b/Admin.NET/.dockerignore
@@ -0,0 +1,25 @@
+**/.classpath
+**/.dockerignore
+**/.env
+**/.git
+**/.gitignore
+**/.project
+**/.settings
+**/.toolstarget
+**/.vs
+**/.vscode
+**/*.*proj.user
+**/*.dbmdl
+**/*.jfm
+**/azds.yaml
+**/bin
+**/charts
+**/docker-compose*
+**/Dockerfile*
+**/node_modules
+**/npm-debug.log
+**/obj
+**/secrets.dev.yaml
+**/values.dev.yaml
+LICENSE
+README.md
\ No newline at end of file
diff --git a/Admin.NET/.editorconfig b/Admin.NET/.editorconfig
new file mode 100644
index 00000000..aab71a9f
--- /dev/null
+++ b/Admin.NET/.editorconfig
@@ -0,0 +1,178 @@
+
+[*.cs]
+#### 命名样式 ####
+
+# 命名规则
+
+dotnet_naming_rule.interface_should_be_begins_with_i.severity = suggestion
+dotnet_naming_rule.interface_should_be_begins_with_i.symbols = interface
+dotnet_naming_rule.interface_should_be_begins_with_i.style = begins_with_i
+
+dotnet_naming_rule.types_should_be_pascal_case.severity = suggestion
+dotnet_naming_rule.types_should_be_pascal_case.symbols = types
+dotnet_naming_rule.types_should_be_pascal_case.style = pascal_case
+
+dotnet_naming_rule.non_field_members_should_be_pascal_case.severity = suggestion
+dotnet_naming_rule.non_field_members_should_be_pascal_case.symbols = non_field_members
+dotnet_naming_rule.non_field_members_should_be_pascal_case.style = pascal_case
+
+# 符号规范
+
+dotnet_naming_symbols.interface.applicable_kinds = interface
+dotnet_naming_symbols.interface.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
+dotnet_naming_symbols.interface.required_modifiers =
+
+dotnet_naming_symbols.types.applicable_kinds = class, struct, interface, enum
+dotnet_naming_symbols.types.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
+dotnet_naming_symbols.types.required_modifiers =
+
+dotnet_naming_symbols.non_field_members.applicable_kinds = property, event, method
+dotnet_naming_symbols.non_field_members.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
+dotnet_naming_symbols.non_field_members.required_modifiers =
+
+# 命名样式
+
+dotnet_naming_style.begins_with_i.required_prefix = I
+dotnet_naming_style.begins_with_i.required_suffix =
+dotnet_naming_style.begins_with_i.word_separator =
+dotnet_naming_style.begins_with_i.capitalization = pascal_case
+
+dotnet_naming_style.pascal_case.required_prefix =
+dotnet_naming_style.pascal_case.required_suffix =
+dotnet_naming_style.pascal_case.word_separator =
+dotnet_naming_style.pascal_case.capitalization = pascal_case
+
+dotnet_naming_style.pascal_case.required_prefix =
+dotnet_naming_style.pascal_case.required_suffix =
+dotnet_naming_style.pascal_case.word_separator =
+dotnet_naming_style.pascal_case.capitalization = pascal_case
+csharp_using_directive_placement = outside_namespace:silent
+csharp_style_expression_bodied_methods = false:silent
+csharp_style_expression_bodied_constructors = false:silent
+csharp_style_expression_bodied_operators = false:silent
+csharp_style_expression_bodied_properties = true:silent
+csharp_style_expression_bodied_indexers = true:silent
+csharp_style_expression_bodied_accessors = true:silent
+csharp_style_expression_bodied_lambdas = true:silent
+csharp_style_expression_bodied_local_functions = false:silent
+csharp_style_conditional_delegate_call = true:suggestion
+csharp_style_var_for_built_in_types = false:silent
+csharp_style_var_when_type_is_apparent = false:silent
+csharp_style_var_elsewhere = false:silent
+csharp_prefer_simple_using_statement = true:suggestion
+csharp_prefer_braces = true:silent
+csharp_style_namespace_declarations = file_scoped:silent
+csharp_style_prefer_top_level_statements = true:silent
+csharp_style_prefer_method_group_conversion = true:silent
+csharp_prefer_static_local_function = true:suggestion
+csharp_style_allow_embedded_statements_on_same_line_experimental = true:silent
+csharp_style_allow_blank_lines_between_consecutive_braces_experimental = true:silent
+csharp_style_allow_blank_line_after_colon_in_constructor_initializer_experimental = true:silent
+csharp_style_prefer_switch_expression = true:suggestion
+csharp_style_prefer_pattern_matching = true:silent
+csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion
+csharp_style_pattern_matching_over_as_with_null_check = true:suggestion
+csharp_style_prefer_not_pattern = true:suggestion
+csharp_style_prefer_extended_property_pattern = true:suggestion
+csharp_style_throw_expression = true:suggestion
+csharp_style_prefer_null_check_over_type_check = true:suggestion
+csharp_prefer_simple_default_expression = true:suggestion
+csharp_style_prefer_local_over_anonymous_function = true:suggestion
+csharp_style_prefer_index_operator = true:suggestion
+csharp_style_prefer_range_operator = true:suggestion
+csharp_style_implicit_object_creation_when_type_is_apparent = true:suggestion
+csharp_style_prefer_tuple_swap = true:suggestion
+csharp_style_prefer_utf8_string_literals = true:suggestion
+csharp_style_inlined_variable_declaration = true:suggestion
+csharp_style_deconstructed_variable_declaration = true:suggestion
+csharp_style_unused_value_assignment_preference = discard_variable:suggestion
+csharp_style_unused_value_expression_statement_preference = discard_variable:silent
+csharp_space_around_binary_operators = before_and_after
+csharp_indent_labels = one_less_than_current
+
+[*.vb]
+#### 命名样式 ####
+
+# 命名规则
+
+dotnet_naming_rule.interface_should_be_以_i_开始.severity = suggestion
+dotnet_naming_rule.interface_should_be_以_i_开始.symbols = interface
+dotnet_naming_rule.interface_should_be_以_i_开始.style = 以_i_开始
+
+dotnet_naming_rule.类型_should_be_帕斯卡拼写法.severity = suggestion
+dotnet_naming_rule.类型_should_be_帕斯卡拼写法.symbols = 类型
+dotnet_naming_rule.类型_should_be_帕斯卡拼写法.style = 帕斯卡拼写法
+
+dotnet_naming_rule.非字段成员_should_be_帕斯卡拼写法.severity = suggestion
+dotnet_naming_rule.非字段成员_should_be_帕斯卡拼写法.symbols = 非字段成员
+dotnet_naming_rule.非字段成员_should_be_帕斯卡拼写法.style = 帕斯卡拼写法
+
+# 符号规范
+
+dotnet_naming_symbols.interface.applicable_kinds = interface
+dotnet_naming_symbols.interface.applicable_accessibilities = public, friend, private, protected, protected_friend, private_protected
+dotnet_naming_symbols.interface.required_modifiers =
+
+dotnet_naming_symbols.类型.applicable_kinds = class, struct, interface, enum
+dotnet_naming_symbols.类型.applicable_accessibilities = public, friend, private, protected, protected_friend, private_protected
+dotnet_naming_symbols.类型.required_modifiers =
+
+dotnet_naming_symbols.非字段成员.applicable_kinds = property, event, method
+dotnet_naming_symbols.非字段成员.applicable_accessibilities = public, friend, private, protected, protected_friend, private_protected
+dotnet_naming_symbols.非字段成员.required_modifiers =
+
+# 命名样式
+
+dotnet_naming_style.以_i_开始.required_prefix = I
+dotnet_naming_style.以_i_开始.required_suffix =
+dotnet_naming_style.以_i_开始.word_separator =
+dotnet_naming_style.以_i_开始.capitalization = pascal_case
+
+dotnet_naming_style.帕斯卡拼写法.required_prefix =
+dotnet_naming_style.帕斯卡拼写法.required_suffix =
+dotnet_naming_style.帕斯卡拼写法.word_separator =
+dotnet_naming_style.帕斯卡拼写法.capitalization = pascal_case
+
+dotnet_naming_style.帕斯卡拼写法.required_prefix =
+dotnet_naming_style.帕斯卡拼写法.required_suffix =
+dotnet_naming_style.帕斯卡拼写法.word_separator =
+dotnet_naming_style.帕斯卡拼写法.capitalization = pascal_case
+
+[*.{cs,vb}]
+end_of_line = crlf
+dotnet_style_qualification_for_field = false:silent
+dotnet_style_qualification_for_property = false:silent
+dotnet_style_qualification_for_method = false:silent
+dotnet_style_qualification_for_event = false:silent
+dotnet_style_require_accessibility_modifiers = for_non_interface_members:silent
+dotnet_code_quality_unused_parameters = all:suggestion
+dotnet_style_readonly_field = true:suggestion
+dotnet_style_parentheses_in_arithmetic_binary_operators = always_for_clarity:silent
+dotnet_style_parentheses_in_other_binary_operators = always_for_clarity:silent
+dotnet_style_parentheses_in_other_operators = never_if_unnecessary:silent
+dotnet_style_parentheses_in_relational_binary_operators = always_for_clarity:silent
+dotnet_style_allow_multiple_blank_lines_experimental = true:silent
+dotnet_style_allow_statement_immediately_after_block_experimental = true:silent
+dotnet_style_coalesce_expression = true:suggestion
+dotnet_style_null_propagation = true:suggestion
+dotnet_style_prefer_is_null_check_over_reference_equality_method = true:suggestion
+dotnet_style_prefer_auto_properties = true:silent
+dotnet_style_object_initializer = true:suggestion
+dotnet_style_collection_initializer = true:suggestion
+dotnet_style_prefer_simplified_boolean_expressions = true:suggestion
+dotnet_style_prefer_conditional_expression_over_assignment = true:silent
+dotnet_style_prefer_conditional_expression_over_return = true:silent
+dotnet_style_explicit_tuple_names = true:suggestion
+dotnet_style_prefer_inferred_tuple_names = true:suggestion
+dotnet_style_prefer_inferred_anonymous_type_member_names = true:suggestion
+dotnet_style_prefer_compound_assignment = true:suggestion
+dotnet_style_prefer_simplified_interpolation = true:suggestion
+dotnet_style_namespace_match_folder = true:suggestion
+dotnet_style_predefined_type_for_locals_parameters_members = true:silent
+dotnet_style_predefined_type_for_member_access = true:silent
+indent_size = 4
+tab_width = 4
+dotnet_style_operator_placement_when_wrapping = beginning_of_line
+
+# Add copyright file header
+file_header_template = Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。\n\n本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。\n\n不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
\ No newline at end of file
diff --git a/Admin.NET/Admin.NET.Application/Admin.NET.Application.csproj b/Admin.NET/Admin.NET.Application/Admin.NET.Application.csproj
new file mode 100644
index 00000000..2ccdc952
--- /dev/null
+++ b/Admin.NET/Admin.NET.Application/Admin.NET.Application.csproj
@@ -0,0 +1,43 @@
+
+
+
+ net6.0;net8.0
+ 1701;1702;1591;8632
+
+ enable
+ True
+ disable
+ Admin.NET
+ Admin.NET 通用权限开发平台
+
+
+
+
+ true
+ PreserveNewest
+ PreserveNewest
+
+
+ true
+ PreserveNewest
+ PreserveNewest
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Admin.NET/Admin.NET.Application/Configuration/APIJSON.json b/Admin.NET/Admin.NET.Application/Configuration/APIJSON.json
new file mode 100644
index 00000000..5baf2316
--- /dev/null
+++ b/Admin.NET/Admin.NET.Application/Configuration/APIJSON.json
@@ -0,0 +1,34 @@
+{
+ "$schema": "https://gitee.com/dotnetchina/Furion/raw/v4/schemas/v4/furion-schema.json",
+
+ "APIJSON": {
+ "Roles": [
+ {
+ "RoleName": "Role1", // 权限名称 唯一
+ "Select": { // 查询
+ "Table": [ "*" ], // 可操作的表
+ "Column": [ "*" ], // 可操作的字段
+ "Filter": []
+ },
+ "Insert": { // 添加
+ "Table": [ "table1", "table2", "table3" ],
+ "Column": [ "*", "*", "tb.*" ]
+ },
+ "Update": { // 修改
+ "Table": [ "table1", "table2", "table3" ],
+ "Column": [ "*", "tb.*", "tb.*" ]
+ },
+ "Delete": { // 删除
+ "Table": [ "table1", "table2", "table3" ]
+ }
+ },
+ {
+ "RoleName": "Role2",
+ "Select": {
+ "Table": [ "table1" ],
+ "Column": [ "tb.*" ]
+ }
+ }
+ ]
+ }
+}
\ No newline at end of file
diff --git a/Admin.NET/Admin.NET.Application/Configuration/App.json b/Admin.NET/Admin.NET.Application/Configuration/App.json
new file mode 100644
index 00000000..d893a54b
--- /dev/null
+++ b/Admin.NET/Admin.NET.Application/Configuration/App.json
@@ -0,0 +1,52 @@
+{
+ "$schema": "https://gitee.com/dotnetchina/Furion/raw/v4/schemas/v4/furion-schema.json",
+
+ "Urls": "http://*:5005", // 配置默认端口
+ // "https_port": 44325,
+
+ "AllowedHosts": "*",
+
+ "AppSettings": {
+ "InjectSpecificationDocument": true, // 生产环境是否开启Swagger
+ "ExternalAssemblies": [ "plugins" ] // 插件目录
+ },
+ "DynamicApiControllerSettings": {
+ //"DefaultRoutePrefix": "api", // 默认路由前缀
+ "CamelCaseSeparator": "", // 驼峰命名分隔符
+ "SplitCamelCase": false, // 切割骆驼(驼峰)/帕斯卡命名
+ "LowercaseRoute": false, // 小写路由格式
+ "AsLowerCamelCase": true, // 小驼峰命名(首字母小写)
+ "KeepVerb": false, // 保留动作方法请求谓词
+ "KeepName": false // 保持原有名称不处理
+ },
+ "FriendlyExceptionSettings": {
+ "DefaultErrorMessage": "系统异常,请联系管理员",
+ "ThrowBah": true, // 是否将 Oops.Oh 默认抛出为业务异常
+ "LogError": false // 是否输出异常日志
+ },
+ "LocalizationSettings": {
+ "SupportedCultures": [ "zh-CN", "en" ], // 语言列表
+ "DefaultCulture": "zh-CN", // 默认语言
+ "DateTimeFormatCulture": "zh-CN" // 固定时间区域为特定时区(多语言)
+ },
+ "CorsAccessorSettings": {
+ //"PolicyName": "App.Cors.Policy",
+ //"WithOrigins": [ "http://localhost:5005", "https://gitee.com" ],
+ "WithExposedHeaders": [ "Content-Disposition", "X-Pagination", "access-token", "x-access-token" ], // 如果前端不代理且是axios请求
+ "SignalRSupport": true // 启用 SignalR 跨域支持
+ },
+ "SnowId": {
+ "WorkerId": 1, // 机器码 全局唯一
+ "WorkerIdBitLength": 6, // 机器码位长 默认值6,取值范围 [1, 19]
+ "SeqBitLength": 6, // 序列数位长 默认值6,取值范围 [3, 21](建议不小于4,值越大性能越高、Id位数也更长)
+ "WorkerPrefix": "adminnet_" // 缓存前缀
+ },
+ "Cryptogram": {
+ "StrongPassword": false, // 是否开启密码强度验证
+ "PasswordStrengthValidation": "(?=^.{6,16}$)(?=.*\\d)(?=.*\\W+)(?=.*[A-Z])(?=.*[a-z])(?!.*\\n).*$", // 密码强度验证正则表达式,必须须包含大小写字母、数字和特殊字符的组合,长度在6-16之间
+ "PasswordStrengthValidationMsg": "密码必须包含大小写字母、数字和特殊字符的组合,长度在6-16之间", // 密码强度验证消息提示
+ "CryptoType": "SM2", // 密码加密算法:MD5、SM2、SM4
+ "PublicKey": "04851D329AA3E38C2E7670AFE70E6E70E92F8769CA27C8766B12209A0FFBA4493B603EF7A0B9B1E16F0E8930C0406EA0B179B68DF28E25334BDEC4AE76D907E9E9", // 公钥
+ "PrivateKey": "3A61D1D30C6302DABFF36201D936D0143EEF0C850AF28C5CA6D5C045AF8C5C8A" // 私钥
+ }
+}
\ No newline at end of file
diff --git a/Admin.NET/Admin.NET.Application/Configuration/Cache.json b/Admin.NET/Admin.NET.Application/Configuration/Cache.json
new file mode 100644
index 00000000..de9969bd
--- /dev/null
+++ b/Admin.NET/Admin.NET.Application/Configuration/Cache.json
@@ -0,0 +1,35 @@
+{
+ "$schema": "https://gitee.com/dotnetchina/Furion/raw/v4/schemas/v4/furion-schema.json",
+
+ "Cache": {
+ "Prefix": "adminnet_", // 全局缓存前缀
+ "CacheType": "Memory", // Memory、Redis
+ "Redis": {
+ "Configuration": "server=127.0.0.1:6379;password=;db=5;", // Redis连接字符串
+ "Prefix": "adminnet_", // Redis前缀(目前没用)
+ "MaxMessageSize": "1048576" // 最大消息大小 默认1024 * 1024
+ }
+ },
+ "Cluster": { // 集群配置
+ "Enabled": false, // 启用集群:前提开启Redis缓存模式
+ "ServerId": "adminnet", // 服务器标识
+ "ServerIp": "", // 服务器IP
+ "SignalR": {
+ "RedisConfiguration": "127.0.0.1:6379,ssl=false,password=,defaultDatabase=5",
+ "ChannelPrefix": "signalrPrefix_"
+ },
+ "DataProtecteKey": "AdminNet:DataProtection-Keys",
+ "IsSentinel": false, // 是否哨兵模式
+ "SentinelConfig": {
+ "DefaultDb": "4",
+ "EndPoints": [ // 哨兵端口
+ // "10.10.0.124:26380"
+ ],
+ "MainPrefix": "adminNet:",
+ "Password": "123456",
+ "SentinelPassword": "adminNet",
+ "ServiceName": "adminNet",
+ "SignalRChannelPrefix": "signalR:"
+ }
+ }
+}
\ No newline at end of file
diff --git a/Admin.NET/Admin.NET.Application/Configuration/Captcha.json b/Admin.NET/Admin.NET.Application/Configuration/Captcha.json
new file mode 100644
index 00000000..0d8646fd
--- /dev/null
+++ b/Admin.NET/Admin.NET.Application/Configuration/Captcha.json
@@ -0,0 +1,28 @@
+{
+ "$schema": "https://gitee.com/dotnetchina/Furion/raw/v4/schemas/v4/furion-schema.json",
+
+ "CaptchaOptions": {
+ "CaptchaType": 10, // 验证码类型0、1、2、3、4、5、6、7、8、9、10、11
+ "CodeLength": 1, // 验证码长度, 要放在CaptchaType设置后 当类型为算术表达式时,长度代表操作的个数, 例如2
+ "ExpirySeconds": 60, // 验证码过期秒数
+ "IgnoreCase": true, // 比较时是否忽略大小写
+ "StoreageKeyPrefix": "", // 存储键前缀
+ "ImageOption": {
+ "Animation": true, // 是否启用动画
+ "FontSize": 36, // 字体大小
+ "Width": 150, // 验证码宽度
+ "Height": 50, // 验证码高度
+ "BubbleMinRadius": 5, // 气泡最小半径
+ "BubbleMaxRadius": 10, // 气泡最大半径
+ "BubbleCount": 3, // 气泡数量
+ "BubbleThickness": 1.0, // 气泡边沿厚度
+ "InterferenceLineCount": 3, // 干扰线数量
+ "FontFamily": "kaiti", // 包含actionj,epilog,fresnel,headache,lexo,prefix,progbot,ransom,robot,scandal,kaiti
+ "FrameDelay": 300, // 每帧延迟,Animation=true时有效, 默认300
+ "BackgroundColor": "#ffffff", // 格式: rgb, rgba, rrggbb, or rrggbbaa format to match web syntax, 默认#fff
+ "ForegroundColors": "", // 颜色格式同BackgroundColor,多个颜色逗号分割,随机选取。不填,空值,则使用默认颜色集
+ "Quality": 100, // 图片质量(质量越高图片越大,gif调整无效可能会更大)
+ "TextBold": true // 粗体
+ }
+ }
+}
\ No newline at end of file
diff --git a/Admin.NET/Admin.NET.Application/Configuration/CodeGen.json b/Admin.NET/Admin.NET.Application/Configuration/CodeGen.json
new file mode 100644
index 00000000..275087a8
--- /dev/null
+++ b/Admin.NET/Admin.NET.Application/Configuration/CodeGen.json
@@ -0,0 +1,20 @@
+{
+ "$schema": "https://gitee.com/dotnetchina/Furion/raw/v4/schemas/v4/furion-schema.json",
+
+ // 代码生成配置项-程序集名称集合
+ "CodeGen": {
+ "EntityAssemblyNames": [ "Admin.NET.Core", "Admin.NET.Application" ],
+ "BaseEntityNames": [ "EntityTenantId", "EntityTenant", "EntityTenantBaseData", "EntityBaseData", "EntityBase", "EntityBaseId" ],
+ "EntityBaseColumn": {
+ "EntityTenantId": [ "Id", "TenantId" ],
+ "EntityTenant": [ "Id", "CreateTime", "UpdateTime", "CreateUserId", "UpdateUserId", "CreateUserName", "UpdateUserName", "IsDelete", "TenantId" ],
+ "EntityTenantBaseData": [ "Id", "CreateTime", "UpdateTime", "CreateUserId", "UpdateUserId", "CreateUserName", "UpdateUserName", "IsDelete", "CreateOrgId", "CreateOrgName", "TenantId" ],
+ "EntityBaseData": [ "Id", "CreateTime", "UpdateTime", "CreateUserId", "UpdateUserId", "CreateUserName", "UpdateUserName", "IsDelete", "CreateOrgId", "CreateOrgName" ],
+ "EntityBase": [ "Id", "CreateTime", "UpdateTime", "CreateUserId", "UpdateUserId", "CreateUserName", "UpdateUserName", "IsDelete" ],
+ "EntityBaseId": [ "Id" ]
+ //"BaseId": [ "Id" ]
+ },
+ "FrontRootPath": "Web", // 前端项目根目录
+ "BackendApplicationNamespaces": [ "Admin.NET.Application", "Admin.NET.Application2" ] // 后端生成到的项目
+ }
+}
\ No newline at end of file
diff --git a/Admin.NET/Admin.NET.Application/Configuration/Database.json b/Admin.NET/Admin.NET.Application/Configuration/Database.json
new file mode 100644
index 00000000..5e5401a5
--- /dev/null
+++ b/Admin.NET/Admin.NET.Application/Configuration/Database.json
@@ -0,0 +1,76 @@
+{
+ "$schema": "https://gitee.com/dotnetchina/Furion/raw/v4/schemas/v4/furion-schema.json",
+
+ // 详细数据库配置见SqlSugar官网(第一个为默认库)
+ "DbConnection": {
+ "EnableConsoleSql": true, // 启用控制台打印SQL
+ "ConnectionConfigs": [
+ {
+ //"ConfigId": "1300000000001", // 默认库标识-禁止修改
+ "DbType": "Sqlite", // MySql、SqlServer、Sqlite、Oracle、PostgreSQL、Dm、Kdbndp、Oscar、MySqlConnector、Access、OpenGauss、QuestDB、HG、ClickHouse、GBase、Odbc、Custom
+ "ConnectionString": "DataSource=./Admin.NET.db", // 库连接字符串
+ //"SlaveConnectionConfigs": [ // 读写分离/主从
+ // {
+ // "HitRate": 10,
+ // "ConnectionString": "DataSource=./Admin.NET1.db"
+ // },
+ // {
+ // "HitRate": 10,
+ // "ConnectionString": "DataSource=./Admin.NET2.db"
+ // }
+ //],
+ "DbSettings": {
+ "EnableInitDb": true, // 启用库初始化
+ "EnableDiffLog": false, // 启用库表差异日志
+ "EnableUnderLine": false // 启用驼峰转下划线
+ },
+ "TableSettings": {
+ "EnableInitTable": true, // 启用表初始化
+ "EnableIncreTable": false // 启用表增量更新-特性[IncreTable]
+ },
+ "SeedSettings": {
+ "EnableInitSeed": true, // 启用种子初始化
+ "EnableIncreSeed": false // 启用种子增量更新-特性[IncreSeed]
+ }
+ }
+ //// 日志独立数据库配置
+ //{
+ // "ConfigId": "1300000000002", // 日志库标识-禁止修改
+ // "DbType": "Sqlite",
+ // "ConnectionString": "DataSource=./Admin.NET.Log.db", // 库连接字符串
+ // "DbSettings": {
+ // "EnableInitDb": true, // 启用库初始化
+ // "EnableDiffLog": false, // 启用库表差异日志
+ // "EnableUnderLine": false // 启用驼峰转下划线
+ // },
+ // "TableSettings": {
+ // "EnableInitTable": true, // 启用表初始化
+ // "EnableIncreTable": false // 启用表增量更新-特性[IncreTable]
+ // },
+ // "SeedSettings": {
+ // "EnableInitSeed": false, // 启用种子初始化
+ // "EnableIncreSeed": false // 启用种子增量更新-特性[IncreSeed]
+ // }
+ //},
+ //// 其他数据库配置(可以配置多个)
+ //{
+ // "ConfigId": "test", // 库标识
+ // "DbType": "Sqlite", // 库类型
+ // "ConnectionString": "DataSource=./Admin.NET.Test.db", // 库连接字符串
+ // "DbSettings": {
+ // "EnableInitDb": true, // 启用库初始化
+ // "EnableDiffLog": false, // 启用库表差异日志
+ // "EnableUnderLine": false // 启用驼峰转下划线
+ // },
+ // "TableSettings": {
+ // "EnableInitTable": true, // 启用表初始化
+ // "EnableIncreTable": false // 启用表增量更新-特性[IncreTable]
+ // },
+ // "SeedSettings": {
+ // "EnableInitSeed": true, // 启用种子初始化
+ // "EnableIncreSeed": false // 启用种子增量更新-特性[IncreSeed]
+ // }
+ //}
+ ]
+ }
+}
\ No newline at end of file
diff --git a/Admin.NET/Admin.NET.Application/Configuration/Email.json b/Admin.NET/Admin.NET.Application/Configuration/Email.json
new file mode 100644
index 00000000..bc53ba93
--- /dev/null
+++ b/Admin.NET/Admin.NET.Application/Configuration/Email.json
@@ -0,0 +1,14 @@
+{
+ "$schema": "https://gitee.com/dotnetchina/Furion/raw/v4/schemas/v4/furion-schema.json",
+
+ "Email": {
+ "Host": "smtp.163.com", // 主机
+ "Port": 465, // 端口 465、994、25
+ "EnableSsl": true, // 启用SSL
+ "DefaultFromEmail": "xxx@163.com", // 默认发件者邮箱
+ "DefaultToEmail": "xxx@qq.com", // 默认接收人邮箱
+ "UserName": "xxx@163.com", // 邮箱账号
+ "Password": "", // 邮箱授权码
+ "DefaultFromName": "Admin.NET 通用权限开发平台" // 默认邮件标题
+ }
+}
\ No newline at end of file
diff --git a/Admin.NET/Admin.NET.Application/Configuration/Enum.json b/Admin.NET/Admin.NET.Application/Configuration/Enum.json
new file mode 100644
index 00000000..dbcbbb11
--- /dev/null
+++ b/Admin.NET/Admin.NET.Application/Configuration/Enum.json
@@ -0,0 +1,8 @@
+{
+ "$schema": "https://gitee.com/dotnetchina/Furion/raw/v4/schemas/v4/furion-schema.json",
+
+ // 枚举实体所在程序集名称集合
+ "Enum": {
+ "EntityAssemblyNames": [ "Admin.NET.Core", "Admin.NET.Application", "Admin.NET.AppCMS" ]
+ }
+}
\ No newline at end of file
diff --git a/Admin.NET/Admin.NET.Application/Configuration/EventBus.json b/Admin.NET/Admin.NET.Application/Configuration/EventBus.json
new file mode 100644
index 00000000..520123e8
--- /dev/null
+++ b/Admin.NET/Admin.NET.Application/Configuration/EventBus.json
@@ -0,0 +1,12 @@
+{
+ "$schema": "https://gitee.com/dotnetchina/Furion/raw/v4/schemas/v4/furion-schema.json",
+
+ "EventBus": {
+ "RabbitMQ": {
+ "UserName": "adminnet",
+ "Password": "adminnet++123456",
+ "HostName": "127.0.0.1",
+ "Port": 5672
+ }
+ }
+}
\ No newline at end of file
diff --git a/Admin.NET/Admin.NET.Application/Configuration/JWT.json b/Admin.NET/Admin.NET.Application/Configuration/JWT.json
new file mode 100644
index 00000000..1864eaa4
--- /dev/null
+++ b/Admin.NET/Admin.NET.Application/Configuration/JWT.json
@@ -0,0 +1,17 @@
+{
+ "$schema": "https://gitee.com/dotnetchina/Furion/raw/v4/schemas/v4/furion-schema.json",
+
+ "JWTSettings": {
+ "ValidateIssuerSigningKey": true, // 是否验证密钥,bool 类型,默认true
+ "IssuerSigningKey": "3F025D682370B0126BBAE7A93D9B66CE3F025D682370B0126BBAE7A93D9B66CE", // 密钥,string 类型,必须是复杂密钥,长度大于16,.NET8+ 长度需大于 32,推荐MD5直接生成
+ "ValidateIssuer": true, // 是否验证签发方,bool 类型,默认true
+ "ValidIssuer": "Admin.NET", // 签发方,string 类型
+ "ValidateAudience": true, // 是否验证签收方,bool 类型,默认true
+ "ValidAudience": "Admin.NET", // 签收方,string 类型
+ "ValidateLifetime": true, // 是否验证过期时间,bool 类型,默认true,建议true
+ //"ExpiredTime": 20, // 过期时间,long 类型,单位分钟,默认20分钟,最大支持 13 年
+ "ClockSkew": 5, // 过期时间容错值,long 类型,单位秒,默认5秒
+ "Algorithm": "HS256", // 加密算法,string 类型,默认 HS256
+ "RequireExpirationTime": true // 验证过期时间,设置 false 将永不过期
+ }
+}
\ No newline at end of file
diff --git a/Admin.NET/Admin.NET.Application/Configuration/Limit.json b/Admin.NET/Admin.NET.Application/Configuration/Limit.json
new file mode 100644
index 00000000..9bce62cb
--- /dev/null
+++ b/Admin.NET/Admin.NET.Application/Configuration/Limit.json
@@ -0,0 +1,121 @@
+{
+ "$schema": "https://gitee.com/dotnetchina/Furion/raw/v4/schemas/v4/furion-schema.json",
+
+ // IP限流配置
+ "IpRateLimiting": {
+ // 例如:设置每分钟5次访问限流
+ // 当False时:每个接口都加入计数,不管你访问哪个接口,只要在一分钟内累计够5次,将禁止访问。
+ // 当True 时:当一分钟请求了5次GetData接口,则该接口将在时间段内禁止访问,但是还可以访问PostData()5次,总得来说是每个接口都有5次在这一分钟,互不干扰。
+ "EnableEndpointRateLimiting": true,
+ // 如果StackBlockedRequests设置为false,拒绝的API调用不会添加到调用次数计数器上。比如:如果客户端每秒发出3个请求并且您设置了每秒一个调用的限制,
+ // 则每分钟或每天计数器等其他限制将仅记录第一个调用,即成功的API调用。如果您希望被拒绝的API调用计入其他时间的显示(分钟,小时等),则必须设置
+ "StackBlockedRequests": false,
+ // 在RealIpHeader使用时,你的Kestrel服务器背后是一个反向代理,如果你的代理服务器使用不同的页眉然后提取客户端IP X-Real-IP使用此选项来设置它。
+ "RealIpHeader": "X-Real-IP",
+ // 将ClientIdHeader被用于提取白名单的客户端ID。如果此标头中存在客户端ID并且与ClientWhitelist中指定的值匹配,则不应用速率限制。
+ "ClientIdHeader": "X-ClientId",
+ // IP白名单:支持Ipv4和Ipv6
+ "IpWhitelist": [],
+ // 端点白名单
+ "EndpointWhitelist": [],
+ // 客户端白名单
+ "ClientWhitelist": [],
+ "QuotaExceededResponse": {
+ "Content": "{{\"code\":429,\"type\":\"error\",\"message\":\"访问过于频繁,请稍后重试!\",\"result\":null,\"extras\":null}}",
+ "ContentType": "application/json",
+ "StatusCode": 429
+ },
+ // 返回状态码
+ "HttpStatusCode": 429,
+ // API规则,结尾一定要带*
+ "GeneralRules": [
+ // 1秒钟只能调用10次
+ {
+ "Endpoint": "*",
+ "Period": "1s",
+ "Limit": 10
+ },
+ // 1分钟只能调用600次
+ {
+ "Endpoint": "*",
+ "Period": "1m",
+ "Limit": 600
+ },
+ // 1小时只能调用3600
+ {
+ "Endpoint": "*",
+ "Period": "1h",
+ "Limit": 3600
+ },
+ // 1天只能调用86400次
+ {
+ "Endpoint": "*",
+ "Period": "1d",
+ "Limit": 86400
+ }
+ ]
+ },
+ "IpRateLimitPolicies": {
+ "IpRules": [
+ {
+ "Ip": "XXX.XXX.XXX.XXX",
+ "Rules": [
+ {
+ "Endpoint": "*",
+ "Period": "1s",
+ "Limit": 10
+ },
+ {
+ "Endpoint": "*",
+ "Period": "1m",
+ "Limit": 600
+ }
+ ]
+ }
+ ]
+ },
+ // 客户端限流配置
+ "ClientRateLimiting": {
+ "EnableEndpointRateLimiting": true,
+ "ClientIdHeader": "X-ClientId",
+ "EndpointWhitelist": [],
+ "ClientWhitelist": [],
+ "QuotaExceededResponse": {
+ "Content": "{{\"code\":429,\"type\":\"error\",\"message\":\"访问人数过多,请稍后重试!\",\"result\":null,\"extras\":null}}",
+ "ContentType": "application/json",
+ "StatusCode": 429
+ },
+ "HttpStatusCode": 429,
+ "GeneralRules": [
+ {
+ "Endpoint": "*",
+ "Period": "1s",
+ "Limit": 10
+ },
+ {
+ "Endpoint": "*",
+ "Period": "1m",
+ "Limit": 600
+ }
+ ]
+ },
+ "ClientRateLimitPolicies": {
+ "ClientRules": [
+ {
+ "ClientId": "xxx-xxx",
+ "Rules": [
+ {
+ "Endpoint": "*",
+ "Period": "1s",
+ "Limit": 10
+ },
+ {
+ "Endpoint": "*",
+ "Period": "1m",
+ "Limit": 600
+ }
+ ]
+ }
+ ]
+ }
+}
\ No newline at end of file
diff --git a/Admin.NET/Admin.NET.Application/Configuration/Logging.json b/Admin.NET/Admin.NET.Application/Configuration/Logging.json
new file mode 100644
index 00000000..5dee96c3
--- /dev/null
+++ b/Admin.NET/Admin.NET.Application/Configuration/Logging.json
@@ -0,0 +1,47 @@
+{
+ "$schema": "https://gitee.com/dotnetchina/Furion/raw/v4/schemas/v4/furion-schema.json",
+
+ "Logging": {
+ "LogLevel": {
+ "Default": "Information",
+ "Microsoft.AspNetCore": "Warning",
+ "Microsoft.EntityFrameworkCore": "Information"
+ },
+ "File": {
+ "Enabled": false, // 启用文件日志
+ "FileName": "logs/{0:yyyyMMdd}_{1}.log", // 日志文件
+ "Append": true, // 追加覆盖
+ // "MinimumLevel": "Information", // 日志级别
+ "FileSizeLimitBytes": 10485760, // 10M=10*1024*1024
+ "MaxRollingFiles": 30 // 只保留30个文件
+ },
+ "Database": {
+ "Enabled": true, // 启用数据库日志
+ "MinimumLevel": "Information"
+ },
+ "ElasticSearch": {
+ "Enabled": false, // 启用ES日志
+ "AuthType": "Basic", // ES认证类型,可选 Basic、ApiKey、Base64ApiKey
+ "User": "admin", // Basic认证的用户名,使用Basic认证类型时必填
+ "Password": "123456", // Basic认证的密码,使用Basic认证类型时必填
+ "ApiId": "", // 使用ApiKey认证类型时必填
+ "ApiKey": "", // 使用ApiKey认证类型时必填
+ "Base64ApiKey": "TmtrOEszNEJuQ0NyaWlydGtROFk6SG1RZ0w3YzBTc2lCanJTYlV3aXNzZw==", // 使用Base64ApiKey认证类型时必填
+ "Fingerprint": "37:08:6A:C6:06:CC:9A:43:CF:ED:25:A2:1C:A4:69:57:90:31:2C:06:CA:61:56:39:6A:9C:46:11:BD:22:51:DA", // ES使用Https时的证书指纹
+ "ServerUris": [ "http://192.168.1.100:9200" ], // 地址
+ "DefaultIndex": "adminnet" // 索引
+ },
+ "Monitor": {
+ "GlobalEnabled": true, // 启用全局拦截日志
+ "IncludeOfMethods": [], // 拦截特定方法,当GlobalEnabled=false有效
+ "ExcludeOfMethods": [], // 排除特定方法,当GlobalEnabled=true有效
+ "BahLogLevel": "Information", // Oops.Oh 和 Oops.Bah 业务日志输出级别
+ "WithReturnValue": true, // 是否包含返回值,默认true
+ "ReturnValueThreshold": 500, // 返回值字符串阈值,默认0全量输出
+ "JsonBehavior": "None", // 是否输出Json,默认None(OnlyJson、All)
+ "JsonIndented": false, // 是否格式化Json
+ "UseUtcTimestamp": false, // 时间格式UTC、LOCAL
+ "ConsoleLog": true // 是否显示控制台日志
+ }
+ }
+}
\ No newline at end of file
diff --git a/Admin.NET/Admin.NET.Application/Configuration/OAuth.json b/Admin.NET/Admin.NET.Application/Configuration/OAuth.json
new file mode 100644
index 00000000..f2f28aa1
--- /dev/null
+++ b/Admin.NET/Admin.NET.Application/Configuration/OAuth.json
@@ -0,0 +1,14 @@
+{
+ "$schema": "https://gitee.com/dotnetchina/Furion/raw/v4/schemas/v4/furion-schema.json",
+
+ "OAuth": {
+ "Weixin": {
+ "ClientId": "xxx",
+ "ClientSecret": "xxx"
+ },
+ "Gitee": {
+ "ClientId": "xxx",
+ "ClientSecret": "xxx"
+ }
+ }
+}
\ No newline at end of file
diff --git a/Admin.NET/Admin.NET.Application/Configuration/SMS.json b/Admin.NET/Admin.NET.Application/Configuration/SMS.json
new file mode 100644
index 00000000..f126bff1
--- /dev/null
+++ b/Admin.NET/Admin.NET.Application/Configuration/SMS.json
@@ -0,0 +1,19 @@
+{
+ "$schema": "https://gitee.com/dotnetchina/Furion/raw/v4/schemas/v4/furion-schema.json",
+
+ "SMS": {
+ "Aliyun": {
+ "AccessKeyId": "",
+ "AccessKeySecret": "",
+ "SignName": "AdminNET 平台", // 短信签名
+ "TemplateCode": "" // 短信模板
+ },
+ "Tencentyun": {
+ "SdkAppId": "",
+ "AccessKeyId": "",
+ "AccessKeySecret": "",
+ "SignName": "AdminNET 平台", // 短信签名
+ "TemplateCode": "" // 短信模板
+ }
+ }
+}
\ No newline at end of file
diff --git a/Admin.NET/Admin.NET.Application/Configuration/Swagger.json b/Admin.NET/Admin.NET.Application/Configuration/Swagger.json
new file mode 100644
index 00000000..b8179caa
--- /dev/null
+++ b/Admin.NET/Admin.NET.Application/Configuration/Swagger.json
@@ -0,0 +1,32 @@
+{
+ "$schema": "https://gitee.com/dotnetchina/Furion/raw/v4/schemas/v4/furion-schema.json",
+
+ "SpecificationDocumentSettings": {
+ "DocumentTitle": "Admin.NET 通用权限开发平台",
+ "GroupOpenApiInfos": [
+ {
+ "Group": "Default",
+ "Title": "Admin.NET 通用权限开发平台",
+ "Description": "让 .NET 开发更简单、更通用、更流行。整合最新技术,模块插件式开发,前后端分离,开箱即用。",
+ "Version": "1.0.0",
+ "Order": 1000
+ },
+ {
+ "Group": "All Groups",
+ "Title": "所有接口",
+ "Description": "让 .NET 开发更简单、更通用、更流行。整合最新技术,模块插件式开发,前后端分离,开箱即用。",
+ "Version": "1.0.0",
+ "Order": 0
+ }
+ ],
+ "DefaultGroupName": "Default", // 默认分组名
+ "DocExpansionState": "List", // List、Full、None
+ "EnableAllGroups": true,
+ "LoginInfo": {
+ "Enabled": true, // 是否开启Swagger登录
+ "CheckUrl": "/api/swagger/checkUrl",
+ "SubmitUrl": "/api/swagger/submitUrl"
+ },
+ "EnumToNumber": true // 枚举类型生成值类型
+ }
+}
\ No newline at end of file
diff --git a/Admin.NET/Admin.NET.Application/Configuration/Upload.json b/Admin.NET/Admin.NET.Application/Configuration/Upload.json
new file mode 100644
index 00000000..85936520
--- /dev/null
+++ b/Admin.NET/Admin.NET.Application/Configuration/Upload.json
@@ -0,0 +1,28 @@
+{
+ "$schema": "https://gitee.com/dotnetchina/Furion/raw/v4/schemas/v4/furion-schema.json",
+
+ "Upload": {
+ "Path": "Upload/{yyyy}/{MM}/{dd}", // 文件上传目录
+ "MaxSize": 20480, // 文件最大限制KB:1024*20
+ "ContentType": [ "image/jpg", "image/png", "image/jpeg", "image/gif", "image/bmp", "text/plain", "application/pdf", "application/msword", "application/vnd.ms-excel", "application/vnd.ms-powerpoint", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", "application/vnd.openxmlformats-officedocument.wordprocessingml.document", "video/mp4", "application/wps-office.docx", "application/wps-office.xlsx" ],
+ "EnableMd5": false // 启用文件MDF5验证-防止重复上传
+ },
+ "OSSProvider": {
+ "IsEnable": false,
+ "Provider": "Minio", // OSS提供者 Invalid/Minio/Aliyun/QCloud/Qiniu/HuaweiCloud
+ "Endpoint": "xxx.xxx.xxx.xxx:8090", // 节点/API地址(在腾讯云OSS中表示AppId)
+ "Region": "xxx.xxx.xxx.xxx", // 地域
+ "AccessKey": "",
+ "SecretKey": "",
+ "IsEnableHttps": false, // 是否启用HTTPS
+ "IsEnableCache": true, // 是否启用缓存
+ "Bucket": "admin.net"
+ },
+ "SSHProvider": {
+ "IsEnable": false,
+ "Host": "127.0.0.1",
+ "Port": 8222,
+ "Username": "sshuser",
+ "Password": "Password.1"
+ }
+}
\ No newline at end of file
diff --git a/Admin.NET/Admin.NET.Application/Configuration/Wechat.json b/Admin.NET/Admin.NET.Application/Configuration/Wechat.json
new file mode 100644
index 00000000..b642ffd1
--- /dev/null
+++ b/Admin.NET/Admin.NET.Application/Configuration/Wechat.json
@@ -0,0 +1,31 @@
+{
+ "$schema": "https://gitee.com/dotnetchina/Furion/raw/v4/schemas/v4/furion-schema.json",
+
+ "Wechat": {
+ // 公众号
+ "WechatAppId": "",
+ "WechatAppSecret": "",
+ "WechatToken": "", // 微信公众号服务器配置中的令牌(Token)
+ "WechatEncodingAESKey": "", // 微信公众号服务器配置中的消息加解密密钥(EncodingAESKey)
+ // 小程序
+ "WxOpenAppId": "",
+ "WxOpenAppSecret": "",
+ "WxToken": "", // 小程序消息推送中的令牌(Token)
+ "WxEncodingAESKey": "" // 小程序消息推送中的消息加解密密钥(EncodingAESKey)
+ },
+ // 微信支付
+ "WechatPay": {
+ "AppId": "", // 微信公众平台AppId、开放平台AppId、小程序AppId、企业微信CorpId
+ "MerchantId": "", // 商户平台的商户号
+ "MerchantV3Secret": "", // 商户平台的APIv3密钥
+ "MerchantCertificateSerialNumber": "", // 商户平台的证书序列号
+ "MerchantCertificatePrivateKey": "\\WxPayCert\\apiclient_key.pem" // 商户平台的API证书私钥(apiclient_key.pem文件内容)
+ },
+ // 支付回调
+ "PayCallBack": {
+ "WechatPayUrl": "https://xxx/api/sysWechatPay/payCallBack", // 微信支付回调
+ "WechatRefundUrl": "", // 微信退款回调
+ "AlipayUrl": "", // 支付宝支付回调
+ "AlipayRefundUrl": "" // 支付宝退款回调
+ }
+}
\ No newline at end of file
diff --git a/Admin.NET/Admin.NET.Application/Const/AppClaimConst.cs b/Admin.NET/Admin.NET.Application/Const/AppClaimConst.cs
new file mode 100644
index 00000000..939eb975
--- /dev/null
+++ b/Admin.NET/Admin.NET.Application/Const/AppClaimConst.cs
@@ -0,0 +1,15 @@
+// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
+//
+// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
+//
+// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
+
+namespace Admin.NET.Application;
+
+///
+/// 移动端Claim相关常量
+///
+public class AppClaimConst : ClaimConst
+{
+
+}
\ No newline at end of file
diff --git a/Admin.NET/Admin.NET.Application/Const/ApplicationConst.cs b/Admin.NET/Admin.NET.Application/Const/ApplicationConst.cs
new file mode 100644
index 00000000..70ee2b6b
--- /dev/null
+++ b/Admin.NET/Admin.NET.Application/Const/ApplicationConst.cs
@@ -0,0 +1,18 @@
+// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
+//
+// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
+//
+// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
+
+namespace Admin.NET.Application;
+
+///
+/// 业务应用相关常量
+///
+public class ApplicationConst
+{
+ ///
+ /// API分组名称
+ ///
+ public const string GroupName = "xxx业务应用";
+}
\ No newline at end of file
diff --git a/Admin.NET/Admin.NET.Application/GlobalUsings.cs b/Admin.NET/Admin.NET.Application/GlobalUsings.cs
new file mode 100644
index 00000000..7dd67391
--- /dev/null
+++ b/Admin.NET/Admin.NET.Application/GlobalUsings.cs
@@ -0,0 +1,22 @@
+// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
+//
+// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
+//
+// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
+
+global using Admin.NET.Core;
+global using Furion;
+global using Furion.DependencyInjection;
+global using Furion.DynamicApiController;
+global using Furion.FriendlyException;
+global using Mapster;
+global using Microsoft.AspNetCore.Authorization;
+global using Microsoft.AspNetCore.Mvc;
+global using Microsoft.Extensions.DependencyInjection;
+global using SqlSugar;
+global using System;
+global using System.Collections.Generic;
+global using System.ComponentModel;
+global using System.ComponentModel.DataAnnotations;
+global using System.Threading.Tasks;
+global using System.Linq;
\ No newline at end of file
diff --git a/Admin.NET/Admin.NET.Application/OpenApi/DemoOpenApi.cs b/Admin.NET/Admin.NET.Application/OpenApi/DemoOpenApi.cs
new file mode 100644
index 00000000..22b91b3b
--- /dev/null
+++ b/Admin.NET/Admin.NET.Application/OpenApi/DemoOpenApi.cs
@@ -0,0 +1,28 @@
+// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
+//
+// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
+//
+// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
+
+namespace Admin.NET.Application;
+
+/////
+///// 示例开放接口
+/////
+//[ApiDescriptionSettings("开放接口", Name = "Demo", Order = 100)]
+//[Authorize(AuthenticationSchemes = SignatureAuthenticationDefaults.AuthenticationScheme)]
+//public class DemoOpenApi : IDynamicApiController
+//{
+// private readonly UserManager _userManager;
+
+// public DemoOpenApi(UserManager userManager)
+// {
+// _userManager = userManager;
+// }
+
+// [HttpGet("helloWord")]
+// public Task HelloWord()
+// {
+// return Task.FromResult($"Hello word. {_userManager.Account}");
+// }
+//}
\ No newline at end of file
diff --git a/Admin.NET/Admin.NET.Application/Service/App/Auth/AppAuthService.cs b/Admin.NET/Admin.NET.Application/Service/App/Auth/AppAuthService.cs
new file mode 100644
index 00000000..ee4309cb
--- /dev/null
+++ b/Admin.NET/Admin.NET.Application/Service/App/Auth/AppAuthService.cs
@@ -0,0 +1,313 @@
+// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
+//
+// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
+//
+// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
+
+using Admin.NET.Core.Service;
+using Furion.DataEncryption;
+using Furion.DataValidation;
+using Lazy.Captcha.Core;
+using Microsoft.AspNetCore.Http;
+using Yitter.IdGenerator;
+
+namespace Admin.NET.Application.Service.App;
+
+///
+/// 移动应用服务
+///
+[ApiDescriptionSettings(ApplicationConst.GroupName, Order = 500)]
+public class AppAuthService : IDynamicApiController, ITransient
+{
+ private readonly AppUserManager _appUserManager;
+ private readonly SqlSugarRepository _sysUserRep;
+ private readonly IHttpContextAccessor _httpContextAccessor;
+ private readonly SysMenuService _sysMenuService;
+ private readonly SysOnlineUserService _sysOnlineUserService;
+ private readonly SysConfigService _sysConfigService;
+ private readonly ICaptcha _captcha;
+ private readonly SysCacheService _sysCacheService;
+
+ public AppAuthService(AppUserManager appUserManager,
+ SqlSugarRepository sysUserRep,
+ IHttpContextAccessor httpContextAccessor,
+ SysMenuService sysMenuService,
+ SysOnlineUserService sysOnlineUserService,
+ SysConfigService sysConfigService,
+ ICaptcha captcha,
+ SysCacheService sysCacheService)
+ {
+ _appUserManager = appUserManager;
+ _sysUserRep = sysUserRep;
+ _httpContextAccessor = httpContextAccessor;
+ _sysMenuService = sysMenuService;
+ _sysOnlineUserService = sysOnlineUserService;
+ _sysConfigService = sysConfigService;
+ _captcha = captcha;
+ _sysCacheService = sysCacheService;
+ }
+
+ ///
+ /// 账号密码登录 🔖
+ ///
+ ///
+ ///
+ [AllowAnonymous]
+ [DisplayName("账号密码登录")]
+ public virtual async Task Login([Required] LoginInput input)
+ {
+ // 判断密码错误次数(默认5次,缓存30分钟)
+ var keyErrorPasswordCount = $"{CacheConst.KeyErrorPasswordCount}{input.Account}";
+ var errorPasswordCount = _sysCacheService.Get(keyErrorPasswordCount);
+ if (errorPasswordCount >= 5)
+ throw Oops.Oh(ErrorCodeEnum.D1027);
+
+ // 是否开启验证码
+ if (await _sysConfigService.GetConfigValue(CommonConst.SysCaptcha))
+ {
+ // 判断验证码
+ if (!_captcha.Validate(input.CodeId.ToString(), input.Code))
+ throw Oops.Oh(ErrorCodeEnum.D0008);
+ }
+
+ // 账号是否存在
+ var user = await _sysUserRep.AsQueryable().Includes(t => t.SysOrg).ClearFilter().FirstAsync(u => u.Account.Equals(input.Account));
+ _ = user ?? throw Oops.Oh(ErrorCodeEnum.D0009);
+
+ // 账号是否被冻结
+ if (user.Status == StatusEnum.Disable)
+ throw Oops.Oh(ErrorCodeEnum.D1017);
+
+ // 租户是否被禁用
+ var tenant = await _sysUserRep.ChangeRepository>().GetFirstAsync(u => u.Id == user.TenantId);
+ if (tenant != null && tenant.Status == StatusEnum.Disable)
+ throw Oops.Oh(ErrorCodeEnum.Z1003);
+
+ // 国密SM2解密(前端密码传输SM2加密后的)
+ try
+ {
+ input.Password = CryptogramUtil.SM2Decrypt(input.Password);
+ }
+ catch
+ {
+ throw Oops.Oh(ErrorCodeEnum.D0010);
+ }
+
+ VerifyPassword(input, keyErrorPasswordCount, errorPasswordCount, user);
+
+ // 登录成功则清空密码错误次数
+ _sysCacheService.Remove(keyErrorPasswordCount);
+
+ return await CreateToken(user);
+ }
+
+ ///
+ /// 验证用户密码
+ ///
+ ///
+ ///
+ ///
+ ///
+ private void VerifyPassword(LoginInput input, string keyErrorPasswordCount, int errorPasswordCount, SysUser user)
+ {
+ if (CryptogramUtil.CryptoType == CryptogramEnum.MD5.ToString())
+ {
+ if (!user.Password.Equals(MD5Encryption.Encrypt(input.Password)))
+ {
+ _sysCacheService.Set(keyErrorPasswordCount, ++errorPasswordCount, TimeSpan.FromMinutes(30));
+ throw Oops.Oh(ErrorCodeEnum.D1000);
+ }
+ }
+ else
+ {
+ if (!CryptogramUtil.Decrypt(user.Password).Equals(input.Password))
+ {
+ _sysCacheService.Set(keyErrorPasswordCount, ++errorPasswordCount, TimeSpan.FromMinutes(30));
+ throw Oops.Oh(ErrorCodeEnum.D1000);
+ }
+ }
+ }
+
+ ///
+ /// 手机号登录 🔖
+ ///
+ ///
+ ///
+ [AllowAnonymous]
+ [DisplayName("手机号登录")]
+ public virtual async Task LoginPhone([Required] LoginPhoneInput input)
+ {
+ var verifyCode = _sysCacheService.Get($"{CacheConst.KeyPhoneVerCode}{input.Phone}");
+ if (string.IsNullOrWhiteSpace(verifyCode))
+ throw Oops.Oh("验证码不存在或已失效,请重新获取!");
+ if (verifyCode != input.Code)
+ throw Oops.Oh("验证码错误!");
+
+ // 账号是否存在
+ var user = await _sysUserRep.AsQueryable().Includes(t => t.SysOrg).ClearFilter().FirstAsync(u => u.Phone.Equals(input.Phone));
+ _ = user ?? throw Oops.Oh(ErrorCodeEnum.D0009);
+
+ return await CreateToken(user);
+ }
+
+ ///
+ /// 生成Token令牌 🔖
+ ///
+ ///
+ ///
+ [NonAction]
+ public virtual async Task CreateToken(SysUser user)
+ {
+ // 单用户登录
+ await _sysOnlineUserService.SingleLogin(user.Id);
+
+ // 生成Token令牌
+ var tokenExpire = await _sysConfigService.GetTokenExpire();
+ var accessToken = JWTEncryption.Encrypt(new Dictionary
+ {
+ { AppClaimConst.UserId, user.Id },
+ { AppClaimConst.TenantId, user.TenantId },
+ { AppClaimConst.Account, user.Account },
+ { AppClaimConst.RealName, user.RealName },
+ { AppClaimConst.AccountType, user.AccountType },
+ { AppClaimConst.OrgId, user.OrgId },
+ { AppClaimConst.OrgName, user.SysOrg?.Name },
+ { AppClaimConst.OrgType, user.SysOrg?.Type },
+ }, tokenExpire);
+
+ // 生成刷新Token令牌
+ var refreshTokenExpire = await _sysConfigService.GetRefreshTokenExpire();
+ var refreshToken = JWTEncryption.GenerateRefreshToken(accessToken, refreshTokenExpire);
+
+ // 设置响应报文头
+ _httpContextAccessor.HttpContext.SetTokensOfResponseHeaders(accessToken, refreshToken);
+
+ // Swagger Knife4UI-AfterScript登录脚本
+ // ke.global.setAllHeader('Authorization', 'Bearer ' + ke.response.headers['access-token']);
+
+ return new LoginOutput
+ {
+ AccessToken = accessToken,
+ RefreshToken = refreshToken
+ };
+ }
+
+ ///
+ /// 获取登录账号 🔖
+ ///
+ ///
+ [DisplayName("获取登录账号")]
+ public virtual async Task GetUserInfo()
+ {
+ var user = await _sysUserRep.GetFirstAsync(u => u.Id == _appUserManager.UserId) ?? throw Oops.Oh(ErrorCodeEnum.D1011).StatusCode(401);
+ // 获取机构
+ var org = await _sysUserRep.ChangeRepository>().GetFirstAsync(u => u.Id == user.OrgId);
+ // 获取职位
+ var pos = await _sysUserRep.ChangeRepository>().GetFirstAsync(u => u.Id == user.PosId);
+ // 获取按钮集合
+ var buttons = await _sysMenuService.GetOwnBtnPermList();
+ // 获取角色集合
+ var roleIds = await _sysUserRep.ChangeRepository>().AsQueryable()
+ .Where(u => u.UserId == user.Id).Select(u => u.RoleId).ToListAsync();
+
+ return new LoginUserOutput
+ {
+ Id = user.Id,
+ Account = user.Account,
+ RealName = user.RealName,
+ Phone = user.Phone,
+ IdCardNum = user.IdCardNum,
+ Email = user.Email,
+ AccountType = user.AccountType,
+ Avatar = user.Avatar,
+ Address = user.Address,
+ Signature = user.Signature,
+ OrgId = user.OrgId,
+ OrgName = org?.Name,
+ OrgType = org?.Type,
+ PosName = pos?.Name,
+ Buttons = buttons,
+ RoleIds = roleIds
+ };
+ }
+
+ ///
+ /// 获取刷新Token 🔖
+ ///
+ ///
+ ///
+ [DisplayName("获取刷新Token")]
+ public virtual string GetRefreshToken([FromQuery] string accessToken)
+ {
+ var refreshTokenExpire = _sysConfigService.GetRefreshTokenExpire().GetAwaiter().GetResult();
+ return JWTEncryption.GenerateRefreshToken(accessToken, refreshTokenExpire);
+ }
+
+ ///
+ /// 退出系统 🔖
+ ///
+ [DisplayName("退出系统")]
+ public void Logout()
+ {
+ if (string.IsNullOrWhiteSpace(_appUserManager.Account))
+ throw Oops.Oh(ErrorCodeEnum.D1011);
+
+ _httpContextAccessor.HttpContext.SignoutToSwagger();
+ }
+
+ ///
+ /// 获取验证码 🔖
+ ///
+ ///
+ [AllowAnonymous]
+ [SuppressMonitor]
+ [DisplayName("获取验证码")]
+ public dynamic GetCaptcha()
+ {
+ var codeId = YitIdHelper.NextId().ToString();
+ var captcha = _captcha.Generate(codeId);
+ return new { Id = codeId, Img = captcha.Base64 };
+ }
+
+ ///
+ /// 修改用户密码
+ ///
+ ///
+ ///
+ [DisplayName("修改用户密码")]
+ public async Task ChangePwd(ChangePwdInput input)
+ {
+ // 国密SM2解密(前端密码传输SM2加密后的)
+ input.PasswordOld = CryptogramUtil.SM2Decrypt(input.PasswordOld);
+ input.PasswordNew = CryptogramUtil.SM2Decrypt(input.PasswordNew);
+
+ var user = await _sysUserRep.GetFirstAsync(u => u.Id == _appUserManager.UserId) ?? throw Oops.Oh(ErrorCodeEnum.D0009);
+ if (CryptogramUtil.CryptoType == CryptogramEnum.MD5.ToString())
+ {
+ if (user.Password != MD5Encryption.Encrypt(input.PasswordOld))
+ throw Oops.Oh(ErrorCodeEnum.D1004);
+ }
+ else
+ {
+ if (CryptogramUtil.Decrypt(user.Password) != input.PasswordOld)
+ throw Oops.Oh(ErrorCodeEnum.D1004);
+ }
+
+ if (input.PasswordOld == input.PasswordNew)
+ throw Oops.Oh(ErrorCodeEnum.D1028);
+
+ // 验证密码强度
+ if (CryptogramUtil.StrongPassword)
+ {
+ user.Password = input.PasswordNew.TryValidate(CryptogramUtil.PasswordStrengthValidation)
+ ? CryptogramUtil.Encrypt(input.PasswordNew)
+ : throw Oops.Oh(CryptogramUtil.PasswordStrengthValidationMsg);
+ }
+ else
+ {
+ user.Password = CryptogramUtil.Encrypt(input.PasswordNew);
+ }
+
+ return await _sysUserRep.AsUpdateable(user).UpdateColumns(u => u.Password).ExecuteCommandAsync();
+ }
+}
\ No newline at end of file
diff --git a/Admin.NET/Admin.NET.Application/Service/App/Auth/AppUserManager.cs b/Admin.NET/Admin.NET.Application/Service/App/Auth/AppUserManager.cs
new file mode 100644
index 00000000..9d091059
--- /dev/null
+++ b/Admin.NET/Admin.NET.Application/Service/App/Auth/AppUserManager.cs
@@ -0,0 +1,22 @@
+// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
+//
+// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
+//
+// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
+
+using Microsoft.AspNetCore.Http;
+
+namespace Admin.NET.Application.Service.App;
+
+public class AppUserManager : UserManager
+{
+ private readonly IHttpContextAccessor _httpContextAccessor;
+
+ public AppUserManager(IHttpContextAccessor httpContextAccessor) : base(httpContextAccessor)
+ {
+ _httpContextAccessor = httpContextAccessor;
+ }
+
+ // 扩展属性
+
+}
\ No newline at end of file
diff --git a/Admin.NET/Admin.NET.Application/Startup.cs b/Admin.NET/Admin.NET.Application/Startup.cs
new file mode 100644
index 00000000..29aa3182
--- /dev/null
+++ b/Admin.NET/Admin.NET.Application/Startup.cs
@@ -0,0 +1,22 @@
+// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
+//
+// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
+//
+// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
+
+using Microsoft.AspNetCore.Builder;
+using Microsoft.AspNetCore.Hosting;
+
+namespace Admin.NET.Application;
+
+[AppStartup(100)]
+public class Startup : AppStartup
+{
+ public void ConfigureServices(IServiceCollection services)
+ {
+ }
+
+ public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
+ {
+ }
+}
\ No newline at end of file
diff --git a/Admin.NET/Admin.NET.Core/Admin.NET.Core.csproj b/Admin.NET/Admin.NET.Core/Admin.NET.Core.csproj
new file mode 100644
index 00000000..583bdf82
--- /dev/null
+++ b/Admin.NET/Admin.NET.Core/Admin.NET.Core.csproj
@@ -0,0 +1,65 @@
+
+
+
+ net6.0;net8.0
+ 1701;1702;1591;8632
+
+ enable
+ true
+ disable
+ True
+ Admin.NET
+ Admin.NET 通用权限开发平台
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Admin.NET/Admin.NET.Core/Attribute/AppSeedAttribute.cs b/Admin.NET/Admin.NET.Core/Attribute/AppSeedAttribute.cs
new file mode 100644
index 00000000..869bbf22
--- /dev/null
+++ b/Admin.NET/Admin.NET.Core/Attribute/AppSeedAttribute.cs
@@ -0,0 +1,16 @@
+// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
+//
+// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
+//
+// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
+
+namespace Admin.NET.Core;
+
+///
+/// 业务应用种子特性
+///
+[SuppressSniffer]
+[AttributeUsage(AttributeTargets.Class, AllowMultiple = true, Inherited = true)]
+public class AppSeedAttribute : Attribute
+{
+}
\ No newline at end of file
diff --git a/Admin.NET/Admin.NET.Core/Attribute/ConstAttribute.cs b/Admin.NET/Admin.NET.Core/Attribute/ConstAttribute.cs
new file mode 100644
index 00000000..baf5a609
--- /dev/null
+++ b/Admin.NET/Admin.NET.Core/Attribute/ConstAttribute.cs
@@ -0,0 +1,22 @@
+// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
+//
+// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
+//
+// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
+
+namespace Admin.NET.Core;
+
+///
+/// 常量特性
+///
+[SuppressSniffer]
+[AttributeUsage(AttributeTargets.All, AllowMultiple = true, Inherited = true)]
+public class ConstAttribute : Attribute
+{
+ public string Name { get; set; }
+
+ public ConstAttribute(string name)
+ {
+ Name = name;
+ }
+}
\ No newline at end of file
diff --git a/Admin.NET/Admin.NET.Core/Attribute/CustomUnifyResultAttribute.cs b/Admin.NET/Admin.NET.Core/Attribute/CustomUnifyResultAttribute.cs
new file mode 100644
index 00000000..05434228
--- /dev/null
+++ b/Admin.NET/Admin.NET.Core/Attribute/CustomUnifyResultAttribute.cs
@@ -0,0 +1,22 @@
+// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
+//
+// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
+//
+// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
+
+namespace Admin.NET.Core;
+
+///
+/// 自定义规范化结果特性
+///
+[SuppressSniffer]
+[AttributeUsage(AttributeTargets.All, AllowMultiple = true, Inherited = true)]
+public class CustomUnifyResultAttribute : Attribute
+{
+ public string Name { get; set; }
+
+ public CustomUnifyResultAttribute(string name)
+ {
+ Name = name;
+ }
+}
\ No newline at end of file
diff --git a/Admin.NET/Admin.NET.Core/Attribute/IdempotentAttribute.cs b/Admin.NET/Admin.NET.Core/Attribute/IdempotentAttribute.cs
new file mode 100644
index 00000000..d9664b62
--- /dev/null
+++ b/Admin.NET/Admin.NET.Core/Attribute/IdempotentAttribute.cs
@@ -0,0 +1,105 @@
+// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
+//
+// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
+//
+// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
+
+using System.Security.Claims;
+
+namespace Admin.NET.Core;
+
+///
+/// 防止重复请求过滤器特性
+///
+[SuppressSniffer]
+[AttributeUsage(AttributeTargets.All, AllowMultiple = true, Inherited = true)]
+public class IdempotentAttribute : Attribute, IAsyncActionFilter
+{
+ ///
+ /// 请求间隔时间/秒
+ ///
+ public int IntervalTime { get; set; } = 5;
+
+ ///
+ /// 错误提示内容
+ ///
+ public string Message { get; set; } = "你操作频率过快,请稍后重试!";
+
+ ///
+ /// 缓存前缀: Key+请求路由+用户Id+请求参数
+ ///
+ public string CacheKey { get; set; }
+
+ ///
+ /// 是否直接抛出异常:Ture是,False返回上次请求结果
+ ///
+ public bool ThrowBah { get; set; }
+
+ public IdempotentAttribute()
+ {
+ }
+
+ public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
+ {
+ var httpContext = context.HttpContext;
+ var path = httpContext.Request.Path.Value.ToString();
+ var userId = httpContext.User?.FindFirstValue(ClaimConst.UserId);
+ var cacheExpireTime = TimeSpan.FromSeconds(IntervalTime);
+
+ var parameters = "";
+ foreach (var parameter in context.ActionDescriptor.Parameters)
+ {
+ parameters += parameter.Name;
+ parameters += context.ActionArguments[parameter.Name].ToJson();
+ }
+
+ var cacheKey = MD5Encryption.Encrypt($"{CacheKey}{path}{userId}{parameters}");
+ var sysCacheService = App.GetRequiredService();
+ if (sysCacheService.ExistKey(cacheKey))
+ {
+ if (ThrowBah) throw Oops.Oh(Message);
+
+ try
+ {
+ var cachedResult = sysCacheService.Get(cacheKey);
+ context.Result = new ObjectResult(cachedResult.Value);
+ }
+ catch (Exception ex)
+ {
+ throw Oops.Oh($"{Message}-{ex}");
+ }
+ }
+ else
+ {
+ // 先加入一个空缓存,防止第一次请求结果没回来导致连续请求
+ sysCacheService.Set(cacheKey, "", cacheExpireTime);
+ var resultContext = await next();
+ if (resultContext.Result is ObjectResult objectResult)
+ {
+ var valueType = objectResult.Value.GetType();
+ var responseData = new ResponseData
+ {
+ Type = valueType.Name,
+ Value = objectResult.Value
+ };
+ sysCacheService.Set(cacheKey, responseData, cacheExpireTime);
+ }
+ }
+ }
+
+ ///
+ /// 请求结果数据
+ ///
+ private class ResponseData
+ {
+ ///
+ /// 结果类型
+ ///
+ public string Type { get; set; }
+
+ ///
+ /// 请求结果
+ ///
+ public dynamic Value { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/Admin.NET/Admin.NET.Core/Attribute/IgnoreTableAttribute.cs b/Admin.NET/Admin.NET.Core/Attribute/IgnoreTableAttribute.cs
new file mode 100644
index 00000000..5fb65b99
--- /dev/null
+++ b/Admin.NET/Admin.NET.Core/Attribute/IgnoreTableAttribute.cs
@@ -0,0 +1,16 @@
+// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
+//
+// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
+//
+// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
+
+namespace Admin.NET.Core;
+
+///
+/// 忽略表结构初始化特性(标记在实体)
+///
+[SuppressSniffer]
+[AttributeUsage(AttributeTargets.Class, AllowMultiple = true, Inherited = true)]
+public class IgnoreTableAttribute : Attribute
+{
+}
\ No newline at end of file
diff --git a/Admin.NET/Admin.NET.Core/Attribute/IgnoreUpdateSeedAttribute.cs b/Admin.NET/Admin.NET.Core/Attribute/IgnoreUpdateSeedAttribute.cs
new file mode 100644
index 00000000..9ea18dab
--- /dev/null
+++ b/Admin.NET/Admin.NET.Core/Attribute/IgnoreUpdateSeedAttribute.cs
@@ -0,0 +1,16 @@
+// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
+//
+// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
+//
+// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
+
+namespace Admin.NET.Core;
+
+///
+/// 忽略更新种子特性(标记在种子类)
+///
+[SuppressSniffer]
+[AttributeUsage(AttributeTargets.Class, AllowMultiple = true, Inherited = true)]
+public class IgnoreUpdateSeedAttribute : Attribute
+{
+}
\ No newline at end of file
diff --git a/Admin.NET/Admin.NET.Core/Attribute/IgnoreUpdateSeedColumnAttribute.cs b/Admin.NET/Admin.NET.Core/Attribute/IgnoreUpdateSeedColumnAttribute.cs
new file mode 100644
index 00000000..1bccc81d
--- /dev/null
+++ b/Admin.NET/Admin.NET.Core/Attribute/IgnoreUpdateSeedColumnAttribute.cs
@@ -0,0 +1,16 @@
+// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
+//
+// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
+//
+// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
+
+namespace Admin.NET.Core;
+
+///
+/// 忽略更新种子列特性(标记在实体属性)
+///
+[SuppressSniffer]
+[AttributeUsage(AttributeTargets.Property, AllowMultiple = true, Inherited = true)]
+public class IgnoreUpdateSeedColumnAttribute : Attribute
+{
+}
\ No newline at end of file
diff --git a/Admin.NET/Admin.NET.Core/Attribute/ImportDictAttribute.cs b/Admin.NET/Admin.NET.Core/Attribute/ImportDictAttribute.cs
new file mode 100644
index 00000000..552df72f
--- /dev/null
+++ b/Admin.NET/Admin.NET.Core/Attribute/ImportDictAttribute.cs
@@ -0,0 +1,24 @@
+// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
+//
+// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
+//
+// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
+
+namespace Admin.NET.Core;
+
+///
+/// 属性字典配置
+///
+[AttributeUsage(AttributeTargets.Property)]
+public class ImportDictAttribute : Attribute
+{
+ ///
+ /// 字典Code
+ ///
+ public string TypeCode { get; set; }
+
+ ///
+ /// 目标对象名称
+ ///
+ public string TargetPropName { get; set; }
+}
\ No newline at end of file
diff --git a/Admin.NET/Admin.NET.Core/Attribute/IncreSeedAttribute.cs b/Admin.NET/Admin.NET.Core/Attribute/IncreSeedAttribute.cs
new file mode 100644
index 00000000..9ab1f027
--- /dev/null
+++ b/Admin.NET/Admin.NET.Core/Attribute/IncreSeedAttribute.cs
@@ -0,0 +1,16 @@
+// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
+//
+// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
+//
+// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
+
+namespace Admin.NET.Core;
+
+///
+/// 增量种子特性
+///
+[SuppressSniffer]
+[AttributeUsage(AttributeTargets.Class, AllowMultiple = true, Inherited = true)]
+public class IncreSeedAttribute : Attribute
+{
+}
\ No newline at end of file
diff --git a/Admin.NET/Admin.NET.Core/Attribute/IncreTableAttribute.cs b/Admin.NET/Admin.NET.Core/Attribute/IncreTableAttribute.cs
new file mode 100644
index 00000000..31f31b76
--- /dev/null
+++ b/Admin.NET/Admin.NET.Core/Attribute/IncreTableAttribute.cs
@@ -0,0 +1,16 @@
+// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
+//
+// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
+//
+// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
+
+namespace Admin.NET.Core;
+
+///
+/// 增量表特性
+///
+[SuppressSniffer]
+[AttributeUsage(AttributeTargets.Class, AllowMultiple = true, Inherited = true)]
+public class IncreTableAttribute : Attribute
+{
+}
\ No newline at end of file
diff --git a/Admin.NET/Admin.NET.Core/Attribute/LogTableAttribute.cs b/Admin.NET/Admin.NET.Core/Attribute/LogTableAttribute.cs
new file mode 100644
index 00000000..aa07fd43
--- /dev/null
+++ b/Admin.NET/Admin.NET.Core/Attribute/LogTableAttribute.cs
@@ -0,0 +1,16 @@
+// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
+//
+// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
+//
+// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
+
+namespace Admin.NET.Core;
+
+///
+/// 日志表特性
+///
+[SuppressSniffer]
+[AttributeUsage(AttributeTargets.Class, AllowMultiple = true, Inherited = true)]
+public class LogTableAttribute : Attribute
+{
+}
\ No newline at end of file
diff --git a/Admin.NET/Admin.NET.Core/Attribute/MaskNewtonsoftJsonConverter.cs b/Admin.NET/Admin.NET.Core/Attribute/MaskNewtonsoftJsonConverter.cs
new file mode 100644
index 00000000..a09c801d
--- /dev/null
+++ b/Admin.NET/Admin.NET.Core/Attribute/MaskNewtonsoftJsonConverter.cs
@@ -0,0 +1,60 @@
+// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
+//
+// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
+//
+// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
+
+using Newtonsoft.Json;
+
+namespace Admin.NET.Core;
+
+///
+/// 字符串掩码
+///
+[SuppressSniffer]
+public class MaskNewtonsoftJsonConverter : JsonConverter
+{
+ public override string ReadJson(JsonReader reader, Type objectType, string existingValue, bool hasExistingValue, JsonSerializer serializer)
+ {
+ return reader.Value.ToString();
+ }
+
+ public override void WriteJson(JsonWriter writer, string value, JsonSerializer serializer)
+ {
+ writer.WriteValue(value?.ToString().Mask());
+ }
+}
+
+///
+/// 身份证掩码
+///
+[SuppressSniffer]
+public class MaskIdCardNewtonsoftJsonConverter : JsonConverter
+{
+ public override string ReadJson(JsonReader reader, Type objectType, string existingValue, bool hasExistingValue, JsonSerializer serializer)
+ {
+ return reader.Value.ToString();
+ }
+
+ public override void WriteJson(JsonWriter writer, string value, JsonSerializer serializer)
+ {
+ writer.WriteValue(value?.ToString().MaskIdCard());
+ }
+}
+
+///
+/// 邮箱掩码
+///
+[SuppressSniffer]
+public class MaskEmailNewtonsoftJsonConverter : JsonConverter
+{
+ public override string ReadJson(JsonReader reader, Type objectType, string existingValue, bool hasExistingValue, JsonSerializer serializer)
+ {
+ return reader.Value.ToString();
+ }
+
+ public override void WriteJson(JsonWriter writer, string value, JsonSerializer serializer)
+ {
+ writer.WriteValue(value?.ToString().MaskEmail());
+ }
+}
\ No newline at end of file
diff --git a/Admin.NET/Admin.NET.Core/Attribute/MaskSystemTextJsonConverter.cs b/Admin.NET/Admin.NET.Core/Attribute/MaskSystemTextJsonConverter.cs
new file mode 100644
index 00000000..6b1a12fb
--- /dev/null
+++ b/Admin.NET/Admin.NET.Core/Attribute/MaskSystemTextJsonConverter.cs
@@ -0,0 +1,61 @@
+// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
+//
+// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
+//
+// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
+
+using System.Text.Json;
+using System.Text.Json.Serialization;
+
+namespace Admin.NET.Core;
+
+///
+/// 字符串掩码
+///
+[SuppressSniffer]
+public class MaskSystemTextJsonConverter : JsonConverter
+{
+ public override string Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
+ {
+ return reader.GetString();
+ }
+
+ public override void Write(Utf8JsonWriter writer, string value, JsonSerializerOptions options)
+ {
+ writer.WriteStringValue(value?.ToString().Mask());
+ }
+}
+
+///
+/// 身份证掩码
+///
+[SuppressSniffer]
+public class MaskIdCardSystemTextJsonConverter : JsonConverter
+{
+ public override string Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
+ {
+ return reader.GetString();
+ }
+
+ public override void Write(Utf8JsonWriter writer, string value, JsonSerializerOptions options)
+ {
+ writer.WriteStringValue(value?.ToString().MaskIdCard());
+ }
+}
+
+///
+/// 邮箱掩码
+///
+[SuppressSniffer]
+public class MaskEmailSystemTextJsonConverter : JsonConverter
+{
+ public override string Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
+ {
+ return reader.GetString();
+ }
+
+ public override void Write(Utf8JsonWriter writer, string value, JsonSerializerOptions options)
+ {
+ writer.WriteStringValue(value?.ToString().MaskEmail());
+ }
+}
\ No newline at end of file
diff --git a/Admin.NET/Admin.NET.Core/Attribute/MaxValueAttribute.cs b/Admin.NET/Admin.NET.Core/Attribute/MaxValueAttribute.cs
new file mode 100644
index 00000000..81328901
--- /dev/null
+++ b/Admin.NET/Admin.NET.Core/Attribute/MaxValueAttribute.cs
@@ -0,0 +1,39 @@
+// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
+//
+// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
+//
+// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
+
+namespace Admin.NET.Core;
+
+///
+/// 最大值校验
+///
+[SuppressSniffer]
+public class MaxValueAttribute : ValidationAttribute
+{
+ private double MaxValue { get; }
+
+ ///
+ /// 最大值
+ ///
+ ///
+ public MaxValueAttribute(double value) => this.MaxValue = value;
+
+ ///
+ /// 最大值校验
+ ///
+ ///
+ ///
+ public override bool IsValid(object value)
+ {
+ return value == null || Convert.ToDouble(value) <= this.MaxValue;
+ }
+
+ ///
+ /// 错误信息
+ ///
+ ///
+ ///
+ public override string FormatErrorMessage(string name) => base.FormatErrorMessage(name);
+}
\ No newline at end of file
diff --git a/Admin.NET/Admin.NET.Core/Attribute/MinValueAttribute.cs b/Admin.NET/Admin.NET.Core/Attribute/MinValueAttribute.cs
new file mode 100644
index 00000000..40c73786
--- /dev/null
+++ b/Admin.NET/Admin.NET.Core/Attribute/MinValueAttribute.cs
@@ -0,0 +1,39 @@
+// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
+//
+// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
+//
+// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
+
+namespace Admin.NET.Core;
+
+///
+/// 最小值校验
+///
+[SuppressSniffer]
+public class MinValueAttribute : ValidationAttribute
+{
+ private double MinValue { get; set; }
+
+ ///
+ /// 最小值
+ ///
+ ///
+ public MinValueAttribute(double value) => this.MinValue = value;
+
+ ///
+ /// 最小值校验
+ ///
+ ///
+ ///
+ public override bool IsValid(object value)
+ {
+ return value == null || Convert.ToDouble(value) > this.MinValue;
+ }
+
+ ///
+ /// 错误信息
+ ///
+ ///
+ ///
+ public override string FormatErrorMessage(string name) => base.FormatErrorMessage(name);
+}
\ No newline at end of file
diff --git a/Admin.NET/Admin.NET.Core/Attribute/SysTableAttribute.cs b/Admin.NET/Admin.NET.Core/Attribute/SysTableAttribute.cs
new file mode 100644
index 00000000..f526b42c
--- /dev/null
+++ b/Admin.NET/Admin.NET.Core/Attribute/SysTableAttribute.cs
@@ -0,0 +1,16 @@
+// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
+//
+// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
+//
+// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
+
+namespace Admin.NET.Core;
+
+///
+/// 系统表特性
+///
+[SuppressSniffer]
+[AttributeUsage(AttributeTargets.Class, AllowMultiple = true, Inherited = true)]
+public class SysTableAttribute : Attribute
+{
+}
\ No newline at end of file
diff --git a/Admin.NET/Admin.NET.Core/Cache/CacheSetup.cs b/Admin.NET/Admin.NET.Core/Cache/CacheSetup.cs
new file mode 100644
index 00000000..6281765b
--- /dev/null
+++ b/Admin.NET/Admin.NET.Core/Cache/CacheSetup.cs
@@ -0,0 +1,33 @@
+// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
+//
+// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
+//
+// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
+
+namespace Admin.NET.Core;
+
+public static class CacheSetup
+{
+ ///
+ /// 缓存注册(新生命Redis组件)
+ ///
+ ///
+ public static void AddCache(this IServiceCollection services)
+ {
+ ICache cache = Cache.Default;
+
+ var cacheOptions = App.GetConfig("Cache", true);
+ if (cacheOptions.CacheType == CacheTypeEnum.Redis.ToString())
+ {
+ cache = new FullRedis(new RedisOptions
+ {
+ Configuration = cacheOptions.Redis.Configuration,
+ Prefix = cacheOptions.Redis.Prefix
+ });
+ if (cacheOptions.Redis.MaxMessageSize > 0)
+ ((FullRedis)cache).MaxMessageSize = cacheOptions.Redis.MaxMessageSize;
+ }
+
+ services.AddSingleton(cache);
+ }
+}
\ No newline at end of file
diff --git a/Admin.NET/Admin.NET.Core/Cache/SqlSugarCache.cs b/Admin.NET/Admin.NET.Core/Cache/SqlSugarCache.cs
new file mode 100644
index 00000000..6bbcda64
--- /dev/null
+++ b/Admin.NET/Admin.NET.Core/Cache/SqlSugarCache.cs
@@ -0,0 +1,56 @@
+// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
+//
+// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
+//
+// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
+
+namespace Admin.NET.Core;
+
+///
+/// SqlSugar二级缓存
+///
+public class SqlSugarCache : ICacheService
+{
+ ///
+ /// 系统缓存服务
+ ///
+ private static readonly SysCacheService _cache = App.GetRequiredService();
+
+ public void Add(string key, V value)
+ {
+ _cache.Set($"{CacheConst.SqlSugar}{key}", value);
+ }
+
+ public void Add(string key, V value, int cacheDurationInSeconds)
+ {
+ _cache.Set($"{CacheConst.SqlSugar}{key}", value, TimeSpan.FromSeconds(cacheDurationInSeconds));
+ }
+
+ public bool ContainsKey(string key)
+ {
+ return _cache.ExistKey($"{CacheConst.SqlSugar}{key}");
+ }
+
+ public V Get(string key)
+ {
+ return _cache.Get($"{CacheConst.SqlSugar}{key}");
+ }
+
+ public IEnumerable GetAllKey()
+ {
+ return _cache.GetKeysByPrefixKey(CacheConst.SqlSugar);
+ }
+
+ public V GetOrCreate(string key, Func create, int cacheDurationInSeconds = int.MaxValue)
+ {
+ return _cache.GetOrAdd($"{CacheConst.SqlSugar}{key}", (cacheKey) =>
+ {
+ return create();
+ }, cacheDurationInSeconds);
+ }
+
+ public void Remove(string key)
+ {
+ _cache.Remove(key); // SqlSugar调用Remove方法时,key中已包含了CacheConst.SqlSugar前缀
+ }
+}
\ No newline at end of file
diff --git a/Admin.NET/Admin.NET.Core/Const/CacheConst.cs b/Admin.NET/Admin.NET.Core/Const/CacheConst.cs
new file mode 100644
index 00000000..d3ae76e3
--- /dev/null
+++ b/Admin.NET/Admin.NET.Core/Const/CacheConst.cs
@@ -0,0 +1,93 @@
+// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
+//
+// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
+//
+// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
+
+namespace Admin.NET.Core;
+
+///
+/// 缓存相关常量
+///
+public class CacheConst
+{
+ ///
+ /// 用户权限缓存(按钮集合)
+ ///
+ public const string KeyUserButton = "sys_user_button:";
+
+ ///
+ /// 用户接口缓存(接口集合)
+ ///
+ public const string KeyUserApi = "sys_user_api:";
+
+ ///
+ /// 用户机构缓存
+ ///
+ public const string KeyUserOrg = "sys_user_org:";
+
+ ///
+ /// 角色最大数据范围缓存
+ ///
+ public const string KeyRoleMaxDataScope = "sys_role_maxDataScope:";
+
+ ///
+ /// 在线用户缓存
+ ///
+ public const string KeyUserOnline = "sys_user_online:";
+
+ ///
+ /// 图形验证码缓存
+ ///
+ public const string KeyVerCode = "sys_verCode:";
+
+ ///
+ /// 手机验证码缓存
+ ///
+ public const string KeyPhoneVerCode = "sys_phoneVerCode:";
+
+ ///
+ /// 密码错误次数缓存
+ ///
+ public const string KeyErrorPasswordCount = "sys_errorPasswordCount:";
+
+ ///
+ /// 租户缓存
+ ///
+ public const string KeyTenant = "sys_tenant";
+
+ ///
+ /// 常量下拉框
+ ///
+ public const string KeyConst = "sys_const:";
+
+ ///
+ /// 所有缓存关键字集合
+ ///
+ public const string KeyAll = "sys_keys";
+
+ ///
+ /// SqlSugar二级缓存
+ ///
+ public const string SqlSugar = "sys_sqlSugar:";
+
+ ///
+ /// 开放接口身份缓存
+ ///
+ public const string KeyOpenAccess = "sys_open_access:";
+
+ ///
+ /// 开放接口身份随机数缓存
+ ///
+ public const string KeyOpenAccessNonce = "sys_open_access_nonce:";
+
+ ///
+ /// 登录黑名单
+ ///
+ public const string KeyBlacklist = "sys_blacklist:";
+
+ ///
+ /// 系统配置缓存
+ ///
+ public const string KeyConfig = "sys_config:";
+}
\ No newline at end of file
diff --git a/Admin.NET/Admin.NET.Core/Const/ClaimConst.cs b/Admin.NET/Admin.NET.Core/Const/ClaimConst.cs
new file mode 100644
index 00000000..7fdf85f3
--- /dev/null
+++ b/Admin.NET/Admin.NET.Core/Const/ClaimConst.cs
@@ -0,0 +1,68 @@
+// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
+//
+// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
+//
+// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
+
+namespace Admin.NET.Core;
+
+///
+/// Claim相关常量
+///
+public class ClaimConst
+{
+ ///
+ /// 用户Id
+ ///
+ public const string UserId = "UserId";
+
+ ///
+ /// 账号
+ ///
+ public const string Account = "Account";
+
+ ///
+ /// 真实姓名
+ ///
+ public const string RealName = "RealName";
+
+ ///
+ /// 昵称
+ ///
+ public const string NickName = "NickName";
+
+ ///
+ /// 账号类型
+ ///
+ public const string AccountType = "AccountType";
+
+ ///
+ /// 租户Id
+ ///
+ public const string TenantId = "TenantId";
+
+ ///
+ /// 组织机构Id
+ ///
+ public const string OrgId = "OrgId";
+
+ ///
+ /// 组织机构名称
+ ///
+ public const string OrgName = "OrgName";
+
+ ///
+ /// 组织机构类型
+ ///
+ public const string OrgType = "OrgType";
+
+ ///
+ /// 微信OpenId
+ ///
+ public const string OpenId = "OpenId";
+
+ ///
+ /// 登录模式PC、APP
+ ///
+ public const string LoginMode = "LoginMode";
+}
\ No newline at end of file
diff --git a/Admin.NET/Admin.NET.Core/Const/CommonConst.cs b/Admin.NET/Admin.NET.Core/Const/CommonConst.cs
new file mode 100644
index 00000000..ca46ed81
--- /dev/null
+++ b/Admin.NET/Admin.NET.Core/Const/CommonConst.cs
@@ -0,0 +1,101 @@
+// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
+//
+// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
+//
+// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
+
+namespace Admin.NET.Core;
+
+///
+/// 通用常量
+///
+[Const("平台配置")]
+public class CommonConst
+{
+ ///
+ /// 演示环境开关
+ ///
+ public const string SysDemoEnv = "sys_demo";
+
+ ///
+ /// 默认密码
+ ///
+ public const string SysPassword = "sys_password";
+
+ ///
+ /// 登录二次验证
+ ///
+ public const string SysSecondVer = "sys_second_ver";
+
+ ///
+ /// 开启图形验证码
+ ///
+ public const string SysCaptcha = "sys_captcha";
+
+ ///
+ /// 开启水印
+ ///
+ public const string SysWatermark = "sys_watermark";
+
+ ///
+ /// 开启操作日志
+ ///
+ public const string SysOpLog = "sys_oplog";
+
+ ///
+ /// Token过期时间
+ ///
+ public const string SysTokenExpire = "sys_token_expire";
+
+ ///
+ /// RefreshToken过期时间
+ ///
+ public const string SysRefreshTokenExpire = "sys_refresh_token_expire";
+
+ ///
+ /// 开启发送异常日志邮件
+ ///
+ public const string SysErrorMail = "sys_error_mail";
+
+ ///
+ /// 单用户登录
+ ///
+ public const string SysSingleLogin = "sys_single_login";
+
+ ///
+ /// 系统管理员角色编码
+ ///
+ public const string SysAdminRole = "sys_admin";
+
+ /////
+ ///// 开启全局脱敏处理(默认不开启)
+ /////
+ //public static bool SysSensitiveDetection = false;
+
+ ///
+ /// 开启域登录验证
+ ///
+ public const string SysDomainLogin = "sys_domain_login";
+
+ ///
+ /// 日志分组名称
+ ///
+ public const string SysLogCategoryName = "System.Logging.LoggingMonitor";
+
+ ///
+ /// 事件-增加异常日志
+ ///
+ public const string AddExLog = "Add:ExLog";
+
+ ///
+ /// 事件-发送异常邮件
+ ///
+ public const string SendErrorMail = "Send:ErrorMail";
+
+ ///
+ /// 基础接口资源列表
+ ///
+
+ public static readonly List SysBaseRoutes = new() { "sysAuth/login", "sysAuth/unLockScreen", "sysAuth/loginPhone", "sysAuth/userInfo", "sysAuth/refreshToken", "sysAuth/logout", "sysAuth/loginConfig", "sysAuth/watermarkConfig", "sysAuth/captcha", "sysMenu/loginMenuTree", "sysOAuth/signIn", "sysOAuth/signInCallback", "sysOnlineUser/page", "sysOrg/list", "sysPos/list", "sysRole/page", "sysRole/list",
+ "sysFile/uploadAvatar", "sysFile/uploadSignature", "sysUser/baseInfo", "sysUser/baseInfo", "sysUser/changePwd", "sysNotice/page", "sysNotice/add", "sysNotice/update", "sysNotice/delete", "sysNotice/public", "sysNotice/setRead", "sysNotice/pageReceived", "sysNotice/unReadList" };
+}
\ No newline at end of file
diff --git a/Admin.NET/Admin.NET.Core/Const/SqlSugarConst.cs b/Admin.NET/Admin.NET.Core/Const/SqlSugarConst.cs
new file mode 100644
index 00000000..ddbcbd43
--- /dev/null
+++ b/Admin.NET/Admin.NET.Core/Const/SqlSugarConst.cs
@@ -0,0 +1,33 @@
+// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
+//
+// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
+//
+// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
+
+namespace Admin.NET.Core;
+
+///
+/// SqlSugar相关常量
+///
+public class SqlSugarConst
+{
+ ///
+ /// 默认主数据库标识(默认租户)
+ ///
+ public const string MainConfigId = "1300000000001";
+
+ ///
+ /// 默认日志数据库标识
+ ///
+ public const string LogConfigId = "1300000000002";
+
+ ///
+ /// 默认表主键
+ ///
+ public const string PrimaryKey = "Id";
+
+ ///
+ /// 默认租户Id
+ ///
+ public const long DefaultTenantId = 1300000000001;
+}
\ No newline at end of file
diff --git a/Admin.NET/Admin.NET.Core/Entity/EntityBase.cs b/Admin.NET/Admin.NET.Core/Entity/EntityBase.cs
new file mode 100644
index 00000000..d000be13
--- /dev/null
+++ b/Admin.NET/Admin.NET.Core/Entity/EntityBase.cs
@@ -0,0 +1,146 @@
+// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
+//
+// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
+//
+// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
+
+namespace Admin.NET.Core;
+
+///
+/// 框架实体基类Id
+///
+public abstract class EntityBaseId
+{
+ ///
+ /// 雪花Id
+ ///
+ [SugarColumn(ColumnName = "Id", ColumnDescription = "主键Id", IsPrimaryKey = true, IsIdentity = false)]
+ public virtual long Id { get; set; }
+}
+
+///
+/// 框架实体基类
+///
+[SugarIndex("index_{table}_CT", nameof(CreateTime), OrderByType.Asc)]
+public abstract class EntityBase : EntityBaseId, IDeletedFilter
+{
+ ///
+ /// 创建时间
+ ///
+ [SugarColumn(ColumnDescription = "创建时间", IsNullable = true, IsOnlyIgnoreUpdate = true, InsertServerTime = true)]
+ public virtual DateTime CreateTime { get; set; }
+
+ ///
+ /// 更新时间
+ ///
+ [SugarColumn(ColumnDescription = "更新时间", IsOnlyIgnoreInsert = true, UpdateServerTime = true)]
+ public virtual DateTime? UpdateTime { get; set; }
+
+ ///
+ /// 创建者Id
+ ///
+ [SugarColumn(ColumnDescription = "创建者Id", IsOnlyIgnoreUpdate = true)]
+ public virtual long? CreateUserId { get; set; }
+
+ /////
+ ///// 创建者
+ /////
+ //[Newtonsoft.Json.JsonIgnore]
+ //[System.Text.Json.Serialization.JsonIgnore]
+ //[Navigate(NavigateType.OneToOne, nameof(CreateUserId))]
+ //public virtual SysUser CreateUser { get; set; }
+
+ ///
+ /// 创建者姓名
+ ///
+ [SugarColumn(ColumnDescription = "创建者姓名", Length = 64, IsOnlyIgnoreUpdate = true)]
+ public virtual string? CreateUserName { get; set; }
+
+ ///
+ /// 修改者Id
+ ///
+ [SugarColumn(ColumnDescription = "修改者Id")]
+ public virtual long? UpdateUserId { get; set; }
+
+ /////
+ ///// 修改者
+ /////
+ //[Newtonsoft.Json.JsonIgnore]
+ //[System.Text.Json.Serialization.JsonIgnore]
+ //[Navigate(NavigateType.OneToOne, nameof(UpdateUserId))]
+ //public virtual SysUser UpdateUser { get; set; }
+
+ ///
+ /// 修改者姓名
+ ///
+ [SugarColumn(ColumnDescription = "修改者姓名", Length = 64)]
+ public virtual string? UpdateUserName { get; set; }
+
+ ///
+ /// 软删除
+ ///
+ [SugarColumn(ColumnDescription = "软删除")]
+ public virtual bool IsDelete { get; set; } = false;
+}
+
+///
+/// 业务数据实体基类(数据权限)
+///
+public abstract class EntityBaseData : EntityBase, IOrgIdFilter
+{
+ ///
+ /// 创建者部门Id
+ ///
+ [SugarColumn(ColumnDescription = "创建者部门Id", IsOnlyIgnoreUpdate = true)]
+ public virtual long? CreateOrgId { get; set; }
+
+ ///
+ /// 创建者部门
+ ///
+ [Newtonsoft.Json.JsonIgnore]
+ [System.Text.Json.Serialization.JsonIgnore]
+ [Navigate(NavigateType.OneToOne, nameof(CreateOrgId))]
+ public virtual SysOrg CreateOrg { get; set; }
+
+ ///
+ /// 创建者部门名称
+ ///
+ [SugarColumn(ColumnDescription = "创建者部门名称", Length = 64, IsOnlyIgnoreUpdate = true)]
+ public virtual string? CreateOrgName { get; set; }
+}
+
+///
+/// 租户实体基类
+///
+public abstract class EntityTenant : EntityBase, ITenantIdFilter
+{
+ ///
+ /// 租户Id
+ ///
+ [SugarColumn(ColumnDescription = "租户Id", IsOnlyIgnoreUpdate = true)]
+ public virtual long? TenantId { get; set; }
+}
+
+///
+/// 租户实体基类Id
+///
+public abstract class EntityTenantId : EntityBaseId, ITenantIdFilter
+{
+ ///
+ /// 租户Id
+ ///
+ [SugarColumn(ColumnDescription = "租户Id", IsOnlyIgnoreUpdate = true)]
+ public virtual long? TenantId { get; set; }
+}
+
+///
+/// 租户实体基类 + 业务数据(数据权限)
+///
+public abstract class EntityTenantBaseData : EntityBaseData, ITenantIdFilter
+{
+ ///
+ /// 租户Id
+ ///
+ [SugarColumn(ColumnDescription = "租户Id", IsOnlyIgnoreUpdate = true)]
+ public virtual long? TenantId { get; set; }
+}
\ No newline at end of file
diff --git a/Admin.NET/Admin.NET.Core/Entity/IEntityFilter.cs b/Admin.NET/Admin.NET.Core/Entity/IEntityFilter.cs
new file mode 100644
index 00000000..05c8727d
--- /dev/null
+++ b/Admin.NET/Admin.NET.Core/Entity/IEntityFilter.cs
@@ -0,0 +1,40 @@
+// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
+//
+// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
+//
+// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
+
+namespace Admin.NET.Core;
+
+///
+/// 假删除接口过滤器
+///
+internal interface IDeletedFilter
+{
+ ///
+ /// 软删除
+ ///
+ bool IsDelete { get; set; }
+}
+
+///
+/// 租户Id接口过滤器
+///
+internal interface ITenantIdFilter
+{
+ ///
+ /// 租户Id
+ ///
+ long? TenantId { get; set; }
+}
+
+///
+/// 机构Id接口过滤器
+///
+internal interface IOrgIdFilter
+{
+ ///
+ /// 创建者部门Id
+ ///
+ long? CreateOrgId { get; set; }
+}
\ No newline at end of file
diff --git a/Admin.NET/Admin.NET.Core/Entity/SysCodeGen.cs b/Admin.NET/Admin.NET.Core/Entity/SysCodeGen.cs
new file mode 100644
index 00000000..ba23d162
--- /dev/null
+++ b/Admin.NET/Admin.NET.Core/Entity/SysCodeGen.cs
@@ -0,0 +1,125 @@
+// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
+//
+// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
+//
+// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
+
+namespace Admin.NET.Core;
+
+///
+/// 代码生成表
+///
+[SugarTable(null, "代码生成表")]
+[SysTable]
+[SugarIndex("index_{table}_B", nameof(BusName), OrderByType.Asc)]
+[SugarIndex("index_{table}_T", nameof(TableName), OrderByType.Asc)]
+public partial class SysCodeGen : EntityBase
+{
+ ///
+ /// 作者姓名
+ ///
+ [SugarColumn(ColumnDescription = "作者姓名", Length = 32)]
+ [MaxLength(32)]
+ public string? AuthorName { get; set; }
+
+ ///
+ /// 是否移除表前缀
+ ///
+ [SugarColumn(ColumnDescription = "是否移除表前缀", Length = 8)]
+ [MaxLength(8)]
+ public string? TablePrefix { get; set; }
+
+ ///
+ /// 生成方式
+ ///
+ [SugarColumn(ColumnDescription = "生成方式", Length = 32)]
+ [MaxLength(32)]
+ public string? GenerateType { get; set; }
+
+ ///
+ /// 库定位器名
+ ///
+ [SugarColumn(ColumnDescription = "库定位器名", Length = 64)]
+ [MaxLength(64)]
+ public string? ConfigId { get; set; }
+
+ ///
+ /// 数据库名(保留字段)
+ ///
+ [SugarColumn(ColumnDescription = "数据库库名", Length = 64)]
+ [MaxLength(64)]
+ public string? DbName { get; set; }
+
+ ///
+ /// 数据库类型
+ ///
+ [SugarColumn(ColumnDescription = "数据库类型", Length = 64)]
+ [MaxLength(64)]
+ public string? DbType { get; set; }
+
+ ///
+ /// 数据库链接
+ ///
+ [SugarColumn(ColumnDescription = "数据库链接", Length = 256)]
+ [MaxLength(256)]
+ public string? ConnectionString { get; set; }
+
+ ///
+ /// 数据库表名
+ ///
+ [SugarColumn(ColumnDescription = "数据库表名", Length = 128)]
+ [MaxLength(128)]
+ public string? TableName { get; set; }
+
+ ///
+ /// 命名空间
+ ///
+ [SugarColumn(ColumnDescription = "命名空间", Length = 128)]
+ [MaxLength(128)]
+ public string? NameSpace { get; set; }
+
+ ///
+ /// 业务名
+ ///
+ [SugarColumn(ColumnDescription = "业务名", Length = 128)]
+ [MaxLength(128)]
+ public string? BusName { get; set; }
+
+ ///
+ /// 是否生成菜单
+ ///
+ [SugarColumn(ColumnDescription = "是否生成菜单")]
+ public bool GenerateMenu { get; set; } = true;
+
+ ///
+ /// 菜单图标
+ ///
+ [SugarColumn(ColumnDescription = "菜单图标", Length = 32)]
+ public string? MenuIcon { get; set; } = "ele-Menu";
+
+ ///
+ /// 菜单编码
+ ///
+ [SugarColumn(ColumnDescription = "菜单编码")]
+ public long? MenuPid { get; set; }
+
+ ///
+ /// 页面目录
+ ///
+ [SugarColumn(ColumnDescription = "页面目录", Length = 32)]
+ public string? PagePath { get; set; }
+
+ ///
+ /// 支持打印类型
+ ///
+ [SugarColumn(ColumnDescription = "支持打印类型", Length = 32)]
+ [MaxLength(32)]
+ public string? PrintType { get; set; }
+
+ ///
+ /// 打印模版名称
+ ///
+ [SugarColumn(ColumnDescription = "打印模版名称", Length = 32)]
+ [MaxLength(32)]
+ public string? PrintName { get; set; }
+}
\ No newline at end of file
diff --git a/Admin.NET/Admin.NET.Core/Entity/SysCodeGenConfig.cs b/Admin.NET/Admin.NET.Core/Entity/SysCodeGenConfig.cs
new file mode 100644
index 00000000..03f6b814
--- /dev/null
+++ b/Admin.NET/Admin.NET.Core/Entity/SysCodeGenConfig.cs
@@ -0,0 +1,193 @@
+// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
+//
+// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
+//
+// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
+
+namespace Admin.NET.Core;
+
+///
+/// 代码生成字段配置表
+///
+[SugarTable(null, "代码生成字段配置表")]
+[SysTable]
+public partial class SysCodeGenConfig : EntityBase
+{
+ ///
+ /// 代码生成主表Id
+ ///
+ [SugarColumn(ColumnDescription = "主表Id")]
+ public long CodeGenId { get; set; }
+
+ ///
+ /// 数据库字段名
+ ///
+ [SugarColumn(ColumnDescription = "字段名称", Length = 128)]
+ [Required, MaxLength(128)]
+ public virtual string ColumnName { get; set; }
+
+ ///
+ /// 实体属性名
+ ///
+ [SugarColumn(ColumnDescription = "属性名称", Length = 128)]
+ [Required, MaxLength(128)]
+ public virtual string PropertyName { get; set; }
+
+ ///
+ /// 字段数据长度
+ ///
+ [SugarColumn(ColumnDescription = "字段数据长度", DefaultValue = "0")]
+ public int ColumnLength { get; set; }
+
+ ///
+ /// 字段描述
+ ///
+ [SugarColumn(ColumnDescription = "字段描述", Length = 128)]
+ [MaxLength(128)]
+ public string? ColumnComment { get; set; }
+
+ ///
+ /// .NET数据类型
+ ///
+ [SugarColumn(ColumnDescription = "NET数据类型", Length = 64)]
+ [MaxLength(64)]
+ public string? NetType { get; set; }
+
+ ///
+ /// 作用类型(字典)
+ ///
+ [SugarColumn(ColumnDescription = "作用类型", Length = 64)]
+ [MaxLength(64)]
+ public string? EffectType { get; set; }
+
+ ///
+ /// 外键实体名称
+ ///
+ [SugarColumn(ColumnDescription = "外键实体名称", Length = 64)]
+ [MaxLength(64)]
+ public string? FkEntityName { get; set; }
+
+ ///
+ /// 外键表名称
+ ///
+ [SugarColumn(ColumnDescription = "外键表名称", Length = 128)]
+ [MaxLength(128)]
+ public string? FkTableName { get; set; }
+
+ ///
+ /// 外键显示字段
+ ///
+ [SugarColumn(ColumnDescription = "外键显示字段", Length = 64)]
+ [MaxLength(64)]
+ public string? FkColumnName { get; set; }
+
+ ///
+ /// 外键显示字段.NET类型
+ ///
+ [SugarColumn(ColumnDescription = "外键显示字段.NET类型", Length = 64)]
+ [MaxLength(64)]
+ public string? FkColumnNetType { get; set; }
+
+ ///
+ /// 字典编码
+ ///
+ [SugarColumn(ColumnDescription = "字典编码", Length = 64)]
+ [MaxLength(64)]
+ public string? DictTypeCode { get; set; }
+
+ ///
+ /// 列表是否缩进(字典)
+ ///
+ [SugarColumn(ColumnDescription = "列表是否缩进", Length = 8)]
+ [MaxLength(8)]
+ public string? WhetherRetract { get; set; }
+
+ ///
+ /// 是否必填(字典)
+ ///
+ [SugarColumn(ColumnDescription = "是否必填", Length = 8)]
+ [MaxLength(8)]
+ public string? WhetherRequired { get; set; }
+
+ ///
+ /// 是否可排序(字典)
+ ///
+ [SugarColumn(ColumnDescription = "是否可排序", Length = 8)]
+ [MaxLength(8)]
+ public string? WhetherSortable { get; set; }
+
+ ///
+ /// 是否是查询条件
+ ///
+ [SugarColumn(ColumnDescription = "是否是查询条件", Length = 8)]
+ [MaxLength(8)]
+ public string? QueryWhether { get; set; }
+
+ ///
+ /// 查询方式
+ ///
+ [SugarColumn(ColumnDescription = "查询方式", Length = 16)]
+ [MaxLength(16)]
+ public string? QueryType { get; set; }
+
+ ///
+ /// 列表显示
+ ///
+ [SugarColumn(ColumnDescription = "列表显示", Length = 8)]
+ [MaxLength(8)]
+ public string? WhetherTable { get; set; }
+
+ ///
+ /// 增改
+ ///
+ [SugarColumn(ColumnDescription = "增改", Length = 8)]
+ [MaxLength(8)]
+ public string? WhetherAddUpdate { get; set; }
+
+ ///
+ /// 主键
+ ///
+ [SugarColumn(ColumnDescription = "主键", Length = 8)]
+ [MaxLength(8)]
+ public string? ColumnKey { get; set; }
+
+ ///
+ /// 数据库中类型(物理类型)
+ ///
+ [SugarColumn(ColumnDescription = "数据库中类型", Length = 64)]
+ [MaxLength(64)]
+ public string? DataType { get; set; }
+
+ ///
+ /// 是否通用字段
+ ///
+ [SugarColumn(ColumnDescription = "是否通用字段", Length = 8)]
+ [MaxLength(8)]
+ public string? WhetherCommon { get; set; }
+
+ ///
+ /// 显示文本字段
+ ///
+ [SugarColumn(ColumnDescription = "显示文本字段", ColumnDataType = StaticConfig.CodeFirst_BigString)]
+ public string? DisplayColumn { get; set; }
+
+ ///
+ /// 选中值字段
+ ///
+ [SugarColumn(ColumnDescription = "选中值字段", Length = 128)]
+ [MaxLength(128)]
+ public string? ValueColumn { get; set; }
+
+ ///
+ /// 父级字段
+ ///
+ [SugarColumn(ColumnDescription = "父级字段", Length = 128)]
+ [MaxLength(128)]
+ public string? PidColumn { get; set; }
+
+ ///
+ /// 排序
+ ///
+ [SugarColumn(ColumnDescription = "排序")]
+ public int OrderNo { get; set; } = 100;
+}
\ No newline at end of file
diff --git a/Admin.NET/Admin.NET.Core/Entity/SysConfig.cs b/Admin.NET/Admin.NET.Core/Entity/SysConfig.cs
new file mode 100644
index 00000000..d4fb5f17
--- /dev/null
+++ b/Admin.NET/Admin.NET.Core/Entity/SysConfig.cs
@@ -0,0 +1,65 @@
+// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
+//
+// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
+//
+// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
+
+namespace Admin.NET.Core;
+
+///
+/// 系统参数配置表
+///
+[SugarTable(null, "系统参数配置表")]
+[SysTable]
+[SugarIndex("index_{table}_N", nameof(Name), OrderByType.Asc)]
+[SugarIndex("index_{table}_C", nameof(Code), OrderByType.Asc)]
+public partial class SysConfig : EntityBase
+{
+ ///
+ /// 名称
+ ///
+ [SugarColumn(ColumnDescription = "名称", Length = 64)]
+ [Required, MaxLength(64)]
+ public virtual string Name { get; set; }
+
+ ///
+ /// 编码
+ ///
+ [SugarColumn(ColumnDescription = "编码", Length = 64)]
+ [MaxLength(64)]
+ public string? Code { get; set; }
+
+ ///
+ /// 属性值
+ ///
+ [SugarColumn(ColumnDescription = "属性值", Length = 64)]
+ [MaxLength(64)]
+ [IgnoreUpdateSeedColumn]
+ public string? Value { get; set; }
+
+ ///
+ /// 是否是内置参数(Y-是,N-否)
+ ///
+ [SugarColumn(ColumnDescription = "是否是内置参数")]
+ public YesNoEnum SysFlag { get; set; }
+
+ ///
+ /// 分组编码
+ ///
+ [SugarColumn(ColumnDescription = "分组编码", Length = 64)]
+ [MaxLength(64)]
+ public string? GroupCode { get; set; }
+
+ ///
+ /// 排序
+ ///
+ [SugarColumn(ColumnDescription = "排序")]
+ public int OrderNo { get; set; } = 100;
+
+ ///
+ /// 备注
+ ///
+ [SugarColumn(ColumnDescription = "备注", Length = 256)]
+ [MaxLength(256)]
+ public string? Remark { get; set; }
+}
\ No newline at end of file
diff --git a/Admin.NET/Admin.NET.Core/Entity/SysDictData.cs b/Admin.NET/Admin.NET.Core/Entity/SysDictData.cs
new file mode 100644
index 00000000..c8d1b6e2
--- /dev/null
+++ b/Admin.NET/Admin.NET.Core/Entity/SysDictData.cs
@@ -0,0 +1,97 @@
+// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
+//
+// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
+//
+// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
+
+namespace Admin.NET.Core;
+
+///
+/// 系统字典值表
+///
+[SugarTable(null, "系统字典值表")]
+[SysTable]
+[SugarIndex("index_{table}_C", nameof(Code), OrderByType.Asc)]
+public partial class SysDictData : EntityBase
+{
+ ///
+ /// 字典类型Id
+ ///
+ [SugarColumn(ColumnDescription = "字典类型Id")]
+ public long DictTypeId { get; set; }
+
+ ///
+ /// 字典类型
+ ///
+ [Newtonsoft.Json.JsonIgnore]
+ [System.Text.Json.Serialization.JsonIgnore]
+ [Navigate(NavigateType.OneToOne, nameof(DictTypeId))]
+ public SysDictType DictType { get; set; }
+
+ ///
+ /// 值
+ ///
+ [SugarColumn(ColumnDescription = "值", Length = 128)]
+ [Required, MaxLength(128)]
+ public virtual string Value { get; set; }
+
+ ///
+ /// 编码
+ ///
+ [SugarColumn(ColumnDescription = "编码", Length = 128)]
+ [Required, MaxLength(128)]
+ public virtual string Code { get; set; }
+
+ ///
+ /// 名称
+ ///
+ [SugarColumn(ColumnDescription = "名称", Length = 128)]
+ [MaxLength(128)]
+ public virtual string? Name { get; set; }
+
+ ///
+ /// 显示样式-标签颜色
+ ///
+ [SugarColumn(ColumnDescription = "显示样式-标签颜色", Length = 16)]
+ [MaxLength(16)]
+ public string? TagType { get; set; }
+
+ ///
+ /// 显示样式-Style(控制显示样式)
+ ///
+ [SugarColumn(ColumnDescription = "显示样式-Style", Length = 512)]
+ [MaxLength(512)]
+ public string? StyleSetting { get; set; }
+
+ ///
+ /// 显示样式-Class(控制显示样式)
+ ///
+ [SugarColumn(ColumnDescription = "显示样式-Class", Length = 512)]
+ [MaxLength(512)]
+ public string? ClassSetting { get; set; }
+
+ ///
+ /// 排序
+ ///
+ [SugarColumn(ColumnDescription = "排序")]
+ public int OrderNo { get; set; } = 100;
+
+ ///
+ /// 备注
+ ///
+ [SugarColumn(ColumnDescription = "备注", Length = 2048)]
+ [MaxLength(2048)]
+ public string? Remark { get; set; }
+
+ ///
+ /// 拓展数据(保存业务功能的配置项)
+ ///
+ [SugarColumn(ColumnDescription = "拓展数据(保存业务功能的配置项)", ColumnDataType = StaticConfig.CodeFirst_BigString)]
+ public string? ExtData { get; set; }
+
+ ///
+ /// 状态
+ ///
+ [SugarColumn(ColumnDescription = "状态")]
+ public StatusEnum Status { get; set; } = StatusEnum.Enable;
+}
\ No newline at end of file
diff --git a/Admin.NET/Admin.NET.Core/Entity/SysDictType.cs b/Admin.NET/Admin.NET.Core/Entity/SysDictType.cs
new file mode 100644
index 00000000..df1d3d2a
--- /dev/null
+++ b/Admin.NET/Admin.NET.Core/Entity/SysDictType.cs
@@ -0,0 +1,56 @@
+// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
+//
+// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
+//
+// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
+
+namespace Admin.NET.Core;
+
+///
+/// 系统字典类型表
+///
+[SugarTable(null, "系统字典类型表")]
+[SysTable]
+[SugarIndex("index_{table}_N", nameof(Name), OrderByType.Asc)]
+[SugarIndex("index_{table}_C", nameof(Code), OrderByType.Asc)]
+public partial class SysDictType : EntityBase
+{
+ ///
+ /// 名称
+ ///
+ [SugarColumn(ColumnDescription = "名称", Length = 64)]
+ [Required, MaxLength(64)]
+ public virtual string Name { get; set; }
+
+ ///
+ /// 编码
+ ///
+ [SugarColumn(ColumnDescription = "编码", Length = 64)]
+ [Required, MaxLength(64)]
+ public virtual string Code { get; set; }
+
+ ///
+ /// 排序
+ ///
+ [SugarColumn(ColumnDescription = "排序")]
+ public int OrderNo { get; set; } = 100;
+
+ ///
+ /// 备注
+ ///
+ [SugarColumn(ColumnDescription = "备注", Length = 256)]
+ [MaxLength(256)]
+ public string? Remark { get; set; }
+
+ ///
+ /// 状态
+ ///
+ [SugarColumn(ColumnDescription = "状态")]
+ public StatusEnum Status { get; set; } = StatusEnum.Enable;
+
+ ///
+ /// 字典值集合
+ ///
+ [Navigate(NavigateType.OneToMany, nameof(SysDictData.DictTypeId))]
+ public List Children { get; set; }
+}
\ No newline at end of file
diff --git a/Admin.NET/Admin.NET.Core/Entity/SysFile.cs b/Admin.NET/Admin.NET.Core/Entity/SysFile.cs
new file mode 100644
index 00000000..ccb1c103
--- /dev/null
+++ b/Admin.NET/Admin.NET.Core/Entity/SysFile.cs
@@ -0,0 +1,104 @@
+// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
+//
+// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
+//
+// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
+
+namespace Admin.NET.Core;
+
+///
+/// 系统文件表
+///
+[SugarTable(null, "系统文件表")]
+[SysTable]
+[SugarIndex("index_{table}_F", nameof(FileName), OrderByType.Asc)]
+public partial class SysFile : EntityBase
+{
+ ///
+ /// 提供者
+ ///
+ [SugarColumn(ColumnDescription = "提供者", Length = 128)]
+ [MaxLength(128)]
+ public string? Provider { get; set; }
+
+ ///
+ /// 仓储名称
+ ///
+ [SugarColumn(ColumnDescription = "仓储名称", Length = 128)]
+ [MaxLength(128)]
+ public string? BucketName { get; set; }
+
+ ///
+ /// 文件名称(源文件名)
+ ///
+ [SugarColumn(ColumnDescription = "文件名称", Length = 128)]
+ [MaxLength(128)]
+ public string? FileName { get; set; }
+
+ ///
+ /// 文件后缀
+ ///
+ [SugarColumn(ColumnDescription = "文件后缀", Length = 16)]
+ [MaxLength(16)]
+ public string? Suffix { get; set; }
+
+ ///
+ /// 存储路径
+ ///
+ [SugarColumn(ColumnDescription = "存储路径", Length = 512)]
+ [MaxLength(512)]
+ public string? FilePath { get; set; }
+
+ ///
+ /// 文件大小KB
+ ///
+ [SugarColumn(ColumnDescription = "文件大小KB")]
+ public long SizeKb { get; set; }
+
+ ///
+ /// 文件大小信息-计算后的
+ ///
+ [SugarColumn(ColumnDescription = "文件大小信息", Length = 64)]
+ [MaxLength(64)]
+ public string? SizeInfo { get; set; }
+
+ ///
+ /// 外链地址-OSS上传后生成外链地址方便前端预览
+ ///
+ [SugarColumn(ColumnDescription = "外链地址", Length = 512)]
+ [MaxLength(512)]
+ public string? Url { get; set; }
+
+ ///
+ /// 文件MD5
+ ///
+ [SugarColumn(ColumnDescription = "文件MD5", Length = 128)]
+ [MaxLength(128)]
+ public string? FileMd5 { get; set; }
+
+ ///
+ /// 关联对象名称(如子对象)
+ ///
+ [SugarColumn(ColumnDescription = "关联对象名称", Length = 128)]
+ [MaxLength(128)]
+ public string? RelationName { get; set; }
+
+ ///
+ /// 关联对象Id
+ ///
+ [SugarColumn(ColumnDescription = "关联对象Id")]
+ public long? RelationId { get; set; }
+
+ ///
+ /// 所属Id(如主对象)
+ ///
+ [SugarColumn(ColumnDescription = "所属Id")]
+ public long? BelongId { get; set; }
+
+ ///
+ /// 文件类别
+ ///
+ [SugarColumn(ColumnDescription = "文件类别", Length = 128)]
+ [MaxLength(128)]
+ public string? FileType { get; set; }
+}
\ No newline at end of file
diff --git a/Admin.NET/Admin.NET.Core/Entity/SysJobCluster.cs b/Admin.NET/Admin.NET.Core/Entity/SysJobCluster.cs
new file mode 100644
index 00000000..6687cf6d
--- /dev/null
+++ b/Admin.NET/Admin.NET.Core/Entity/SysJobCluster.cs
@@ -0,0 +1,41 @@
+// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
+//
+// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
+//
+// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
+
+namespace Admin.NET.Core;
+
+///
+/// 系统作业集群表
+///
+[SugarTable(null, "系统作业集群表")]
+[SysTable]
+public partial class SysJobCluster : EntityBaseId
+{
+ ///
+ /// 作业集群Id
+ ///
+ [SugarColumn(ColumnDescription = "作业集群Id", Length = 64)]
+ [Required, MaxLength(64)]
+ public virtual string ClusterId { get; set; }
+
+ ///
+ /// 描述信息
+ ///
+ [SugarColumn(ColumnDescription = "描述信息", Length = 128)]
+ [MaxLength(128)]
+ public string? Description { get; set; }
+
+ ///
+ /// 状态
+ ///
+ [SugarColumn(ColumnDescription = "状态")]
+ public ClusterStatus Status { get; set; }
+
+ ///
+ /// 更新时间
+ ///
+ [SugarColumn(ColumnDescription = "更新时间")]
+ public DateTime? UpdatedTime { get; set; }
+}
\ No newline at end of file
diff --git a/Admin.NET/Admin.NET.Core/Entity/SysJobDetail.cs b/Admin.NET/Admin.NET.Core/Entity/SysJobDetail.cs
new file mode 100644
index 00000000..3c2868f4
--- /dev/null
+++ b/Admin.NET/Admin.NET.Core/Entity/SysJobDetail.cs
@@ -0,0 +1,87 @@
+// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
+//
+// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
+//
+// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
+
+namespace Admin.NET.Core;
+
+///
+/// 系统作业信息表
+///
+[SugarTable(null, "系统作业信息表")]
+[SysTable]
+[SugarIndex("index_{table}_J", nameof(JobId), OrderByType.Asc)]
+public partial class SysJobDetail : EntityBaseId
+{
+ ///
+ /// 作业Id
+ ///
+ [SugarColumn(ColumnDescription = "作业Id", Length = 64)]
+ [Required, MaxLength(64)]
+ public virtual string JobId { get; set; }
+
+ ///
+ /// 组名称
+ ///
+ [SugarColumn(ColumnDescription = "组名称", Length = 128)]
+ [MaxLength(128)]
+ public string? GroupName { get; set; } = "default";
+
+ ///
+ /// 作业类型FullName
+ ///
+ [SugarColumn(ColumnDescription = "作业类型", Length = 128)]
+ [MaxLength(128)]
+ public string? JobType { get; set; }
+
+ ///
+ /// 程序集Name
+ ///
+ [SugarColumn(ColumnDescription = "程序集", Length = 128)]
+ [MaxLength(128)]
+ public string? AssemblyName { get; set; }
+
+ ///
+ /// 描述信息
+ ///
+ [SugarColumn(ColumnDescription = "描述信息", Length = 128)]
+ [MaxLength(128)]
+ public string? Description { get; set; }
+
+ ///
+ /// 是否并行执行
+ ///
+ [SugarColumn(ColumnDescription = "是否并行执行")]
+ public bool Concurrent { get; set; } = true;
+
+ ///
+ /// 是否扫描特性触发器
+ ///
+ [SugarColumn(ColumnDescription = "是否扫描特性触发器", ColumnName = "annotation")]
+ public bool IncludeAnnotation { get; set; } = false;
+
+ ///
+ /// 额外数据
+ ///
+ [SugarColumn(ColumnDescription = "额外数据", ColumnDataType = StaticConfig.CodeFirst_BigString)]
+ public string? Properties { get; set; } = "{}";
+
+ ///
+ /// 更新时间
+ ///
+ [SugarColumn(ColumnDescription = "更新时间")]
+ public DateTime? UpdatedTime { get; set; }
+
+ ///
+ /// 作业创建类型
+ ///
+ [SugarColumn(ColumnDescription = "作业创建类型")]
+ public JobCreateTypeEnum CreateType { get; set; } = JobCreateTypeEnum.BuiltIn;
+
+ ///
+ /// 脚本代码
+ ///
+ [SugarColumn(ColumnDescription = "脚本代码", ColumnDataType = StaticConfig.CodeFirst_BigString)]
+ public string? ScriptCode { get; set; }
+}
\ No newline at end of file
diff --git a/Admin.NET/Admin.NET.Core/Entity/SysJobTrigger.cs b/Admin.NET/Admin.NET.Core/Entity/SysJobTrigger.cs
new file mode 100644
index 00000000..dc6d5c85
--- /dev/null
+++ b/Admin.NET/Admin.NET.Core/Entity/SysJobTrigger.cs
@@ -0,0 +1,147 @@
+// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
+//
+// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
+//
+// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
+
+namespace Admin.NET.Core;
+
+///
+/// 系统作业触发器表
+///
+[SugarTable(null, "系统作业触发器表")]
+[SysTable]
+public partial class SysJobTrigger : EntityBaseId
+{
+ ///
+ /// 触发器Id
+ ///
+ [SugarColumn(ColumnDescription = "触发器Id", Length = 64)]
+ [Required, MaxLength(64)]
+ public virtual string TriggerId { get; set; }
+
+ ///
+ /// 作业Id
+ ///
+ [SugarColumn(ColumnDescription = "作业Id", Length = 64)]
+ [Required, MaxLength(64)]
+ public virtual string JobId { get; set; }
+
+ ///
+ /// 触发器类型FullName
+ ///
+ [SugarColumn(ColumnDescription = "触发器类型", Length = 128)]
+ [MaxLength(128)]
+ public string? TriggerType { get; set; }
+
+ ///
+ /// 程序集Name
+ ///
+ [SugarColumn(ColumnDescription = "程序集", Length = 128)]
+ [MaxLength(128)]
+ public string? AssemblyName { get; set; } = "Furion.Pure";
+
+ ///
+ /// 参数
+ ///
+ [SugarColumn(ColumnDescription = "参数", Length = 128)]
+ [MaxLength(128)]
+ public string? Args { get; set; }
+
+ ///
+ /// 描述信息
+ ///
+ [SugarColumn(ColumnDescription = "描述信息", Length = 128)]
+ [MaxLength(128)]
+ public string? Description { get; set; }
+
+ ///
+ /// 状态
+ ///
+ [SugarColumn(ColumnDescription = "状态")]
+ public TriggerStatus Status { get; set; } = TriggerStatus.Ready;
+
+ ///
+ /// 起始时间
+ ///
+ [SugarColumn(ColumnDescription = "起始时间")]
+ public DateTime? StartTime { get; set; }
+
+ ///
+ /// 结束时间
+ ///
+ [SugarColumn(ColumnDescription = "结束时间")]
+ public DateTime? EndTime { get; set; }
+
+ ///
+ /// 最近运行时间
+ ///
+ [SugarColumn(ColumnDescription = "最近运行时间")]
+ public DateTime? LastRunTime { get; set; }
+
+ ///
+ /// 下一次运行时间
+ ///
+ [SugarColumn(ColumnDescription = "下一次运行时间")]
+ public DateTime? NextRunTime { get; set; }
+
+ ///
+ /// 触发次数
+ ///
+ [SugarColumn(ColumnDescription = "触发次数")]
+ public long NumberOfRuns { get; set; }
+
+ ///
+ /// 最大触发次数(0:不限制,n:N次)
+ ///
+ [SugarColumn(ColumnDescription = "最大触发次数")]
+ public long MaxNumberOfRuns { get; set; }
+
+ ///
+ /// 出错次数
+ ///
+ [SugarColumn(ColumnDescription = "出错次数")]
+ public long NumberOfErrors { get; set; }
+
+ ///
+ /// 最大出错次数(0:不限制,n:N次)
+ ///
+ [SugarColumn(ColumnDescription = "最大出错次数")]
+ public long MaxNumberOfErrors { get; set; }
+
+ ///
+ /// 重试次数
+ ///
+ [SugarColumn(ColumnDescription = "重试次数")]
+ public int NumRetries { get; set; }
+
+ ///
+ /// 重试间隔时间(ms)
+ ///
+ [SugarColumn(ColumnDescription = "重试间隔时间(ms)")]
+ public int RetryTimeout { get; set; } = 1000;
+
+ ///
+ /// 是否立即启动
+ ///
+ [SugarColumn(ColumnDescription = "是否立即启动")]
+ public bool StartNow { get; set; } = true;
+
+ ///
+ /// 是否启动时执行一次
+ ///
+ [SugarColumn(ColumnDescription = "是否启动时执行一次")]
+ public bool RunOnStart { get; set; } = false;
+
+ ///
+ /// 是否在启动时重置最大触发次数等于一次的作业
+ ///
+ [SugarColumn(ColumnDescription = "是否重置触发次数")]
+ public bool ResetOnlyOnce { get; set; } = true;
+
+ ///
+ /// 更新时间
+ ///
+ [SugarColumn(ColumnDescription = "更新时间")]
+ public DateTime? UpdatedTime { get; set; }
+}
\ No newline at end of file
diff --git a/Admin.NET/Admin.NET.Core/Entity/SysJobTriggerRecord.cs b/Admin.NET/Admin.NET.Core/Entity/SysJobTriggerRecord.cs
new file mode 100644
index 00000000..080c5cce
--- /dev/null
+++ b/Admin.NET/Admin.NET.Core/Entity/SysJobTriggerRecord.cs
@@ -0,0 +1,72 @@
+// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
+//
+// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
+//
+// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
+
+namespace Admin.NET.Core;
+
+///
+/// 系统作业触发器运行记录表
+///
+[SugarTable(null, "系统作业触发器运行记录表")]
+[SysTable]
+public partial class SysJobTriggerRecord : EntityBaseId
+{
+ ///
+ /// 作业Id
+ ///
+ [SugarColumn(ColumnDescription = "作业Id", Length = 64)]
+ [Required, MaxLength(64)]
+ public virtual string JobId { get; set; }
+
+ ///
+ /// 触发器Id
+ ///
+ [SugarColumn(ColumnDescription = "触发器Id", Length = 64)]
+ [Required, MaxLength(64)]
+ public virtual string TriggerId { get; set; }
+
+ ///
+ /// 当前运行次数
+ ///
+ [SugarColumn(ColumnDescription = "当前运行次数")]
+ public long NumberOfRuns { get; set; }
+
+ ///
+ /// 最近运行时间
+ ///
+ [SugarColumn(ColumnDescription = "最近运行时间")]
+ public DateTime? LastRunTime { get; set; }
+
+ ///
+ /// 下一次运行时间
+ ///
+ [SugarColumn(ColumnDescription = "下一次运行时间")]
+ public DateTime? NextRunTime { get; set; }
+
+ ///
+ /// 触发器状态
+ ///
+ [SugarColumn(ColumnDescription = "触发器状态")]
+ public TriggerStatus Status { get; set; } = TriggerStatus.Ready;
+
+ ///
+ /// 本次执行结果
+ ///
+ [SugarColumn(ColumnDescription = "本次执行结果", Length = 128)]
+ [MaxLength(128)]
+ public string? Result { get; set; }
+
+ ///
+ /// 本次执行耗时
+ ///
+ [SugarColumn(ColumnDescription = "本次执行耗时")]
+ public long ElapsedTime { get; set; }
+
+ ///
+ /// 创建时间
+ ///
+ [SugarColumn(ColumnDescription = "创建时间")]
+ public DateTime? CreatedTime { get; set; }
+}
\ No newline at end of file
diff --git a/Admin.NET/Admin.NET.Core/Entity/SysLdap.cs b/Admin.NET/Admin.NET.Core/Entity/SysLdap.cs
new file mode 100644
index 00000000..a8d629b7
--- /dev/null
+++ b/Admin.NET/Admin.NET.Core/Entity/SysLdap.cs
@@ -0,0 +1,89 @@
+// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
+//
+// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
+//
+// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
+
+namespace Admin.NET.Core;
+
+///
+/// 系统域登录信息配置表
+///
+[SugarTable(null, "系统域登录信息配置表")]
+[SysTable]
+public class SysLdap : EntityTenant
+{
+ ///
+ /// 主机
+ ///
+ [SugarColumn(ColumnDescription = "主机", Length = 128)]
+ [Required]
+ public virtual string Host { get; set; }
+
+ ///
+ /// 端口
+ ///
+ [SugarColumn(ColumnDescription = "端口")]
+ public virtual int Port { get; set; }
+
+ ///
+ /// 用户搜索基准
+ ///
+ [SugarColumn(ColumnDescription = "用户搜索基准", Length = 128)]
+ [Required]
+ public virtual string BaseDn { get; set; }
+
+ ///
+ /// 绑定DN(有管理权限制的用户)
+ ///
+ [SugarColumn(ColumnDescription = "绑定DN", Length = 32)]
+ [Required]
+ public virtual string BindDn { get; set; }
+
+ ///
+ /// 绑定密码(有管理权限制的用户密码)
+ ///
+ [SugarColumn(ColumnDescription = "绑定密码", Length = 512)]
+ [Required]
+ public virtual string BindPass { get; set; }
+
+ ///
+ /// 用户过滤规则
+ ///
+ [SugarColumn(ColumnDescription = "用户过滤规则", Length = 128)]
+ [Required]
+ public virtual string AuthFilter { get; set; } = "sAMAccountName=%s";
+
+ ///
+ /// Ldap版本
+ ///
+ [SugarColumn(ColumnDescription = "Ldap版本")]
+ public int Version { get; set; }
+
+ ///
+ /// 绑定域账号字段属性值
+ ///
+ [SugarColumn(ColumnDescription = "绑定域账号字段属性值", Length = 32)]
+ [Required]
+ public virtual string BindAttrAccount { get; set; } = "sAMAccountName";
+
+ ///
+ /// 绑定用户EmployeeId属性值
+ ///
+ [SugarColumn(ColumnDescription = "绑定用户EmployeeId属性值", Length = 32)]
+ [Required]
+ public virtual string BindAttrEmployeeId { get; set; } = "EmployeeId";
+
+ ///
+ /// 绑定Code属性值
+ ///
+ [SugarColumn(ColumnDescription = "绑定对象Code属性值", Length = 64)]
+ [Required]
+ public virtual string BindAttrCode { get; set; } = "objectGUID";
+
+ ///
+ /// 状态
+ ///
+ [SugarColumn(ColumnDescription = "状态")]
+ public StatusEnum Status { get; set; } = StatusEnum.Enable;
+}
\ No newline at end of file
diff --git a/Admin.NET/Admin.NET.Core/Entity/SysLogDiff.cs b/Admin.NET/Admin.NET.Core/Entity/SysLogDiff.cs
new file mode 100644
index 00000000..a25de06b
--- /dev/null
+++ b/Admin.NET/Admin.NET.Core/Entity/SysLogDiff.cs
@@ -0,0 +1,58 @@
+// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
+//
+// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
+//
+// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
+
+namespace Admin.NET.Core;
+
+///
+/// 系统差异日志表
+///
+[SugarTable(null, "系统差异日志表")]
+[SysTable]
+[LogTable]
+public partial class SysLogDiff : EntityBase
+{
+ ///
+ /// 操作前记录
+ ///
+ [SugarColumn(ColumnDescription = "操作前记录", ColumnDataType = StaticConfig.CodeFirst_BigString)]
+ public string? BeforeData { get; set; }
+
+ ///
+ /// 操作后记录
+ ///
+ [SugarColumn(ColumnDescription = "操作后记录", ColumnDataType = StaticConfig.CodeFirst_BigString)]
+ public string? AfterData { get; set; }
+
+ ///
+ /// Sql
+ ///
+ [SugarColumn(ColumnDescription = "Sql", ColumnDataType = StaticConfig.CodeFirst_BigString)]
+ public string? Sql { get; set; }
+
+ ///
+ /// 参数 手动传入的参数
+ ///
+ [SugarColumn(ColumnDescription = "参数", ColumnDataType = StaticConfig.CodeFirst_BigString)]
+ public string? Parameters { get; set; }
+
+ ///
+ /// 业务对象
+ ///
+ [SugarColumn(ColumnDescription = "业务对象", ColumnDataType = StaticConfig.CodeFirst_BigString)]
+ public string? BusinessData { get; set; }
+
+ ///
+ /// 差异操作
+ ///
+ [SugarColumn(ColumnDescription = "差异操作", ColumnDataType = StaticConfig.CodeFirst_BigString)]
+ public string? DiffType { get; set; }
+
+ ///
+ /// 耗时
+ ///
+ [SugarColumn(ColumnDescription = "耗时")]
+ public long? Elapsed { get; set; }
+}
\ No newline at end of file
diff --git a/Admin.NET/Admin.NET.Core/Entity/SysLogEx.cs b/Admin.NET/Admin.NET.Core/Entity/SysLogEx.cs
new file mode 100644
index 00000000..e650144c
--- /dev/null
+++ b/Admin.NET/Admin.NET.Core/Entity/SysLogEx.cs
@@ -0,0 +1,72 @@
+// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
+//
+// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
+//
+// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
+
+namespace Admin.NET.Core;
+
+///
+/// 系统异常日志表
+///
+[SugarTable(null, "系统异常日志表")]
+[SysTable]
+[LogTable]
+public partial class SysLogEx : SysLogVis
+{
+ ///
+ /// 请求方式
+ ///
+ [SugarColumn(ColumnDescription = "请求方式", Length = 32)]
+ [MaxLength(32)]
+ public string? HttpMethod { get; set; }
+
+ ///
+ /// 请求地址
+ ///
+ [SugarColumn(ColumnDescription = "请求地址", ColumnDataType = StaticConfig.CodeFirst_BigString)]
+ public string? RequestUrl { get; set; }
+
+ ///
+ /// 请求参数
+ ///
+ [SugarColumn(ColumnDescription = "请求参数", ColumnDataType = StaticConfig.CodeFirst_BigString)]
+ public string? RequestParam { get; set; }
+
+ ///
+ /// 返回结果
+ ///
+ [SugarColumn(ColumnDescription = "返回结果", ColumnDataType = StaticConfig.CodeFirst_BigString)]
+ public string? ReturnResult { get; set; }
+
+ ///
+ /// 事件Id
+ ///
+ [SugarColumn(ColumnDescription = "事件Id")]
+ public int? EventId { get; set; }
+
+ ///
+ /// 线程Id
+ ///
+ [SugarColumn(ColumnDescription = "线程Id")]
+ public int? ThreadId { get; set; }
+
+ ///
+ /// 请求跟踪Id
+ ///
+ [SugarColumn(ColumnDescription = "请求跟踪Id", Length = 128)]
+ [MaxLength(128)]
+ public string? TraceId { get; set; }
+
+ ///
+ /// 异常信息
+ ///
+ [SugarColumn(ColumnDescription = "异常信息", ColumnDataType = StaticConfig.CodeFirst_BigString)]
+ public string? Exception { get; set; }
+
+ ///
+ /// 日志消息Json
+ ///
+ [SugarColumn(ColumnDescription = "日志消息Json", ColumnDataType = StaticConfig.CodeFirst_BigString)]
+ public string? Message { get; set; }
+}
\ No newline at end of file
diff --git a/Admin.NET/Admin.NET.Core/Entity/SysLogOp.cs b/Admin.NET/Admin.NET.Core/Entity/SysLogOp.cs
new file mode 100644
index 00000000..e5ba1c1d
--- /dev/null
+++ b/Admin.NET/Admin.NET.Core/Entity/SysLogOp.cs
@@ -0,0 +1,72 @@
+// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
+//
+// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
+//
+// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
+
+namespace Admin.NET.Core;
+
+///
+/// 系统操作日志表
+///
+[SugarTable(null, "系统操作日志表")]
+[SysTable]
+[LogTable]
+public partial class SysLogOp : SysLogVis
+{
+ ///
+ /// 请求方式
+ ///
+ [SugarColumn(ColumnDescription = "请求方式", Length = 32)]
+ [MaxLength(32)]
+ public string? HttpMethod { get; set; }
+
+ ///
+ /// 请求地址
+ ///
+ [SugarColumn(ColumnDescription = "请求地址", ColumnDataType = StaticConfig.CodeFirst_BigString)]
+ public string? RequestUrl { get; set; }
+
+ ///
+ /// 请求参数
+ ///
+ [SugarColumn(ColumnDescription = "请求参数", ColumnDataType = StaticConfig.CodeFirst_BigString)]
+ public string? RequestParam { get; set; }
+
+ ///
+ /// 返回结果
+ ///
+ [SugarColumn(ColumnDescription = "返回结果", ColumnDataType = StaticConfig.CodeFirst_BigString)]
+ public string? ReturnResult { get; set; }
+
+ ///
+ /// 事件Id
+ ///
+ [SugarColumn(ColumnDescription = "事件Id")]
+ public int? EventId { get; set; }
+
+ ///
+ /// 线程Id
+ ///
+ [SugarColumn(ColumnDescription = "线程Id")]
+ public int? ThreadId { get; set; }
+
+ ///
+ /// 请求跟踪Id
+ ///
+ [SugarColumn(ColumnDescription = "请求跟踪Id", Length = 128)]
+ [MaxLength(128)]
+ public string? TraceId { get; set; }
+
+ ///
+ /// 异常信息
+ ///
+ [SugarColumn(ColumnDescription = "异常信息", ColumnDataType = StaticConfig.CodeFirst_BigString)]
+ public string? Exception { get; set; }
+
+ ///
+ /// 日志消息Json
+ ///
+ [SugarColumn(ColumnDescription = "日志消息Json", ColumnDataType = StaticConfig.CodeFirst_BigString)]
+ public string? Message { get; set; }
+}
\ No newline at end of file
diff --git a/Admin.NET/Admin.NET.Core/Entity/SysLogVis.cs b/Admin.NET/Admin.NET.Core/Entity/SysLogVis.cs
new file mode 100644
index 00000000..2e0928f6
--- /dev/null
+++ b/Admin.NET/Admin.NET.Core/Entity/SysLogVis.cs
@@ -0,0 +1,116 @@
+// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
+//
+// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
+//
+// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
+
+namespace Admin.NET.Core;
+
+///
+/// 系统访问日志表
+///
+[SugarTable(null, "系统访问日志表")]
+[SysTable]
+[LogTable]
+public partial class SysLogVis : EntityTenant
+{
+ ///
+ /// 模块名称
+ ///
+ [SugarColumn(ColumnDescription = "模块名称", Length = 256)]
+ [MaxLength(256)]
+ public string? ControllerName { get; set; }
+
+ ///
+ /// 方法名称
+ ///
+ [SugarColumn(ColumnDescription = "方法名称", Length = 256)]
+ [MaxLength(256)]
+ public string? ActionName { get; set; }
+
+ ///
+ /// 显示名称
+ ///
+ [SugarColumn(ColumnDescription = "显示名称", Length = 256)]
+ [MaxLength(256)]
+ public string? DisplayTitle { get; set; }
+
+ ///
+ /// 执行状态
+ ///
+ [SugarColumn(ColumnDescription = "执行状态", Length = 32)]
+ [MaxLength(32)]
+ public string? Status { get; set; }
+
+ ///
+ /// IP地址
+ ///
+ [SugarColumn(ColumnDescription = "IP地址", Length = 256)]
+ [MaxLength(256)]
+ public string? RemoteIp { get; set; }
+
+ ///
+ /// 登录地点
+ ///
+ [SugarColumn(ColumnDescription = "登录地点", Length = 128)]
+ [MaxLength(128)]
+ public string? Location { get; set; }
+
+ ///
+ /// 经度
+ ///
+ [SugarColumn(ColumnDescription = "经度")]
+ public double? Longitude { get; set; }
+
+ ///
+ /// 维度
+ ///
+ [SugarColumn(ColumnDescription = "维度")]
+ public double? Latitude { get; set; }
+
+ ///
+ /// 浏览器
+ ///
+ [SugarColumn(ColumnDescription = "浏览器", Length = 1024)]
+ [MaxLength(1024)]
+ public string? Browser { get; set; }
+
+ ///
+ /// 操作系统
+ ///
+ [SugarColumn(ColumnDescription = "操作系统", Length = 256)]
+ [MaxLength(256)]
+ public string? Os { get; set; }
+
+ ///
+ /// 操作用时
+ ///
+ [SugarColumn(ColumnDescription = "操作用时")]
+ public long? Elapsed { get; set; }
+
+ ///
+ /// 日志时间
+ ///
+ [SugarColumn(ColumnDescription = "日志时间")]
+ public DateTime? LogDateTime { get; set; }
+
+ ///
+ /// 日志级别
+ ///
+ [SugarColumn(ColumnDescription = "日志级别")]
+ public LogLevel? LogLevel { get; set; }
+
+ ///
+ /// 账号
+ ///
+ [SugarColumn(ColumnDescription = "账号", Length = 32)]
+ [MaxLength(32)]
+ public string? Account { get; set; }
+
+ ///
+ /// 真实姓名
+ ///
+ [SugarColumn(ColumnDescription = "真实姓名", Length = 32)]
+ [MaxLength(32)]
+ public string? RealName { get; set; }
+}
\ No newline at end of file
diff --git a/Admin.NET/Admin.NET.Core/Entity/SysMenu.cs b/Admin.NET/Admin.NET.Core/Entity/SysMenu.cs
new file mode 100644
index 00000000..3f6a51a9
--- /dev/null
+++ b/Admin.NET/Admin.NET.Core/Entity/SysMenu.cs
@@ -0,0 +1,134 @@
+// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
+//
+// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
+//
+// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
+
+namespace Admin.NET.Core;
+
+///
+/// 系统菜单表
+///
+[SugarTable(null, "系统菜单表")]
+[SysTable]
+[SugarIndex("index_{table}_T", nameof(Title), OrderByType.Asc)]
+[SugarIndex("index_{table}_T2", nameof(Type), OrderByType.Asc)]
+public partial class SysMenu : EntityBase
+{
+ ///
+ /// 父Id
+ ///
+ [SugarColumn(ColumnDescription = "父Id")]
+ public long Pid { get; set; }
+
+ ///
+ /// 菜单类型(1目录 2菜单 3按钮)
+ ///
+ [SugarColumn(ColumnDescription = "菜单类型")]
+ public MenuTypeEnum Type { get; set; }
+
+ ///
+ /// 路由名称
+ ///
+ [SugarColumn(ColumnDescription = "路由名称", Length = 64)]
+ [MaxLength(64)]
+ public string? Name { get; set; }
+
+ ///
+ /// 路由地址
+ ///
+ [SugarColumn(ColumnDescription = "路由地址", Length = 128)]
+ [MaxLength(128)]
+ public string? Path { get; set; }
+
+ ///
+ /// 组件路径
+ ///
+ [SugarColumn(ColumnDescription = "组件路径", Length = 128)]
+ [MaxLength(128)]
+ public string? Component { get; set; }
+
+ ///
+ /// 重定向
+ ///
+ [SugarColumn(ColumnDescription = "重定向", Length = 128)]
+ [MaxLength(128)]
+ public string? Redirect { get; set; }
+
+ ///
+ /// 权限标识
+ ///
+ [SugarColumn(ColumnDescription = "权限标识", Length = 128)]
+ [MaxLength(128)]
+ public string? Permission { get; set; }
+
+ ///
+ /// 菜单名称
+ ///
+ [SugarColumn(ColumnDescription = "菜单名称", Length = 64)]
+ [Required, MaxLength(64)]
+ public virtual string Title { get; set; }
+
+ ///
+ /// 图标
+ ///
+ [SugarColumn(ColumnDescription = "图标", Length = 128)]
+ [MaxLength(128)]
+ public string? Icon { get; set; }
+
+ ///
+ /// 是否内嵌
+ ///
+ [SugarColumn(ColumnDescription = "是否内嵌")]
+ public bool IsIframe { get; set; }
+
+ ///
+ /// 外链链接
+ ///
+ [SugarColumn(ColumnDescription = "外链链接", Length = 256)]
+ [MaxLength(256)]
+ public string? OutLink { get; set; }
+
+ ///
+ /// 是否隐藏
+ ///
+ [SugarColumn(ColumnDescription = "是否隐藏")]
+ public bool IsHide { get; set; }
+
+ ///
+ /// 是否缓存
+ ///
+ [SugarColumn(ColumnDescription = "是否缓存")]
+ public bool IsKeepAlive { get; set; } = true;
+
+ ///
+ /// 是否固定
+ ///
+ [SugarColumn(ColumnDescription = "是否固定")]
+ public bool IsAffix { get; set; }
+
+ ///
+ /// 排序
+ ///
+ [SugarColumn(ColumnDescription = "排序")]
+ public int OrderNo { get; set; } = 100;
+
+ ///
+ /// 状态
+ ///
+ [SugarColumn(ColumnDescription = "状态")]
+ public StatusEnum Status { get; set; } = StatusEnum.Enable;
+
+ ///
+ /// 备注
+ ///
+ [SugarColumn(ColumnDescription = "备注", Length = 256)]
+ [MaxLength(256)]
+ public string? Remark { get; set; }
+
+ ///
+ /// 菜单子项
+ ///
+ [SugarColumn(IsIgnore = true)]
+ public List Children { get; set; } = new List();
+}
\ No newline at end of file
diff --git a/Admin.NET/Admin.NET.Core/Entity/SysNotice.cs b/Admin.NET/Admin.NET.Core/Entity/SysNotice.cs
new file mode 100644
index 00000000..7aa7d012
--- /dev/null
+++ b/Admin.NET/Admin.NET.Core/Entity/SysNotice.cs
@@ -0,0 +1,82 @@
+// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
+//
+// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
+//
+// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
+
+namespace Admin.NET.Core;
+
+///
+/// 系统通知公告表
+///
+[SugarTable(null, "系统通知公告表")]
+[SysTable]
+[SugarIndex("index_{table}_T", nameof(Type), OrderByType.Asc)]
+public partial class SysNotice : EntityBase
+{
+ ///
+ /// 标题
+ ///
+ [SugarColumn(ColumnDescription = "标题", Length = 32)]
+ [Required, MaxLength(32)]
+ [SensitiveDetection('*')]
+ public virtual string Title { get; set; }
+
+ ///
+ /// 内容
+ ///
+ [SugarColumn(ColumnDescription = "内容", ColumnDataType = StaticConfig.CodeFirst_BigString)]
+ [Required]
+ [SensitiveDetection('*')]
+ public virtual string Content { get; set; }
+
+ ///
+ /// 类型(1通知 2公告)
+ ///
+ [SugarColumn(ColumnDescription = "类型(1通知 2公告)")]
+ public NoticeTypeEnum Type { get; set; }
+
+ ///
+ /// 发布人Id
+ ///
+ [SugarColumn(ColumnDescription = "发布人Id")]
+ public long PublicUserId { get; set; }
+
+ ///
+ /// 发布人姓名
+ ///
+ [SugarColumn(ColumnDescription = "发布人姓名", Length = 32)]
+ [MaxLength(32)]
+ public string? PublicUserName { get; set; }
+
+ ///
+ /// 发布机构Id
+ ///
+ [SugarColumn(ColumnDescription = "发布机构Id")]
+ public long PublicOrgId { get; set; }
+
+ ///
+ /// 发布机构名称
+ ///
+ [SugarColumn(ColumnDescription = "发布机构名称", Length = 64)]
+ [MaxLength(64)]
+ public string? PublicOrgName { get; set; }
+
+ ///
+ /// 发布时间
+ ///
+ [SugarColumn(ColumnDescription = "发布时间")]
+ public DateTime? PublicTime { get; set; }
+
+ ///
+ /// 撤回时间
+ ///
+ [SugarColumn(ColumnDescription = "撤回时间")]
+ public DateTime? CancelTime { get; set; }
+
+ ///
+ /// 状态(0草稿 1发布 2撤回 3删除)
+ ///
+ [SugarColumn(ColumnDescription = "状态(0草稿 1发布 2撤回 3删除)")]
+ public NoticeStatusEnum Status { get; set; }
+}
\ No newline at end of file
diff --git a/Admin.NET/Admin.NET.Core/Entity/SysNoticeUser.cs b/Admin.NET/Admin.NET.Core/Entity/SysNoticeUser.cs
new file mode 100644
index 00000000..5f71ba4a
--- /dev/null
+++ b/Admin.NET/Admin.NET.Core/Entity/SysNoticeUser.cs
@@ -0,0 +1,45 @@
+// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
+//
+// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
+//
+// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
+
+namespace Admin.NET.Core;
+
+///
+/// 系统通知公告用户表
+///
+[SugarTable(null, "系统通知公告用户表")]
+[SysTable]
+public partial class SysNoticeUser : EntityBaseId
+{
+ ///
+ /// 通知公告Id
+ ///
+ [SugarColumn(ColumnDescription = "通知公告Id")]
+ public long NoticeId { get; set; }
+
+ ///
+ /// 通知公告
+ ///
+ [Navigate(NavigateType.OneToOne, nameof(NoticeId))]
+ public SysNotice SysNotice { get; set; }
+
+ ///
+ /// 用户Id
+ ///
+ [SugarColumn(ColumnDescription = "用户Id")]
+ public long UserId { get; set; }
+
+ ///
+ /// 阅读时间
+ ///
+ [SugarColumn(ColumnDescription = "阅读时间")]
+ public DateTime? ReadTime { get; set; }
+
+ ///
+ /// 状态(0未读 1已读)
+ ///
+ [SugarColumn(ColumnDescription = "状态(0未读 1已读)")]
+ public NoticeUserStatusEnum ReadStatus { get; set; } = NoticeUserStatusEnum.UNREAD;
+}
\ No newline at end of file
diff --git a/Admin.NET/Admin.NET.Core/Entity/SysOAuthUser.cs b/Admin.NET/Admin.NET.Core/Entity/SysOAuthUser.cs
new file mode 100644
index 00000000..b001414a
--- /dev/null
+++ b/Admin.NET/Admin.NET.Core/Entity/SysOAuthUser.cs
@@ -0,0 +1,166 @@
+// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
+//
+// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
+//
+// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
+
+namespace Admin.NET.Core;
+
+///
+/// 系统三方用户表
+///
+[SugarTable(null, "系统三方用户表")]
+[SysTable]
+[SugarIndex("index_{table}_N", nameof(NickName), OrderByType.Asc)]
+[SugarIndex("index_{table}_M", nameof(Mobile), OrderByType.Asc)]
+public partial class SysOAuthUser : EntityBase
+{
+ ///
+ /// 系统用户Id
+ ///
+ [SugarColumn(ColumnDescription = "系统用户Id")]
+ public long UserId { get; set; }
+
+ ///
+ /// 系统用户
+ ///
+ [Newtonsoft.Json.JsonIgnore]
+ [System.Text.Json.Serialization.JsonIgnore]
+ [Navigate(NavigateType.OneToOne, nameof(UserId))]
+ public SysUser SysUser { get; set; }
+
+ ///
+ /// 平台类型
+ ///
+ [SugarColumn(ColumnDescription = "平台类型")]
+ public PlatformTypeEnum PlatformType { get; set; } = PlatformTypeEnum.微信公众号;
+
+ ///
+ /// OpenId
+ ///
+ [SugarColumn(ColumnDescription = "OpenId", Length = 64)]
+ [MaxLength(64)]
+ public virtual string? OpenId { get; set; }
+
+ ///
+ /// 会话密钥
+ ///
+ [SugarColumn(ColumnDescription = "会话密钥", Length = 256)]
+ [MaxLength(256)]
+ public string? SessionKey { get; set; }
+
+ ///
+ /// UnionId
+ ///
+ [SugarColumn(ColumnDescription = "UnionId", Length = 64)]
+ [MaxLength(64)]
+ public string? UnionId { get; set; }
+
+ ///
+ /// 账号
+ ///
+ [SugarColumn(ColumnDescription = "账号", Length = 128)]
+ [MaxLength(128)]
+ public string? Account { get; set; }
+
+ ///
+ /// 昵称
+ ///
+ [SugarColumn(ColumnDescription = "昵称", Length = 64)]
+ [Required, MaxLength(64)]
+ public string NickName { get; set; }
+
+ ///
+ /// 头像
+ ///
+ [SugarColumn(ColumnDescription = "头像", Length = 256)]
+ [MaxLength(256)]
+ public string? Avatar { get; set; }
+
+ ///
+ /// 邮箱
+ ///
+ [SugarColumn(ColumnDescription = "邮箱", Length = 128)]
+ [MaxLength(128)]
+ public virtual string? Email { get; set; }
+
+ ///
+ /// 手机号码
+ ///
+ [SugarColumn(ColumnDescription = "手机号码", Length = 16)]
+ [MaxLength(16)]
+ public string? Mobile { get; set; }
+
+ ///
+ /// 性别
+ ///
+ [SugarColumn(ColumnDescription = "性别")]
+ public int? Sex { get; set; } = 1;
+
+ ///
+ /// IP 地址
+ ///
+ [SugarColumn(ColumnDescription = "IP 地址", Length = 256)]
+ [MaxLength(256)]
+ public string? IpAddress { get; set; }
+
+ ///
+ /// 语言
+ ///
+ [SugarColumn(ColumnDescription = "语言", Length = 64)]
+ [MaxLength(64)]
+ public string? Language { get; set; }
+
+ ///
+ /// 城市
+ ///
+ [SugarColumn(ColumnDescription = "城市", Length = 64)]
+ [MaxLength(64)]
+ public string? City { get; set; }
+
+ ///
+ /// 省
+ ///
+ [SugarColumn(ColumnDescription = "省", Length = 64)]
+ [MaxLength(64)]
+ public string? Province { get; set; }
+
+ ///
+ /// 国家
+ ///
+ [SugarColumn(ColumnDescription = "国家", Length = 64)]
+ [MaxLength(64)]
+ public string? Country { get; set; }
+
+ ///
+ /// AccessToken
+ ///
+ [SugarColumn(ColumnDescription = "AccessToken", ColumnDataType = StaticConfig.CodeFirst_BigString)]
+ public string? AccessToken { get; set; }
+
+ ///
+ /// RefreshToken
+ ///
+ [SugarColumn(ColumnDescription = "RefreshToken", ColumnDataType = StaticConfig.CodeFirst_BigString)]
+ public string? RefreshToken { get; set; }
+
+ ///
+ /// 过期时间
+ ///
+ [SugarColumn(ColumnDescription = "ExpiresIn")]
+ public int? ExpiresIn { get; set; }
+
+ ///
+ /// 用户授权的作用域,使用逗号分隔
+ ///
+ [SugarColumn(ColumnDescription = "授权作用域", Length = 64)]
+ [MaxLength(64)]
+ public string? Scope { get; set; }
+
+ ///
+ /// 备注
+ ///
+ [SugarColumn(ColumnDescription = "备注", Length = 128)]
+ [MaxLength(128)]
+ public string? Remark { get; set; }
+}
\ No newline at end of file
diff --git a/Admin.NET/Admin.NET.Core/Entity/SysOnlineUser.cs b/Admin.NET/Admin.NET.Core/Entity/SysOnlineUser.cs
new file mode 100644
index 00000000..7fd95b2d
--- /dev/null
+++ b/Admin.NET/Admin.NET.Core/Entity/SysOnlineUser.cs
@@ -0,0 +1,68 @@
+// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
+//
+// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
+//
+// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
+
+namespace Admin.NET.Core;
+
+///
+/// 系统在线用户表
+///
+[SugarTable(null, "系统在线用户表")]
+[SysTable]
+public partial class SysOnlineUser : EntityTenantId
+{
+ ///
+ /// 连接Id
+ ///
+ [SugarColumn(ColumnDescription = "连接Id")]
+ public string? ConnectionId { get; set; }
+
+ ///
+ /// 用户Id
+ ///
+ [SugarColumn(ColumnDescription = "用户Id")]
+ public long UserId { get; set; }
+
+ ///
+ /// 账号
+ ///
+ [SugarColumn(ColumnDescription = "账号", Length = 32)]
+ [Required, MaxLength(32)]
+ public virtual string UserName { get; set; }
+
+ ///
+ /// 真实姓名
+ ///
+ [SugarColumn(ColumnDescription = "真实姓名", Length = 32)]
+ [MaxLength(32)]
+ public string? RealName { get; set; }
+
+ ///
+ /// 连接时间
+ ///
+ [SugarColumn(ColumnDescription = "连接时间")]
+ public DateTime? Time { get; set; }
+
+ ///
+ /// 连接IP
+ ///
+ [SugarColumn(ColumnDescription = "连接IP", Length = 256)]
+ [MaxLength(256)]
+ public string? Ip { get; set; }
+
+ ///
+ /// 浏览器
+ ///
+ [SugarColumn(ColumnDescription = "浏览器", Length = 128)]
+ [MaxLength(128)]
+ public string? Browser { get; set; }
+
+ ///
+ /// 操作系统
+ ///
+ [SugarColumn(ColumnDescription = "操作系统", Length = 128)]
+ [MaxLength(128)]
+ public string? Os { get; set; }
+}
\ No newline at end of file
diff --git a/Admin.NET/Admin.NET.Core/Entity/SysOpenAccess.cs b/Admin.NET/Admin.NET.Core/Entity/SysOpenAccess.cs
new file mode 100644
index 00000000..68185cfb
--- /dev/null
+++ b/Admin.NET/Admin.NET.Core/Entity/SysOpenAccess.cs
@@ -0,0 +1,58 @@
+// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
+//
+// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
+//
+// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
+
+namespace Admin.NET.Core;
+
+///
+/// 开放接口身份表
+///
+[SugarTable(null, "开放接口身份表")]
+[SysTable]
+[SugarIndex("index_{table}_A", nameof(AccessKey), OrderByType.Asc)]
+public partial class SysOpenAccess : EntityBase
+{
+ ///
+ /// 身份标识
+ ///
+ [SugarColumn(ColumnDescription = "身份标识", Length = 128)]
+ [Required, MaxLength(128)]
+ public virtual string AccessKey { get; set; }
+
+ ///
+ /// 密钥
+ ///
+ [SugarColumn(ColumnDescription = "密钥", Length = 256)]
+ [Required, MaxLength(256)]
+ public virtual string AccessSecret { get; set; }
+
+ ///
+ /// 绑定租户Id
+ ///
+ [SugarColumn(ColumnDescription = "绑定租户Id")]
+ public long BindTenantId { get; set; }
+
+ ///
+ /// 绑定租户
+ ///
+ [Newtonsoft.Json.JsonIgnore]
+ [System.Text.Json.Serialization.JsonIgnore]
+ [Navigate(NavigateType.OneToOne, nameof(BindTenantId))]
+ public SysTenant BindTenant { get; set; }
+
+ ///
+ /// 绑定用户Id
+ ///
+ [SugarColumn(ColumnDescription = "绑定用户Id")]
+ public virtual long BindUserId { get; set; }
+
+ ///
+ /// 绑定用户
+ ///
+ [Newtonsoft.Json.JsonIgnore]
+ [System.Text.Json.Serialization.JsonIgnore]
+ [Navigate(NavigateType.OneToOne, nameof(BindUserId))]
+ public SysUser BindUser { get; set; }
+}
\ No newline at end of file
diff --git a/Admin.NET/Admin.NET.Core/Entity/SysOrg.cs b/Admin.NET/Admin.NET.Core/Entity/SysOrg.cs
new file mode 100644
index 00000000..f6dc77ee
--- /dev/null
+++ b/Admin.NET/Admin.NET.Core/Entity/SysOrg.cs
@@ -0,0 +1,96 @@
+// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
+//
+// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
+//
+// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
+
+namespace Admin.NET.Core;
+
+///
+/// 系统机构表
+///
+[SugarTable(null, "系统机构表")]
+[SysTable]
+[SugarIndex("index_{table}_N", nameof(Name), OrderByType.Asc)]
+[SugarIndex("index_{table}_C", nameof(Code), OrderByType.Asc)]
+[SugarIndex("index_{table}_T", nameof(Type), OrderByType.Asc)]
+public partial class SysOrg : EntityTenant
+{
+ ///
+ /// 父Id
+ ///
+ [SugarColumn(ColumnDescription = "父Id")]
+ public long Pid { get; set; }
+
+ ///
+ /// 名称
+ ///
+ [SugarColumn(ColumnDescription = "名称", Length = 64)]
+ [Required, MaxLength(64)]
+ public virtual string Name { get; set; }
+
+ ///
+ /// 编码
+ ///
+ [SugarColumn(ColumnDescription = "编码", Length = 64)]
+ [MaxLength(64)]
+ public string? Code { get; set; }
+
+ ///
+ /// 级别
+ ///
+ [SugarColumn(ColumnDescription = "级别")]
+ public int? Level { get; set; }
+
+ ///
+ /// 机构类型-数据字典
+ ///
+ [SugarColumn(ColumnDescription = "机构类型", Length = 64)]
+ [MaxLength(64)]
+ public string? Type { get; set; }
+
+ ///
+ /// 负责人Id
+ ///
+ [SugarColumn(ColumnDescription = "负责人Id", IsNullable = true)]
+ public long? DirectorId { get; set; }
+
+ ///
+ /// 负责人
+ ///
+ [Newtonsoft.Json.JsonIgnore]
+ [System.Text.Json.Serialization.JsonIgnore]
+ [Navigate(NavigateType.OneToOne, nameof(DirectorId))]
+ public SysUser Director { get; set; }
+
+ ///
+ /// 排序
+ ///
+ [SugarColumn(ColumnDescription = "排序")]
+ public int OrderNo { get; set; } = 100;
+
+ ///
+ /// 状态
+ ///
+ [SugarColumn(ColumnDescription = "状态")]
+ public StatusEnum Status { get; set; } = StatusEnum.Enable;
+
+ ///
+ /// 备注
+ ///
+ [SugarColumn(ColumnDescription = "备注", Length = 128)]
+ [MaxLength(128)]
+ public string? Remark { get; set; }
+
+ ///
+ /// 机构子项
+ ///
+ [SugarColumn(IsIgnore = true)]
+ public List Children { get; set; }
+
+ ///
+ /// 是否禁止选中
+ ///
+ [SugarColumn(IsIgnore = true)]
+ public bool Disabled { get; set; }
+}
\ No newline at end of file
diff --git a/Admin.NET/Admin.NET.Core/Entity/SysPlugin.cs b/Admin.NET/Admin.NET.Core/Entity/SysPlugin.cs
new file mode 100644
index 00000000..2cc8e581
--- /dev/null
+++ b/Admin.NET/Admin.NET.Core/Entity/SysPlugin.cs
@@ -0,0 +1,56 @@
+// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
+//
+// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
+//
+// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
+
+namespace Admin.NET.Core;
+
+///
+/// 系统动态插件表
+///
+[SugarTable(null, "系统动态插件表")]
+[SysTable]
+[SugarIndex("index_{table}_N", nameof(Name), OrderByType.Asc)]
+public partial class SysPlugin : EntityTenant
+{
+ ///
+ /// 名称
+ ///
+ [SugarColumn(ColumnDescription = "名称", Length = 64)]
+ [Required, MaxLength(64)]
+ public virtual string Name { get; set; }
+
+ ///
+ /// C#代码
+ ///
+ [SugarColumn(ColumnDescription = "C#代码", ColumnDataType = StaticConfig.CodeFirst_BigString)]
+ [Required]
+ public virtual string CsharpCode { get; set; }
+
+ ///
+ /// 程序集名称
+ ///
+ [SugarColumn(ColumnDescription = "程序集名称", Length = 512)]
+ [MaxLength(512)]
+ public string? AssemblyName { get; set; }
+
+ ///
+ /// 排序
+ ///
+ [SugarColumn(ColumnDescription = "排序")]
+ public int OrderNo { get; set; } = 100;
+
+ ///
+ /// 状态
+ ///
+ [SugarColumn(ColumnDescription = "状态")]
+ public StatusEnum Status { get; set; } = StatusEnum.Enable;
+
+ ///
+ /// 备注
+ ///
+ [SugarColumn(ColumnDescription = "备注", Length = 128)]
+ [MaxLength(128)]
+ public string? Remark { get; set; }
+}
\ No newline at end of file
diff --git a/Admin.NET/Admin.NET.Core/Entity/SysPos.cs b/Admin.NET/Admin.NET.Core/Entity/SysPos.cs
new file mode 100644
index 00000000..d20f060c
--- /dev/null
+++ b/Admin.NET/Admin.NET.Core/Entity/SysPos.cs
@@ -0,0 +1,50 @@
+// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
+//
+// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
+//
+// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
+
+namespace Admin.NET.Core;
+
+///
+/// 系统职位表
+///
+[SugarTable(null, "系统职位表")]
+[SysTable]
+[SugarIndex("index_{table}_N", nameof(Name), OrderByType.Asc)]
+[SugarIndex("index_{table}_C", nameof(Code), OrderByType.Asc)]
+public partial class SysPos : EntityTenant
+{
+ ///
+ /// 名称
+ ///
+ [SugarColumn(ColumnDescription = "名称", Length = 64)]
+ [Required, MaxLength(64)]
+ public virtual string Name { get; set; }
+
+ ///
+ /// 编码
+ ///
+ [SugarColumn(ColumnDescription = "编码", Length = 64)]
+ [MaxLength(64)]
+ public string? Code { get; set; }
+
+ ///
+ /// 排序
+ ///
+ [SugarColumn(ColumnDescription = "排序")]
+ public int OrderNo { get; set; } = 100;
+
+ ///
+ /// 备注
+ ///
+ [SugarColumn(ColumnDescription = "备注", Length = 128)]
+ [MaxLength(128)]
+ public string? Remark { get; set; }
+
+ ///
+ /// 状态
+ ///
+ [SugarColumn(ColumnDescription = "状态")]
+ public StatusEnum Status { get; set; } = StatusEnum.Enable;
+}
\ No newline at end of file
diff --git a/Admin.NET/Admin.NET.Core/Entity/SysPrint.cs b/Admin.NET/Admin.NET.Core/Entity/SysPrint.cs
new file mode 100644
index 00000000..d7f69c22
--- /dev/null
+++ b/Admin.NET/Admin.NET.Core/Entity/SysPrint.cs
@@ -0,0 +1,69 @@
+// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
+//
+// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
+//
+// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
+
+namespace Admin.NET.Core;
+
+///
+/// 系统打印模板表
+///
+[SugarTable(null, "系统打印模板表")]
+[SysTable]
+[SugarIndex("index_{table}_N", nameof(Name), OrderByType.Asc)]
+public partial class SysPrint : EntityTenant
+{
+ ///
+ /// 名称
+ ///
+ [SugarColumn(ColumnDescription = "名称", Length = 64)]
+ [Required, MaxLength(64)]
+ public virtual string Name { get; set; }
+
+ ///
+ /// 打印模板
+ ///
+ [SugarColumn(ColumnDescription = "打印模板", ColumnDataType = StaticConfig.CodeFirst_BigString)]
+ [Required]
+ public virtual string Template { get; set; }
+
+ ///
+ /// 打印类型
+ ///
+ [SugarColumn(ColumnDescription = "打印类型")]
+ [Required]
+ public virtual PrintTypeEnum? PrintType { get; set; }
+
+ ///
+ /// 客户端服务地址
+ ///
+ [SugarColumn(ColumnDescription = "客户端服务地址", Length = 128)]
+ [MaxLength(128)]
+ public virtual string? ClientServiceAddress { get; set; }
+
+ ///
+ /// 打印参数
+ ///
+ [SugarColumn(ColumnDescription = "打印参数", ColumnDataType = "text")]
+ public virtual string? PrintParam { get; set; }
+
+ ///
+ /// 排序
+ ///
+ [SugarColumn(ColumnDescription = "排序")]
+ public int OrderNo { get; set; } = 100;
+
+ ///
+ /// 状态
+ ///
+ [SugarColumn(ColumnDescription = "状态")]
+ public StatusEnum Status { get; set; } = StatusEnum.Enable;
+
+ ///
+ /// 备注
+ ///
+ [SugarColumn(ColumnDescription = "备注", Length = 128)]
+ [MaxLength(128)]
+ public string? Remark { get; set; }
+}
\ No newline at end of file
diff --git a/Admin.NET/Admin.NET.Core/Entity/SysRegion.cs b/Admin.NET/Admin.NET.Core/Entity/SysRegion.cs
new file mode 100644
index 00000000..103f20e0
--- /dev/null
+++ b/Admin.NET/Admin.NET.Core/Entity/SysRegion.cs
@@ -0,0 +1,109 @@
+// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
+//
+// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
+//
+// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
+
+namespace Admin.NET.Core;
+
+///
+/// 系统行政地区表
+///
+[SugarTable(null, "系统行政地区表")]
+[SysTable]
+[SugarIndex("index_{table}_N", nameof(Name), OrderByType.Asc)]
+[SugarIndex("index_{table}_C", nameof(Code), OrderByType.Asc)]
+public partial class SysRegion : EntityBaseId
+{
+ ///
+ /// 父Id
+ ///
+ [SugarColumn(ColumnDescription = "父Id")]
+ public long Pid { get; set; }
+
+ ///
+ /// 名称
+ ///
+ [SugarColumn(ColumnDescription = "名称", Length = 128)]
+ [Required, MaxLength(128)]
+ public virtual string Name { get; set; }
+
+ ///
+ /// 简称
+ ///
+ [SugarColumn(ColumnDescription = "简称", Length = 32)]
+ [MaxLength(32)]
+ public string? ShortName { get; set; }
+
+ ///
+ /// 组合名
+ ///
+ [SugarColumn(ColumnDescription = "组合名", Length = 64)]
+ [MaxLength(64)]
+ public string? MergerName { get; set; }
+
+ ///
+ /// 行政代码
+ ///
+ [SugarColumn(ColumnDescription = "行政代码", Length = 32)]
+ [MaxLength(32)]
+ public string? Code { get; set; }
+
+ ///
+ /// 邮政编码
+ ///
+ [SugarColumn(ColumnDescription = "邮政编码", Length = 6)]
+ [MaxLength(6)]
+ public string? ZipCode { get; set; }
+
+ ///
+ /// 区号
+ ///
+ [SugarColumn(ColumnDescription = "区号", Length = 6)]
+ [MaxLength(6)]
+ public string? CityCode { get; set; }
+
+ ///
+ /// 层级
+ ///
+ [SugarColumn(ColumnDescription = "层级")]
+ public int Level { get; set; }
+
+ ///
+ /// 拼音
+ ///
+ [SugarColumn(ColumnDescription = "拼音", Length = 128)]
+ [MaxLength(128)]
+ public string? PinYin { get; set; }
+
+ ///
+ /// 经度
+ ///
+ [SugarColumn(ColumnDescription = "经度")]
+ public float Lng { get; set; }
+
+ ///
+ /// 维度
+ ///
+ [SugarColumn(ColumnDescription = "维度")]
+ public float Lat { get; set; }
+
+ ///
+ /// 排序
+ ///
+ [SugarColumn(ColumnDescription = "排序")]
+ public int OrderNo { get; set; } = 100;
+
+ ///
+ /// 备注
+ ///
+ [SugarColumn(ColumnDescription = "备注", Length = 128)]
+ [MaxLength(128)]
+ public string? Remark { get; set; }
+
+ ///
+ /// 机构子项
+ ///
+ [SugarColumn(IsIgnore = true)]
+ public List Children { get; set; }
+}
\ No newline at end of file
diff --git a/Admin.NET/Admin.NET.Core/Entity/SysRole.cs b/Admin.NET/Admin.NET.Core/Entity/SysRole.cs
new file mode 100644
index 00000000..3b1de1e9
--- /dev/null
+++ b/Admin.NET/Admin.NET.Core/Entity/SysRole.cs
@@ -0,0 +1,62 @@
+// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
+//
+// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
+//
+// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
+
+namespace Admin.NET.Core;
+
+///
+/// 系统角色表
+///
+[SugarTable(null, "系统角色表")]
+[SysTable]
+[SugarIndex("index_{table}_N", nameof(Name), OrderByType.Asc)]
+[SugarIndex("index_{table}_C", nameof(Code), OrderByType.Asc)]
+public partial class SysRole : EntityTenant
+{
+ ///
+ /// 名称
+ ///
+ [SugarColumn(ColumnDescription = "名称", Length = 64)]
+ [Required, MaxLength(64)]
+ public virtual string Name { get; set; }
+
+ ///
+ /// 编码
+ ///
+ [SugarColumn(ColumnDescription = "编码", Length = 64)]
+ [MaxLength(64)]
+ public string? Code { get; set; }
+
+ ///
+ /// 排序
+ ///
+ [SugarColumn(ColumnDescription = "排序")]
+ public int OrderNo { get; set; } = 100;
+
+ ///
+ /// 数据范围(1全部数据 2本部门及以下数据 3本部门数据 4仅本人数据 5自定义数据)
+ ///
+ [SugarColumn(ColumnDescription = "数据范围")]
+ public DataScopeEnum DataScope { get; set; } = DataScopeEnum.Self;
+
+ ///
+ /// 是否是内置(Y-是,N-否)
+ ///
+ [SugarColumn(ColumnDescription = "是否是内置")]
+ public YesNoEnum SysFlag { get; set; }
+
+ ///
+ /// 备注
+ ///
+ [SugarColumn(ColumnDescription = "备注", Length = 128)]
+ [MaxLength(128)]
+ public string? Remark { get; set; }
+
+ ///
+ /// 状态
+ ///
+ [SugarColumn(ColumnDescription = "状态")]
+ public StatusEnum Status { get; set; } = StatusEnum.Enable;
+}
\ No newline at end of file
diff --git a/Admin.NET/Admin.NET.Core/Entity/SysRoleApi.cs b/Admin.NET/Admin.NET.Core/Entity/SysRoleApi.cs
new file mode 100644
index 00000000..d6c8ad22
--- /dev/null
+++ b/Admin.NET/Admin.NET.Core/Entity/SysRoleApi.cs
@@ -0,0 +1,28 @@
+// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
+//
+// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
+//
+// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
+
+namespace Admin.NET.Core;
+
+///
+/// 系统角色接口表
+///
+[SugarTable(null, "系统角色接口表")]
+[SysTable]
+public class SysRoleApi : EntityBaseId
+{
+ ///
+ /// 角色Id
+ ///
+ [SugarColumn(ColumnDescription = "角色Id")]
+ public long RoleId { get; set; }
+
+ ///
+ /// 接口路由
+ ///
+ [SugarColumn(ColumnDescription = "接口路由", ColumnDataType = StaticConfig.CodeFirst_BigString)]
+ [Required]
+ public string Route { get; set; }
+}
\ No newline at end of file
diff --git a/Admin.NET/Admin.NET.Core/Entity/SysRoleMenu.cs b/Admin.NET/Admin.NET.Core/Entity/SysRoleMenu.cs
new file mode 100644
index 00000000..04e3f1d4
--- /dev/null
+++ b/Admin.NET/Admin.NET.Core/Entity/SysRoleMenu.cs
@@ -0,0 +1,35 @@
+// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
+//
+// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
+//
+// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
+
+namespace Admin.NET.Core;
+
+///
+/// 系统角色菜单表
+///
+[SugarTable(null, "系统角色菜单表")]
+[SysTable]
+public class SysRoleMenu : EntityBaseId
+{
+ ///
+ /// 角色Id
+ ///
+ [SugarColumn(ColumnDescription = "角色Id")]
+ public long RoleId { get; set; }
+
+ ///
+ /// 菜单Id
+ ///
+ [SugarColumn(ColumnDescription = "菜单Id")]
+ public long MenuId { get; set; }
+
+ ///
+ /// 菜单
+ ///
+ [Newtonsoft.Json.JsonIgnore]
+ [System.Text.Json.Serialization.JsonIgnore]
+ [Navigate(NavigateType.OneToOne, nameof(MenuId))]
+ public SysMenu SysMenu { get; set; }
+}
\ No newline at end of file
diff --git a/Admin.NET/Admin.NET.Core/Entity/SysRoleOrg.cs b/Admin.NET/Admin.NET.Core/Entity/SysRoleOrg.cs
new file mode 100644
index 00000000..c4622f83
--- /dev/null
+++ b/Admin.NET/Admin.NET.Core/Entity/SysRoleOrg.cs
@@ -0,0 +1,35 @@
+// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
+//
+// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
+//
+// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
+
+namespace Admin.NET.Core;
+
+///
+/// 系统角色机构表
+///
+[SugarTable(null, "系统角色机构表")]
+[SysTable]
+public class SysRoleOrg : EntityBaseId
+{
+ ///
+ /// 角色Id
+ ///
+ [SugarColumn(ColumnDescription = "角色Id")]
+ public long RoleId { get; set; }
+
+ ///
+ /// 机构Id
+ ///
+ [SugarColumn(ColumnDescription = "机构Id")]
+ public long OrgId { get; set; }
+
+ ///
+ /// 机构
+ ///
+ [Newtonsoft.Json.JsonIgnore]
+ [System.Text.Json.Serialization.JsonIgnore]
+ [Navigate(NavigateType.OneToOne, nameof(OrgId))]
+ public SysOrg SysOrg { get; set; }
+}
\ No newline at end of file
diff --git a/Admin.NET/Admin.NET.Core/Entity/SysTenant.cs b/Admin.NET/Admin.NET.Core/Entity/SysTenant.cs
new file mode 100644
index 00000000..9d1fa6f1
--- /dev/null
+++ b/Admin.NET/Admin.NET.Core/Entity/SysTenant.cs
@@ -0,0 +1,85 @@
+// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
+//
+// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
+//
+// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
+
+namespace Admin.NET.Core;
+
+///
+/// 系统租户表
+///
+[SugarTable(null, "系统租户表")]
+[SysTable]
+public partial class SysTenant : EntityBase
+{
+ ///
+ /// 用户Id
+ ///
+ [SugarColumn(ColumnDescription = "用户Id")]
+ public long UserId { get; set; }
+
+ ///
+ /// 机构Id
+ ///
+ [SugarColumn(ColumnDescription = "机构Id")]
+ public long OrgId { get; set; }
+
+ ///
+ /// 主机
+ ///
+ [SugarColumn(ColumnDescription = "主机", Length = 128)]
+ [MaxLength(128)]
+ public string? Host { get; set; }
+
+ ///
+ /// 租户类型
+ ///
+ [SugarColumn(ColumnDescription = "租户类型")]
+ public TenantTypeEnum TenantType { get; set; }
+
+ ///
+ /// 数据库类型
+ ///
+ [SugarColumn(ColumnDescription = "数据库类型")]
+ public SqlSugar.DbType DbType { get; set; }
+
+ ///
+ /// 数据库连接
+ ///
+ [SugarColumn(ColumnDescription = "数据库连接", Length = 256)]
+ [MaxLength(256)]
+ public string? Connection { get; set; }
+
+ ///
+ /// 数据库标识
+ ///
+ [SugarColumn(ColumnDescription = "数据库标识", Length = 64)]
+ [MaxLength(64)]
+ public string? ConfigId { get; set; }
+
+ ///
+ /// 从库连接/读写分离
+ ///
+ [SugarColumn(ColumnDescription = "从库连接/读写分离", ColumnDataType = StaticConfig.CodeFirst_BigString)]
+ public string? SlaveConnections { get; set; }
+
+ ///
+ /// 排序
+ ///
+ [SugarColumn(ColumnDescription = "排序")]
+ public int OrderNo { get; set; } = 100;
+
+ ///
+ /// 备注
+ ///
+ [SugarColumn(ColumnDescription = "备注", Length = 128)]
+ [MaxLength(128)]
+ public string? Remark { get; set; }
+
+ ///
+ /// 状态
+ ///
+ [SugarColumn(ColumnDescription = "状态")]
+ public StatusEnum Status { get; set; } = StatusEnum.Enable;
+}
\ No newline at end of file
diff --git a/Admin.NET/Admin.NET.Core/Entity/SysUser.cs b/Admin.NET/Admin.NET.Core/Entity/SysUser.cs
new file mode 100644
index 00000000..eea9f1df
--- /dev/null
+++ b/Admin.NET/Admin.NET.Core/Entity/SysUser.cs
@@ -0,0 +1,315 @@
+// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
+//
+// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
+//
+// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
+
+namespace Admin.NET.Core;
+
+///
+/// 系统用户表
+///
+[SugarTable(null, "系统用户表")]
+[SysTable]
+[SugarIndex("index_{table}_A", nameof(Account), OrderByType.Asc)]
+[SugarIndex("index_{table}_P", nameof(Phone), OrderByType.Asc)]
+public partial class SysUser : EntityTenant
+{
+ ///
+ /// 账号
+ ///
+ [SugarColumn(ColumnDescription = "账号", Length = 32)]
+ [Required, MaxLength(32)]
+ public virtual string Account { get; set; }
+
+ ///
+ /// 密码
+ ///
+ [SugarColumn(ColumnDescription = "密码", Length = 512)]
+ [MaxLength(512)]
+ [Newtonsoft.Json.JsonIgnore]
+ [System.Text.Json.Serialization.JsonIgnore]
+ public virtual string Password { get; set; }
+
+ ///
+ /// 真实姓名
+ ///
+ [SugarColumn(ColumnDescription = "真实姓名", Length = 32)]
+ [MaxLength(32)]
+ public virtual string RealName { get; set; }
+
+ ///
+ /// 昵称
+ ///
+ [SugarColumn(ColumnDescription = "昵称", Length = 32)]
+ [MaxLength(32)]
+ public string? NickName { get; set; }
+
+ ///
+ /// 头像
+ ///
+ [SugarColumn(ColumnDescription = "头像", Length = 512)]
+ [MaxLength(512)]
+ public string? Avatar { get; set; }
+
+ ///
+ /// 性别-男_1、女_2
+ ///
+ [SugarColumn(ColumnDescription = "性别")]
+ public GenderEnum Sex { get; set; } = GenderEnum.Male;
+
+ ///
+ /// 年龄
+ ///
+ [SugarColumn(ColumnDescription = "年龄")]
+ public int Age { get; set; }
+
+ ///
+ /// 出生日期
+ ///
+ [SugarColumn(ColumnDescription = "出生日期")]
+ public DateTime? Birthday { get; set; }
+
+ ///
+ /// 民族
+ ///
+ [SugarColumn(ColumnDescription = "民族", Length = 32)]
+ [MaxLength(32)]
+ public string? Nation { get; set; }
+
+ ///
+ /// 手机号码
+ ///
+ [SugarColumn(ColumnDescription = "手机号码", Length = 16)]
+ [MaxLength(16)]
+ public string? Phone { get; set; }
+
+ ///
+ /// 证件类型
+ ///
+ [SugarColumn(ColumnDescription = "证件类型")]
+ public CardTypeEnum CardType { get; set; }
+
+ ///
+ /// 身份证号
+ ///
+ [SugarColumn(ColumnDescription = "身份证号", Length = 32)]
+ [MaxLength(32)]
+ public string? IdCardNum { get; set; }
+
+ ///
+ /// 邮箱
+ ///
+ [SugarColumn(ColumnDescription = "邮箱", Length = 64)]
+ [MaxLength(64)]
+ public string? Email { get; set; }
+
+ ///
+ /// 地址
+ ///
+ [SugarColumn(ColumnDescription = "地址", Length = 256)]
+ [MaxLength(256)]
+ public string? Address { get; set; }
+
+ ///
+ /// 文化程度
+ ///
+ [SugarColumn(ColumnDescription = "文化程度")]
+ public CultureLevelEnum CultureLevel { get; set; }
+
+ ///
+ /// 政治面貌
+ ///
+ [SugarColumn(ColumnDescription = "政治面貌", Length = 16)]
+ [MaxLength(16)]
+ public string? PoliticalOutlook { get; set; }
+
+ ///
+ /// 毕业院校
+ /// COLLEGE
+ [SugarColumn(ColumnDescription = "毕业院校", Length = 128)]
+ [MaxLength(128)]
+ public string? College { get; set; }
+
+ ///
+ /// 办公电话
+ ///
+ [SugarColumn(ColumnDescription = "办公电话", Length = 16)]
+ [MaxLength(16)]
+ public string? OfficePhone { get; set; }
+
+ ///
+ /// 紧急联系人
+ ///
+ [SugarColumn(ColumnDescription = "紧急联系人", Length = 32)]
+ [MaxLength(32)]
+ public string? EmergencyContact { get; set; }
+
+ ///
+ /// 紧急联系人电话
+ ///
+ [SugarColumn(ColumnDescription = "紧急联系人电话", Length = 16)]
+ [MaxLength(16)]
+ public string? EmergencyPhone { get; set; }
+
+ ///
+ /// 紧急联系人地址
+ ///
+ [SugarColumn(ColumnDescription = "紧急联系人地址", Length = 256)]
+ [MaxLength(256)]
+ public string? EmergencyAddress { get; set; }
+
+ ///
+ /// 个人简介
+ ///
+ [SugarColumn(ColumnDescription = "个人简介", Length = 512)]
+ [MaxLength(512)]
+ public string? Introduction { get; set; }
+
+ ///
+ /// 排序
+ ///
+ [SugarColumn(ColumnDescription = "排序")]
+ public int OrderNo { get; set; } = 100;
+
+ ///
+ /// 状态
+ ///
+ [SugarColumn(ColumnDescription = "状态")]
+ public StatusEnum Status { get; set; } = StatusEnum.Enable;
+
+ ///
+ /// 备注
+ ///
+ [SugarColumn(ColumnDescription = "备注", Length = 256)]
+ [MaxLength(256)]
+ public string? Remark { get; set; }
+
+ ///
+ /// 账号类型
+ ///
+ [SugarColumn(ColumnDescription = "账号类型")]
+ public AccountTypeEnum AccountType { get; set; } = AccountTypeEnum.NormalUser;
+
+ ///
+ /// 直属机构Id
+ ///
+ [SugarColumn(ColumnDescription = "直属机构Id")]
+ public long OrgId { get; set; }
+
+ ///
+ /// 直属机构
+ ///
+ [Navigate(NavigateType.OneToOne, nameof(OrgId))]
+ public SysOrg SysOrg { get; set; }
+
+ ///
+ /// 直属主管Id
+ ///
+ [SugarColumn(ColumnDescription = "直属主管Id")]
+ public long? ManagerUserId { get; set; }
+
+ ///
+ /// 直属主管
+ ///
+ [Newtonsoft.Json.JsonIgnore]
+ [System.Text.Json.Serialization.JsonIgnore]
+ [Navigate(NavigateType.OneToOne, nameof(ManagerUserId))]
+ public SysUser ManagerUser { get; set; }
+
+ ///
+ /// 职位Id
+ ///
+ [SugarColumn(ColumnDescription = "职位Id")]
+ public long PosId { get; set; }
+
+ ///
+ /// 职位
+ ///
+ [Newtonsoft.Json.JsonIgnore]
+ [System.Text.Json.Serialization.JsonIgnore]
+ [Navigate(NavigateType.OneToOne, nameof(PosId))]
+ public SysPos SysPos { get; set; }
+
+ ///
+ /// 工号
+ ///
+ [SugarColumn(ColumnDescription = "工号", Length = 32)]
+ [MaxLength(32)]
+ public string? JobNum { get; set; }
+
+ ///
+ /// 职级
+ ///
+ [SugarColumn(ColumnDescription = "职级", Length = 32)]
+ [MaxLength(32)]
+ public string? PosLevel { get; set; }
+
+ ///
+ /// 职称
+ ///
+ [SugarColumn(ColumnDescription = "职称", Length = 32)]
+ [MaxLength(32)]
+ public string? PosTitle { get; set; }
+
+ ///
+ /// 擅长领域
+ ///
+ [SugarColumn(ColumnDescription = "擅长领域", Length = 32)]
+ [MaxLength(32)]
+ public string? Expertise { get; set; }
+
+ ///
+ /// 办公区域
+ ///
+ [SugarColumn(ColumnDescription = "办公区域", Length = 32)]
+ [MaxLength(32)]
+ public string? OfficeZone { get; set; }
+
+ ///
+ /// 办公室
+ ///
+ [SugarColumn(ColumnDescription = "办公室", Length = 32)]
+ [MaxLength(32)]
+ public string? Office { get; set; }
+
+ ///
+ /// 入职日期
+ ///
+ [SugarColumn(ColumnDescription = "入职日期")]
+ public DateTime? JoinDate { get; set; }
+
+ ///
+ /// 最新登录Ip
+ ///
+ [SugarColumn(ColumnDescription = "最新登录Ip", Length = 256)]
+ [MaxLength(256)]
+ public string? LastLoginIp { get; set; }
+
+ ///
+ /// 最新登录地点
+ ///
+ [SugarColumn(ColumnDescription = "最新登录地点", Length = 128)]
+ [MaxLength(128)]
+ public string? LastLoginAddress { get; set; }
+
+ ///
+ /// 最新登录时间
+ ///
+ [SugarColumn(ColumnDescription = "最新登录时间")]
+ public DateTime? LastLoginTime { get; set; }
+
+ ///
+ /// 最新登录设备
+ ///
+ [SugarColumn(ColumnDescription = "最新登录设备", Length = 128)]
+ [MaxLength(128)]
+ public string? LastLoginDevice { get; set; }
+
+ ///
+ /// 电子签名
+ ///
+ [SugarColumn(ColumnDescription = "电子签名", Length = 512)]
+ [MaxLength(512)]
+ public string? Signature { get; set; }
+}
\ No newline at end of file
diff --git a/Admin.NET/Admin.NET.Core/Entity/SysUserExtOrg.cs b/Admin.NET/Admin.NET.Core/Entity/SysUserExtOrg.cs
new file mode 100644
index 00000000..cc8c3cb7
--- /dev/null
+++ b/Admin.NET/Admin.NET.Core/Entity/SysUserExtOrg.cs
@@ -0,0 +1,77 @@
+// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
+//
+// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
+//
+// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
+
+namespace Admin.NET.Core;
+
+///
+/// 系统用户扩展机构表
+///
+[SugarTable(null, "系统用户扩展机构表")]
+[SysTable]
+public partial class SysUserExtOrg : EntityBaseId
+{
+ ///
+ /// 用户Id
+ ///
+ [SugarColumn(ColumnDescription = "用户Id")]
+ public long UserId { get; set; }
+
+ ///
+ /// 用户
+ ///
+ [Newtonsoft.Json.JsonIgnore]
+ [System.Text.Json.Serialization.JsonIgnore]
+ [Navigate(NavigateType.OneToOne, nameof(UserId))]
+ public SysUser SysUser { get; set; }
+
+ ///
+ /// 机构Id
+ ///
+ [SugarColumn(ColumnDescription = "机构Id")]
+ public long OrgId { get; set; }
+
+ ///
+ /// 机构
+ ///
+ [Newtonsoft.Json.JsonIgnore]
+ [System.Text.Json.Serialization.JsonIgnore]
+ [Navigate(NavigateType.OneToOne, nameof(OrgId))]
+ public SysOrg SysOrg { get; set; }
+
+ ///
+ /// 职位Id
+ ///
+ [SugarColumn(ColumnDescription = "职位Id")]
+ public long PosId { get; set; }
+
+ ///
+ /// 职位
+ ///
+ [Newtonsoft.Json.JsonIgnore]
+ [System.Text.Json.Serialization.JsonIgnore]
+ [Navigate(NavigateType.OneToOne, nameof(PosId))]
+ public SysPos SysPos { get; set; }
+
+ ///
+ /// 工号
+ ///
+ [SugarColumn(ColumnDescription = "工号", Length = 32)]
+ [MaxLength(32)]
+ public string? JobNum { get; set; }
+
+ ///
+ /// 职级
+ ///
+ [SugarColumn(ColumnDescription = "职级", Length = 32)]
+ [MaxLength(32)]
+ public string? PosLevel { get; set; }
+
+ ///
+ /// 入职日期
+ ///
+ [SugarColumn(ColumnDescription = "入职日期")]
+ public DateTime? JoinDate { get; set; }
+}
\ No newline at end of file
diff --git a/Admin.NET/Admin.NET.Core/Entity/SysUserLdap.cs b/Admin.NET/Admin.NET.Core/Entity/SysUserLdap.cs
new file mode 100644
index 00000000..f2e0b74e
--- /dev/null
+++ b/Admin.NET/Admin.NET.Core/Entity/SysUserLdap.cs
@@ -0,0 +1,44 @@
+// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
+//
+// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
+//
+// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
+
+namespace Admin.NET.Core;
+
+///
+/// 系统用户域配置表
+///
+[SugarTable(null, "系统用户域配置表")]
+[SysTable]
+[SugarIndex("index_{table}_A", nameof(Account), OrderByType.Asc)]
+[SugarIndex("index_{table}_U", nameof(UserId), OrderByType.Asc)]
+public class SysUserLdap : EntityTenant
+{
+ ///
+ /// 用户Id
+ ///
+ [SugarColumn(ColumnDescription = "用户Id")]
+ public long UserId { get; set; }
+
+ ///
+ /// 域账号
+ /// AD域对应sAMAccountName
+ /// Ldap对应uid
+ ///
+ [SugarColumn(ColumnDescription = "域账号", Length = 32)]
+ [Required]
+ public string Account { get; set; }
+
+ ///
+ /// 对应EmployeeId(用于数据导入对照)
+ ///
+ [SugarColumn(ColumnDescription = "对应EmployeeId", Length = 32)]
+ public string? EmployeeId { get; set; }
+
+ ///
+ /// 组织代码
+ ///
+ [SugarColumn(ColumnDescription = "组织代码", Length = 64)]
+ public string? DeptCode { get; set; }
+}
\ No newline at end of file
diff --git a/Admin.NET/Admin.NET.Core/Entity/SysUserMenu.cs b/Admin.NET/Admin.NET.Core/Entity/SysUserMenu.cs
new file mode 100644
index 00000000..ee2a6833
--- /dev/null
+++ b/Admin.NET/Admin.NET.Core/Entity/SysUserMenu.cs
@@ -0,0 +1,41 @@
+// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
+//
+// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
+//
+// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
+
+namespace Admin.NET.Core;
+
+///
+/// 系统用户菜单快捷导航表
+///
+[SugarTable(null, "系统用户菜单快捷导航表")]
+[SysTable]
+public partial class SysUserMenu : EntityBaseId
+{
+ ///
+ /// 用户Id
+ ///
+ [SugarColumn(ColumnDescription = "用户Id")]
+ public long UserId { get; set; }
+
+ ///
+ /// 用户
+ ///
+ [Newtonsoft.Json.JsonIgnore]
+ [System.Text.Json.Serialization.JsonIgnore]
+ [Navigate(NavigateType.OneToOne, nameof(UserId))]
+ public SysUser SysUser { get; set; }
+
+ ///
+ /// 菜单Id
+ ///
+ [SugarColumn(ColumnDescription = "菜单Id")]
+ public long MenuId { get; set; }
+
+ ///
+ /// 菜单
+ ///
+ [Navigate(NavigateType.OneToOne, nameof(MenuId))]
+ public SysMenu SysMenu { get; set; }
+}
\ No newline at end of file
diff --git a/Admin.NET/Admin.NET.Core/Entity/SysUserRole.cs b/Admin.NET/Admin.NET.Core/Entity/SysUserRole.cs
new file mode 100644
index 00000000..8d5cff1f
--- /dev/null
+++ b/Admin.NET/Admin.NET.Core/Entity/SysUserRole.cs
@@ -0,0 +1,41 @@
+// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
+//
+// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
+//
+// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
+
+namespace Admin.NET.Core;
+
+///
+/// 系统用户角色表
+///
+[SugarTable(null, "系统用户角色表")]
+[SysTable]
+public class SysUserRole : EntityBaseId
+{
+ ///
+ /// 用户Id
+ ///
+ [SugarColumn(ColumnDescription = "用户Id")]
+ public long UserId { get; set; }
+
+ ///
+ /// 用户
+ ///
+ [Newtonsoft.Json.JsonIgnore]
+ [System.Text.Json.Serialization.JsonIgnore]
+ [Navigate(NavigateType.OneToOne, nameof(UserId))]
+ public SysUser SysUser { get; set; }
+
+ ///
+ /// 角色Id
+ ///
+ [SugarColumn(ColumnDescription = "角色Id")]
+ public long RoleId { get; set; }
+
+ ///
+ /// 角色
+ ///
+ [Navigate(NavigateType.OneToOne, nameof(RoleId))]
+ public SysRole SysRole { get; set; }
+}
\ No newline at end of file
diff --git a/Admin.NET/Admin.NET.Core/Entity/SysWechatPay.cs b/Admin.NET/Admin.NET.Core/Entity/SysWechatPay.cs
new file mode 100644
index 00000000..62e5c127
--- /dev/null
+++ b/Admin.NET/Admin.NET.Core/Entity/SysWechatPay.cs
@@ -0,0 +1,165 @@
+// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
+//
+// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
+//
+// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
+
+namespace Admin.NET.Core;
+
+///
+/// 系统微信支付表
+///
+[SugarTable(null, "系统微信支付表")]
+[SysTable]
+public partial class SysWechatPay : EntityBase
+{
+ ///
+ /// 微信商户号
+ ///
+ [SugarColumn(ColumnDescription = "微信商户号")]
+ [Required]
+ public virtual string MerchantId { get; set; }
+
+ ///
+ /// 服务商AppId
+ ///
+ [SugarColumn(ColumnDescription = "服务商AppId")]
+ [Required]
+ public virtual string AppId { get; set; }
+
+ ///
+ /// 商户订单号
+ ///
+ [SugarColumn(ColumnDescription = "商户订单号")]
+ [Required]
+ public virtual string OutTradeNumber { get; set; }
+
+ ///
+ /// 支付订单号
+ ///
+ [SugarColumn(ColumnDescription = "支付订单号")]
+ [Required]
+ public virtual string TransactionId { get; set; }
+
+ ///
+ /// 交易类型
+ ///
+ [SugarColumn(ColumnDescription = "交易类型")]
+ public string? TradeType { get; set; }
+
+ ///
+ /// 交易状态
+ ///
+ [SugarColumn(ColumnDescription = "交易状态")]
+ public string? TradeState { get; set; }
+
+ ///
+ /// 交易状态描述
+ ///
+ [SugarColumn(ColumnDescription = "交易状态描述")]
+ public string? TradeStateDescription { get; set; }
+
+ ///
+ /// 付款银行类型
+ ///
+ [SugarColumn(ColumnDescription = "付款银行类型")]
+ public string? BankType { get; set; }
+
+ ///
+ /// 订单总金额
+ ///
+ [SugarColumn(ColumnDescription = "订单总金额")]
+ public int Total { get; set; }
+
+ ///
+ /// 用户支付金额
+ ///
+ [SugarColumn(ColumnDescription = "用户支付金额")]
+ public int? PayerTotal { get; set; }
+
+ ///
+ /// 支付完成时间
+ ///
+ [SugarColumn(ColumnDescription = "支付完成时间")]
+ public DateTimeOffset? SuccessTime { get; set; }
+
+ ///
+ /// 交易结束时间
+ ///
+ [SugarColumn(ColumnDescription = "交易结束时间")]
+ public DateTimeOffset? ExpireTime { get; set; }
+
+ ///
+ /// 商品描述
+ ///
+ [SugarColumn(ColumnDescription = "商品描述")]
+ public string? Description { get; set; }
+
+ ///
+ /// 场景信息
+ ///
+ [SugarColumn(ColumnDescription = "场景信息")]
+ public string? Scene { get; set; }
+
+ ///
+ /// 附加数据
+ ///
+ [SugarColumn(ColumnDescription = "附加数据")]
+ public string? Attachment { get; set; }
+
+ ///
+ /// 优惠标记
+ ///
+ [SugarColumn(ColumnDescription = "优惠标记")]
+ public string? GoodsTag { get; set; }
+
+ ///
+ /// 结算信息
+ ///
+ [SugarColumn(ColumnDescription = "结算信息")]
+ public string? Settlement { get; set; }
+
+ ///
+ /// 回调通知地址
+ ///
+ [SugarColumn(ColumnDescription = "回调通知地址")]
+ public string? NotifyUrl { get; set; }
+
+ ///
+ /// 备注
+ ///
+ [SugarColumn(ColumnDescription = "备注")]
+ public string? Remark { get; set; }
+
+ ///
+ /// 微信OpenId标识
+ ///
+ [SugarColumn(ColumnDescription = "微信OpenId标识")]
+ public string? OpenId { get; set; }
+
+ ///
+ /// 关联微信用户
+ ///
+ [Newtonsoft.Json.JsonIgnore]
+ [System.Text.Json.Serialization.JsonIgnore]
+ [Navigate(NavigateType.OneToOne, nameof(OpenId))]
+ public SysOAuthUser SysOAuthUser { get; set; }
+
+ ///
+ /// 子商户号
+ ///
+ [SugarColumn(ColumnDescription = "子商户号")]
+ public string? SubMerchantId { get; set; }
+
+ ///
+ /// 子商户AppId
+ ///
+ [SugarColumn(ColumnDescription = "回调通知地址")]
+ public string? SubAppId { get; set; }
+
+ ///
+ /// 子商户唯一标识
+ ///
+ [SugarColumn(ColumnDescription = "子商户唯一标识")]
+ public string? SubOpenId { get; set; }
+}
\ No newline at end of file
diff --git a/Admin.NET/Admin.NET.Core/Enum/AccountTypeEnum.cs b/Admin.NET/Admin.NET.Core/Enum/AccountTypeEnum.cs
new file mode 100644
index 00000000..bedbec66
--- /dev/null
+++ b/Admin.NET/Admin.NET.Core/Enum/AccountTypeEnum.cs
@@ -0,0 +1,38 @@
+// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
+//
+// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
+//
+// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
+
+namespace Admin.NET.Core;
+
+///
+/// 账号类型枚举
+///
+[Description("账号类型枚举")]
+public enum AccountTypeEnum
+{
+ ///
+ /// 超级管理员
+ ///
+ [Description("超级管理员")]
+ SuperAdmin = 999,
+
+ ///
+ /// 系统管理员
+ ///
+ [Description("系统管理员")]
+ SysAdmin = 888,
+
+ ///
+ /// 普通账号
+ ///
+ [Description("普通账号")]
+ NormalUser = 777,
+
+ ///
+ /// 会员
+ ///
+ [Description("会员")]
+ Member = 666,
+}
\ No newline at end of file
diff --git a/Admin.NET/Admin.NET.Core/Enum/CacheTypeEnum.cs b/Admin.NET/Admin.NET.Core/Enum/CacheTypeEnum.cs
new file mode 100644
index 00000000..e6832ed2
--- /dev/null
+++ b/Admin.NET/Admin.NET.Core/Enum/CacheTypeEnum.cs
@@ -0,0 +1,26 @@
+// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
+//
+// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
+//
+// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
+
+namespace Admin.NET.Core;
+
+///
+/// 缓存类型枚举
+///
+[Description("缓存类型枚举")]
+public enum CacheTypeEnum
+{
+ ///
+ /// 内存缓存
+ ///
+ [Description("内存缓存")]
+ Memory,
+
+ ///
+ /// Redis缓存
+ ///
+ [Description("Redis缓存")]
+ Redis
+}
\ No newline at end of file
diff --git a/Admin.NET/Admin.NET.Core/Enum/CardTypeEnum.cs b/Admin.NET/Admin.NET.Core/Enum/CardTypeEnum.cs
new file mode 100644
index 00000000..774359b0
--- /dev/null
+++ b/Admin.NET/Admin.NET.Core/Enum/CardTypeEnum.cs
@@ -0,0 +1,50 @@
+// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
+//
+// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
+//
+// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
+
+namespace Admin.NET.Core;
+
+///
+/// 证件类型枚举
+///
+[Description("证件类型枚举")]
+public enum CardTypeEnum
+{
+ ///
+ /// 身份证
+ ///
+ [Description("身份证")]
+ IdCard = 0,
+
+ ///
+ /// 护照
+ ///
+ [Description("护照")]
+ PassportCard = 1,
+
+ ///
+ /// 出生证
+ ///
+ [Description("出生证")]
+ BirthCard = 2,
+
+ ///
+ /// 港澳台通行证
+ ///
+ [Description("港澳台通行证")]
+ GatCard = 3,
+
+ ///
+ /// 外国人居留证
+ ///
+ [Description("外国人居留证")]
+ ForeignCard = 4,
+
+ ///
+ /// 营业执照
+ ///
+ [Description("营业执照")]
+ License = 5,
+}
\ No newline at end of file
diff --git a/Admin.NET/Admin.NET.Core/Enum/CryptogramEnum.cs b/Admin.NET/Admin.NET.Core/Enum/CryptogramEnum.cs
new file mode 100644
index 00000000..e259beaa
--- /dev/null
+++ b/Admin.NET/Admin.NET.Core/Enum/CryptogramEnum.cs
@@ -0,0 +1,32 @@
+// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
+//
+// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
+//
+// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
+
+namespace Admin.NET.Core;
+
+///
+/// 密码加密枚举
+///
+[Description("密码加密枚举")]
+public enum CryptogramEnum
+{
+ ///
+ /// MD5
+ ///
+ [Description("MD5")]
+ MD5 = 0,
+
+ ///
+ /// SM2(国密)
+ ///
+ [Description("SM2")]
+ SM2 = 1,
+
+ ///
+ /// SM4(国密)
+ ///
+ [Description("SM4")]
+ SM4 = 2
+}
\ No newline at end of file
diff --git a/Admin.NET/Admin.NET.Core/Enum/CultureLevelEnum.cs b/Admin.NET/Admin.NET.Core/Enum/CultureLevelEnum.cs
new file mode 100644
index 00000000..56b325e3
--- /dev/null
+++ b/Admin.NET/Admin.NET.Core/Enum/CultureLevelEnum.cs
@@ -0,0 +1,92 @@
+// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
+//
+// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
+//
+// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
+
+namespace Admin.NET.Core;
+
+///
+/// 文化程度枚举
+///
+[Description("文化程度枚举")]
+public enum CultureLevelEnum
+{
+ ///
+ /// 其他
+ ///
+ [Description("其他")]
+ Level0 = 0,
+
+ ///
+ /// 文盲
+ ///
+ [Description("文盲")]
+ Level1 = 1,
+
+ ///
+ /// 小学
+ ///
+ [Description("小学")]
+ Level2 = 2,
+
+ ///
+ /// 初中
+ ///
+ [Description("初中")]
+ Level3 = 3,
+
+ ///
+ /// 普通高中
+ ///
+ [Description("普通高中")]
+ Level4 = 4,
+
+ ///
+ /// 技工学校
+ ///
+ [Description("技工学校")]
+ Level5 = 5,
+
+ ///
+ /// 职业教育
+ ///
+ [Description("职业教育")]
+ Level6 = 6,
+
+ ///
+ /// 职业高中
+ ///
+ [Description("职业高中")]
+ Level7 = 7,
+
+ ///
+ /// 中等专科
+ ///
+ [Description("中等专科")]
+ Level8 = 8,
+
+ ///
+ /// 大学专科
+ ///
+ [Description("大学专科")]
+ Level9 = 9,
+
+ ///
+ /// 大学本科
+ ///
+ [Description("大学本科")]
+ Level10 = 10,
+
+ ///
+ /// 硕士研究生
+ ///
+ [Description("硕士研究生")]
+ Level11 = 11,
+
+ ///
+ /// 博士研究生
+ ///
+ [Description("博士研究生")]
+ Level12 = 12,
+}
\ No newline at end of file
diff --git a/Admin.NET/Admin.NET.Core/Enum/DataOpTypeEnum.cs b/Admin.NET/Admin.NET.Core/Enum/DataOpTypeEnum.cs
new file mode 100644
index 00000000..f4c04eac
--- /dev/null
+++ b/Admin.NET/Admin.NET.Core/Enum/DataOpTypeEnum.cs
@@ -0,0 +1,92 @@
+// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
+//
+// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
+//
+// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
+
+namespace Admin.NET.Core;
+
+///
+/// 数据操作类型枚举
+///
+[Description("数据操作类型枚举")]
+public enum DataOpTypeEnum
+{
+ ///
+ /// 其它
+ ///
+ [Description("其它")]
+ Other,
+
+ ///
+ /// 增加
+ ///
+ [Description("增加")]
+ Add,
+
+ ///
+ /// 删除
+ ///
+ [Description("删除")]
+ Delete,
+
+ ///
+ /// 编辑
+ ///
+ [Description("编辑")]
+ Edit,
+
+ ///
+ /// 更新
+ ///
+ [Description("更新")]
+ Update,
+
+ ///
+ /// 查询
+ ///
+ [Description("查询")]
+ Query,
+
+ ///
+ /// 详情
+ ///
+ [Description("详情")]
+ Detail,
+
+ ///
+ /// 树
+ ///
+ [Description("树")]
+ Tree,
+
+ ///
+ /// 导入
+ ///
+ [Description("导入")]
+ Import,
+
+ ///
+ /// 导出
+ ///
+ [Description("导出")]
+ Export,
+
+ ///
+ /// 授权
+ ///
+ [Description("授权")]
+ Grant,
+
+ ///
+ /// 强退
+ ///
+ [Description("强退")]
+ Force,
+
+ ///
+ /// 清空
+ ///
+ [Description("清空")]
+ Clean
+}
\ No newline at end of file
diff --git a/Admin.NET/Admin.NET.Core/Enum/DataScopeEnum.cs b/Admin.NET/Admin.NET.Core/Enum/DataScopeEnum.cs
new file mode 100644
index 00000000..d6fc8bde
--- /dev/null
+++ b/Admin.NET/Admin.NET.Core/Enum/DataScopeEnum.cs
@@ -0,0 +1,44 @@
+// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
+//
+// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
+//
+// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
+
+namespace Admin.NET.Core;
+
+///
+/// 角色数据范围枚举
+///
+[Description("角色数据范围枚举")]
+public enum DataScopeEnum
+{
+ ///
+ /// 全部数据
+ ///
+ [Description("全部数据")]
+ All = 1,
+
+ ///
+ /// 本部门及以下数据
+ ///
+ [Description("本部门及以下数据")]
+ DeptChild = 2,
+
+ ///
+ /// 本部门数据
+ ///
+ [Description("本部门数据")]
+ Dept = 3,
+
+ ///
+ /// 仅本人数据
+ ///
+ [Description("仅本人数据")]
+ Self = 4,
+
+ ///
+ /// 自定义数据
+ ///
+ [Description("自定义数据")]
+ Define = 5
+}
\ No newline at end of file
diff --git a/Admin.NET/Admin.NET.Core/Enum/ElasticSearchAuthTypeEnum.cs b/Admin.NET/Admin.NET.Core/Enum/ElasticSearchAuthTypeEnum.cs
new file mode 100644
index 00000000..60f290f3
--- /dev/null
+++ b/Admin.NET/Admin.NET.Core/Enum/ElasticSearchAuthTypeEnum.cs
@@ -0,0 +1,33 @@
+// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
+//
+// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
+//
+// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
+
+namespace Admin.NET.Core;
+
+///
+/// ES认证类型枚举
+/// https://www.elastic.co/guide/en/elasticsearch/client/net-api/current/_options_on_elasticsearchclientsettings.html
+///
+[Description("ES认证类型枚举")]
+public enum ElasticSearchAuthTypeEnum
+{
+ ///
+ /// BasicAuthentication
+ ///
+ [Description("BasicAuthentication")]
+ Basic = 1,
+
+ ///
+ /// ApiKey
+ ///
+ [Description("ApiKey")]
+ ApiKey = 2,
+
+ ///
+ /// Base64ApiKey
+ ///
+ [Description("Base64ApiKey")]
+ Base64ApiKey = 3
+}
\ No newline at end of file
diff --git a/Admin.NET/Admin.NET.Core/Enum/ErrorCodeEnum.cs b/Admin.NET/Admin.NET.Core/Enum/ErrorCodeEnum.cs
new file mode 100644
index 00000000..104fdffb
--- /dev/null
+++ b/Admin.NET/Admin.NET.Core/Enum/ErrorCodeEnum.cs
@@ -0,0 +1,699 @@
+// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
+//
+// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
+//
+// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
+
+namespace Admin.NET.Core;
+
+///
+/// 系统错误码
+///
+[ErrorCodeType]
+[Description("系统错误码")]
+public enum ErrorCodeEnum
+{
+ ///
+ /// 验证码错误
+ ///
+ [ErrorCodeItemMetadata("验证码错误")]
+ D0008,
+
+ ///
+ /// 账号不存在
+ ///
+ [ErrorCodeItemMetadata("账号不存在")]
+ D0009,
+
+ ///
+ /// 密匙不匹配
+ ///
+ [ErrorCodeItemMetadata("密匙不匹配")]
+ D0010,
+
+ ///
+ /// 密码不正确
+ ///
+ [ErrorCodeItemMetadata("密码不正确")]
+ D1000,
+
+ ///
+ /// 非法操作!禁止删除自己
+ ///
+ [ErrorCodeItemMetadata("非法操作,禁止删除自己")]
+ D1001,
+
+ ///
+ /// 记录不存在
+ ///
+ [ErrorCodeItemMetadata("记录不存在")]
+ D1002,
+
+ ///
+ /// 账号已存在
+ ///
+ [ErrorCodeItemMetadata("账号已存在")]
+ D1003,
+
+ ///
+ /// 旧密码不匹配
+ ///
+ [ErrorCodeItemMetadata("旧密码输入错误")]
+ D1004,
+
+ ///
+ /// 测试数据禁止更改admin密码
+ ///
+ [ErrorCodeItemMetadata("测试数据禁止更改用户【admin】密码")]
+ D1005,
+
+ ///
+ /// 数据已存在
+ ///
+ [ErrorCodeItemMetadata("数据已存在")]
+ D1006,
+
+ ///
+ /// 数据不存在或含有关联引用,禁止删除
+ ///
+ [ErrorCodeItemMetadata("数据不存在或含有关联引用,禁止删除")]
+ D1007,
+
+ ///
+ /// 禁止为管理员分配角色
+ ///
+ [ErrorCodeItemMetadata("禁止为管理员分配角色")]
+ D1008,
+
+ ///
+ /// 重复数据或记录含有不存在数据
+ ///
+ [ErrorCodeItemMetadata("重复数据或记录含有不存在数据")]
+ D1009,
+
+ ///
+ /// 禁止为超级管理员角色分配权限
+ ///
+ [ErrorCodeItemMetadata("禁止为超级管理员角色分配权限")]
+ D1010,
+
+ ///
+ /// 非法操作,未登录
+ ///
+ [ErrorCodeItemMetadata("非法操作,未登录")]
+ D1011,
+
+ ///
+ /// Id不能为空
+ ///
+ [ErrorCodeItemMetadata("Id不能为空")]
+ D1012,
+
+ ///
+ /// 所属机构不在自己的数据范围内
+ ///
+ [ErrorCodeItemMetadata("没有权限操作该数据")]
+ D1013,
+
+ ///
+ /// 禁止删除超级管理员
+ ///
+ [ErrorCodeItemMetadata("禁止删除超级管理员")]
+ D1014,
+
+ ///
+ /// 禁止修改超级管理员状态
+ ///
+ [ErrorCodeItemMetadata("禁止修改超级管理员状态")]
+ D1015,
+
+ ///
+ /// 没有权限
+ ///
+ [ErrorCodeItemMetadata("没有权限")]
+ D1016,
+
+ ///
+ /// 账号已冻结
+ ///
+ [ErrorCodeItemMetadata("账号已冻结")]
+ D1017,
+
+ ///
+ /// 禁止删除管理员
+ ///
+ [ErrorCodeItemMetadata("禁止删除管理员")]
+ D1018,
+
+ ///
+ /// 禁止删除系统管理员角色
+ ///
+ [ErrorCodeItemMetadata("禁止删除系统管理员角色")]
+ D1019,
+
+ ///
+ /// 禁止修改系统管理员角色
+ ///
+ [ErrorCodeItemMetadata("禁止修改系统管理员角色")]
+ D1020,
+
+ ///
+ /// 禁止为系统管理员角色分配权限
+ ///
+ [ErrorCodeItemMetadata("禁止为系统管理员角色分配权限")]
+ D1021,
+
+ ///
+ /// 禁止为超级管理员分配角色
+ ///
+ [ErrorCodeItemMetadata("禁止为超级管理员分配角色")]
+ D1022,
+
+ ///
+ /// 禁止删除默认租户
+ ///
+ [ErrorCodeItemMetadata("禁止删除默认租户")]
+ D1023,
+
+ ///
+ /// 已将其他地方登录账号下线
+ ///
+ [ErrorCodeItemMetadata("已将其他地方登录账号下线")]
+ D1024,
+
+ ///
+ /// 此角色下面存在账号禁止删除
+ ///
+ [ErrorCodeItemMetadata("此角色下面存在账号禁止删除")]
+ D1025,
+
+ ///
+ /// 禁止修改本人账号状态
+ ///
+ [ErrorCodeItemMetadata("禁止修改本人账号状态")]
+ D1026,
+
+ ///
+ /// 密码错误次数过多,账号已锁定,请半小时后重试!
+ ///
+ [ErrorCodeItemMetadata("密码错误次数过多,账号已锁定,请半小时后重试!")]
+ D1027,
+
+ ///
+ /// 新密码不能与旧密码相同
+ ///
+ [ErrorCodeItemMetadata("新密码不能与旧密码相同")]
+ D1028,
+
+ ///
+ /// 父机构不存在
+ ///
+ [ErrorCodeItemMetadata("父机构不存在")]
+ D2000,
+
+ ///
+ /// 当前机构Id不能与父机构Id相同
+ ///
+ [ErrorCodeItemMetadata("当前机构Id不能与父机构Id相同")]
+ D2001,
+
+ ///
+ /// 已有相同组织机构,编码或名称相同
+ ///
+ [ErrorCodeItemMetadata("已有相同组织机构,编码或名称相同")]
+ D2002,
+
+ ///
+ /// 没有权限操作机构
+ ///
+ [ErrorCodeItemMetadata("没有权限操作机构")]
+ D2003,
+
+ ///
+ /// 该机构下有用户禁止删除
+ ///
+ [ErrorCodeItemMetadata("该机构下有用户禁止删除")]
+ D2004,
+
+ ///
+ /// 附属机构下有用户禁止删除
+ ///
+ [ErrorCodeItemMetadata("附属机构下有用户禁止删除")]
+ D2005,
+
+ ///
+ /// 只能增加下级机构
+ ///
+ [ErrorCodeItemMetadata("只能增加下级机构")]
+ D2006,
+
+ ///
+ /// 下级机构下有用户禁止删除
+ ///
+ [ErrorCodeItemMetadata("下级机构下有用户禁止删除")]
+ D2007,
+
+ ///
+ /// 租户默认机构禁止删除
+ ///
+ [ErrorCodeItemMetadata("租户默认机构禁止删除")]
+ D2008,
+
+ ///
+ /// 禁止增加根节点机构
+ ///
+ [ErrorCodeItemMetadata("禁止增加根节点机构")]
+ D2009,
+
+ ///
+ /// 字典类型不存在
+ ///
+ [ErrorCodeItemMetadata("字典类型不存在")]
+ D3000,
+
+ ///
+ /// 字典类型已存在
+ ///
+ [ErrorCodeItemMetadata("字典类型已存在,名称或编码重复")]
+ D3001,
+
+ ///
+ /// 字典类型下面有字典值禁止删除
+ ///
+ [ErrorCodeItemMetadata("字典类型下面有字典值禁止删除")]
+ D3002,
+
+ ///
+ /// 字典值已存在
+ ///
+ [ErrorCodeItemMetadata("字典值已存在,名称或编码重复")]
+ D3003,
+
+ ///
+ /// 字典值不存在
+ ///
+ [ErrorCodeItemMetadata("字典值不存在")]
+ D3004,
+
+ ///
+ /// 字典状态错误
+ ///
+ [ErrorCodeItemMetadata("字典状态错误")]
+ D3005,
+
+ ///
+ /// 菜单已存在
+ ///
+ [ErrorCodeItemMetadata("菜单已存在")]
+ D4000,
+
+ ///
+ /// 路由地址为空
+ ///
+ [ErrorCodeItemMetadata("路由地址为空")]
+ D4001,
+
+ ///
+ /// 打开方式为空
+ ///
+ [ErrorCodeItemMetadata("打开方式为空")]
+ D4002,
+
+ ///
+ /// 权限标识格式为空
+ ///
+ [ErrorCodeItemMetadata("权限标识格式为空")]
+ D4003,
+
+ ///
+ /// 权限标识格式错误
+ ///
+ [ErrorCodeItemMetadata("权限标识格式错误 如xxx:xxx")]
+ D4004,
+
+ ///
+ /// 权限不存在
+ ///
+ [ErrorCodeItemMetadata("权限不存在")]
+ D4005,
+
+ ///
+ /// 父级菜单不能为当前节点,请重新选择父级菜单
+ ///
+ [ErrorCodeItemMetadata("父级菜单不能为当前节点,请重新选择父级菜单")]
+ D4006,
+
+ ///
+ /// 不能移动根节点
+ ///
+ [ErrorCodeItemMetadata("不能移动根节点")]
+ D4007,
+
+ ///
+ /// 禁止本节点与父节点相同
+ ///
+ [ErrorCodeItemMetadata("禁止本节点与父节点相同")]
+ D4008,
+
+ ///
+ /// 路由名称重复
+ ///
+ [ErrorCodeItemMetadata("路由名称重复")]
+ D4009,
+
+ ///
+ /// 父节点不能为按钮类型
+ ///
+ [ErrorCodeItemMetadata("父节点不能为按钮类型")]
+ D4010,
+
+ ///
+ /// 已存在同名或同编码应用
+ ///
+ [ErrorCodeItemMetadata("已存在同名或同编码应用")]
+ D5000,
+
+ ///
+ /// 默认激活系统只能有一个
+ ///
+ [ErrorCodeItemMetadata("默认激活系统只能有一个")]
+ D5001,
+
+ ///
+ /// 该应用下有菜单禁止删除
+ ///
+ [ErrorCodeItemMetadata("该应用下有菜单禁止删除")]
+ D5002,
+
+ ///
+ /// 已存在同名或同编码应用
+ ///
+ [ErrorCodeItemMetadata("已存在同名或同编码应用")]
+ D5003,
+
+ ///
+ /// 已存在同名或同编码职位
+ ///
+ [ErrorCodeItemMetadata("已存在同名或同编码职位")]
+ D6000,
+
+ ///
+ /// 该职位下有用户禁止删除
+ ///
+ [ErrorCodeItemMetadata("该职位下有用户禁止删除")]
+ D6001,
+
+ ///
+ /// 无权修改本职位
+ ///
+ [ErrorCodeItemMetadata("无权修改本职位")]
+ D6002,
+
+ ///
+ /// 职位不存在
+ ///
+ [ErrorCodeItemMetadata("职位不存在")]
+ D6003,
+
+ ///
+ /// 通知公告状态错误
+ ///
+ [ErrorCodeItemMetadata("通知公告状态错误")]
+ D7000,
+
+ ///
+ /// 通知公告删除失败
+ ///
+ [ErrorCodeItemMetadata("通知公告删除失败")]
+ D7001,
+
+ ///
+ /// 通知公告编辑失败
+ ///
+ [ErrorCodeItemMetadata("通知公告编辑失败,类型必须为草稿")]
+ D7002,
+
+ ///
+ /// 通知公告操作失败,非发布者不能进行操作
+ ///
+ [ErrorCodeItemMetadata("通知公告操作失败,非发布者不能进行操作")]
+ D7003,
+
+ ///
+ /// 文件不存在
+ ///
+ [ErrorCodeItemMetadata("文件不存在")]
+ D8000,
+
+ ///
+ /// 不允许的文件类型
+ ///
+ [ErrorCodeItemMetadata("不允许的文件类型")]
+ D8001,
+
+ ///
+ /// 文件超过允许大小
+ ///
+ [ErrorCodeItemMetadata("文件超过允许大小")]
+ D8002,
+
+ ///
+ /// 文件后缀错误
+ ///
+ [ErrorCodeItemMetadata("文件后缀错误")]
+ D8003,
+
+ ///
+ /// 文件已存在
+ ///
+ [ErrorCodeItemMetadata("文件已存在")]
+ D8004,
+
+ ///
+ /// 已存在同名或同编码参数配置
+ ///
+ [ErrorCodeItemMetadata("已存在同名或同编码参数配置")]
+ D9000,
+
+ ///
+ /// 禁止删除系统参数
+ ///
+ [ErrorCodeItemMetadata("禁止删除系统参数")]
+ D9001,
+
+ ///
+ /// 已存在同名任务调度
+ ///
+ [ErrorCodeItemMetadata("已存在同名任务调度")]
+ D1100,
+
+ ///
+ /// 任务调度不存在
+ ///
+ [ErrorCodeItemMetadata("任务调度不存在")]
+ D1101,
+
+ ///
+ /// 演示环境禁止修改数据
+ ///
+ [ErrorCodeItemMetadata("演示环境禁止修改数据")]
+ D1200,
+
+ ///
+ /// 已存在同名的租户
+ ///
+ [ErrorCodeItemMetadata("已存在同名的租户")]
+ D1300,
+
+ ///
+ /// 已存在同名的租户管理员
+ ///
+ [ErrorCodeItemMetadata("已存在同名的租户管理员")]
+ D1301,
+
+ ///
+ /// 租户从库配置错误
+ ///
+ [ErrorCodeItemMetadata("租户从库配置错误")]
+ D1302,
+
+ ///
+ /// 该表代码模板已经生成过
+ ///
+ [ErrorCodeItemMetadata("该表代码模板已经生成过")]
+ D1400,
+
+ ///
+ /// 该类型不存在
+ ///
+ [ErrorCodeItemMetadata("该类型不存在")]
+ D1501,
+
+ ///
+ /// 该字段不存在
+ ///
+ [ErrorCodeItemMetadata("该字段不存在")]
+ D1502,
+
+ ///
+ /// 该类型不是枚举类型
+ ///
+ [ErrorCodeItemMetadata("该类型不是枚举类型")]
+ D1503,
+
+ ///
+ /// 该实体不存在
+ ///
+ [ErrorCodeItemMetadata("该实体不存在")]
+ D1504,
+
+ ///
+ /// 父菜单不存在
+ ///
+ [ErrorCodeItemMetadata("父菜单不存在")]
+ D1505,
+
+ ///
+ /// 父资源不存在
+ ///
+ [ErrorCodeItemMetadata("父资源不存在")]
+ D1600,
+
+ ///
+ /// 当前资源Id不能与父资源Id相同
+ ///
+ [ErrorCodeItemMetadata("当前资源Id不能与父资源Id相同")]
+ D1601,
+
+ ///
+ /// 已有相同编码或名称
+ ///
+ [ErrorCodeItemMetadata("已有相同编码或名称")]
+ D1602,
+
+ ///
+ /// 脚本代码不能为空
+ ///
+ [ErrorCodeItemMetadata("脚本代码不能为空")]
+ D1701,
+
+ ///
+ /// 脚本代码中的作业类,需要定义 [JobDetail] 特性
+ ///
+ [ErrorCodeItemMetadata("脚本代码中的作业类,需要定义 [JobDetail] 特性")]
+ D1702,
+
+ ///
+ /// 作业编号需要与脚本代码中的作业类 [JobDetail('jobId')] 一致
+ ///
+ [ErrorCodeItemMetadata("作业编号需要与脚本代码中的作业类 [JobDetail('jobId')] 一致")]
+ D1703,
+
+ ///
+ /// 禁止修改作业编号
+ ///
+ [ErrorCodeItemMetadata("禁止修改作业编号")]
+ D1704,
+
+ ///
+ /// 执行作业失败
+ ///
+ [ErrorCodeItemMetadata("执行作业失败")]
+ D1705,
+
+ ///
+ /// 已存在同名打印模板
+ ///
+ [ErrorCodeItemMetadata("已存在同名打印模板")]
+ D1800,
+
+ ///
+ /// 已存在同名功能或同名程序及插件
+ ///
+ [ErrorCodeItemMetadata("已存在同名功能或同名程序及插件")]
+ D1900,
+
+ ///
+ /// 已存在同名或同编码项目
+ ///
+ [ErrorCodeItemMetadata("已存在同名或同编码项目")]
+ xg1000,
+
+ ///
+ /// 已存在相同证件号码人员
+ ///
+ [ErrorCodeItemMetadata("已存在相同证件号码人员")]
+ xg1001,
+
+ ///
+ /// 检测数据不存在
+ ///
+ [ErrorCodeItemMetadata("检测数据不存在")]
+ xg1002,
+
+ ///
+ /// 请添加数据列
+ ///
+ [ErrorCodeItemMetadata("请添加数据列")]
+ db1000,
+
+ ///
+ /// 数据表不存在
+ ///
+ [ErrorCodeItemMetadata("数据表不存在")]
+ db1001,
+
+ ///
+ /// 数据表不存在
+ ///
+ [ErrorCodeItemMetadata("不允许添加相同字段名")]
+ db1002,
+
+ ///
+ /// 父节点不存在
+ ///
+ [ErrorCodeItemMetadata("父节点不存在")]
+ R2000,
+
+ ///
+ /// 当前节点Id不能与父节点Id相同
+ ///
+ [ErrorCodeItemMetadata("当前节点Id不能与父节点Id相同")]
+ R2001,
+
+ ///
+ /// 已有相同编码或名称
+ ///
+ [ErrorCodeItemMetadata("已有相同编码或名称")]
+ R2002,
+
+ ///
+ /// 默认租户状态禁止修改
+ ///
+ [ErrorCodeItemMetadata("默认租户状态禁止修改")]
+ Z1001,
+
+ ///
+ /// 禁止创建此类型的数据库
+ ///
+ [ErrorCodeItemMetadata("禁止创建此类型的数据库")]
+ Z1002,
+
+ ///
+ /// 租户已禁用
+ ///
+ [ErrorCodeItemMetadata("租户已禁用")]
+ Z1003,
+
+ ///
+ /// 租户库连接不能为空
+ ///
+ [ErrorCodeItemMetadata("租户库连接不能为空")]
+ Z1004,
+
+ ///
+ /// 身份标识已存在
+ ///
+ [ErrorCodeItemMetadata("身份标识已存在")]
+ O1000,
+}
\ No newline at end of file
diff --git a/Admin.NET/Admin.NET.Core/Enum/GenderEnum.cs b/Admin.NET/Admin.NET.Core/Enum/GenderEnum.cs
new file mode 100644
index 00000000..3284532c
--- /dev/null
+++ b/Admin.NET/Admin.NET.Core/Enum/GenderEnum.cs
@@ -0,0 +1,32 @@
+// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
+//
+// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
+//
+// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
+
+namespace Admin.NET.Core;
+
+///
+/// 性别枚举
+///
+[Description("性别枚举")]
+public enum GenderEnum
+{
+ ///
+ /// 男
+ ///
+ [Description("男")]
+ Male = 1,
+
+ ///
+ /// 女
+ ///
+ [Description("女")]
+ Female = 2,
+
+ ///
+ /// 其他
+ ///
+ [Description("其他")]
+ Other = 3
+}
\ No newline at end of file
diff --git a/Admin.NET/Admin.NET.Core/Enum/HttpMethodEnum.cs b/Admin.NET/Admin.NET.Core/Enum/HttpMethodEnum.cs
new file mode 100644
index 00000000..f9308931
--- /dev/null
+++ b/Admin.NET/Admin.NET.Core/Enum/HttpMethodEnum.cs
@@ -0,0 +1,68 @@
+// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
+//
+// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
+//
+// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
+
+namespace Admin.NET.Core;
+
+///
+/// HTTP请求方法枚举
+///
+[Description("HTTP请求方法枚举")]
+public enum HttpMethodEnum
+{
+ ///
+ /// HTTP "GET" method.
+ ///
+ [Description("HTTP \"GET\" method.")]
+ Get,
+
+ ///
+ /// HTTP "POST" method.
+ ///
+ [Description("HTTP \"POST\" method.")]
+ Post,
+
+ ///
+ /// HTTP "PUT" method.
+ ///
+ [Description(" HTTP \"PUT\" method.")]
+ Put,
+
+ ///
+ /// HTTP "DELETE" method.
+ ///
+ [Description("HTTP \"DELETE\" method.")]
+ Delete,
+
+ ///
+ /// HTTP "PATCH" method.
+ ///
+ [Description("HTTP \"PATCH\" method. ")]
+ Patch,
+
+ ///
+ /// HTTP "HEAD" method.
+ ///
+ [Description("HTTP \"HEAD\" method.")]
+ Head,
+
+ ///
+ /// HTTP "OPTIONS" method.
+ ///
+ [Description("HTTP \"OPTIONS\" method.")]
+ Options,
+
+ ///
+ /// HTTP "TRACE" method.
+ ///
+ [Description(" HTTP \"TRACE\" method.")]
+ Trace,
+
+ ///
+ /// HTTP "CONNECT" method.
+ ///
+ [Description("HTTP \"CONNECT\" method.")]
+ Connect
+}
\ No newline at end of file
diff --git a/Admin.NET/Admin.NET.Core/Enum/JobCreateTypeEnum.cs b/Admin.NET/Admin.NET.Core/Enum/JobCreateTypeEnum.cs
new file mode 100644
index 00000000..acee68ba
--- /dev/null
+++ b/Admin.NET/Admin.NET.Core/Enum/JobCreateTypeEnum.cs
@@ -0,0 +1,32 @@
+// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
+//
+// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
+//
+// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
+
+namespace Admin.NET.Core;
+
+///
+/// 作业创建类型枚举
+///
+[Description("作业创建类型枚举")]
+public enum JobCreateTypeEnum
+{
+ ///
+ /// 内置
+ ///
+ [Description("内置")]
+ BuiltIn = 0,
+
+ ///
+ /// 脚本
+ ///
+ [Description("脚本")]
+ Script = 1,
+
+ ///
+ /// HTTP请求
+ ///
+ [Description("HTTP请求")]
+ Http = 2,
+}
\ No newline at end of file
diff --git a/Admin.NET/Admin.NET.Core/Enum/JobStatusEnum.cs b/Admin.NET/Admin.NET.Core/Enum/JobStatusEnum.cs
new file mode 100644
index 00000000..b06c65c5
--- /dev/null
+++ b/Admin.NET/Admin.NET.Core/Enum/JobStatusEnum.cs
@@ -0,0 +1,38 @@
+// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
+//
+// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
+//
+// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
+
+namespace Admin.NET.Core;
+
+///
+/// 岗位状态枚举
+///
+[Description("岗位状态枚举")]
+public enum JobStatusEnum
+{
+ ///
+ /// 在职
+ ///
+ [Description("在职")]
+ On = 1,
+
+ ///
+ /// 离职
+ ///
+ [Description("离职")]
+ Off = 2,
+
+ ///
+ /// 请假
+ ///
+ [Description("请假")]
+ Leave = 3,
+
+ ///
+ /// 其他
+ ///
+ [Description("其他")]
+ Other = 4,
+}
\ No newline at end of file
diff --git a/Admin.NET/Admin.NET.Core/Enum/LoginModeEnum.cs b/Admin.NET/Admin.NET.Core/Enum/LoginModeEnum.cs
new file mode 100644
index 00000000..55e8ddb6
--- /dev/null
+++ b/Admin.NET/Admin.NET.Core/Enum/LoginModeEnum.cs
@@ -0,0 +1,26 @@
+// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
+//
+// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
+//
+// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
+
+namespace Admin.NET.Core;
+
+///
+/// 登录模式枚举
+///
+[Description("登录模式枚举")]
+public enum LoginModeEnum
+{
+ ///
+ /// PC模式
+ ///
+ [Description("PC模式")]
+ PC = 1,
+
+ ///
+ /// APP
+ ///
+ [Description("APP")]
+ APP = 2
+}
\ No newline at end of file
diff --git a/Admin.NET/Admin.NET.Core/Enum/LoginTypeEnum.cs b/Admin.NET/Admin.NET.Core/Enum/LoginTypeEnum.cs
new file mode 100644
index 00000000..9fa09502
--- /dev/null
+++ b/Admin.NET/Admin.NET.Core/Enum/LoginTypeEnum.cs
@@ -0,0 +1,32 @@
+// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
+//
+// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
+//
+// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
+
+namespace Admin.NET.Core;
+
+///
+/// 登录类型枚举
+///
+[Description("登录类型枚举")]
+public enum LoginTypeEnum
+{
+ ///
+ /// PC登录
+ ///
+ [Description("PC登录")]
+ Login = 1,
+
+ ///
+ /// PC退出
+ ///
+ [Description("PC退出")]
+ Logout = 2,
+
+ ///
+ /// PC注册
+ ///
+ [Description("PC注册")]
+ Register = 3
+}
\ No newline at end of file
diff --git a/Admin.NET/Admin.NET.Core/Enum/MaritalStatusEnum.cs b/Admin.NET/Admin.NET.Core/Enum/MaritalStatusEnum.cs
new file mode 100644
index 00000000..b3787b22
--- /dev/null
+++ b/Admin.NET/Admin.NET.Core/Enum/MaritalStatusEnum.cs
@@ -0,0 +1,50 @@
+// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
+//
+// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
+//
+// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
+
+namespace Admin.NET.Core;
+
+///
+/// 婚姻状况枚举
+///
+[Description("婚姻状况枚举")]
+public enum MaritalStatusEnum
+{
+ ///
+ /// 未婚
+ ///
+ [Description("未婚")]
+ UnMarried = 1,
+
+ ///
+ /// 已婚
+ ///
+ [Description("已婚")]
+ Married = 2,
+
+ ///
+ /// 离异
+ ///
+ [Description("离异")]
+ Divorce = 3,
+
+ ///
+ /// 再婚
+ ///
+ [Description("再婚")]
+ Remarry = 4,
+
+ ///
+ /// 丧偶
+ ///
+ [Description("丧偶")]
+ Widowed = 5,
+
+ ///
+ /// 未知
+ ///
+ [Description("未知")]
+ None = 6,
+}
\ No newline at end of file
diff --git a/Admin.NET/Admin.NET.Core/Enum/MenuTypeEnum.cs b/Admin.NET/Admin.NET.Core/Enum/MenuTypeEnum.cs
new file mode 100644
index 00000000..9d323216
--- /dev/null
+++ b/Admin.NET/Admin.NET.Core/Enum/MenuTypeEnum.cs
@@ -0,0 +1,32 @@
+// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
+//
+// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
+//
+// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
+
+namespace Admin.NET.Core;
+
+///
+/// 系统菜单类型枚举
+///
+[Description("系统菜单类型枚举")]
+public enum MenuTypeEnum
+{
+ ///
+ /// 目录
+ ///
+ [Description("目录")]
+ Dir = 1,
+
+ ///
+ /// 菜单
+ ///
+ [Description("菜单")]
+ Menu = 2,
+
+ ///
+ /// 按钮
+ ///
+ [Description("按钮")]
+ Btn = 3
+}
\ No newline at end of file
diff --git a/Admin.NET/Admin.NET.Core/Enum/MessageTypeEnum.cs b/Admin.NET/Admin.NET.Core/Enum/MessageTypeEnum.cs
new file mode 100644
index 00000000..cfbe3a31
--- /dev/null
+++ b/Admin.NET/Admin.NET.Core/Enum/MessageTypeEnum.cs
@@ -0,0 +1,38 @@
+// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
+//
+// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
+//
+// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
+
+namespace Admin.NET.Core;
+
+///
+/// 消息类型枚举
+///
+[Description("消息类型枚举")]
+public enum MessageTypeEnum
+{
+ ///
+ /// 普通信息
+ ///
+ [Description("消息")]
+ Info = 0,
+
+ ///
+ /// 成功提示
+ ///
+ [Description("成功")]
+ Success = 1,
+
+ ///
+ /// 警告提示
+ ///
+ [Description("警告")]
+ Warning = 2,
+
+ ///
+ /// 错误提示
+ ///
+ [Description("错误")]
+ Error = 3
+}
\ No newline at end of file
diff --git a/Admin.NET/Admin.NET.Core/Enum/NoticeStatusEnum.cs b/Admin.NET/Admin.NET.Core/Enum/NoticeStatusEnum.cs
new file mode 100644
index 00000000..16b4067a
--- /dev/null
+++ b/Admin.NET/Admin.NET.Core/Enum/NoticeStatusEnum.cs
@@ -0,0 +1,38 @@
+// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
+//
+// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
+//
+// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
+
+namespace Admin.NET.Core;
+
+///
+/// 通知公告状态枚举
+///
+[Description("通知公告状态枚举")]
+public enum NoticeStatusEnum
+{
+ ///
+ /// 草稿
+ ///
+ [Description("草稿")]
+ DRAFT = 0,
+
+ ///
+ /// 发布
+ ///
+ [Description("发布")]
+ PUBLIC = 1,
+
+ ///
+ /// 撤回
+ ///
+ [Description("撤回")]
+ CANCEL = 2,
+
+ ///
+ /// 删除
+ ///
+ [Description("删除")]
+ DELETED = 3
+}
\ No newline at end of file
diff --git a/Admin.NET/Admin.NET.Core/Enum/NoticeTypeEnum.cs b/Admin.NET/Admin.NET.Core/Enum/NoticeTypeEnum.cs
new file mode 100644
index 00000000..387bf29c
--- /dev/null
+++ b/Admin.NET/Admin.NET.Core/Enum/NoticeTypeEnum.cs
@@ -0,0 +1,26 @@
+// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
+//
+// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
+//
+// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
+
+namespace Admin.NET.Core;
+
+///
+/// 通知公告状类型枚举
+///
+[Description("通知公告状类型枚举")]
+public enum NoticeTypeEnum
+{
+ ///
+ /// 通知
+ ///
+ [Description("通知")]
+ NOTICE = 1,
+
+ ///
+ /// 公告
+ ///
+ [Description("公告")]
+ ANNOUNCEMENT = 2,
+}
\ No newline at end of file
diff --git a/Admin.NET/Admin.NET.Core/Enum/NoticeUserStatusEnum.cs b/Admin.NET/Admin.NET.Core/Enum/NoticeUserStatusEnum.cs
new file mode 100644
index 00000000..91998b54
--- /dev/null
+++ b/Admin.NET/Admin.NET.Core/Enum/NoticeUserStatusEnum.cs
@@ -0,0 +1,26 @@
+// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
+//
+// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
+//
+// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
+
+namespace Admin.NET.Core;
+
+///
+/// 通知公告用户状态枚举
+///
+[Description("通知公告用户状态枚举")]
+public enum NoticeUserStatusEnum
+{
+ ///
+ /// 未读
+ ///
+ [Description("未读")]
+ UNREAD = 0,
+
+ ///
+ /// 已读
+ ///
+ [Description("已读")]
+ READ = 1
+}
\ No newline at end of file
diff --git a/Admin.NET/Admin.NET.Core/Enum/PlatformTypeEnum.cs b/Admin.NET/Admin.NET.Core/Enum/PlatformTypeEnum.cs
new file mode 100644
index 00000000..94727728
--- /dev/null
+++ b/Admin.NET/Admin.NET.Core/Enum/PlatformTypeEnum.cs
@@ -0,0 +1,44 @@
+// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
+//
+// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
+//
+// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
+
+namespace Admin.NET.Core;
+
+///
+/// 平台类型枚举
+///
+[Description("平台类型枚举")]
+public enum PlatformTypeEnum
+{
+ ///
+ /// 微信公众号
+ ///
+ [Description("微信公众号")]
+ 微信公众号 = 1,
+
+ ///
+ /// 微信小程序
+ ///
+ [Description("微信小程序")]
+ 微信小程序 = 2,
+
+ ///
+ /// QQ
+ ///
+ [Description("QQ")]
+ QQ = 3,
+
+ ///
+ /// Gitee
+ ///
+ [Description("Gitee")]
+ Gitee = 4,
+
+ ///
+ /// 支付宝
+ ///
+ [Description("支付宝")]
+ Alipay = 5,
+}
\ No newline at end of file
diff --git a/Admin.NET/Admin.NET.Core/Enum/PrintTypeEnum.cs b/Admin.NET/Admin.NET.Core/Enum/PrintTypeEnum.cs
new file mode 100644
index 00000000..422972fa
--- /dev/null
+++ b/Admin.NET/Admin.NET.Core/Enum/PrintTypeEnum.cs
@@ -0,0 +1,26 @@
+// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
+//
+// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
+//
+// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
+
+namespace Admin.NET.Core;
+
+///
+/// 打印类型枚举
+///
+[Description("打印类型枚举")]
+public enum PrintTypeEnum
+{
+ ///
+ /// 浏览器打印
+ ///
+ [Description("浏览器打印")]
+ Browser = 1,
+
+ ///
+ /// 浏览器打印
+ ///
+ [Description("客户端打印")]
+ Client = 2,
+}
\ No newline at end of file
diff --git a/Admin.NET/Admin.NET.Core/Enum/RequestTypeEnum.cs b/Admin.NET/Admin.NET.Core/Enum/RequestTypeEnum.cs
new file mode 100644
index 00000000..f1f4aee0
--- /dev/null
+++ b/Admin.NET/Admin.NET.Core/Enum/RequestTypeEnum.cs
@@ -0,0 +1,39 @@
+// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
+//
+// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
+//
+// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
+
+namespace Admin.NET.Core;
+
+///
+/// HTTP请求类型
+///
+[Description("HTTP请求类型")]
+public enum RequestTypeEnum
+{
+ ///
+ /// 执行内部方法
+ ///
+ Run = 0,
+
+ ///
+ /// GET
+ ///
+ Get = 1,
+
+ ///
+ /// POST
+ ///
+ Post = 2,
+
+ ///
+ /// PUT
+ ///
+ Put = 3,
+
+ ///
+ /// DELETE
+ ///
+ Delete = 4
+}
\ No newline at end of file
diff --git a/Admin.NET/Admin.NET.Core/Enum/StatusEnum.cs b/Admin.NET/Admin.NET.Core/Enum/StatusEnum.cs
new file mode 100644
index 00000000..c9560353
--- /dev/null
+++ b/Admin.NET/Admin.NET.Core/Enum/StatusEnum.cs
@@ -0,0 +1,26 @@
+// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
+//
+// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
+//
+// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
+
+namespace Admin.NET.Core;
+
+///
+/// 通用状态枚举
+///
+[Description("通用状态枚举")]
+public enum StatusEnum
+{
+ ///
+ /// 启用
+ ///
+ [Description("启用")]
+ Enable = 1,
+
+ ///
+ /// 停用
+ ///
+ [Description("停用")]
+ Disable = 2,
+}
\ No newline at end of file
diff --git a/Admin.NET/Admin.NET.Core/Enum/TenantTypeEnum.cs b/Admin.NET/Admin.NET.Core/Enum/TenantTypeEnum.cs
new file mode 100644
index 00000000..2873d0e4
--- /dev/null
+++ b/Admin.NET/Admin.NET.Core/Enum/TenantTypeEnum.cs
@@ -0,0 +1,26 @@
+// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
+//
+// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
+//
+// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
+
+namespace Admin.NET.Core;
+
+///
+/// 租户类型枚举
+///
+[Description("租户类型枚举")]
+public enum TenantTypeEnum
+{
+ ///
+ /// Id隔离
+ ///
+ [Description("Id隔离")]
+ Id = 0,
+
+ ///
+ /// 库隔离
+ ///
+ [Description("库隔离")]
+ Db = 1,
+}
\ No newline at end of file
diff --git a/Admin.NET/Admin.NET.Core/Enum/WechatReturnCodeEnum.cs b/Admin.NET/Admin.NET.Core/Enum/WechatReturnCodeEnum.cs
new file mode 100644
index 00000000..ba30a3e1
--- /dev/null
+++ b/Admin.NET/Admin.NET.Core/Enum/WechatReturnCodeEnum.cs
@@ -0,0 +1,289 @@
+// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
+//
+// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
+//
+// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
+
+namespace Admin.NET.Core;
+
+///
+/// 微信开发返回码
+///
+[Description("微信开发返回码")]
+public enum WechatReturnCodeEnum
+{
+ SenparcWeixinSDK配置错误 = -99, // 0xFFFFFF9D
+ 系统繁忙此时请开发者稍候再试 = -1, // 0xFFFFFFFF
+ 请求成功 = 0,
+ 工商数据返回_企业已注销 = 101, // 0x00000065
+ 工商数据返回_企业不存在或企业信息未更新 = 102, // 0x00000066
+ 工商数据返回_企业法定代表人姓名不一致 = 103, // 0x00000067
+ 工商数据返回_企业法定代表人身份证号码不一致 = 104, // 0x00000068
+ 法定代表人身份证号码_工商数据未更新_请5_15个工作日之后尝试 = 105, // 0x00000069
+ 工商数据返回_企业信息或法定代表人信息不一致 = 1000, // 0x000003E8
+ 对方不是粉丝 = 10700, // 0x000029CC
+ 发送消息失败_对方关闭了接收消息 = 10703, // 0x000029CF
+ 发送消息失败_48小时内用户未互动 = 10706, // 0x000029D2
+ POST参数非法 = 20002, // 0x00004E22
+ 获取access_token时AppSecret错误或者access_token无效 = 40001, // 0x00009C41
+
+ ///
+ /// 公众号:不合法的凭证类型
+ /// 小程序:暂无生成权限
+ ///
+ 不合法的凭证类型 = 40002, // 0x00009C42
+
+ 不合法的OpenID = 40003, // 0x00009C43
+ 不合法的媒体文件类型 = 40004, // 0x00009C44
+ 不合法的文件类型 = 40005, // 0x00009C45
+ 不合法的文件大小 = 40006, // 0x00009C46
+ 不合法的媒体文件id = 40007, // 0x00009C47
+ 不合法的消息类型_40008 = 40008, // 0x00009C48
+ 不合法的图片文件大小 = 40009, // 0x00009C49
+ 不合法的语音文件大小 = 40010, // 0x00009C4A
+ 不合法的视频文件大小 = 40011, // 0x00009C4B
+ 不合法的缩略图文件大小 = 40012, // 0x00009C4C
+
+ ///
+ /// 微信:不合法的APPID
+ /// 小程序:生成权限被封禁
+ ///
+ 不合法的APPID = 40013, // 0x00009C4D
+
+ 不合法的access_token = 40014, // 0x00009C4E
+ 不合法的菜单类型 = 40015, // 0x00009C4F
+ 不合法的按钮个数1 = 40016, // 0x00009C50
+ 不合法的按钮个数2 = 40017, // 0x00009C51
+ 不合法的按钮名字长度 = 40018, // 0x00009C52
+ 不合法的按钮KEY长度 = 40019, // 0x00009C53
+ 不合法的按钮URL长度 = 40020, // 0x00009C54
+ 不合法的菜单版本号 = 40021, // 0x00009C55
+ 不合法的子菜单级数 = 40022, // 0x00009C56
+ 不合法的子菜单按钮个数 = 40023, // 0x00009C57
+ 不合法的子菜单按钮类型 = 40024, // 0x00009C58
+ 不合法的子菜单按钮名字长度 = 40025, // 0x00009C59
+ 不合法的子菜单按钮KEY长度 = 40026, // 0x00009C5A
+ 不合法的子菜单按钮URL长度 = 40027, // 0x00009C5B
+ 不合法的自定义菜单使用用户 = 40028, // 0x00009C5C
+ 不合法的oauth_code = 40029, // 0x00009C5D
+ 不合法的refresh_token = 40030, // 0x00009C5E
+ 不合法的openid列表 = 40031, // 0x00009C5F
+ 不合法的openid列表长度 = 40032, // 0x00009C60
+ 不合法的请求字符不能包含uxxxx格式的字符 = 40033, // 0x00009C61
+ 不合法的参数 = 40035, // 0x00009C63
+ template_id不正确 = 40037, // 0x00009C65
+ 不合法的请求格式 = 40038, // 0x00009C66
+ 不合法的URL长度 = 40039, // 0x00009C67
+ 不合法的分组id = 40050, // 0x00009C72
+ 分组名字不合法 = 40051, // 0x00009C73
+
+ ///
+ /// 公众号:输入参数有误
+ /// 小程序:参数expire_time填写错误
+ ///
+ 输入参数有误 = 40097, // 0x00009CA1
+
+ appsecret不正确 = 40125, // 0x00009CBD
+ 调用接口的IP地址不在白名单中 = 40164, // 0x00009CE4
+ 参数path填写错误 = 40165, // 0x00009CE5
+ 小程序Appid不存在 = 40166, // 0x00009CE6
+ 参数query填写错误 = 40212, // 0x00009D14
+ 缺少access_token参数 = 41001, // 0x0000A029
+ 缺少appid参数 = 41002, // 0x0000A02A
+ 缺少refresh_token参数 = 41003, // 0x0000A02B
+ 缺少secret参数 = 41004, // 0x0000A02C
+ 缺少多媒体文件数据 = 41005, // 0x0000A02D
+ 缺少media_id参数 = 41006, // 0x0000A02E
+ 缺少子菜单数据 = 41007, // 0x0000A02F
+ 缺少oauth_code = 41008, // 0x0000A030
+ 缺少openid = 41009, // 0x0000A031
+ form_id不正确_或者过期 = 41028, // 0x0000A044
+ form_id已被使用 = 41029, // 0x0000A045
+ page不正确 = 41030, // 0x0000A046
+ access_token超时 = 42001, // 0x0000A411
+ refresh_token超时 = 42002, // 0x0000A412
+ oauth_code超时 = 42003, // 0x0000A413
+ 需要GET请求 = 43001, // 0x0000A7F9
+ 需要POST请求 = 43002, // 0x0000A7FA
+ 需要HTTPS请求 = 43003, // 0x0000A7FB
+ 需要接收者关注 = 43004, // 0x0000A7FC
+ 需要好友关系 = 43005, // 0x0000A7FD
+
+ /// [小程序订阅消息]用户拒绝接受消息,如果用户之前曾经订阅过,则表示用户取消了订阅关系
+ 用户拒绝接受消息 = 43101, // 0x0000A85D
+
+ 没有权限 = 43104, // 0x0000A860
+ 多媒体文件为空 = 44001, // 0x0000ABE1
+ POST的数据包为空 = 44002, // 0x0000ABE2
+ 图文消息内容为空 = 44003, // 0x0000ABE3
+ 文本消息内容为空 = 44004, // 0x0000ABE4
+ 多媒体文件大小超过限制 = 45001, // 0x0000AFC9
+ 消息内容超过限制 = 45002, // 0x0000AFCA
+ 标题字段超过限制 = 45003, // 0x0000AFCB
+ 描述字段超过限制 = 45004, // 0x0000AFCC
+ 链接字段超过限制 = 45005, // 0x0000AFCD
+ 图片链接字段超过限制 = 45006, // 0x0000AFCE
+ 语音播放时间超过限制 = 45007, // 0x0000AFCF
+ 图文消息超过限制 = 45008, // 0x0000AFD0
+ 接口调用超过限制 = 45009, // 0x0000AFD1
+ 创建菜单个数超过限制 = 45010, // 0x0000AFD2
+ 回复时间超过限制 = 45015, // 0x0000AFD7
+ 系统分组不允许修改 = 45016, // 0x0000AFD8
+ 分组名字过长 = 45017, // 0x0000AFD9
+ 分组数量超过上限 = 45018, // 0x0000AFDA
+ 超出响应数量限制 = 45047, // 0x0000AFF7
+ 创建的标签数过多请注意不能超过100个 = 45056, // 0x0000B000
+ 标签名非法请注意不能和其他标签重名 = 45157, // 0x0000B065
+ 标签名长度超过30个字节 = 45158, // 0x0000B066
+ 不存在媒体数据 = 46001, // 0x0000B3B1
+ 不存在的菜单版本 = 46002, // 0x0000B3B2
+ 不存在的菜单数据 = 46003, // 0x0000B3B3
+ 解析JSON_XML内容错误 = 47001, // 0x0000B799
+
+ /// [小程序订阅消息]模板参数不准确,可能为空或者不满足规则,errmsg会提示具体是哪个字段出错
+ 模板参数不准确 = 47003, // 0x0000B79B
+
+ api功能未授权 = 48001, // 0x0000BB81
+ 用户未授权该api = 50001, // 0x0000C351
+ 名称格式不合法 = 53010, // 0x0000CF12
+ 名称检测命中频率限制 = 53011, // 0x0000CF13
+ 禁止使用该名称 = 53012, // 0x0000CF14
+ 公众号_名称与已有公众号名称重复_小程序_该名称与已有小程序名称重复 = 53013, // 0x0000CF15
+ 公众号_公众号已有_名称A_时_需与该帐号相同主体才可申请_名称A_小程序_小程序已有_名称A_时_需与该帐号相同主体才可申请_名称A_ = 53014, // 0x0000CF16
+ 公众号_该名称与已有小程序名称重复_需与该小程序帐号相同主体才可申请_小程序_该名称与已有公众号名称重复_需与该公众号帐号相同主体才可申请 = 53015, // 0x0000CF17
+ 公众号_该名称与已有多个小程序名称重复_暂不支持申请_小程序_该名称与已有多个公众号名称重复_暂不支持申请 = 53016, // 0x0000CF18
+ 公众号_小程序已有_名称A_时_需与该帐号相同主体才可申请_名称A_小程序_公众号已有_名称A_时_需与该帐号相同主体才可申请_名称A = 53017, // 0x0000CF19
+ 名称命中微信号 = 53018, // 0x0000CF1A
+ 名称在保护期内 = 53019, // 0x0000CF1B
+ 法人姓名与微信号不一致 = 61070, // 0x0000EE8E
+ 系统错误system_error = 61450, // 0x0000F00A
+ 参数错误invalid_parameter = 61451, // 0x0000F00B
+ 无效客服账号invalid_kf_account = 61452, // 0x0000F00C
+ 客服帐号已存在kf_account_exsited = 61453, // 0x0000F00D
+
+ ///
+ /// 客服帐号名长度超过限制(仅允许10个英文字符,不包括@及@后的公众号的微信号)(invalid kf_acount length)
+ ///
+ 客服帐号名长度超过限制 = 61454, // 0x0000F00E
+
+ ///
+ /// 客服帐号名包含非法字符(仅允许英文+数字)(illegal character in kf_account)
+ ///
+ 客服帐号名包含非法字符 = 61455, // 0x0000F00F
+
+ /// 客服帐号个数超过限制(10个客服账号)(kf_account count exceeded)
+ 客服帐号个数超过限制 = 61456, // 0x0000F010
+
+ 无效头像文件类型invalid_file_type = 61457, // 0x0000F011
+ 日期格式错误 = 61500, // 0x0000F03C
+ 日期范围错误 = 61501, // 0x0000F03D
+ 发送消息失败_该用户已被加入黑名单_无法向此发送消息 = 62751, // 0x0000F51F
+ 门店不存在 = 65115, // 0x0000FE5B
+ 该门店状态不允许更新 = 65118, // 0x0000FE5E
+ 标签格式错误 = 85006, // 0x00014C0E
+ 页面路径错误 = 85007, // 0x00014C0F
+ 类目填写错误 = 85008, // 0x00014C10
+ 已经有正在审核的版本 = 85009, // 0x00014C11
+ item_list有项目为空 = 85010, // 0x00014C12
+ 标题填写错误 = 85011, // 0x00014C13
+ 无效的审核id = 85012, // 0x00014C14
+ 版本输入错误 = 85015, // 0x00014C17
+ 没有审核版本 = 85019, // 0x00014C1B
+ 审核状态未满足发布 = 85020, // 0x00014C1C
+ 状态不可变 = 85021, // 0x00014C1D
+ action非法 = 85022, // 0x00014C1E
+ 审核列表填写的项目数不在1到5以内 = 85023, // 0x00014C1F
+ 需要补充相应资料_填写org_code和other_files参数 = 85024, // 0x00014C20
+ 管理员手机登记数量已超过上限 = 85025, // 0x00014C21
+ 该微信号已绑定5个管理员 = 85026, // 0x00014C22
+ 管理员身份证已登记过5次 = 85027, // 0x00014C23
+ 该主体登记数量已超过上限 = 85028, // 0x00014C24
+ 商家名称已被占用 = 85029, // 0x00014C25
+ 不能使用该名称 = 85031, // 0x00014C27
+ 该名称在侵权投诉保护期 = 85032, // 0x00014C28
+ 名称包含违规内容或微信等保留字 = 85033, // 0x00014C29
+ 商家名称在改名15天保护期内 = 85034, // 0x00014C2A
+ 需与该帐号相同主体才可申请 = 85035, // 0x00014C2B
+ 介绍中含有虚假混淆内容 = 85036, // 0x00014C2C
+ 头像或者简介修改达到每个月上限 = 85049, // 0x00014C39
+ 正在审核中_请勿重复提交 = 85050, // 0x00014C3A
+ 请先成功创建门店后再调用 = 85053, // 0x00014C3D
+ 临时mediaid无效 = 85056, // 0x00014C40
+ 链接错误 = 85066, // 0x00014C4A
+ 测试链接不是子链接 = 85068, // 0x00014C4C
+ 校验文件失败 = 85069, // 0x00014C4D
+ 个人类型小程序无法设置二维码规则 = 85070, // 0x00014C4E
+ 已添加该链接_请勿重复添加 = 85071, // 0x00014C4F
+ 该链接已被占用 = 85072, // 0x00014C50
+ 二维码规则已满 = 85073, // 0x00014C51
+ 小程序未发布_小程序必须先发布代码才可以发布二维码跳转规则 = 85074, // 0x00014C52
+ 个人类型小程序无法设置二维码规则1 = 85075, // 0x00014C53
+ 小程序没有线上版本_不能进行灰度 = 85079, // 0x00014C57
+ 小程序提交的审核未审核通过 = 85080, // 0x00014C58
+ 无效的发布比例 = 85081, // 0x00014C59
+ 当前的发布比例需要比之前设置的高 = 85082, // 0x00014C5A
+ 小程序提审数量已达本月上限 = 85085, // 0x00014C5D
+ 提交代码审核之前需提前上传代码 = 85086, // 0x00014C5E
+ 小程序已使用_api_navigateToMiniProgram_请声明跳转_appid_列表后再次提交 = 85087, // 0x00014C5F
+ 不是由第三方代小程序进行调用 = 86000, // 0x00014FF0
+ 不存在第三方的已经提交的代码 = 86001, // 0x00014FF1
+ 小程序还未设置昵称_头像_简介_请先设置完后再重新提交 = 86002, // 0x00014FF2
+ 无效微信号 = 86004, // 0x00014FF4
+
+ ///
+ /// 小程序为“签名错误”。对应公众号: 87009, “errmsg” : “reply is not exists” //该回复不存在
+ ///
+ 签名错误 = 87009, // 0x000153E1
+
+ 现网已经在灰度发布_不能进行版本回退 = 87011, // 0x000153E3
+ 该版本不能回退_可能的原因_1_无上一个线上版用于回退_2_此版本为已回退版本_不能回退_3_此版本为回退功能上线之前的版本_不能回退 = 87012, // 0x000153E4
+ 内容含有违法违规内容 = 87014, // 0x000153E6
+ 没有留言权限 = 88000, // 0x000157C0
+ 该图文不存在 = 88001, // 0x000157C1
+ 文章存在敏感信息 = 88002, // 0x000157C2
+ 精选评论数已达上限 = 88003, // 0x000157C3
+ 已被用户删除_无法精选 = 88004, // 0x000157C4
+ 已经回复过了 = 88005, // 0x000157C5
+ 回复超过长度限制或为0 = 88007, // 0x000157C7
+ 该评论不存在 = 88008, // 0x000157C8
+ 获取评论数目不合法 = 88010, // 0x000157CA
+ 该公众号_小程序已经绑定了开放平台帐号 = 89000, // 0x00015BA8
+ 业务域名无更改_无需重复设置 = 89019, // 0x00015BBB
+ 尚未设置小程序业务域名_请先在第三方平台中设置小程序业务域名后在调用本接口 = 89020, // 0x00015BBC
+ 请求保存的域名不是第三方平台中已设置的小程序业务域名或子域名 = 89021, // 0x00015BBD
+ 业务域名数量超过限制_最多可以添加100个业务域名 = 89029, // 0x00015BC5
+ 个人小程序不支持调用_setwebviewdomain_接口 = 89231, // 0x00015C8F
+ 内部错误 = 89247, // 0x00015C9F
+ 企业代码类型无效_请选择正确类型填写 = 89248, // 0x00015CA0
+ 该主体已有任务执行中_距上次任务24h后再试 = 89249, // 0x00015CA1
+ 未找到该任务 = 89250, // 0x00015CA2
+ 待法人人脸核身校验 = 89251, // 0x00015CA3
+ 法人_企业信息一致性校验中 = 89252, // 0x00015CA4
+ 缺少参数 = 89253, // 0x00015CA5
+ 第三方权限集不全_补全权限集全网发布后生效 = 89254, // 0x00015CA6
+ 系统不稳定_请稍后再试_如多次失败请通过社区反馈 = 89401, // 0x00015D39
+ 该审核单不在待审核队列_请检查是否已提交审核或已审完 = 89402, // 0x00015D3A
+ 本单属于平台不支持加急种类_请等待正常审核流程 = 89403, // 0x00015D3B
+ 本单已加速成功_请勿重复提交 = 89404, // 0x00015D3C
+ 本月加急额度不足_请提升提审质量以获取更多额度 = 89405, // 0x00015D3D
+ 该经营资质已添加_请勿重复添加 = 92000, // 0x00016760
+ 附近地点添加数量达到上线_无法继续添加 = 92002, // 0x00016762
+ 地点已被其它小程序占用 = 92003, // 0x00016763
+ 附近功能被封禁 = 92004, // 0x00016764
+ 地点正在审核中 = 92005, // 0x00016765
+ 地点正在展示小程序 = 92006, // 0x00016766
+ 地点审核失败 = 92007, // 0x00016767
+ 程序未展示在该地点 = 92008, // 0x00016768
+ 小程序未上架或不可见 = 92009, // 0x00016769
+ 地点不存在 = 93010, // 0x00016B52
+ 个人类型小程序不可用 = 93011, // 0x00016B53
+ 已下发的模板消息法人并未确认且已超时_24h_未进行身份证校验 = 100001, // 0x000186A1
+ 已下发的模板消息法人并未确认且已超时_24h_未进行人脸识别校验 = 100002, // 0x000186A2
+ 已下发的模板消息法人并未确认且已超时_24h = 100003, // 0x000186A3
+ 此账号已被封禁_无法操作 = 200011, // 0x00030D4B
+ 私有模板数已达上限_上限_50_个 = 200012, // 0x00030D4C
+ 此模版已被封禁_无法选用 = 200013, // 0x00030D4D
+ 模版tid参数错误 = 200014, // 0x00030D4E
+ 关键词列表kidList参数错误 = 200020, // 0x00030D54
+ 场景描述sceneDesc参数错误 = 200021, // 0x00030D55
+}
\ No newline at end of file
diff --git a/Admin.NET/Admin.NET.Core/Enum/YesNoEnum.cs b/Admin.NET/Admin.NET.Core/Enum/YesNoEnum.cs
new file mode 100644
index 00000000..b241a678
--- /dev/null
+++ b/Admin.NET/Admin.NET.Core/Enum/YesNoEnum.cs
@@ -0,0 +1,26 @@
+// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
+//
+// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
+//
+// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
+
+namespace Admin.NET.Core;
+
+///
+/// 是否枚举
+///
+[Description("是否枚举")]
+public enum YesNoEnum
+{
+ ///
+ /// 是
+ ///
+ [Description("是")]
+ Y = 1,
+
+ ///
+ /// 否
+ ///
+ [Description("否")]
+ N = 2
+}
\ No newline at end of file
diff --git a/Admin.NET/Admin.NET.Core/EventBus/AppEventSubscriber.cs b/Admin.NET/Admin.NET.Core/EventBus/AppEventSubscriber.cs
new file mode 100644
index 00000000..2a438056
--- /dev/null
+++ b/Admin.NET/Admin.NET.Core/EventBus/AppEventSubscriber.cs
@@ -0,0 +1,56 @@
+// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
+//
+// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
+//
+// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
+
+namespace Admin.NET.Core;
+
+///
+/// 事件订阅
+///
+public class AppEventSubscriber : IEventSubscriber, ISingleton, IDisposable
+{
+ private readonly IServiceScope _serviceScope;
+
+ public AppEventSubscriber(IServiceScopeFactory scopeFactory)
+ {
+ _serviceScope = scopeFactory.CreateScope();
+ }
+
+ ///
+ /// 增加异常日志
+ ///
+ ///
+ ///
+ [EventSubscribe(CommonConst.AddExLog)]
+ public async Task CreateExLog(EventHandlerExecutingContext context)
+ {
+ var rep = _serviceScope.ServiceProvider.GetRequiredService>();
+ await rep.InsertAsync((SysLogEx)context.Source.Payload);
+ }
+
+ ///
+ /// 发送异常邮件
+ ///
+ ///
+ ///
+ [EventSubscribe(CommonConst.SendErrorMail)]
+ public async Task SendOrderErrorMail(EventHandlerExecutingContext context)
+ {
+ //var mailTempPath = Path.Combine(App.WebHostEnvironment.WebRootPath, "Temp\\ErrorMail.tp");
+ //var mailTemp = File.ReadAllText(mailTempPath);
+ //var mail = await _serviceScope.ServiceProvider.GetRequiredService().RunCompileFromCachedAsync(mailTemp, );
+
+ var title = "Admin.NET 系统异常";
+ await _serviceScope.ServiceProvider.GetRequiredService().SendEmail(JSON.Serialize(context.Source.Payload), title);
+ }
+
+ ///
+ /// 释放服务作用域
+ ///
+ public void Dispose()
+ {
+ _serviceScope.Dispose();
+ }
+}
\ No newline at end of file
diff --git a/Admin.NET/Admin.NET.Core/EventBus/EventConsumer.cs b/Admin.NET/Admin.NET.Core/EventBus/EventConsumer.cs
new file mode 100644
index 00000000..595bc891
--- /dev/null
+++ b/Admin.NET/Admin.NET.Core/EventBus/EventConsumer.cs
@@ -0,0 +1,112 @@
+// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
+//
+// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
+//
+// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
+
+namespace Admin.NET.Core;
+
+///
+/// Redis 消息扩展
+///
+///
+public class EventConsumer : IDisposable
+{
+ private Task _consumerTask;
+ private CancellationTokenSource _consumerCts;
+
+ ///
+ /// 消费者
+ ///
+ public IProducerConsumer Consumer { get; }
+
+ ///
+ /// ConsumerBuilder
+ ///
+ public FullRedis Builder { get; set; }
+
+ ///
+ /// 消息回调
+ ///
+ public event EventHandler Received;
+
+ ///
+ /// 构造函数
+ ///
+ public EventConsumer(FullRedis redis, string routeKey)
+ {
+ Builder = redis;
+ Consumer = Builder.GetQueue(routeKey);
+ }
+
+ ///
+ /// 启动
+ ///
+ ///
+ public void Start()
+ {
+ if (Consumer is null)
+ {
+ throw new InvalidOperationException("Subscribe first using the Consumer.Subscribe() function");
+ }
+ if (_consumerTask != null)
+ {
+ return;
+ }
+ _consumerCts = new CancellationTokenSource();
+ var ct = _consumerCts.Token;
+ _consumerTask = Task.Factory.StartNew(() =>
+ {
+ while (!ct.IsCancellationRequested)
+ {
+ var cr = Consumer.TakeOne(10);
+ if (cr == null) continue;
+ Received?.Invoke(this, cr);
+ }
+ }, ct, TaskCreationOptions.LongRunning, TaskScheduler.Default);
+ }
+
+ ///
+ /// 停止
+ ///
+ ///
+ public async Task Stop()
+ {
+ if (_consumerCts == null || _consumerTask == null) return;
+ _consumerCts.Cancel();
+ try
+ {
+ await _consumerTask;
+ }
+ finally
+ {
+ _consumerTask = null;
+ _consumerCts = null;
+ }
+ }
+
+ ///
+ /// 释放
+ ///
+ public void Dispose()
+ {
+ Dispose(true);
+ GC.SuppressFinalize(this);
+ }
+
+ ///
+ /// 释放
+ ///
+ ///
+ protected virtual void Dispose(bool disposing)
+ {
+ if (disposing)
+ {
+ if (_consumerTask != null)
+ {
+ Stop().Wait();
+ }
+ Builder.Dispose();
+ }
+ }
+}
\ No newline at end of file
diff --git a/Admin.NET/Admin.NET.Core/EventBus/RabbitMQEventSourceStore.cs b/Admin.NET/Admin.NET.Core/EventBus/RabbitMQEventSourceStore.cs
new file mode 100644
index 00000000..0372eb0c
--- /dev/null
+++ b/Admin.NET/Admin.NET.Core/EventBus/RabbitMQEventSourceStore.cs
@@ -0,0 +1,132 @@
+// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
+//
+// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
+//
+// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
+
+using RabbitMQ.Client;
+using RabbitMQ.Client.Events;
+using System.Threading.Channels;
+
+namespace Admin.NET.Core;
+
+///
+/// RabbitMQ自定义事件源存储器
+///
+public class RabbitMQEventSourceStore : IEventSourceStorer
+{
+ ///
+ /// 内存通道事件源存储器
+ ///
+ private readonly Channel _channel;
+
+ ///
+ /// 通道对象
+ ///
+ private readonly IModel _model;
+
+ ///
+ /// 连接对象
+ ///
+ private readonly IConnection _connection;
+
+ ///
+ /// 路由键
+ ///
+ private readonly string _routeKey;
+
+ ///
+ /// 构造函数
+ ///
+ /// 连接工厂
+ /// 路由键
+ /// 存储器最多能够处理多少消息,超过该容量进入等待写入
+ public RabbitMQEventSourceStore(ConnectionFactory factory, string routeKey, int capacity)
+ {
+ // 配置通道,设置超出默认容量后进入等待
+ var boundedChannelOptions = new BoundedChannelOptions(capacity)
+ {
+ FullMode = BoundedChannelFullMode.Wait
+ };
+
+ // 创建有限容量通道
+ _channel = Channel.CreateBounded(boundedChannelOptions);
+
+ // 创建连接
+ _connection = factory.CreateConnection();
+ _routeKey = routeKey;
+
+ // 创建通道
+ _model = _connection.CreateModel();
+
+ // 声明路由队列
+ _model.QueueDeclare(routeKey, false, false, false, null);
+
+ // 创建消息订阅者
+ var consumer = new EventingBasicConsumer(_model);
+
+ // 订阅消息并写入内存 Channel
+ consumer.Received += (ch, ea) =>
+ {
+ // 读取原始消息
+ var stringEventSource = Encoding.UTF8.GetString(ea.Body.ToArray());
+
+ // 转换为 IEventSource,如果自定义了 EventSource,注意属性是可读可写
+ var eventSource = JSON.Deserialize(stringEventSource);
+
+ // 写入内存管道存储器
+ _channel.Writer.WriteAsync(eventSource);
+
+ // 确认该消息已被消费
+ _model.BasicAck(ea.DeliveryTag, false);
+ };
+
+ // 启动消费者且设置为手动应答消息
+ _model.BasicConsume(routeKey, false, consumer);
+ }
+
+ ///
+ /// 将事件源写入存储器
+ ///
+ /// 事件源对象
+ /// 取消任务 Token
+ ///
+ public async ValueTask WriteAsync(IEventSource eventSource, CancellationToken cancellationToken)
+ {
+ if (eventSource == default)
+ throw new ArgumentNullException(nameof(eventSource));
+
+ // 判断是否是 ChannelEventSource 或自定义的 EventSource
+ if (eventSource is ChannelEventSource source)
+ {
+ // 序列化及发布
+ var data = Encoding.UTF8.GetBytes(JSON.Serialize(source));
+ _model.BasicPublish("", _routeKey, null, data);
+ }
+ else
+ {
+ // 处理动态订阅
+ await _channel.Writer.WriteAsync(eventSource, cancellationToken);
+ }
+ }
+
+ ///
+ /// 从存储器中读取一条事件源
+ ///
+ /// 取消任务 Token
+ /// 事件源对象
+ public async ValueTask ReadAsync(CancellationToken cancellationToken)
+ {
+ var eventSource = await _channel.Reader.ReadAsync(cancellationToken);
+ return eventSource;
+ }
+
+ ///
+ /// 释放非托管资源
+ ///
+ public void Dispose()
+ {
+ _model.Dispose();
+ _connection.Dispose();
+ }
+}
\ No newline at end of file
diff --git a/Admin.NET/Admin.NET.Core/EventBus/RedisEventSourceStorer.cs b/Admin.NET/Admin.NET.Core/EventBus/RedisEventSourceStorer.cs
new file mode 100644
index 00000000..975a3dc3
--- /dev/null
+++ b/Admin.NET/Admin.NET.Core/EventBus/RedisEventSourceStorer.cs
@@ -0,0 +1,132 @@
+// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
+//
+// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
+//
+// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
+
+using System.Threading.Channels;
+
+namespace Admin.NET.Core;
+
+///
+/// Redis自定义事件源存储器
+///
+public sealed class RedisEventSourceStorer : IEventSourceStorer, IDisposable
+{
+ ///
+ /// 消费者
+ ///
+ private readonly EventConsumer _eventConsumer;
+
+ ///
+ /// 内存通道事件源存储器
+ ///
+ private readonly Channel _channel;
+
+ ///
+ /// Redis 连接对象
+ ///
+ private readonly FullRedis _redis;
+
+ ///
+ /// 路由键
+ ///
+ private readonly string _routeKey;
+
+ ///
+ /// 构造函数
+ ///
+ /// Redis 连接对象
+ /// 路由键
+ /// 存储器最多能够处理多少消息,超过该容量进入等待写入
+ public RedisEventSourceStorer(ICache redis, string routeKey, int capacity)
+ {
+ // 配置通道,设置超出默认容量后进入等待
+ var boundedChannelOptions = new BoundedChannelOptions(capacity)
+ {
+ FullMode = BoundedChannelFullMode.Wait
+ };
+
+ // 创建有限容量通道
+ _channel = Channel.CreateBounded(boundedChannelOptions);
+
+ _redis = redis as FullRedis;
+ _routeKey = routeKey;
+
+ // 创建消息订阅者
+ _eventConsumer = new EventConsumer(_redis, _routeKey);
+
+ // 订阅消息写入 Channel
+ _eventConsumer.Received += (send, cr) =>
+ {
+ // 反序列化消息
+ //var eventSource = JsonConvert.DeserializeObject(cr);
+
+ // 写入内存管道存储器
+ Task.Run(async () =>
+ {
+ await _channel.Writer.WriteAsync(cr);
+ });
+ };
+
+ // 启动消费者
+ _eventConsumer.Start();
+ }
+
+ ///
+ /// 将事件源写入存储器
+ ///
+ /// 事件源对象
+ /// 取消任务 Token
+ ///
+ public async ValueTask WriteAsync(IEventSource eventSource, CancellationToken cancellationToken)
+ {
+ // 空检查
+ if (eventSource == default)
+ {
+ throw new ArgumentNullException(nameof(eventSource));
+ }
+
+ // 这里判断是否是 ChannelEventSource 或者 自定义的 EventSource
+ if (eventSource is ChannelEventSource source)
+ {
+ // 序列化消息
+ //var data = JsonSerializer.Serialize(source);
+
+ // 获取一个订阅对象
+ var queue = _redis.GetQueue(_routeKey);
+
+ // 异步发布
+ await Task.Factory.StartNew(() =>
+ {
+ queue.Add(source);
+ }, cancellationToken, TaskCreationOptions.LongRunning, System.Threading.Tasks.TaskScheduler.Default);
+ }
+ else
+ {
+ // 这里处理动态订阅问题
+ await _channel.Writer.WriteAsync(eventSource, cancellationToken);
+ }
+ }
+
+ ///
+ /// 从存储器中读取一条事件源
+ ///
+ /// 取消任务 Token
+ /// 事件源对象
+ public async ValueTask ReadAsync(CancellationToken cancellationToken)
+ {
+ // 读取一条事件源
+ var eventSource = await _channel.Reader.ReadAsync(cancellationToken);
+ return eventSource;
+ }
+
+ ///
+ /// 释放非托管资源
+ ///
+ public async void Dispose()
+ {
+ await _eventConsumer.Stop();
+ GC.SuppressFinalize(this);
+ }
+}
\ No newline at end of file
diff --git a/Admin.NET/Admin.NET.Core/EventBus/RedisQueue.cs b/Admin.NET/Admin.NET.Core/EventBus/RedisQueue.cs
new file mode 100644
index 00000000..ee44149c
--- /dev/null
+++ b/Admin.NET/Admin.NET.Core/EventBus/RedisQueue.cs
@@ -0,0 +1,241 @@
+// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
+//
+// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
+//
+// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
+
+using NewLife.Caching.Queues;
+
+namespace Admin.NET.Core;
+
+///
+/// Redis 消息队列
+///
+public static class RedisQueue
+{
+ private static readonly ICache _cache = App.GetRequiredService();
+
+ ///
+ /// 获取普通队列
+ ///
+ ///
+ ///
+ ///
+ public static IProducerConsumer GetQueue(string topic)
+ {
+ var queue = (_cache as FullRedis).GetQueue(topic);
+ return queue;
+ }
+
+ ///
+ /// 发送一个数据到队列
+ ///
+ ///
+ ///
+ ///
+ ///
+ public static int AddQueue(string topic, T value)
+ {
+ var queue = GetQueue(topic);
+ return queue.Add(value);
+ }
+
+ ///
+ /// 发送一个数据列表到队列
+ ///
+ ///
+ ///
+ ///
+ ///
+ public static int AddQueueList(string topic, List value)
+ {
+ var queue = GetQueue(topic);
+ var count = queue.Count;
+ var result = queue.Add(value.ToArray());
+ return result - count;
+ }
+
+ ///
+ /// 获取一批队列消息
+ ///
+ ///
+ ///
+ ///
+ ///
+ public static List Take(string topic, int count = 1)
+ {
+ var queue = GetQueue(topic);
+ var result = queue.Take(count).ToList();
+ return result;
+ }
+
+ ///
+ /// 获取一个队列消息
+ ///
+ ///
+ ///
+ ///
+ public static async Task TakeOneAsync(string topic)
+ {
+ var queue = GetQueue(topic);
+ return await queue.TakeOneAsync(1);
+ }
+
+ ///
+ /// 获取可信队列,需要确认
+ ///
+ ///
+ ///
+ ///
+ public static RedisReliableQueue GetRedisReliableQueue(string topic)
+ {
+ var queue = (_cache as FullRedis).GetReliableQueue(topic);
+ return queue;
+ }
+
+ ///
+ /// 可信队列回滚
+ ///
+ ///
+ ///
+ ///
+ public static int RollbackAllAck(string topic, int retryInterval = 60)
+ {
+ var queue = GetRedisReliableQueue(topic);
+ queue.RetryInterval = retryInterval;
+ return queue.RollbackAllAck();
+ }
+
+ ///
+ /// 发送一个数据列表到可信队列
+ ///
+ ///
+ ///
+ ///
+ ///
+ public static int AddReliableQueueList(string topic, List value)
+ {
+ var queue = (_cache as FullRedis).GetReliableQueue(topic);
+ var count = queue.Count;
+ var result = queue.Add(value.ToArray());
+ return result - count;
+ }
+
+ ///
+ /// 发送一条数据到可信队列
+ ///
+ ///
+ ///
+ ///
+ ///
+ public static int AddReliableQueue(string topic, T value)
+ {
+ var queue = (_cache as FullRedis).GetReliableQueue(topic);
+ var count = queue.Count;
+ var result = queue.Add(value);
+ return result - count;
+ }
+
+ ///
+ /// 在可信队列获取一条数据
+ ///
+ ///
+ ///
+ ///
+ public static T ReliableTakeOne(string topic)
+ {
+ var queue = GetRedisReliableQueue(topic);
+ return queue.TakeOne(1);
+ }
+
+ ///
+ /// 异步在可信队列获取一条数据
+ ///
+ ///
+ ///
+ ///
+ public static async Task ReliableTakeOneAsync(string topic)
+ {
+ var queue = GetRedisReliableQueue(topic);
+ return await queue.TakeOneAsync(1);
+ }
+
+ ///
+ /// 在可信队列获取多条数据
+ ///
+ ///
+ ///
+ ///
+ ///
+ public static List ReliableTake(string topic, int count)
+ {
+ var queue = GetRedisReliableQueue(topic);
+ return queue.Take(count).ToList();
+ }
+
+ ///
+ /// 获取延迟队列
+ ///
+ ///
+ ///
+ ///
+ public static RedisDelayQueue GetDelayQueue(string topic)
+ {
+ var queue = (_cache as FullRedis).GetDelayQueue(topic);
+ return queue;
+ }
+
+ ///
+ /// 发送一条数据到延迟队列
+ ///
+ ///
+ ///
+ /// 延迟时间。单位秒
+ ///
+ ///
+ public static int AddDelayQueue(string topic, T value, int delay)
+ {
+ var queue = GetDelayQueue(topic);
+ return queue.Add(value, delay);
+ }
+
+ ///
+ /// 发送数据列表到延迟队列
+ ///
+ ///
+ ///
+ ///
+ /// 延迟时间。单位秒
+ ///
+ public static int AddDelayQueue(string topic, List value, int delay)
+ {
+ var queue = GetDelayQueue(topic);
+ queue.Delay = delay;
+ return queue.Add(value.ToArray());
+ }
+
+ ///
+ /// 异步在延迟队列获取一条数据
+ ///
+ ///
+ ///
+ ///
+ public static async Task DelayTakeOne(string topic)
+ {
+ var queue = GetDelayQueue(topic);
+ return await queue.TakeOneAsync(1);
+ }
+
+ ///
+ /// 在延迟队列获取多条数据
+ ///
+ ///
+ ///
+ ///
+ ///
+ public static List DelayTake(string topic, int count = 1)
+ {
+ var queue = GetDelayQueue(topic);
+ return queue.Take(count).ToList();
+ }
+}
\ No newline at end of file
diff --git a/Admin.NET/Admin.NET.Core/EventBus/RetryEventHandlerExecutor.cs b/Admin.NET/Admin.NET.Core/EventBus/RetryEventHandlerExecutor.cs
new file mode 100644
index 00000000..f53f5756
--- /dev/null
+++ b/Admin.NET/Admin.NET.Core/EventBus/RetryEventHandlerExecutor.cs
@@ -0,0 +1,22 @@
+// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
+//
+// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
+//
+// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
+
+namespace Admin.NET.Core;
+
+///
+/// 事件执行器-超时控制、失败重试熔断等等
+///
+public class RetryEventHandlerExecutor : IEventHandlerExecutor
+{
+ public async Task ExecuteAsync(EventHandlerExecutingContext context, Func handler)
+ {
+ // 如果执行失败,每隔 1s 重试,最多三次
+ await Retry.InvokeAsync(async () =>
+ {
+ await handler(context);
+ }, 3, 1000);
+ }
+}
\ No newline at end of file
diff --git a/Admin.NET/Admin.NET.Core/Extension/ConsoleLogoSetup.cs b/Admin.NET/Admin.NET.Core/Extension/ConsoleLogoSetup.cs
new file mode 100644
index 00000000..be20e972
--- /dev/null
+++ b/Admin.NET/Admin.NET.Core/Extension/ConsoleLogoSetup.cs
@@ -0,0 +1,27 @@
+// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
+//
+// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
+//
+// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
+
+namespace Admin.NET.Core;
+
+///
+/// 控制台logo
+///
+public static class ConsoleLogoSetup
+{
+ public static void AddConsoleLogo(this IServiceCollection services)
+ {
+ Console.ForegroundColor = ConsoleColor.Blue;
+ Console.WriteLine(@"
+ _ _ _ _ ______ _______
+ /\ | | (_) | \ | | ____|__ __|
+ / \ __| |_ __ ___ _ _ __ | \| | |__ | |
+ / /\ \ / _` | '_ ` _ \| | '_ \ | . ` | __| | |
+ / ____ \ (_| | | | | | | | | | |_| |\ | |____ | |
+ /_/ \_\__,_|_| |_| |_|_|_| |_(_)_| \_|______| |_| ");
+ Console.ForegroundColor = ConsoleColor.Yellow;
+ Console.WriteLine(@"让.NET更简单、更通用、更流行!");
+ }
+}
\ No newline at end of file
diff --git a/Admin.NET/Admin.NET.Core/Extension/EnumExtension.cs b/Admin.NET/Admin.NET.Core/Extension/EnumExtension.cs
new file mode 100644
index 00000000..89447cfe
--- /dev/null
+++ b/Admin.NET/Admin.NET.Core/Extension/EnumExtension.cs
@@ -0,0 +1,225 @@
+// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
+//
+// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
+//
+// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
+
+namespace Admin.NET.Core;
+
+///
+/// 枚举拓展
+///
+public static class EnumExtension
+{
+ // 枚举显示字典缓存
+ private static readonly ConcurrentDictionary> EnumDisplayValueDict = new();
+
+ // 枚举值字典缓存
+ private static readonly ConcurrentDictionary> EnumNameValueDict = new();
+
+ // 枚举类型缓存
+ private static ConcurrentDictionary _enumTypeDict;
+
+ ///
+ /// 获取枚举对象Key与名称的字典(缓存)
+ ///
+ ///
+ ///
+ public static Dictionary GetEnumDictionary(this Type enumType)
+ {
+ if (!enumType.IsEnum)
+ throw new ArgumentException("Type '" + enumType.Name + "' is not an enum.");
+
+ // 查询缓存
+ var enumDic = EnumNameValueDict.ContainsKey(enumType) ? EnumNameValueDict[enumType] : new Dictionary();
+ if (enumDic.Count != 0)
+ return enumDic;
+ // 取枚举类型的Key/Value字典集合
+ enumDic = GetEnumDictionaryItems(enumType);
+
+ // 缓存
+ EnumNameValueDict[enumType] = enumDic;
+
+ return enumDic;
+ }
+
+ ///
+ /// 获取枚举对象Key与名称的字典
+ ///
+ ///
+ ///
+ private static Dictionary GetEnumDictionaryItems(this Type enumType)
+ {
+ // 获取类型的字段,初始化一个有限长度的字典
+ var enumFields = enumType.GetFields(BindingFlags.Public | BindingFlags.Static);
+ Dictionary enumDic = new(enumFields.Length);
+
+ // 遍历字段数组获取key和name
+ foreach (var enumField in enumFields)
+ {
+ var intValue = (int)enumField.GetValue(enumType);
+ enumDic[intValue] = enumField.Name;
+ }
+
+ return enumDic;
+ }
+
+ ///
+ /// 获取枚举类型key与描述的字典(缓存)
+ ///
+ ///
+ ///
+ ///
+ public static Dictionary GetEnumDescDictionary(this Type enumType)
+ {
+ if (!enumType.IsEnum)
+ throw new ArgumentException("Type '" + enumType.Name + "' is not an enum.");
+
+ // 查询缓存
+ var enumDic = EnumDisplayValueDict.ContainsKey(enumType)
+ ? EnumDisplayValueDict[enumType]
+ : new Dictionary();
+ if (enumDic.Count != 0)
+ return enumDic;
+ // 取枚举类型的Key/Value字典集合
+ enumDic = GetEnumDescDictionaryItems(enumType);
+
+ // 缓存
+ EnumDisplayValueDict[enumType] = enumDic;
+
+ return enumDic;
+ }
+
+ ///
+ /// 获取枚举类型key与描述的字典(没有描述则获取name)
+ ///
+ ///
+ ///
+ ///
+ private static Dictionary GetEnumDescDictionaryItems(this Type enumType)
+ {
+ // 获取类型的字段,初始化一个有限长度的字典
+ var enumFields = enumType.GetFields(BindingFlags.Public | BindingFlags.Static);
+ Dictionary enumDic = new(enumFields.Length);
+
+ // 遍历字段数组获取key和name
+ foreach (var enumField in enumFields)
+ {
+ var intValue = (int)enumField.GetValue(enumType);
+ var desc = enumField.GetDescriptionValue();
+ enumDic[intValue] = desc != null && !string.IsNullOrEmpty(desc.Description) ? desc.Description : enumField.Name;
+ }
+
+ return enumDic;
+ }
+
+ ///
+ /// 从程序集中查找指定枚举类型
+ ///
+ ///
+ ///
+ ///
+ public static Type TryToGetEnumType(Assembly assembly, string typeName)
+ {
+ // 枚举缓存为空则重新加载枚举类型字典
+ _enumTypeDict ??= LoadEnumTypeDict(assembly);
+
+ // 按名称查找
+ return _enumTypeDict.ContainsKey(typeName) ? _enumTypeDict[typeName] : null;
+ }
+
+ ///
+ /// 从程序集中加载所有枚举类型
+ ///
+ ///
+ ///
+ private static ConcurrentDictionary LoadEnumTypeDict(Assembly assembly)
+ {
+ // 取程序集中所有类型
+ var typeArray = assembly.GetTypes();
+
+ // 过滤非枚举类型,转成字典格式并返回
+ var dict = typeArray.Where(o => o.IsEnum).ToDictionary(o => o.Name, o => o);
+ ConcurrentDictionary enumTypeDict = new(dict);
+ return enumTypeDict;
+ }
+
+ ///
+ /// 获取枚举的Description
+ ///
+ ///
+ ///
+ public static string GetDescription(this System.Enum value)
+ {
+ return value.GetType().GetMember(value.ToString()).FirstOrDefault()?.GetCustomAttribute()
+ ?.Description;
+ }
+
+ ///
+ /// 获取枚举的Description
+ ///
+ ///
+ ///
+ public static string GetDescription(this object value)
+ {
+ return value.GetType().GetMember(value.ToString() ?? string.Empty).FirstOrDefault()
+ ?.GetCustomAttribute()?.Description;
+ }
+
+ ///
+ /// 将枚举转成枚举信息集合
+ ///
+ ///
+ ///
+ public static List EnumToList(this Type type)
+ {
+ if (!type.IsEnum)
+ throw new ArgumentException("Type '" + type.Name + "' is not an enum.");
+ var arr = System.Enum.GetNames(type);
+ return arr.Select(sl =>
+ {
+ var item = System.Enum.Parse(type, sl);
+ return new EnumEntity
+ {
+ Name = item.ToString(),
+ Describe = item.GetDescription() ?? item.ToString(),
+ Value = item.GetHashCode()
+ };
+ }).ToList();
+ }
+
+ ///
+ /// 枚举ToList
+ ///
+ ///
+ ///
+ ///
+ public static List EnumToList(this Type type)
+ {
+ if (!type.IsEnum)
+ throw new ArgumentException("Type '" + type.Name + "' is not an enum.");
+ var arr = System.Enum.GetNames(type);
+ return arr.Select(name => (T)System.Enum.Parse(type, name)).ToList();
+ }
+}
+
+///
+/// 枚举实体
+///
+public class EnumEntity
+{
+ ///
+ /// 枚举的描述
+ ///
+ public string Describe { set; get; }
+
+ ///
+ /// 枚举名称
+ ///
+ public string Name { set; get; }
+
+ ///
+ /// 枚举对象的值
+ ///
+ public int Value { set; get; }
+}
\ No newline at end of file
diff --git a/Admin.NET/Admin.NET.Core/Extension/ListExtensions.cs b/Admin.NET/Admin.NET.Core/Extension/ListExtensions.cs
new file mode 100644
index 00000000..77d8c903
--- /dev/null
+++ b/Admin.NET/Admin.NET.Core/Extension/ListExtensions.cs
@@ -0,0 +1,26 @@
+// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
+//
+// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
+//
+// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
+
+namespace Admin.NET.Core;
+
+public static class ListExtensions
+{
+ public static async Task ForEachAsync(this List list, Func func)
+ {
+ foreach (var value in list)
+ {
+ await func(value);
+ }
+ }
+
+ public static async Task ForEachAsync(this IEnumerable source, Func action)
+ {
+ foreach (var value in source)
+ {
+ await action(value);
+ }
+ }
+}
\ No newline at end of file
diff --git a/Admin.NET/Admin.NET.Core/Extension/ObjectExtension.cs b/Admin.NET/Admin.NET.Core/Extension/ObjectExtension.cs
new file mode 100644
index 00000000..8f6c106c
--- /dev/null
+++ b/Admin.NET/Admin.NET.Core/Extension/ObjectExtension.cs
@@ -0,0 +1,449 @@
+// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
+//
+// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
+//
+// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
+
+namespace Admin.NET.Core;
+
+///
+/// 对象拓展
+///
+[SuppressSniffer]
+public static partial class ObjectExtension
+{
+ ///
+ /// 判断类型是否实现某个泛型
+ ///
+ /// 类型
+ /// 泛型类型
+ /// bool
+ public static bool HasImplementedRawGeneric(this Type type, Type generic)
+ {
+ // 检查接口类型
+ var isTheRawGenericType = type.GetInterfaces().Any(IsTheRawGenericType);
+ if (isTheRawGenericType) return true;
+
+ // 检查类型
+ while (type != null && type != typeof(object))
+ {
+ isTheRawGenericType = IsTheRawGenericType(type);
+ if (isTheRawGenericType) return true;
+ type = type.BaseType;
+ }
+
+ return false;
+
+ // 判断逻辑
+ bool IsTheRawGenericType(Type type) => generic == (type.IsGenericType ? type.GetGenericTypeDefinition() : type);
+ }
+
+ ///
+ /// 将字典转化为QueryString格式
+ ///
+ ///
+ ///
+ ///
+ public static string ToQueryString(this Dictionary dict, bool urlEncode = true)
+ {
+ return string.Join("&", dict.Select(p => $"{(urlEncode ? p.Key?.UrlEncode() : "")}={(urlEncode ? p.Value?.UrlEncode() : "")}"));
+ }
+
+ ///
+ /// 将字符串URL编码
+ ///
+ ///
+ ///
+ public static string UrlEncode(this string str)
+ {
+ return string.IsNullOrEmpty(str) ? "" : System.Uri.EscapeDataString(str);
+ }
+
+ ///
+ /// 对象序列化成Json字符串
+ ///
+ ///
+ ///
+ public static string ToJson(this object obj)
+ {
+ return JSON.GetJsonSerializer().Serialize(obj);
+ }
+
+ ///
+ /// Json字符串反序列化成对象
+ ///
+ ///
+ ///
+ ///
+ public static T ToObject(this string json)
+ {
+ return JSON.GetJsonSerializer().Deserialize(json);
+ }
+
+ ///
+ /// 将object转换为long,若失败则返回0
+ ///
+ ///
+ ///
+ public static long ParseToLong(this object obj)
+ {
+ try
+ {
+ return long.Parse(obj.ToString());
+ }
+ catch
+ {
+ return 0L;
+ }
+ }
+
+ ///
+ /// 将object转换为long,若失败则返回指定值
+ ///
+ ///
+ ///
+ ///
+ public static long ParseToLong(this string str, long defaultValue)
+ {
+ try
+ {
+ return long.Parse(str);
+ }
+ catch
+ {
+ return defaultValue;
+ }
+ }
+
+ ///
+ /// 将object转换为double,若失败则返回0
+ ///
+ ///
+ ///
+ public static double ParseToDouble(this object obj)
+ {
+ try
+ {
+ return double.Parse(obj.ToString());
+ }
+ catch
+ {
+ return 0;
+ }
+ }
+
+ ///
+ /// 将object转换为double,若失败则返回指定值
+ ///
+ ///
+ ///
+ ///
+ public static double ParseToDouble(this object str, double defaultValue)
+ {
+ try
+ {
+ return double.Parse(str.ToString());
+ }
+ catch
+ {
+ return defaultValue;
+ }
+ }
+
+ ///
+ /// 将string转换为DateTime,若失败则返回日期最小值
+ ///
+ ///
+ ///
+ public static DateTime ParseToDateTime(this string str)
+ {
+ try
+ {
+ if (string.IsNullOrWhiteSpace(str))
+ {
+ return DateTime.MinValue;
+ }
+ if (str.Contains('-') || str.Contains('/'))
+ {
+ return DateTime.Parse(str);
+ }
+ else
+ {
+ int length = str.Length;
+ switch (length)
+ {
+ case 4:
+ return DateTime.ParseExact(str, "yyyy", System.Globalization.CultureInfo.CurrentCulture);
+
+ case 6:
+ return DateTime.ParseExact(str, "yyyyMM", System.Globalization.CultureInfo.CurrentCulture);
+
+ case 8:
+ return DateTime.ParseExact(str, "yyyyMMdd", System.Globalization.CultureInfo.CurrentCulture);
+
+ case 10:
+ return DateTime.ParseExact(str, "yyyyMMddHH", System.Globalization.CultureInfo.CurrentCulture);
+
+ case 12:
+ return DateTime.ParseExact(str, "yyyyMMddHHmm", System.Globalization.CultureInfo.CurrentCulture);
+
+ case 14:
+ return DateTime.ParseExact(str, "yyyyMMddHHmmss", System.Globalization.CultureInfo.CurrentCulture);
+
+ default:
+ return DateTime.ParseExact(str, "yyyyMMddHHmmss", System.Globalization.CultureInfo.CurrentCulture);
+ }
+ }
+ }
+ catch
+ {
+ return DateTime.MinValue;
+ }
+ }
+
+ ///
+ /// 将string转换为DateTime,若失败则返回默认值
+ ///
+ ///
+ ///
+ ///
+ public static DateTime ParseToDateTime(this string str, DateTime? defaultValue)
+ {
+ try
+ {
+ if (string.IsNullOrWhiteSpace(str))
+ {
+ return defaultValue.GetValueOrDefault();
+ }
+ if (str.Contains('-') || str.Contains('/'))
+ {
+ return DateTime.Parse(str);
+ }
+ else
+ {
+ int length = str.Length;
+ switch (length)
+ {
+ case 4:
+ return DateTime.ParseExact(str, "yyyy", System.Globalization.CultureInfo.CurrentCulture);
+
+ case 6:
+ return DateTime.ParseExact(str, "yyyyMM", System.Globalization.CultureInfo.CurrentCulture);
+
+ case 8:
+ return DateTime.ParseExact(str, "yyyyMMdd", System.Globalization.CultureInfo.CurrentCulture);
+
+ case 10:
+ return DateTime.ParseExact(str, "yyyyMMddHH", System.Globalization.CultureInfo.CurrentCulture);
+
+ case 12:
+ return DateTime.ParseExact(str, "yyyyMMddHHmm", System.Globalization.CultureInfo.CurrentCulture);
+
+ case 14:
+ return DateTime.ParseExact(str, "yyyyMMddHHmmss", System.Globalization.CultureInfo.CurrentCulture);
+
+ default:
+ return DateTime.ParseExact(str, "yyyyMMddHHmmss", System.Globalization.CultureInfo.CurrentCulture);
+ }
+ }
+ }
+ catch
+ {
+ return defaultValue.GetValueOrDefault();
+ }
+ }
+
+ ///
+ /// 将 string 时间日期格式转换成字符串 如 {yyyy} => 2024
+ ///
+ ///
+ ///
+ public static string ParseToDateTimeForRep(this string str)
+ {
+ if (string.IsNullOrWhiteSpace(str))
+ str = $"{DateTime.Now.Year}/{DateTime.Now.Month}/{DateTime.Now.Day}";
+
+ var date = DateTime.Now;
+ var reg = new Regex(@"(\{.+?})");
+ var match = reg.Matches(str);
+ match.ToList().ForEach(u =>
+ {
+ var temp = date.ToString(u.ToString().Substring(1, u.Length - 2));
+ str = str.Replace(u.ToString(), temp);
+ });
+ return str;
+ }
+
+ ///
+ /// 是否有值
+ ///
+ ///
+ ///
+ public static bool IsNullOrEmpty(this object obj)
+ {
+ return obj == null || string.IsNullOrEmpty(obj.ToString());
+ }
+
+ ///
+ /// 字符串掩码
+ ///
+ /// 字符串
+ /// 掩码符
+ ///
+ public static string Mask(this string str, char mask = '*')
+ {
+ if (string.IsNullOrWhiteSpace(str?.Trim()))
+ return str;
+
+ str = str.Trim();
+ var masks = mask.ToString().PadLeft(4, mask);
+ return str.Length switch
+ {
+ >= 11 => Regex.Replace(str, "(.{3}).*(.{4})", $"$1{masks}$2"),
+ 10 => Regex.Replace(str, "(.{3}).*(.{3})", $"$1{masks}$2"),
+ 9 => Regex.Replace(str, "(.{2}).*(.{3})", $"$1{masks}$2"),
+ 8 => Regex.Replace(str, "(.{2}).*(.{2})", $"$1{masks}$2"),
+ 7 => Regex.Replace(str, "(.{1}).*(.{2})", $"$1{masks}$2"),
+ 6 => Regex.Replace(str, "(.{1}).*(.{1})", $"$1{masks}$2"),
+ _ => Regex.Replace(str, "(.{1}).*", $"$1{masks}")
+ };
+ }
+
+ ///
+ /// 身份证号掩码
+ ///
+ /// 身份证号
+ /// 掩码符
+ ///
+ public static string MaskIdCard(this string idCard, char mask = '*')
+ {
+ if (!idCard.TryValidate(ValidationTypes.IDCard).IsValid) return idCard;
+
+ var masks = mask.ToString().PadLeft(8, mask);
+ return Regex.Replace(idCard, @"^(.{6})(.*)(.{4})$", $"$1{masks}$3");
+ }
+
+ ///
+ /// 邮箱掩码
+ ///
+ /// 邮箱
+ /// 掩码符
+ ///
+ public static string MaskEmail(this string email, char mask = '*')
+ {
+ if (!email.TryValidate(ValidationTypes.EmailAddress).IsValid) return email;
+
+ var pos = email.IndexOf("@");
+ return Mask(email[..pos], mask) + email[pos..];
+ }
+
+ ///
+ /// 将字符串转为值类型,若没有得到或者错误返回为空
+ ///
+ /// 指定值类型
+ /// 传入字符串
+ /// 可空值
+ public static T? ParseTo(this string str) where T : struct
+ {
+ try
+ {
+ if (!string.IsNullOrWhiteSpace(str))
+ {
+ MethodInfo method = typeof(T).GetMethod("Parse", new Type[] { typeof(string) });
+ if (method != null)
+ {
+ T result = (T)method.Invoke(null, new string[] { str });
+ return result;
+ }
+ }
+ }
+ catch
+ {
+ }
+ return null;
+ }
+
+ ///
+ /// 将字符串转为值类型,若没有得到或者错误返回为空
+ ///
+ /// 传入字符串
+ /// 目标类型
+ /// 可空值
+ public static object ParseTo(this string str, Type type)
+ {
+ try
+ {
+ if (type.Name == "String")
+ return str;
+
+ if (!string.IsNullOrWhiteSpace(str))
+ {
+ var _type = type;
+ if (type.Name.StartsWith("Nullable"))
+ _type = type.GetGenericArguments()[0];
+
+ MethodInfo method = _type.GetMethod("Parse", new Type[] { typeof(string) });
+ if (method != null)
+ return method.Invoke(null, new string[] { str });
+ }
+ }
+ catch
+ {
+ }
+ return null;
+ }
+
+ ///
+ /// 将一个对象属性值赋给另一个指定对象属性, 只复制相同属性的
+ ///
+ /// 原数据对象
+ /// 目标数据对象
+ /// 属性集,键为原属性,值为目标属性
+ /// 属性集,目标不修改的属性
+ public static void CopyTo(object src, object target, Dictionary changeProperties = null, string[] unChangeProperties = null)
+ {
+ if (src == null || target == null)
+ throw new ArgumentException("src == null || target == null ");
+
+ var SourceType = src.GetType();
+ var TargetType = target.GetType();
+
+ if (changeProperties == null || changeProperties.Count == 0)
+ {
+ var fields = TargetType.GetProperties();
+ changeProperties = fields.Select(m => m.Name).ToDictionary(m => m);
+ }
+
+ if (unChangeProperties == null || unChangeProperties.Length == 0)
+ {
+ foreach (var item in changeProperties)
+ {
+ var srcProperty = SourceType.GetProperty(item.Key);
+ if (srcProperty != null)
+ {
+ var sourceVal = srcProperty.GetValue(src, null);
+
+ var tarProperty = TargetType.GetProperty(item.Value);
+ tarProperty?.SetValue(target, sourceVal, null);
+ }
+ }
+ }
+ else
+ {
+ foreach (var item in changeProperties)
+ {
+ if (!unChangeProperties.Any(m => m == item.Value))
+ {
+ var srcProperty = SourceType.GetProperty(item.Key);
+ if (srcProperty != null)
+ {
+ var sourceVal = srcProperty.GetValue(src, null);
+
+ var tarProperty = TargetType.GetProperty(item.Value);
+ tarProperty?.SetValue(target, sourceVal, null);
+ }
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/Admin.NET/Admin.NET.Core/Extension/RepositoryExtension.cs b/Admin.NET/Admin.NET.Core/Extension/RepositoryExtension.cs
new file mode 100644
index 00000000..c0b518ac
--- /dev/null
+++ b/Admin.NET/Admin.NET.Core/Extension/RepositoryExtension.cs
@@ -0,0 +1,407 @@
+// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
+//
+// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
+//
+// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
+
+using MapsterMapper;
+
+namespace Admin.NET.Core;
+
+public static class RepositoryExtension
+{
+ ///
+ /// 实体假删除 _rep.FakeDelete(entity)
+ ///
+ ///
+ ///
+ ///
+ ///
+ public static int FakeDelete(this ISugarRepository repository, T entity) where T : EntityBase, new()
+ {
+ return repository.Context.FakeDelete(entity);
+ }
+
+ ///
+ /// 实体假删除 db.FakeDelete(entity)
+ ///
+ ///
+ ///
+ ///
+ ///
+ public static int FakeDelete(this ISqlSugarClient db, T entity) where T : EntityBase, new()
+ {
+ return db.Updateable(entity).AS().ReSetValue(x => { x.IsDelete = true; })
+ .IgnoreColumns(ignoreAllNullColumns: true)
+ .EnableDiffLogEvent() // 记录差异日志
+ .UpdateColumns(x => new { x.IsDelete, x.UpdateTime, x.UpdateUserId }) // 允许更新的字段-AOP拦截自动设置UpdateTime、UpdateUserId
+ .ExecuteCommand();
+ }
+
+ ///
+ /// 实体集合批量假删除 _rep.FakeDelete(entity)
+ ///
+ ///
+ ///
+ ///
+ ///
+ public static int FakeDelete(this ISugarRepository repository, List entity) where T : EntityBase, new()
+ {
+ return repository.Context.FakeDelete(entity);
+ }
+
+ ///
+ /// 实体集合批量假删除 db.FakeDelete(entity)
+ ///
+ ///
+ ///
+ ///
+ ///
+ public static int FakeDelete(this ISqlSugarClient db, List entity) where T : EntityBase, new()
+ {
+ return db.Updateable(entity).AS().ReSetValue(x => { x.IsDelete = true; })
+ .IgnoreColumns(ignoreAllNullColumns: true)
+ .EnableDiffLogEvent() // 记录差异日志
+ .UpdateColumns(x => new { x.IsDelete, x.UpdateTime, x.UpdateUserId }) // 允许更新的字段-AOP拦截自动设置UpdateTime、UpdateUserId
+ .ExecuteCommand();
+ }
+
+ ///
+ /// 实体假删除异步 _rep.FakeDeleteAsync(entity)
+ ///
+ ///
+ ///
+ ///
+ ///
+ public static Task FakeDeleteAsync(this ISugarRepository repository, T entity) where T : EntityBase, new()
+ {
+ return repository.Context.FakeDeleteAsync(entity);
+ }
+
+ ///
+ /// 实体假删除 db.FakeDelete(entity)
+ ///
+ ///
+ ///
+ ///
+ ///
+ public static Task FakeDeleteAsync(this ISqlSugarClient db, T entity) where T : EntityBase, new()
+ {
+ return db.Updateable(entity).AS().ReSetValue(x => { x.IsDelete = true; })
+ .IgnoreColumns(ignoreAllNullColumns: true)
+ .EnableDiffLogEvent() // 记录差异日志
+ .UpdateColumns(x => new { x.IsDelete, x.UpdateTime, x.UpdateUserId }) // 允许更新的字段-AOP拦截自动设置UpdateTime、UpdateUserId
+ .ExecuteCommandAsync();
+ }
+
+ ///
+ /// 实体集合批量假删除异步 _rep.FakeDeleteAsync(entity)
+ ///
+ ///
+ ///
+ ///
+ ///
+ public static Task FakeDeleteAsync(this ISugarRepository repository, List entity) where T : EntityBase, new()
+ {
+ return repository.Context.FakeDeleteAsync(entity);
+ }
+
+ ///
+ /// 实体集合批量假删除 db.FakeDelete(entity)
+ ///
+ ///
+ ///
+ ///
+ ///
+ public static Task FakeDeleteAsync(this ISqlSugarClient db, List entity) where T : EntityBase, new()
+ {
+ return db.Updateable(entity).AS().ReSetValue(x => { x.IsDelete = true; })
+ .IgnoreColumns(ignoreAllNullColumns: true)
+ .EnableDiffLogEvent() // 记录差异日志
+ .UpdateColumns(x => new { x.IsDelete, x.UpdateTime, x.UpdateUserId }) // 允许更新的字段-AOP拦截自动设置UpdateTime、UpdateUserId
+ .ExecuteCommandAsync();
+ }
+
+ ///
+ /// 排序方式(默认降序)
+ ///
+ ///
+ ///
+ ///
+ /// 默认排序字段
+ /// 是否降序
+ ///
+ public static ISugarQueryable OrderBuilder(this ISugarQueryable queryable, BasePageInput pageInput, string prefix = "", string defaultSortField = "Id", bool descSort = true)
+ {
+ // 约定默认每张表都有Id排序
+ var orderStr = string.IsNullOrWhiteSpace(defaultSortField) ? "" : $"{prefix}{defaultSortField}" + (descSort ? " Desc" : " Asc");
+
+ TypeAdapterConfig typeAdapterConfig = new();
+ typeAdapterConfig.ForType().IgnoreNullValues(true);
+ Mapper mapper = new(typeAdapterConfig); // 务必将mapper设为单实例
+ var nowPagerInput = mapper.Map(pageInput);
+ // 排序是否可用-排序字段和排序顺序都为非空才启用排序
+ if (!string.IsNullOrEmpty(nowPagerInput.Field) && !string.IsNullOrEmpty(nowPagerInput.Order))
+ {
+ var col = queryable.Context.EntityMaintenance.GetEntityInfo().Columns.FirstOrDefault(u => u.PropertyName.Equals(nowPagerInput.Field, StringComparison.CurrentCultureIgnoreCase));
+ orderStr = col != null
+ ? $"{prefix}{col.DbColumnName} {(nowPagerInput.Order == nowPagerInput.DescStr ? "Desc" : "Asc")}"
+ : $"{prefix}{nowPagerInput.Field} {(nowPagerInput.Order == nowPagerInput.DescStr ? "Desc" : "Asc")}";
+ }
+ return queryable.OrderByIF(!string.IsNullOrWhiteSpace(orderStr), orderStr);
+ }
+
+ ///
+ /// 更新实体并记录差异日志 _rep.UpdateWithDiffLog(entity)
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ public static int UpdateWithDiffLog(this ISugarRepository repository, T entity, bool ignoreAllNullColumns = true) where T : EntityBase, new()
+ {
+ return repository.Context.UpdateWithDiffLog(entity, ignoreAllNullColumns);
+ }
+
+ ///
+ /// 更新实体并记录差异日志 _rep.UpdateWithDiffLog(entity)
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ public static int UpdateWithDiffLog(this ISqlSugarClient db, T entity, bool ignoreAllNullColumns = true) where T : EntityBase, new()
+ {
+ return db.Updateable(entity).AS()
+ .IgnoreColumns(ignoreAllNullColumns: ignoreAllNullColumns)
+ .EnableDiffLogEvent()
+ .ExecuteCommand();
+ }
+
+ ///
+ /// 更新实体并记录差异日志 _rep.UpdateWithDiffLogAsync(entity)
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ public static Task UpdateWithDiffLogAsync(this ISugarRepository repository, T entity, bool ignoreAllNullColumns = true) where T : EntityBase, new()
+ {
+ return repository.Context.UpdateWithDiffLogAsync(entity, ignoreAllNullColumns);
+ }
+
+ ///
+ /// 更新实体并记录差异日志 _rep.UpdateWithDiffLogAsync(entity)
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ public static Task UpdateWithDiffLogAsync(this ISqlSugarClient db, T entity, bool ignoreAllNullColumns = true) where T : EntityBase, new()
+ {
+ return db.Updateable(entity)
+ .IgnoreColumns(ignoreAllNullColumns: ignoreAllNullColumns)
+ .EnableDiffLogEvent()
+ .ExecuteCommandAsync();
+ }
+
+ ///
+ /// 新增实体并记录差异日志 _rep.InsertWithDiffLog(entity)
+ ///
+ ///
+ ///
+ ///
+ ///
+ public static int InsertWithDiffLog(this ISugarRepository repository, T entity) where T : EntityBase, new()
+ {
+ return repository.Context.InsertWithDiffLog(entity);
+ }
+
+ ///
+ /// 新增实体并记录差异日志 _rep.InsertWithDiffLog(entity)
+ ///
+ ///
+ ///
+ ///
+ ///
+ public static int InsertWithDiffLog(this ISqlSugarClient db, T entity) where T : EntityBase, new()
+ {
+ return db.Insertable(entity).AS().EnableDiffLogEvent().ExecuteCommand();
+ }
+
+ ///
+ /// 新增实体并记录差异日志 _rep.InsertWithDiffLogAsync(entity)
+ ///
+ ///
+ ///
+ ///
+ ///
+ public static Task InsertWithDiffLogAsync(this ISugarRepository repository, T entity) where T : EntityBase, new()
+ {
+ return repository.Context.InsertWithDiffLogAsync(entity);
+ }
+
+ ///
+ /// 新增实体并记录差异日志 _rep.InsertWithDiffLog(entity)
+ ///
+ ///
+ ///
+ ///
+ ///
+ public static Task InsertWithDiffLogAsync(this ISqlSugarClient db, T entity) where T : EntityBase, new()
+ {
+ return db.Insertable(entity).AS().EnableDiffLogEvent().ExecuteCommandAsync();
+ }
+
+ ///
+ /// 多库查询
+ ///
+ ///
+ ///
+ public static ISugarQueryable AS(this ISugarQueryable queryable)
+ {
+ var info = GetTableInfo();
+ return queryable.AS($"{info.Item1}.{info.Item2}");
+ }
+
+ ///
+ /// 多库查询
+ ///
+ ///
+ ///
+ ///
+ ///
+ public static ISugarQueryable AS(this ISugarQueryable queryable)
+ {
+ var info = GetTableInfo();
+ return queryable.AS($"{info.Item1}.{info.Item2}");
+ }
+
+ ///
+ /// 多库更新
+ ///
+ ///
+ ///
+ public static IUpdateable AS(this IUpdateable updateable) where T : EntityBase, new()
+ {
+ var info = GetTableInfo();
+ return updateable.AS($"{info.Item1}.{info.Item2}");
+ }
+
+ ///
+ /// 多库新增
+ ///
+ ///
+ ///
+ public static IInsertable AS(this IInsertable insertable) where T : EntityBase, new()
+ {
+ var info = GetTableInfo();
+ return insertable.AS($"{info.Item1}.{info.Item2}");
+ }
+
+ ///
+ /// 多库删除
+ ///
+ ///
+ ///
+ public static IDeleteable AS(this IDeleteable deleteable) where T : EntityBase, new()
+ {
+ var info = GetTableInfo();
+ return deleteable.AS($"{info.Item1}.{info.Item2}");
+ }
+
+ ///
+ /// 根据实体类型获取表信息
+ ///
+ ///
+ ///
+ private static Tuple GetTableInfo()
+ {
+ var entityType = typeof(T);
+ var attr = entityType.GetCustomAttribute();
+ var configId = attr == null ? SqlSugarConst.MainConfigId : attr.configId.ToString();
+ var tableName = entityType.GetCustomAttribute().TableName;
+ return new Tuple(configId, tableName);
+ }
+
+ ///
+ /// 禁用过滤器-适用于更新和删除操作(只对当前请求有效,禁止使用异步)
+ ///
+ ///
+ /// 禁止异步
+ ///
+ public static void RunWithoutFilter(this ISugarRepository repository, Action action)
+ {
+ repository.Context.QueryFilter.ClearAndBackup(); // 清空并备份过滤器
+ action.Invoke();
+ repository.Context.QueryFilter.Restore(); // 还原过滤器
+
+ // 用例
+ //_rep.RunWithoutFilter(() =>
+ //{
+ // 执行更新或者删除
+ // 禁止使用异步函数
+ //});
+ }
+
+ ///
+ /// 忽略租户
+ ///
+ ///
+ /// 是否忽略 默认true
+ ///
+ public static ISugarQueryable IgnoreTenant(this ISugarQueryable queryable, bool ignore = true)
+ {
+ return ignore ? queryable.ClearFilter() : queryable;
+ }
+
+ ///
+ /// 导航+子表过滤 创建一个扩展函数,默认是Class不支持Where
+ ///
+ ///
+ ///
+ ///
+ ///
+ public static List Where(this T thisValue, Func whereExpression) where T : class, new()
+ {
+ return new List() { thisValue };
+ }
+
+ ///
+ /// 导航+子表过滤 创建一个扩展函数,默认是Class不支持WhereIF
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ public static List WhereIF(this T thisValue, bool isWhere, Func whereExpression) where T : class, new()
+ {
+ return new List() { thisValue };
+ }
+
+ ///
+ /// 只更新某些列
+ ///
+ ///
+ ///
+ ///
+ ///
+ public static IUpdateable OnlyUpdateColumn(this IUpdateable updateable) where T : EntityBase, new() where R : class, new()
+ {
+ if (updateable.UpdateBuilder.UpdateColumns == null)
+ updateable.UpdateBuilder.UpdateColumns = new List();
+
+ foreach (PropertyInfo info in typeof(R).GetProperties())
+ {
+ // 判断是否是相同属性
+ if (typeof(T).GetProperty(info.Name) != null)
+ updateable.UpdateBuilder.UpdateColumns.Add(info.Name);
+ }
+ return updateable;
+ }
+}
\ No newline at end of file
diff --git a/Admin.NET/Admin.NET.Core/GlobalUsings.cs b/Admin.NET/Admin.NET.Core/GlobalUsings.cs
new file mode 100644
index 00000000..8382f900
--- /dev/null
+++ b/Admin.NET/Admin.NET.Core/GlobalUsings.cs
@@ -0,0 +1,62 @@
+// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
+//
+// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
+//
+// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
+
+global using Admin.NET.Core.Service;
+global using Furion;
+global using Furion.ClayObject;
+global using Furion.ConfigurableOptions;
+global using Furion.DatabaseAccessor;
+global using Furion.DataEncryption;
+global using Furion.DataValidation;
+global using Furion.DependencyInjection;
+global using Furion.DynamicApiController;
+global using Furion.EventBus;
+global using Furion.FriendlyException;
+global using Furion.JsonSerialization;
+global using Furion.Logging;
+global using Furion.RemoteRequest.Extensions;
+global using Furion.Schedule;
+global using Furion.UnifyResult;
+global using Furion.ViewEngine;
+global using Magicodes.ExporterAndImporter.Core;
+global using Magicodes.ExporterAndImporter.Core.Extension;
+global using Magicodes.ExporterAndImporter.Excel;
+global using Mapster;
+global using Microsoft.AspNetCore.Authorization;
+global using Microsoft.AspNetCore.Http;
+global using Microsoft.AspNetCore.Mvc;
+global using Microsoft.AspNetCore.Mvc.Filters;
+global using Microsoft.Extensions.Configuration;
+global using Microsoft.Extensions.DependencyInjection;
+global using Microsoft.Extensions.Hosting;
+global using Microsoft.Extensions.Logging;
+global using Microsoft.Extensions.Options;
+global using NewLife;
+global using NewLife.Caching;
+global using Newtonsoft.Json.Linq;
+global using SKIT.FlurlHttpClient;
+global using SKIT.FlurlHttpClient.Wechat.Api;
+global using SKIT.FlurlHttpClient.Wechat.Api.Models;
+global using SKIT.FlurlHttpClient.Wechat.TenpayV3;
+global using SKIT.FlurlHttpClient.Wechat.TenpayV3.Events;
+global using SKIT.FlurlHttpClient.Wechat.TenpayV3.Models;
+global using SKIT.FlurlHttpClient.Wechat.TenpayV3.Settings;
+global using SqlSugar;
+global using System.Collections;
+global using System.Collections.Concurrent;
+global using System.ComponentModel;
+global using System.ComponentModel.DataAnnotations;
+global using System.Data;
+global using System.Diagnostics;
+global using System.Linq.Dynamic.Core;
+global using System.Linq.Expressions;
+global using System.Reflection;
+global using System.Runtime.InteropServices;
+global using System.Text;
+global using System.Text.RegularExpressions;
+global using System.Web;
+global using UAParser;
+global using Yitter.IdGenerator;
\ No newline at end of file
diff --git a/Admin.NET/Admin.NET.Core/Hub/Dto/OnlineUserHubInput.cs b/Admin.NET/Admin.NET.Core/Hub/Dto/OnlineUserHubInput.cs
new file mode 100644
index 00000000..386ad74b
--- /dev/null
+++ b/Admin.NET/Admin.NET.Core/Hub/Dto/OnlineUserHubInput.cs
@@ -0,0 +1,12 @@
+// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
+//
+// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
+//
+// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
+
+namespace Admin.NET.Core;
+
+public class OnlineUserHubInput
+{
+ public string ConnectionId { get; set; }
+}
\ No newline at end of file
diff --git a/Admin.NET/Admin.NET.Core/Hub/Dto/OnlineUserHubOutput.cs b/Admin.NET/Admin.NET.Core/Hub/Dto/OnlineUserHubOutput.cs
new file mode 100644
index 00000000..90c44251
--- /dev/null
+++ b/Admin.NET/Admin.NET.Core/Hub/Dto/OnlineUserHubOutput.cs
@@ -0,0 +1,16 @@
+// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
+//
+// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
+//
+// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
+
+namespace Admin.NET.Core;
+
+public class OnlineUserList
+{
+ public string RealName { get; set; }
+
+ public bool Online { get; set; }
+
+ public List UserList { get; set; }
+}
\ No newline at end of file
diff --git a/Admin.NET/Admin.NET.Core/Hub/IOnlineUserHub.cs b/Admin.NET/Admin.NET.Core/Hub/IOnlineUserHub.cs
new file mode 100644
index 00000000..64fa9a29
--- /dev/null
+++ b/Admin.NET/Admin.NET.Core/Hub/IOnlineUserHub.cs
@@ -0,0 +1,38 @@
+// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
+//
+// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
+//
+// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
+
+namespace Admin.NET.Core;
+
+public interface IOnlineUserHub
+{
+ ///
+ /// 在线用户列表
+ ///
+ ///
+ ///
+ Task OnlineUserList(OnlineUserList context);
+
+ ///
+ /// 强制下线
+ ///
+ ///
+ ///
+ Task ForceOffline(object context);
+
+ ///
+ /// 发布站内消息
+ ///
+ ///
+ ///
+ Task PublicNotice(SysNotice context);
+
+ ///
+ /// 接收消息
+ ///
+ ///
+ ///
+ Task ReceiveMessage(object context);
+}
\ No newline at end of file
diff --git a/Admin.NET/Admin.NET.Core/Hub/OnlineUserHub.cs b/Admin.NET/Admin.NET.Core/Hub/OnlineUserHub.cs
new file mode 100644
index 00000000..7973e694
--- /dev/null
+++ b/Admin.NET/Admin.NET.Core/Hub/OnlineUserHub.cs
@@ -0,0 +1,179 @@
+// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
+//
+// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
+//
+// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
+
+using Furion.InstantMessaging;
+using Microsoft.AspNetCore.SignalR;
+
+namespace Admin.NET.Core;
+
+///
+/// 在线用户集线器
+///
+[MapHub("/hubs/onlineUser")]
+public class OnlineUserHub : Hub
+{
+ private const string GROUP_ONLINE = "GROUP_ONLINE_"; // 租户分组前缀
+
+ private readonly SqlSugarRepository _sysOnlineUerRep;
+ private readonly SysMessageService _sysMessageService;
+ private readonly IHubContext _onlineUserHubContext;
+ private readonly SysCacheService _sysCacheService;
+ private readonly SysConfigService _sysConfigService;
+
+ public OnlineUserHub(SqlSugarRepository sysOnlineUerRep,
+ SysMessageService sysMessageService,
+ IHubContext onlineUserHubContext,
+ SysCacheService sysCacheService,
+ SysConfigService sysConfigService)
+ {
+ _sysOnlineUerRep = sysOnlineUerRep;
+ _sysMessageService = sysMessageService;
+ _onlineUserHubContext = onlineUserHubContext;
+ _sysCacheService = sysCacheService;
+ _sysConfigService = sysConfigService;
+ }
+
+ ///
+ /// 连接
+ ///
+ ///
+ public override async Task OnConnectedAsync()
+ {
+ var httpContext = Context.GetHttpContext();
+ var token = httpContext.Request.Query["access_token"];
+ var claims = JWTEncryption.ReadJwtToken(token)?.Claims;
+ var client = Parser.GetDefault().Parse(httpContext.Request.Headers["User-Agent"]);
+
+ var userId = claims?.FirstOrDefault(u => u.Type == ClaimConst.UserId)?.Value;
+ var tenantId = claims?.FirstOrDefault(u => u.Type == ClaimConst.TenantId)?.Value;
+ var user = new SysOnlineUser
+ {
+ ConnectionId = Context.ConnectionId,
+ UserId = string.IsNullOrWhiteSpace(userId) ? 0 : long.Parse(userId),
+ UserName = claims?.FirstOrDefault(u => u.Type == ClaimConst.Account)?.Value,
+ RealName = claims?.FirstOrDefault(u => u.Type == ClaimConst.RealName)?.Value,
+ Time = DateTime.Now,
+ Ip = httpContext.Connection.RemoteIpAddress.MapToIPv4().ToString(),
+ Browser = client.UA.Family + client.UA.Major,
+ Os = client.OS.Family + client.OS.Major,
+ TenantId = string.IsNullOrWhiteSpace(tenantId) ? 0 : Convert.ToInt64(tenantId),
+ };
+ await _sysOnlineUerRep.InsertAsync(user);
+
+ // 是否开启单用户登录
+ if (await _sysConfigService.GetConfigValue(CommonConst.SysSingleLogin))
+ {
+ _sysCacheService.Set(CacheConst.KeyUserOnline + user.UserId, user);
+ }
+ else
+ {
+ var device = (client.UA.Family + client.UA.Major + client.OS.Family + client.OS.Major).Trim();
+ _sysCacheService.Set(CacheConst.KeyUserOnline + user.UserId + device, user);
+ }
+
+ // 以租户Id进行分组
+ var groupName = $"{GROUP_ONLINE}{user.TenantId}";
+ await _onlineUserHubContext.Groups.AddToGroupAsync(Context.ConnectionId, groupName);
+
+ var userList = await _sysOnlineUerRep.AsQueryable().Filter("", true)
+ .Where(u => u.TenantId == user.TenantId).Take(10).ToListAsync();
+ await _onlineUserHubContext.Clients.Groups(groupName).OnlineUserList(new OnlineUserList
+ {
+ RealName = user.RealName,
+ Online = true,
+ UserList = userList
+ });
+ }
+
+ ///
+ /// 断开
+ ///
+ ///
+ ///
+ public override async Task OnDisconnectedAsync(Exception exception)
+ {
+ if (string.IsNullOrEmpty(Context.ConnectionId)) return;
+
+ var httpContext = Context.GetHttpContext();
+ var client = Parser.GetDefault().Parse(httpContext.Request.Headers["User-Agent"]);
+
+ var user = await _sysOnlineUerRep.AsQueryable().Filter("", true).FirstAsync(u => u.ConnectionId == Context.ConnectionId);
+ if (user == null) return;
+
+ await _sysOnlineUerRep.DeleteAsync(u => u.Id == user.Id);
+
+ // 是否开启单用户登录
+ if (await _sysConfigService.GetConfigValue(CommonConst.SysSingleLogin))
+ {
+ _sysCacheService.Remove(CacheConst.KeyUserOnline + user.UserId);
+ }
+ else
+ {
+ var device = (client.UA.Family + client.UA.Major + client.OS.Family + client.OS.Major).Trim();
+ _sysCacheService.Remove(CacheConst.KeyUserOnline + user.UserId + device);
+ }
+
+ // 通知当前组用户变动
+ var userList = await _sysOnlineUerRep.AsQueryable().Filter("", true)
+ .Where(u => u.TenantId == user.TenantId).Take(10).ToListAsync();
+ await _onlineUserHubContext.Clients.Groups($"{GROUP_ONLINE}{user.TenantId}").OnlineUserList(new OnlineUserList
+ {
+ RealName = user.RealName,
+ Online = false,
+ UserList = userList
+ });
+ }
+
+ ///
+ /// 强制下线
+ ///
+ ///
+ ///
+ public async Task ForceOffline(OnlineUserHubInput input)
+ {
+ await _onlineUserHubContext.Clients.Client(input.ConnectionId).ForceOffline("强制下线");
+ }
+
+ ///
+ /// 发送信息给某个人
+ ///
+ ///
+ ///
+ public async Task ClientsSendMessage(MessageInput message)
+ {
+ await _sysMessageService.SendUser(message);
+ }
+
+ ///
+ /// 发送信息给所有人
+ ///
+ ///
+ ///
+ public async Task ClientsSendMessagetoAll(MessageInput message)
+ {
+ await _sysMessageService.SendAllUser(message);
+ }
+
+ ///
+ /// 发送消息给某些人(除了本人)
+ ///
+ ///
+ ///
+ public async Task ClientsSendMessagetoOther(MessageInput message)
+ {
+ await _sysMessageService.SendOtherUser(message);
+ }
+
+ ///
+ /// 发送消息给某些人
+ ///
+ ///
+ ///
+ public async Task ClientsSendMessagetoUsers(MessageInput message)
+ {
+ await _sysMessageService.SendUsers(message);
+ }
+}
\ No newline at end of file
diff --git a/Admin.NET/Admin.NET.Core/Hub/UserIdProvider.cs b/Admin.NET/Admin.NET.Core/Hub/UserIdProvider.cs
new file mode 100644
index 00000000..fa6dec89
--- /dev/null
+++ b/Admin.NET/Admin.NET.Core/Hub/UserIdProvider.cs
@@ -0,0 +1,17 @@
+// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
+//
+// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
+//
+// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
+
+using Microsoft.AspNetCore.SignalR;
+
+namespace Admin.NET.Core;
+
+public interface UserIdProvider : IUserIdProvider
+{
+ public new string GetUserId(HubConnectionContext connection)
+ {
+ return connection.User?.Claims?.FirstOrDefault(u => u.Type == ClaimConst.UserId)?.Value;
+ }
+}
\ No newline at end of file
diff --git a/Admin.NET/Admin.NET.Core/Job/DynamicJobCompiler.cs b/Admin.NET/Admin.NET.Core/Job/DynamicJobCompiler.cs
new file mode 100644
index 00000000..67eb8fa2
--- /dev/null
+++ b/Admin.NET/Admin.NET.Core/Job/DynamicJobCompiler.cs
@@ -0,0 +1,25 @@
+// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
+//
+// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
+//
+// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
+
+namespace Admin.NET.Core;
+
+///
+/// 动态作业编译
+///
+public class DynamicJobCompiler : ISingleton
+{
+ ///
+ /// 编译代码并返回其中实现 IJob 的类型
+ ///
+ /// 动态编译的作业代码
+ ///
+ public Type BuildJob(string script)
+ {
+ var jobAssembly = Schedular.CompileCSharpClassCode(script);
+ var jobType = jobAssembly.GetTypes().FirstOrDefault(u => typeof(IJob).IsAssignableFrom(u));
+ return jobType;
+ }
+}
\ No newline at end of file
diff --git a/Admin.NET/Admin.NET.Core/Job/EnumToDictJob.cs b/Admin.NET/Admin.NET.Core/Job/EnumToDictJob.cs
new file mode 100644
index 00000000..c113b1bb
--- /dev/null
+++ b/Admin.NET/Admin.NET.Core/Job/EnumToDictJob.cs
@@ -0,0 +1,148 @@
+// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
+//
+// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
+//
+// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
+
+namespace Admin.NET.Core;
+
+///
+/// 枚举转字典
+///
+[JobDetail("job_EnumToDictJob", Description = "枚举转字典", GroupName = "default", Concurrent = false)]
+[PeriodSeconds(1, TriggerId = "trigger_EnumToDictJob", Description = "枚举转字典", MaxNumberOfRuns = 1, RunOnStart = true)]
+public class EnumToDictJob : IJob
+{
+ private readonly IServiceScopeFactory _scopeFactory;
+ private readonly IJsonSerializerProvider _jsonSerializer;
+
+ public EnumToDictJob(IServiceScopeFactory scopeFactory, IJsonSerializerProvider jsonSerializer)
+ {
+ _scopeFactory = scopeFactory;
+ _jsonSerializer = jsonSerializer;
+ }
+
+ public async Task ExecuteAsync(JobExecutingContext context, CancellationToken stoppingToken)
+ {
+ using var serviceScope = _scopeFactory.CreateScope();
+ var sysEnumService = serviceScope.ServiceProvider.GetRequiredService();
+ var db = serviceScope.ServiceProvider.GetRequiredService().CopyNew();
+
+ var enumTypeList = sysEnumService.GetEnumTypeList();
+ var enumCodeList = enumTypeList.Select(u => u.TypeName);
+ var sysDictTypeCodeList = await db.Queryable().Where(u => enumCodeList.Contains(u.Code)).Select(u => u.Code).ToListAsync(stoppingToken);
+
+ // 更新的枚举转换字典
+ var uEnumType = enumTypeList.Where(u => sysDictTypeCodeList.Contains(u.TypeName)).ToList();
+ var waitUpdateSysDictType = await db.Queryable().Where(u => uEnumType.Any(a => a.TypeName == u.Code)).ToListAsync(stoppingToken);
+ var waitUpdateSysDictTypeDict = waitUpdateSysDictType.ToDictionary(u => u.Code, u => u);
+ var waitUpdateSysDictData = await db.Queryable().Where(u => uEnumType.Any(a => a.TypeName == u.DictType.Code)).ToListAsync(stoppingToken);
+ var uSysDictType = new List();
+ var uSysDictData = new List();
+ if (uEnumType.Count > 0)
+ {
+ uEnumType.ForEach(e =>
+ {
+ if (waitUpdateSysDictTypeDict.TryGetValue(e.TypeName, out SysDictType value))
+ {
+ var uDictType = value;
+ uDictType.Name = e.TypeDescribe;
+ uDictType.Remark = e.TypeRemark;
+ var uDictData = waitUpdateSysDictData.Where(u => u.DictTypeId == uDictType.Id).ToList();
+ if (uDictData.Count > 0)
+ {
+ uDictData.ForEach(dictData =>
+ {
+ var enumData = e.EnumEntities.Where(u => dictData.Code == u.Name).FirstOrDefault();
+ if (enumData != null)
+ {
+ dictData.Value = enumData.Value.ToString();
+ dictData.Code = enumData.Name;
+ dictData.OrderNo = enumData.Value + 10;
+ uSysDictData.Add(dictData);
+ }
+ });
+ }
+ if (!uSysDictType.Any(u => u.Id == uDictType.Id))
+ uSysDictType.Add(uDictType);
+ }
+ });
+ try
+ {
+ db.Ado.BeginTran();
+
+ if (uSysDictType.Count > 0)
+ await db.Updateable(uSysDictType).ExecuteCommandAsync(stoppingToken);
+
+ if (uSysDictData.Count > 0)
+ await db.Updateable(uSysDictData).ExecuteCommandAsync(stoppingToken);
+
+ db.Ado.CommitTran();
+ }
+ catch (Exception error)
+ {
+ db.Ado.RollbackTran();
+ Log.Error($"{context.Trigger.Description}更新枚举转换字典入库错误:" + _jsonSerializer.Serialize(error));
+ throw new Exception($"{context.Trigger.Description}更新枚举转换字典入库错误");
+ }
+ }
+
+ // 新增的枚举转换字典
+ var iEnumType = enumTypeList.Where(u => !sysDictTypeCodeList.Contains(u.TypeName)).ToList();
+ if (iEnumType.Count > 0)
+ {
+ // 新增字典类型
+ var iDictType = iEnumType.Select(u => new SysDictType
+ {
+ Id = YitIdHelper.NextId(),
+ Code = u.TypeName,
+ Name = u.TypeDescribe,
+ Remark = u.TypeRemark,
+ Status = StatusEnum.Enable
+ }).ToList();
+ // 新增字典数据
+ var dictData = iEnumType.Join(iDictType, t1 => t1.TypeName, t2 => t2.Code, (t1, t2) => new
+ {
+ data = t1.EnumEntities.Select(u => new SysDictData
+ {
+ Id = YitIdHelper.NextId(), // 性能优化,使用BulkCopyAsync必须手动获取Id
+ DictTypeId = t2.Id,
+ Name = u.Describe,
+ Value = u.Value.ToString(),
+ Code = u.Name,
+ Remark = t2.Remark,
+ OrderNo = u.Value + 10,
+ TagType = "info"
+ }).ToList()
+ }).ToList();
+ var iDictData = new List();
+ dictData.ForEach(item =>
+ {
+ iDictData.AddRange(item.data);
+ });
+ try
+ {
+ db.Ado.BeginTran();
+
+ if (iDictType.Count > 0)
+ await db.Insertable(iDictType).ExecuteCommandAsync(stoppingToken);
+
+ if (iDictData.Count > 0)
+ await db.Insertable(iDictData).ExecuteCommandAsync(stoppingToken);
+
+ db.Ado.CommitTran();
+ }
+ catch (Exception error)
+ {
+ db.Ado.RollbackTran();
+ Log.Error($"{context.Trigger.Description}新增枚举转换字典入库错误:" + _jsonSerializer.Serialize(error));
+ throw new Exception($"{context.Trigger.Description}新增枚举转换字典入库错误");
+ }
+ }
+
+ var originColor = Console.ForegroundColor;
+ Console.ForegroundColor = ConsoleColor.Green;
+ Console.WriteLine($"【{DateTime.Now}】系统枚举转换字典");
+ Console.ForegroundColor = originColor;
+ }
+}
\ No newline at end of file
diff --git a/Admin.NET/Admin.NET.Core/Job/LogJob.cs b/Admin.NET/Admin.NET.Core/Job/LogJob.cs
new file mode 100644
index 00000000..b8afb512
--- /dev/null
+++ b/Admin.NET/Admin.NET.Core/Job/LogJob.cs
@@ -0,0 +1,46 @@
+// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
+//
+// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
+//
+// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
+
+namespace Admin.NET.Core;
+
+///
+/// 清理日志作业任务
+///
+[JobDetail("job_log", Description = "清理操作日志", GroupName = "default", Concurrent = false)]
+[Daily(TriggerId = "trigger_log", Description = "清理操作日志")]
+public class LogJob : IJob
+{
+ private readonly IServiceScopeFactory _scopeFactory;
+ private readonly ILogger _logger;
+
+ public LogJob(IServiceScopeFactory scopeFactory, ILoggerFactory loggerFactory)
+ {
+ _scopeFactory = scopeFactory;
+ _logger = loggerFactory.CreateLogger(CommonConst.SysLogCategoryName);
+ }
+
+ public async Task ExecuteAsync(JobExecutingContext context, CancellationToken stoppingToken)
+ {
+ using var serviceScope = _scopeFactory.CreateScope();
+
+ var logVisRep = serviceScope.ServiceProvider.GetRequiredService>();
+ var logOpRep = serviceScope.ServiceProvider.GetRequiredService>();
+ var logDiffRep = serviceScope.ServiceProvider.GetRequiredService>();
+
+ var daysAgo = 30; // 删除30天以前
+ await logVisRep.CopyNew().AsDeleteable().Where(u => (DateTime)u.CreateTime < DateTime.Now.AddDays(-daysAgo)).ExecuteCommandAsync(stoppingToken); // 删除访问日志
+ await logOpRep.CopyNew().AsDeleteable().Where(u => (DateTime)u.CreateTime < DateTime.Now.AddDays(-daysAgo)).ExecuteCommandAsync(stoppingToken); // 删除操作日志
+ await logDiffRep.CopyNew().AsDeleteable().Where(u => (DateTime)u.CreateTime < DateTime.Now.AddDays(-daysAgo)).ExecuteCommandAsync(stoppingToken); // 删除差异日志
+
+ var originColor = Console.ForegroundColor;
+ Console.ForegroundColor = ConsoleColor.Yellow;
+ Console.WriteLine($"【{DateTime.Now}】清理系统日志(30天前)");
+ Console.ForegroundColor = originColor;
+
+ // 自定义日志
+ _logger.LogInformation($"【{DateTime.Now}】清理系统日志...");
+ }
+}
\ No newline at end of file
diff --git a/Admin.NET/Admin.NET.Core/Job/OnlineUserJob.cs b/Admin.NET/Admin.NET.Core/Job/OnlineUserJob.cs
new file mode 100644
index 00000000..e1e929ea
--- /dev/null
+++ b/Admin.NET/Admin.NET.Core/Job/OnlineUserJob.cs
@@ -0,0 +1,45 @@
+// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
+//
+// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
+//
+// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
+
+using Furion.Logging.Extensions;
+
+namespace Admin.NET.Core;
+
+///
+/// 清理在线用户作业任务
+///
+[JobDetail("job_onlineUser", Description = "清理在线用户", GroupName = "default", Concurrent = false)]
+[PeriodSeconds(1, TriggerId = "trigger_onlineUser", Description = "清理在线用户", MaxNumberOfRuns = 1, RunOnStart = true)]
+public class OnlineUserJob : IJob
+{
+ private readonly IServiceScopeFactory _scopeFactory;
+ private readonly ILogger _logger;
+
+ public OnlineUserJob(IServiceScopeFactory scopeFactory, ILoggerFactory loggerFactory)
+ {
+ _scopeFactory = scopeFactory;
+ _logger = loggerFactory.CreateLogger(CommonConst.SysLogCategoryName);
+ }
+
+ public async Task ExecuteAsync(JobExecutingContext context, CancellationToken stoppingToken)
+ {
+ using var serviceScope = _scopeFactory.CreateScope();
+
+ var rep = serviceScope.ServiceProvider.GetRequiredService>();
+ await rep.CopyNew().AsDeleteable().ExecuteCommandAsync(stoppingToken);
+
+ var originColor = Console.ForegroundColor;
+ Console.ForegroundColor = ConsoleColor.Red;
+ Console.WriteLine($"【{DateTime.Now}】清空在线用户列表");
+ Console.ForegroundColor = originColor;
+
+ // 缓存租户列表
+ await serviceScope.ServiceProvider.GetRequiredService().CacheTenant();
+
+ // 自定义日志
+ _logger.LogInformation($"【{DateTime.Now}】服务已重启...");
+ }
+}
\ No newline at end of file
diff --git a/Admin.NET/Admin.NET.Core/Job/RoleApiJob.cs b/Admin.NET/Admin.NET.Core/Job/RoleApiJob.cs
new file mode 100644
index 00000000..b7e3a388
--- /dev/null
+++ b/Admin.NET/Admin.NET.Core/Job/RoleApiJob.cs
@@ -0,0 +1,63 @@
+// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
+//
+// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
+//
+// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
+
+using Furion.Logging.Extensions;
+
+namespace Admin.NET.Core;
+
+///
+/// 初始化管理员角色接口资源作业任务
+///
+[JobDetail("job_roleApi", Description = "初始化管理员角色接口资源", GroupName = "default", Concurrent = false)]
+[PeriodSeconds(1, TriggerId = "trigger_roleApi", Description = "初始化管理员角色接口资源", MaxNumberOfRuns = 1, RunOnStart = true)]
+public class RoleApiJob : IJob
+{
+ private readonly IServiceScopeFactory _scopeFactory;
+ private readonly ILogger _logger;
+
+ public RoleApiJob(IServiceScopeFactory scopeFactory, ILoggerFactory loggerFactory)
+ {
+ _scopeFactory = scopeFactory;
+ _logger = loggerFactory.CreateLogger(CommonConst.SysLogCategoryName);
+ }
+
+ public async Task ExecuteAsync(JobExecutingContext context, CancellationToken stoppingToken)
+ {
+ using var serviceScope = _scopeFactory.CreateScope();
+
+ // 获取所有接口列表-排除租户接口
+ var apiList = App.GetRequiredService().GetApiList();
+
+ var index = 0;
+ var sysRoleApis = new List();
+ foreach (var baseApi in apiList)
+ {
+ foreach (var api in baseApi.Apis)
+ {
+ // 排除租户管理接口
+ if (api.ControllerName == "sysTenant") continue;
+
+ // 为系统管理员分配接口
+ sysRoleApis.Add(new SysRoleApi { Id = 1400000000101 + index, RoleId = 1300000000101, Route = api.Route });
+ index++;
+ }
+ }
+ var db = serviceScope.ServiceProvider.GetRequiredService();
+ var storage = db.StorageableByObject(sysRoleApis).ToStorage();
+ storage.AsInsertable.ExecuteCommand();
+ storage.AsUpdateable.ExecuteCommand();
+
+ var originColor = Console.ForegroundColor;
+ Console.ForegroundColor = ConsoleColor.Blue;
+ Console.WriteLine($"【{DateTime.Now}】初始化管理员角色接口资源");
+ Console.ForegroundColor = originColor;
+
+ // 自定义日志
+ _logger.LogInformation($"【{DateTime.Now}】初始化管理员角色接口资源");
+
+ await Task.CompletedTask;
+ }
+}
\ No newline at end of file
diff --git a/Admin.NET/Admin.NET.Core/Logging/DatabaseLoggingWriter.cs b/Admin.NET/Admin.NET.Core/Logging/DatabaseLoggingWriter.cs
new file mode 100644
index 00000000..5d40a339
--- /dev/null
+++ b/Admin.NET/Admin.NET.Core/Logging/DatabaseLoggingWriter.cs
@@ -0,0 +1,225 @@
+// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
+//
+// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
+//
+// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
+
+using IPTools.Core;
+
+namespace Admin.NET.Core;
+
+///
+/// 数据库日志写入器
+///
+public class DatabaseLoggingWriter : IDatabaseLoggingWriter, IDisposable
+{
+ private readonly IServiceScope _serviceScope;
+ private readonly ISqlSugarClient _db;
+ private readonly SysConfigService _sysConfigService; // 参数配置服务
+ private readonly ILogger _logger; // 日志组件
+
+ public DatabaseLoggingWriter(IServiceScopeFactory scopeFactory)
+ {
+ _serviceScope = scopeFactory.CreateScope();
+ //_db = _serviceScope.ServiceProvider.GetRequiredService();
+ _sysConfigService = _serviceScope.ServiceProvider.GetRequiredService();
+ _logger = _serviceScope.ServiceProvider.GetRequiredService>();
+
+ // 切换日志独立数据库
+ _db = SqlSugarSetup.ITenant.IsAnyConnection(SqlSugarConst.LogConfigId)
+ ? SqlSugarSetup.ITenant.GetConnectionScope(SqlSugarConst.LogConfigId)
+ : SqlSugarSetup.ITenant.GetConnectionScope(SqlSugarConst.MainConfigId);
+ }
+
+ public async Task WriteAsync(LogMessage logMsg, bool flush)
+ {
+ var jsonStr = logMsg.Context?.Get("loggingMonitor")?.ToString();
+ if (string.IsNullOrWhiteSpace(jsonStr))
+ {
+ await _db.Insertable(new SysLogOp
+ {
+ DisplayTitle = "自定义操作日志",
+ LogDateTime = logMsg.LogDateTime,
+ EventId = logMsg.EventId.Id,
+ ThreadId = logMsg.ThreadId,
+ TraceId = logMsg.TraceId,
+ Exception = logMsg.Exception == null ? null : JSON.Serialize(logMsg.Exception),
+ Message = logMsg.Message,
+ LogLevel = logMsg.LogLevel,
+ Status = "200",
+ }).ExecuteCommandAsync();
+ return;
+ }
+
+ var loggingMonitor = JSON.Deserialize(jsonStr);
+ // 不记录数据校验日志
+ if (loggingMonitor.validation != null) return;
+
+ // 获取当前操作者
+ string account = "", realName = "", userId = "", tenantId = "";
+ if (loggingMonitor.authorizationClaims != null)
+ {
+ foreach (var item in loggingMonitor.authorizationClaims)
+ {
+ if (item.type == ClaimConst.Account)
+ account = item.value;
+ if (item.type == ClaimConst.RealName)
+ realName = item.value;
+ if (item.type == ClaimConst.TenantId)
+ tenantId = item.value;
+ if (item.type == ClaimConst.UserId)
+ userId = item.value;
+ }
+ }
+
+ string remoteIPv4 = loggingMonitor.remoteIPv4;
+ (string ipLocation, double? longitude, double? latitude) = GetIpAddress(remoteIPv4);
+
+ var browser = "";
+ var os = "";
+ if (loggingMonitor.userAgent != null)
+ {
+ var client = Parser.GetDefault().Parse(loggingMonitor.userAgent.ToString());
+ browser = $"{client.UA.Family} {client.UA.Major}.{client.UA.Minor} / {client.Device.Family}";
+ os = $"{client.OS.Family} {client.OS.Major} {client.OS.Minor}";
+ }
+
+ // 捕捉异常,否则会由于 unhandled exception 导致程序崩溃
+ try
+ {
+ // 记录异常日志-发送邮件
+ if (logMsg.Exception != null || loggingMonitor.exception != null)
+ {
+ await _db.Insertable(new SysLogEx
+ {
+ ControllerName = loggingMonitor.controllerName,
+ ActionName = loggingMonitor.actionTypeName,
+ DisplayTitle = loggingMonitor.displayTitle,
+ Status = loggingMonitor.returnInformation?.httpStatusCode,
+ RemoteIp = remoteIPv4,
+ Location = ipLocation,
+ Longitude = longitude,
+ Latitude = latitude,
+ Browser = browser, // loggingMonitor.userAgent,
+ Os = os, // loggingMonitor.osDescription + " " + loggingMonitor.osArchitecture,
+ Elapsed = loggingMonitor.timeOperationElapsedMilliseconds,
+ LogDateTime = logMsg.LogDateTime,
+ Account = account,
+ RealName = realName,
+ HttpMethod = loggingMonitor.httpMethod,
+ RequestUrl = loggingMonitor.requestUrl,
+ RequestParam = (loggingMonitor.parameters == null || loggingMonitor.parameters.Count == 0) ? null : JSON.Serialize(loggingMonitor.parameters[0].value),
+ ReturnResult = loggingMonitor.returnInformation == null ? null : JSON.Serialize(loggingMonitor.returnInformation),
+ EventId = logMsg.EventId.Id,
+ ThreadId = logMsg.ThreadId,
+ TraceId = logMsg.TraceId,
+ Exception = JSON.Serialize(loggingMonitor.exception),
+ Message = logMsg.Message,
+ CreateUserId = string.IsNullOrWhiteSpace(userId) ? 0 : long.Parse(userId),
+ TenantId = string.IsNullOrWhiteSpace(tenantId) ? 0 : long.Parse(tenantId),
+ LogLevel = logMsg.LogLevel
+ }).ExecuteCommandAsync();
+
+ // 将异常日志发送到邮件
+ if (await _sysConfigService.GetConfigValue(CommonConst.SysErrorMail))
+ {
+ await App.GetRequiredService().PublishAsync(CommonConst.SendErrorMail, loggingMonitor.exception);
+ }
+
+ return;
+ }
+
+ // 记录访问日志-登录退出
+ if (loggingMonitor.actionName == "userInfo" || loggingMonitor.actionName == "logout")
+ {
+ await _db.Insertable(new SysLogVis
+ {
+ ControllerName = loggingMonitor.controllerName,
+ ActionName = loggingMonitor.actionTypeName,
+ DisplayTitle = loggingMonitor.displayTitle,
+ Status = loggingMonitor.returnInformation?.httpStatusCode,
+ RemoteIp = remoteIPv4,
+ Location = ipLocation,
+ Longitude = longitude,
+ Latitude = latitude,
+ Browser = browser, // loggingMonitor.userAgent,
+ Os = os, // loggingMonitor.osDescription + " " + loggingMonitor.osArchitecture,
+ Elapsed = loggingMonitor.timeOperationElapsedMilliseconds,
+ LogDateTime = logMsg.LogDateTime,
+ Account = account,
+ RealName = realName,
+ CreateUserId = string.IsNullOrWhiteSpace(userId) ? 0 : long.Parse(userId),
+ TenantId = string.IsNullOrWhiteSpace(tenantId) ? 0 : long.Parse(tenantId),
+ LogLevel = logMsg.LogLevel
+ }).ExecuteCommandAsync();
+ return;
+ }
+
+ // 记录操作日志
+ if (!(await _sysConfigService.GetConfigValue(CommonConst.SysOpLog))) return;
+ await _db.Insertable(new SysLogOp
+ {
+ ControllerName = loggingMonitor.controllerName,
+ ActionName = loggingMonitor.actionTypeName,
+ DisplayTitle = loggingMonitor.displayTitle,
+ Status = loggingMonitor.returnInformation?.httpStatusCode,
+ RemoteIp = remoteIPv4,
+ Location = ipLocation,
+ Longitude = longitude,
+ Latitude = latitude,
+ Browser = browser, // loggingMonitor.userAgent,
+ Os = os, // loggingMonitor.osDescription + " " + loggingMonitor.osArchitecture,
+ Elapsed = loggingMonitor.timeOperationElapsedMilliseconds,
+ LogDateTime = logMsg.LogDateTime,
+ Account = account,
+ RealName = realName,
+ HttpMethod = loggingMonitor.httpMethod,
+ RequestUrl = loggingMonitor.requestUrl,
+ RequestParam = (loggingMonitor.parameters == null || loggingMonitor.parameters.Count == 0) ? null : JSON.Serialize(loggingMonitor.parameters[0].value),
+ ReturnResult = loggingMonitor.returnInformation == null ? null : JSON.Serialize(loggingMonitor.returnInformation),
+ EventId = logMsg.EventId.Id,
+ ThreadId = logMsg.ThreadId,
+ TraceId = logMsg.TraceId,
+ Exception = loggingMonitor.exception == null ? null : JSON.Serialize(loggingMonitor.exception),
+ Message = logMsg.Message,
+ CreateUserId = string.IsNullOrWhiteSpace(userId) ? 0 : long.Parse(userId),
+ TenantId = string.IsNullOrWhiteSpace(tenantId) ? 0 : long.Parse(tenantId),
+ LogLevel = logMsg.LogLevel
+ }).ExecuteCommandAsync();
+
+ await Task.Delay(50); // 延迟 0.05 秒写入数据库,有效减少高频写入数据库导致死锁问题
+ }
+ catch (Exception ex)
+ {
+ _logger.LogError(ex, "操作日志入库");
+ }
+ }
+
+ ///
+ /// 解析IP地址
+ ///
+ ///
+ ///
+ internal static (string ipLocation, double? longitude, double? latitude) GetIpAddress(string ip)
+ {
+ try
+ {
+ var ipInfo = IpTool.SearchWithI18N(ip); // 国际化查询,默认中文 中文zh-CN、英文en
+ var addressList = new List() { ipInfo.Country, ipInfo.Province, ipInfo.City, ipInfo.NetworkOperator };
+ return (string.Join(" ", addressList.Where(u => u != "0" && !string.IsNullOrWhiteSpace(u)).ToList()), ipInfo.Longitude, ipInfo.Latitude); // 去掉0及空并用空格连接
+ }
+ catch
+ {
+ // 不做处理
+ }
+ return ("未知", 0, 0);
+ }
+
+ ///
+ /// 释放服务作用域
+ ///
+ public void Dispose()
+ {
+ _serviceScope.Dispose();
+ }
+}
\ No newline at end of file
diff --git a/Admin.NET/Admin.NET.Core/Logging/ElasticSearchLoggingWriter.cs b/Admin.NET/Admin.NET.Core/Logging/ElasticSearchLoggingWriter.cs
new file mode 100644
index 00000000..731647ff
--- /dev/null
+++ b/Admin.NET/Admin.NET.Core/Logging/ElasticSearchLoggingWriter.cs
@@ -0,0 +1,101 @@
+// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
+//
+// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
+//
+// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
+
+using Elastic.Clients.Elasticsearch;
+
+namespace Admin.NET.Core;
+
+///
+/// ES日志写入器
+///
+public class ElasticSearchLoggingWriter : IDatabaseLoggingWriter, IDisposable
+{
+ private readonly IServiceScope _serviceScope;
+ private readonly ElasticsearchClient _esClient;
+ private readonly SysConfigService _sysConfigService;
+
+ public ElasticSearchLoggingWriter(IServiceScopeFactory scopeFactory)
+ {
+ _serviceScope = scopeFactory.CreateScope();
+ _esClient = _serviceScope.ServiceProvider.GetRequiredService();
+ _sysConfigService = _serviceScope.ServiceProvider.GetRequiredService();
+ }
+
+ public async Task WriteAsync(LogMessage logMsg, bool flush)
+ {
+ // 是否启用操作日志
+ var sysOpLogEnabled = await _sysConfigService.GetConfigValue(CommonConst.SysOpLog);
+ if (!sysOpLogEnabled) return;
+
+ var jsonStr = logMsg.Context?.Get("loggingMonitor")?.ToString();
+ if (string.IsNullOrWhiteSpace(jsonStr)) return;
+
+ var loggingMonitor = JSON.Deserialize(jsonStr);
+
+ // 不记录登录退出日志
+ if (loggingMonitor.actionName == "userInfo" || loggingMonitor.actionName == "logout")
+ return;
+
+ // 获取当前操作者
+ string account = "", realName = "", userId = "", tenantId = "";
+ if (loggingMonitor.authorizationClaims != null)
+ {
+ foreach (var item in loggingMonitor.authorizationClaims)
+ {
+ if (item.type == ClaimConst.Account)
+ account = item.value;
+ if (item.type == ClaimConst.RealName)
+ realName = item.value;
+ if (item.type == ClaimConst.TenantId)
+ tenantId = item.value;
+ if (item.type == ClaimConst.UserId)
+ userId = item.value;
+ }
+ }
+
+ string remoteIPv4 = loggingMonitor.remoteIPv4;
+ (string ipLocation, double? longitude, double? latitude) = DatabaseLoggingWriter.GetIpAddress(remoteIPv4);
+
+ var sysLogOp = new SysLogOp
+ {
+ Id = DateTime.Now.Ticks,
+ ControllerName = loggingMonitor.controllerName,
+ ActionName = loggingMonitor.actionTypeName,
+ DisplayTitle = loggingMonitor.displayTitle,
+ Status = loggingMonitor.returnInformation.httpStatusCode,
+ RemoteIp = remoteIPv4,
+ Location = ipLocation,
+ Longitude = longitude,
+ Latitude = latitude,
+ Browser = loggingMonitor.userAgent,
+ Os = loggingMonitor.osDescription + " " + loggingMonitor.osArchitecture,
+ Elapsed = loggingMonitor.timeOperationElapsedMilliseconds,
+ LogDateTime = logMsg.LogDateTime,
+ Account = account,
+ RealName = realName,
+ HttpMethod = loggingMonitor.httpMethod,
+ RequestUrl = loggingMonitor.requestUrl,
+ RequestParam = (loggingMonitor.parameters == null || loggingMonitor.parameters.Count == 0) ? null : JSON.Serialize(loggingMonitor.parameters[0].value),
+ ReturnResult = JSON.Serialize(loggingMonitor.returnInformation),
+ EventId = logMsg.EventId.Id,
+ ThreadId = logMsg.ThreadId,
+ TraceId = logMsg.TraceId,
+ Exception = (loggingMonitor.exception == null) ? null : JSON.Serialize(loggingMonitor.exception),
+ Message = logMsg.Message,
+ CreateUserId = string.IsNullOrWhiteSpace(userId) ? 0 : long.Parse(userId),
+ TenantId = string.IsNullOrWhiteSpace(tenantId) ? 0 : long.Parse(tenantId)
+ };
+ await _esClient.IndexAsync(sysLogOp);
+ }
+
+ ///
+ /// 释放服务作用域
+ ///
+ public void Dispose()
+ {
+ _serviceScope.Dispose();
+ }
+}
\ No newline at end of file
diff --git a/Admin.NET/Admin.NET.Core/Logging/ElasticSearchSetup.cs b/Admin.NET/Admin.NET.Core/Logging/ElasticSearchSetup.cs
new file mode 100644
index 00000000..aa53c17c
--- /dev/null
+++ b/Admin.NET/Admin.NET.Core/Logging/ElasticSearchSetup.cs
@@ -0,0 +1,53 @@
+// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
+//
+// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
+//
+// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
+
+using Elastic.Clients.Elasticsearch;
+using Elastic.Transport;
+
+namespace Admin.NET.Core;
+
+///
+/// ES服务注册
+///
+public static class ElasticSearchSetup
+{
+ public static void AddElasticSearch(this IServiceCollection services)
+ {
+ var option = App.GetConfig("Logging:ElasticSearch");
+ if (!option.Enabled) return;
+
+ var uris = option.ServerUris.Select(u => new Uri(u));
+ // 集群
+ var connectionPool = new StaticNodePool(uris);
+ var connectionSettings = new ElasticsearchClientSettings(connectionPool).DefaultIndex(option.DefaultIndex);
+ // 单连接
+ //var connectionSettings = new ElasticsearchClientSettings(new StaticNodePool(new List { uris.FirstOrDefault() })).DefaultIndex(option.DefaultIndex);
+
+ // 认证类型
+ if (option.AuthType == ElasticSearchAuthTypeEnum.Basic) // Basic 认证
+ {
+ connectionSettings.Authentication(new BasicAuthentication(option.User, option.Password));
+ }
+ else if (option.AuthType == ElasticSearchAuthTypeEnum.ApiKey) // ApiKey 认证
+ {
+ connectionSettings.Authentication(new ApiKey(option.ApiKey));
+ }
+ else if (option.AuthType == ElasticSearchAuthTypeEnum.Base64ApiKey) // Base64ApiKey 认证
+ {
+ connectionSettings.Authentication(new Base64ApiKey(option.Base64ApiKey));
+ }
+ else return;
+
+ // ES使用Https时的证书指纹
+ if (!string.IsNullOrEmpty(option.Fingerprint))
+ {
+ connectionSettings.CertificateFingerprint(option.Fingerprint);
+ }
+
+ var client = new ElasticsearchClient(connectionSettings);
+ services.AddSingleton(client); // 单例注册
+ }
+}
\ No newline at end of file
diff --git a/Admin.NET/Admin.NET.Core/Logging/LogExceptionHandler.cs b/Admin.NET/Admin.NET.Core/Logging/LogExceptionHandler.cs
new file mode 100644
index 00000000..7895563b
--- /dev/null
+++ b/Admin.NET/Admin.NET.Core/Logging/LogExceptionHandler.cs
@@ -0,0 +1,53 @@
+// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
+//
+// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
+//
+// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
+
+//using Microsoft.AspNetCore.Mvc.Controllers;
+//using System.Security.Claims;
+
+//namespace Admin.NET.Core.Logging;
+
+/////