feat: 前端表格高级筛选 (#100)

* chore: 🔨 css 基础单位

[skip ci]

* fix: 🐛 ca2263 System.Enum.GetValues<TEnum>()

[skip ci]

* feat:  前端表格高级筛选

[skip ci]
This commit is contained in:
nsnail 2024-04-22 21:16:53 +08:00 committed by GitHub
parent 1dc953a2b2
commit 3847d6fdbb
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
175 changed files with 1901 additions and 630 deletions

View File

@ -1,56 +1,58 @@
# 此文件为 EditorConfig 配置文件,用于设置跨编辑器的代码格式化规则。
# root = true 表示此文件是根配置文件。
root = true root = true
[*] [*]
charset = utf-8 charset = utf-8 # 文件字符集为 UTF-8
end_of_line = lf end_of_line = lf # 行结束符为 LF
ij_xml_attribute_wrap = off ij_xml_attribute_wrap = off # IntelliJ IDEA 中 XML 属性不换行
ij_xml_text_wrap = off ij_xml_text_wrap = off # IntelliJ IDEA 中 XML 文本不换行
indent_size = 4 indent_size = 4 # 缩进大小为 4 个空格
indent_style = space indent_style = space # 使用空格进行缩进
insert_final_newline = false insert_final_newline = false # 不在文件末尾插入空行
trim_trailing_whitespace = true trim_trailing_whitespace = true # 删除行尾的空格
[{*.json,*.yml}] [{*.json,*.yml}]
indent_size = 2 indent_size = 2 # 对于 JSON 和 YAML 文件,缩进大小为 2 个空格
[*.cs] [*.cs]
dotnet_analyzer_diagnostic.severity = warning dotnet_analyzer_diagnostic.severity = warning # 设置 C# 文件中所有 dotnet_analyzer_diagnostic 的严重性级别为 warning
# ReSharper properties # ReSharper properties
resharper_align_linq_query = true resharper_align_linq_query = true # 启用对LINQ查询的对齐
resharper_align_multiline_argument = true resharper_align_multiline_argument = true # 启用多行参数的对齐
resharper_align_multiline_array_and_object_initializer = true resharper_align_multiline_array_and_object_initializer = true # 启用多行数组和对象初始化器的对齐
resharper_align_multiline_binary_patterns = true resharper_align_multiline_binary_patterns = true # 启用多行二元模式的对齐
resharper_align_multiline_calls_chain = true resharper_align_multiline_calls_chain = true # 启用多行调用链的对齐
resharper_align_multiline_extends_list = true resharper_align_multiline_extends_list = true # 启用多行扩展列表的对齐
resharper_align_multiline_parameter = true resharper_align_multiline_parameter = true # 启用多行参数的对齐
resharper_align_multiline_property_pattern = true resharper_align_multiline_property_pattern = true # 启用多行属性模式的对齐
resharper_align_multiline_switch_expression = true resharper_align_multiline_switch_expression = true # 启用多行切换表达式的对齐
resharper_align_multiple_declaration = true resharper_align_multiple_declaration = true # 启用多个声明的对齐
resharper_align_multline_type_parameter_constrains = true resharper_align_multline_type_parameter_constrains = true # 启用多行类型参数约束的对齐
resharper_align_multline_type_parameter_list = true resharper_align_multline_type_parameter_list = true # 启用多行类型参数列表的对齐
resharper_align_tuple_components = true resharper_align_tuple_components = true # 启用元组组件的对齐
resharper_allow_comment_after_lbrace = true resharper_allow_comment_after_lbrace = true # 允许在大括号前添加注释
resharper_blank_lines_before_single_line_comment = 1 resharper_blank_lines_before_single_line_comment = 1 # 在单行注释前添加空行
resharper_csharp_empty_block_style = together_same_line resharper_csharp_empty_block_style = together_same_line # 设置空块的样式为“在一起,在同一行”
resharper_csharp_outdent_commas = true resharper_csharp_outdent_commas = true # 是否将逗号后的代码退缩
resharper_csharp_place_type_constraints_on_same_line = false resharper_csharp_place_type_constraints_on_same_line = false # 在类型约束上是否保持在同一行
resharper_csharp_stick_comment = false resharper_csharp_stick_comment = false # 是否将注释粘贴在代码行的末尾
resharper_csharp_wrap_before_comma = true resharper_csharp_wrap_before_comma = true # 在逗号前是否添加换行
resharper_indent_nested_for_stmt = true resharper_indent_nested_for_stmt = true # 是否对嵌套的for语句进行缩进
resharper_indent_nested_foreach_stmt = true resharper_indent_nested_foreach_stmt = true # 是否对嵌套的foreach语句进行缩进
resharper_indent_nested_while_stmt = true resharper_indent_nested_while_stmt = true # 是否对嵌套的while语句进行缩进
resharper_indent_preprocessor_if = usual_indent resharper_indent_preprocessor_if = usual_indent # 设置预处理器指令`if`的缩进方式
resharper_indent_preprocessor_other = usual_indent resharper_indent_preprocessor_other = usual_indent # 设置其他预处理器指令的缩进方式
resharper_int_align = true resharper_int_align = true # 启用整数对齐
resharper_keep_existing_arrangement = false resharper_keep_existing_arrangement = false # 在重新排列时是否保留现有的布局
resharper_place_linq_into_on_new_line = false resharper_place_linq_into_on_new_line = false # 是否将LINQ表达式放在新行
resharper_place_simple_embedded_statement_on_same_line = false resharper_place_simple_embedded_statement_on_same_line = false # 是否将简单的嵌入式语句放在同一行
resharper_place_simple_switch_expression_on_single_line = true resharper_place_simple_switch_expression_on_single_line = true # 是否将简单的切换表达式放在单行
resharper_wrap_before_eq = true resharper_wrap_before_eq = true # 在等号前是否添加换行
resharper_wrap_chained_method_calls = chop_if_long resharper_wrap_chained_method_calls = chop_if_long # 是否拆分链式方法调用
resharper_wrap_switch_expression = chop_if_long resharper_wrap_switch_expression = chop_if_long # 是否拆分切换表达式
# Microsoft .NET properties # Microsoft .NET properties
csharp_indent_braces = false csharp_indent_braces = false # 设置为false表示花括号不跟随代码行缩进
csharp_new_line_before_open_brace = local_functions, methods, types csharp_new_line_before_open_brace = local_functions, methods, types # 这里设置为local_functions, methods, types表示在局部函数、方法和类型定义的开放花括号前应换行

View File

@ -25,7 +25,7 @@
<Title>$(AssemblyName)</Title> <Title>$(AssemblyName)</Title>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="MinVer" Version="5.0.0-beta.1"> <PackageReference Include="MinVer" Version="5.0.0">
<PrivateAssets>all</PrivateAssets> <PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference> </PackageReference>

View File

@ -1,4 +1,4 @@
FROM mcr.microsoft.com/dotnet/aspnet:9.0.0-preview.1 AS base FROM mcr.microsoft.com/dotnet/aspnet:9.0.0-preview.3 AS base
WORKDIR /app WORKDIR /app
EXPOSE 8080 EXPOSE 8080
RUN apt update RUN apt update

View File

@ -5,6 +5,7 @@
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpPlaceEmbeddedOnSameLineMigration/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpPlaceEmbeddedOnSameLineMigration/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpUseContinuousIndentInsideBracesMigration/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpUseContinuousIndentInsideBracesMigration/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EMigrateBlankLinesAroundFieldToBlankLinesAroundProperty/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EMigrateBlankLinesAroundFieldToBlankLinesAroundProperty/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EPredefinedNamingRulesToUserRulesUpgrade/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/ReSpeller/ReSpellerEnabled/@EntryValue">True</s:Boolean> <s:Boolean x:Key="/Default/ReSpeller/ReSpellerEnabled/@EntryValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Aigc/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/UserDictionary/Words/=Aigc/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Biji/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/UserDictionary/Words/=Biji/@EntryIndexedValue">True</s:Boolean>
@ -19,10 +20,15 @@
<s:Boolean x:Key="/Default/UserDictionary/Words/=Decaptcha/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/UserDictionary/Words/=Decaptcha/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Depts/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/UserDictionary/Words/=Depts/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=FFFFFF/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/UserDictionary/Words/=FFFFFF/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=FLG/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=FLGL/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Furion/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/UserDictionary/Words/=Furion/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=GETDATE/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/UserDictionary/Words/=GETDATE/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Haojia/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/UserDictionary/Words/=Haojia/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Meituan/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/UserDictionary/Words/=Meituan/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=PWD/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=RGX/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=RGXL/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Responsing/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/UserDictionary/Words/=Responsing/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Smzdm/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/UserDictionary/Words/=Smzdm/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Tabao/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/UserDictionary/Words/=Tabao/@EntryIndexedValue">True</s:Boolean>
@ -71,12 +77,14 @@
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpCodeStyle/BRACES_FOR_IFELSE/@EntryValue">Required</s:String> <s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpCodeStyle/BRACES_FOR_IFELSE/@EntryValue">Required</s:String>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpCodeStyle/BRACES_FOR_WHILE/@EntryValue">Required</s:String> <s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpCodeStyle/BRACES_FOR_WHILE/@EntryValue">Required</s:String>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/PLACE_ACCESSORHOLDER_ATTRIBUTE_ON_SAME_LINE_EX/@EntryValue">NEVER</s:String> <s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/PLACE_ACCESSORHOLDER_ATTRIBUTE_ON_SAME_LINE_EX/@EntryValue">NEVER</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=Constants/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="AA_BB" /&gt;</s:String> <s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/PLACE_ACCESSOR_ATTRIBUTE_ON_SAME_LINE_EX/@EntryValue">NEVER</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=PrivateConstants/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="_" Suffix="" Style="AA_BB" /&gt;</s:String> <s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/PLACE_FIELD_ATTRIBUTE_ON_SAME_LINE_EX/@EntryValue">NEVER</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=PrivateStaticReadonly/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="_" Suffix="" Style="aaBb" /&gt;</s:String> <s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/PLACE_RECORD_FIELD_ATTRIBUTE_ON_SAME_LINE_EX/@EntryValue">NEVER</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=StaticReadonly/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /&gt;</s:String> <s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/UserRules/=15b5b1f1_002D457c_002D4ca6_002Db278_002D5615aedc07d3/@EntryIndexedValue">&lt;Policy&gt;&lt;Descriptor Staticness="Static" AccessRightKinds="Private" Description="Static readonly fields (private)"&gt;&lt;ElementKinds&gt;&lt;Kind Name="READONLY_FIELD" /&gt;&lt;/ElementKinds&gt;&lt;/Descriptor&gt;&lt;Policy Inspect="True" Prefix="_" Suffix="" Style="aaBb" /&gt;&lt;/Policy&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=TypesAndNamespaces/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="AaBb_AaBb" /&gt;</s:String> <s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/UserRules/=236f7aa5_002D7b06_002D43ca_002Dbf2a_002D9b31bfcff09a/@EntryIndexedValue">&lt;Policy&gt;&lt;Descriptor Staticness="Any" AccessRightKinds="Private" Description="Constant fields (private)"&gt;&lt;ElementKinds&gt;&lt;Kind Name="CONSTANT_FIELD" /&gt;&lt;/ElementKinds&gt;&lt;/Descriptor&gt;&lt;Policy Inspect="True" Prefix="_" Suffix="" Style="AA_BB" /&gt;&lt;/Policy&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/UserRules/=669e5282_002Dfb4b_002D4e90_002D91e7_002D07d269d04b60/@EntryIndexedValue">&lt;Policy&gt;&lt;Descriptor Staticness="Any" AccessRightKinds="Protected, ProtectedInternal, Internal, Public, PrivateProtected" Description="Constant fields (not private)"&gt;&lt;ElementKinds&gt;&lt;Kind Name="CONSTANT_FIELD" /&gt;&lt;/ElementKinds&gt;&lt;/Descriptor&gt;&lt;Policy Inspect="True" Prefix="" Suffix="" Style="AA_BB" /&gt;&lt;/Policy&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/UserRules/=a0b4bc4d_002Dd13b_002D4a37_002Db37e_002Dc9c6864e4302/@EntryIndexedValue">&lt;Policy&gt;&lt;Descriptor Staticness="Any" AccessRightKinds="Any" Description="Types and namespaces"&gt;&lt;ElementKinds&gt;&lt;Kind Name="NAMESPACE" /&gt;&lt;Kind Name="CLASS" /&gt;&lt;Kind Name="STRUCT" /&gt;&lt;Kind Name="ENUM" /&gt;&lt;Kind Name="DELEGATE" /&gt;&lt;/ElementKinds&gt;&lt;/Descriptor&gt;&lt;Policy Inspect="True" Prefix="" Suffix="" Style="AaBb_AaBb" /&gt;&lt;/Policy&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/UserRules/=c873eafb_002Dd57f_002D481d_002D8c93_002D77f6863c2f88/@EntryIndexedValue">&lt;Policy&gt;&lt;Descriptor Staticness="Static" AccessRightKinds="Protected, ProtectedInternal, Internal, Public, PrivateProtected" Description="Static readonly fields (not private)"&gt;&lt;ElementKinds&gt;&lt;Kind Name="READONLY_FIELD" /&gt;&lt;/ElementKinds&gt;&lt;/Descriptor&gt;&lt;Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /&gt;&lt;/Policy&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/CSharpFileLayoutPatterns/Pattern/@EntryValue">&lt;?xml version="1.0" encoding="utf-16"?&gt; <s:String x:Key="/Default/CodeStyle/CSharpFileLayoutPatterns/Pattern/@EntryValue">&lt;?xml version="1.0" encoding="utf-16"?&gt;
&lt;Patterns xmlns="urn:schemas-jetbrains-com:member-reordering-patterns"&gt; &lt;Patterns xmlns="urn:schemas-jetbrains-com:member-reordering-patterns"&gt;

View File

@ -84,5 +84,6 @@
重设密码 重设密码
链接 链接
错误 错误
随机排序
顺序排序 顺序排序
高中 高中

View File

@ -1,7 +1,7 @@
{ {
"version": "1.0.0", "version": "1.0.0",
"devDependencies": { "devDependencies": {
"cz-git": "^1.8.0", "cz-git": "^1.9.1",
"commitizen": "^4.3.0", "commitizen": "^4.3.0",
"prettier": "^3.2.5", "prettier": "^3.2.5",
"standard-version": "^9.5.0" "standard-version": "^9.5.0"

View File

@ -10,6 +10,7 @@ while ($null -eq $types[$prefix])
$prefix = Read-Host "请选择版本类型`n" $( & { param($i) $i | ForEach-Object { "$_ : $( $types[$_][0] )$( $types[$_][1] )`n" } } $types.Keys | Sort-Object ) $prefix = Read-Host "请选择版本类型`n" $( & { param($i) $i | ForEach-Object { "$_ : $( $types[$_][0] )$( $types[$_][1] )`n" } } $types.Keys | Sort-Object )
} }
git checkout main git checkout main
git pull
git branch -D release git branch -D release
git checkout -b release git checkout -b release
./node_modules/.bin/standard-version -r $types[$prefix][0] ./node_modules/.bin/standard-version -r $types[$prefix][0]

View File

@ -10,11 +10,11 @@
"packages": [ "packages": [
{ {
"packageName": "FreeSql.NS", "packageName": "FreeSql.NS",
"version": "3.2.802-preview20231010-ns1" "version": "3.2.821-ns1"
}, },
{ {
"packageName": "FreeSql.DbContext.NS", "packageName": "FreeSql.DbContext.NS",
"version": "3.2.802-preview20231010-ns1" "version": "3.2.821-ns1"
} }
] ]
} }

View File

@ -9,7 +9,7 @@
"packages": [ "packages": [
{ {
"packageName": "Furion.Pure.NS", "packageName": "Furion.Pure.NS",
"version": "4.9.1.31-ns2" "version": "4.9.2.19-ns3"
} }
] ]
} }

View File

@ -27,6 +27,11 @@ public interface ICrudModule<in TCreateReq, TCreateRsp, TQueryReq, TQueryRsp, in
/// </summary> /// </summary>
Task<int> BulkDeleteAsync(BulkReq<TDelReq> req); Task<int> BulkDeleteAsync(BulkReq<TDelReq> req);
/// <summary>
/// 实体计数
/// </summary>
Task<long> CountAsync(QueryReq<TQueryReq> req);
/// <summary> /// <summary>
/// 创建实体 /// 创建实体
/// </summary> /// </summary>

View File

@ -6,10 +6,7 @@ namespace NetAdmin.Application.Repositories;
/// <summary> /// <summary>
/// 默认仓储 /// 默认仓储
/// </summary> /// </summary>
public sealed class DefaultRepository<TEntity>( public sealed class DefaultRepository<TEntity>(IFreeSql fSql, UnitOfWorkManager uowManger, ContextUserToken userToken)
IFreeSql fSql //
, UnitOfWorkManager uowManger //
, ContextUserToken userToken) //
: DefaultRepository<TEntity, long>(fSql, uowManger) : DefaultRepository<TEntity, long>(fSql, uowManger)
where TEntity : EntityBase where TEntity : EntityBase
{ {

View File

@ -22,7 +22,7 @@ public static class ServiceCollectionExtensions
(Startup.Args.InsertSeedData ? FreeSqlInitMethods.InsertSeedData : FreeSqlInitMethods.None), freeSql => { (Startup.Args.InsertSeedData ? FreeSqlInitMethods.InsertSeedData : FreeSqlInitMethods.None), freeSql => {
// 数据权限过滤器 // 数据权限过滤器
_ = freeSql.GlobalFilter.ApplyOnlyIf<IFieldOwner>( // _ = freeSql.GlobalFilter.ApplyOnlyIf<IFieldOwner>( //
Chars.FLG_GLOBAL_FILTER_DATA Chars.FLG_FREE_SQL_GLOBAL_FILTER_DATA
, () => ContextUserInfo.Create()?.Roles.All(x => x.DataScope == DataScopes.Self) ?? false , () => ContextUserInfo.Create()?.Roles.All(x => x.DataScope == DataScopes.Self) ?? false
, a => a.OwnerId == ContextUserInfo.Create().Id); , a => a.OwnerId == ContextUserInfo.Create().Id);
}); });

View File

@ -26,10 +26,10 @@ namespace NetAdmin.BizServer.Host
/// <summary> /// <summary>
/// 配置应用程序中间件 /// 配置应用程序中间件
/// </summary> /// </summary>
public void Configure(IApplicationBuilder app) public void Configure(IApplicationBuilder app, IHostApplicationLifetime lifeTime)
{ {
_ = app // _ = app //
.UseRealIp() // 使用RealIp中间件用于获取真实客户端IP地址 .UseMiddleware<SafetyShopHostMiddleware>() // 安全停机中间件
.EnableBuffering() // 启用请求体缓冲,允许多次读取请求体 .EnableBuffering() // 启用请求体缓冲,允许多次读取请求体
.UseMiddleware<RequestAuditMiddleware>() // 使用RequestAuditMiddleware中间件执行请求审计 .UseMiddleware<RequestAuditMiddleware>() // 使用RequestAuditMiddleware中间件执行请求审计
#if DEBUG #if DEBUG
@ -46,6 +46,7 @@ namespace NetAdmin.BizServer.Host
.UseAuthorization() // 使用Authorization中间件启用授权 .UseAuthorization() // 使用Authorization中间件启用授权
.UseMiddleware<RemoveNullNodeMiddleware>() // 使用RemoveNullNodeMiddleware中间件删除JSON中的空节点 .UseMiddleware<RemoveNullNodeMiddleware>() // 使用RemoveNullNodeMiddleware中间件删除JSON中的空节点
.UseEndpoints(); // 配置端点以处理请求 .UseEndpoints(); // 配置端点以处理请求
_ = lifeTime.ApplicationStopping.Register(SafetyShopHostMiddleware.OnStopping);
} }
/// <summary> /// <summary>

View File

@ -19,8 +19,8 @@ namespace NetAdmin.BizServer.Tests;
/// 所有测试 /// 所有测试
/// </summary> /// </summary>
[SuppressMessage("Usage", "xUnit1028:Test method must have valid return type")] [SuppressMessage("Usage", "xUnit1028:Test method must have valid return type")]
public class AllTests(WebApplicationFactory<Startup> factory, ITestOutputHelper testOutputHelper) : public class AllTests(WebApplicationFactory<Startup> factory, ITestOutputHelper testOutputHelper)
WebApiTestBase<Startup>(factory, testOutputHelper), IToolsModule, ICacheModule, IApiModule, IConfigModule : WebApiTestBase<Startup>(factory, testOutputHelper), IToolsModule, ICacheModule, IApiModule, IConfigModule
{ {
/// <inheritdoc cref="ICrudModule{TCreateReq,TCreateRsp,TQueryReq,TQueryRsp,TUpdateReq,TUpdateRsp,TDelReq}.BulkDeleteAsync" /> /// <inheritdoc cref="ICrudModule{TCreateReq,TCreateRsp,TQueryReq,TQueryRsp,TUpdateReq,TUpdateRsp,TDelReq}.BulkDeleteAsync" />
@ -38,6 +38,18 @@ public class AllTests(WebApplicationFactory<Startup> factory, ITestOutputHelper
return default; return default;
} }
/// <inheritdoc />
public Task<long> CountAsync(QueryReq<QueryConfigReq> req)
{
throw new NotImplementedException();
}
/// <inheritdoc />
public Task<long> CountAsync(QueryReq<QueryApiReq> req)
{
throw new NotImplementedException();
}
/// <inheritdoc /> /// <inheritdoc />
public Task<QueryConfigRsp> CreateAsync(CreateConfigReq req) public Task<QueryConfigRsp> CreateAsync(CreateConfigReq req)
{ {

View File

@ -41,8 +41,13 @@ public abstract class DistributedCache<TService>(IDistributedCache cache, TServi
protected async Task<T> GetAsync<T>(string key) protected async Task<T> GetAsync<T>(string key)
{ {
var cacheRead = await Cache.GetStringAsync(key).ConfigureAwait(false); var cacheRead = await Cache.GetStringAsync(key).ConfigureAwait(false);
try {
return cacheRead != null ? cacheRead.ToObject<T>() : default; return cacheRead != null ? cacheRead.ToObject<T>() : default;
} }
catch (JsonException) {
return default;
}
}
/// <summary> /// <summary>
/// 获取缓存键 /// 获取缓存键

View File

@ -10,7 +10,7 @@ public sealed class ChineseNameAttribute : RegexAttribute
/// Initializes a new instance of the <see cref="ChineseNameAttribute" /> class. /// Initializes a new instance of the <see cref="ChineseNameAttribute" /> class.
/// </summary> /// </summary>
public ChineseNameAttribute() // public ChineseNameAttribute() //
: base(Chars.RGX_CHINESE_NAME) : base(Chars.RGXL_CHINESE_NAME)
{ {
ErrorMessageResourceName = nameof(Ln.); ErrorMessageResourceName = nameof(Ln.);
ErrorMessageResourceType = typeof(Ln); ErrorMessageResourceType = typeof(Ln);

View File

@ -10,7 +10,7 @@ public sealed class CronAttribute : RegexAttribute
/// Initializes a new instance of the <see cref="CronAttribute" /> class. /// Initializes a new instance of the <see cref="CronAttribute" /> class.
/// </summary> /// </summary>
public CronAttribute() // public CronAttribute() //
: base(Chars.RGX_CRON) : base(Chars.RGXL_CRON)
{ {
ErrorMessageResourceName = nameof(Ln.); ErrorMessageResourceName = nameof(Ln.);
ErrorMessageResourceType = typeof(Ln); ErrorMessageResourceType = typeof(Ln);

View File

@ -10,7 +10,7 @@ public sealed class EmailAttribute : RegexAttribute
/// Initializes a new instance of the <see cref="EmailAttribute" /> class. /// Initializes a new instance of the <see cref="EmailAttribute" /> class.
/// </summary> /// </summary>
public EmailAttribute() // public EmailAttribute() //
: base(Chars.RGX_EMAIL) : base(Chars.RGXL_EMAIL)
{ {
ErrorMessageResourceName = nameof(Ln.); ErrorMessageResourceName = nameof(Ln.);
ErrorMessageResourceType = typeof(Ln); ErrorMessageResourceType = typeof(Ln);

View File

@ -6,7 +6,7 @@ namespace NetAdmin.Domain.DbMaps.Sys;
/// <summary> /// <summary>
/// Api接口表 /// Api接口表
/// </summary> /// </summary>
[Table(Name = Chars.FLG_TABLE_NAME_PREFIX + nameof(Sys_Api))] [Table(Name = Chars.FLG_DB_TABLE_NAME_PREFIX + nameof(Sys_Api))]
public record Sys_Api : ImmutableEntity<string>, IFieldSummary public record Sys_Api : ImmutableEntity<string>, IFieldSummary
{ {
/// <summary> /// <summary>

View File

@ -6,7 +6,7 @@ namespace NetAdmin.Domain.DbMaps.Sys;
/// <summary> /// <summary>
/// 配置表 /// 配置表
/// </summary> /// </summary>
[Table(Name = Chars.FLG_TABLE_NAME_PREFIX + nameof(Sys_Config))] [Table(Name = Chars.FLG_DB_TABLE_NAME_PREFIX + nameof(Sys_Config))]
public record Sys_Config : VersionEntity, IFieldEnabled public record Sys_Config : VersionEntity, IFieldEnabled
{ {
/// <summary> /// <summary>

View File

@ -6,7 +6,7 @@ namespace NetAdmin.Domain.DbMaps.Sys;
/// <summary> /// <summary>
/// 部门表 /// 部门表
/// </summary> /// </summary>
[Table(Name = Chars.FLG_TABLE_NAME_PREFIX + nameof(Sys_Dept))] [Table(Name = Chars.FLG_DB_TABLE_NAME_PREFIX + nameof(Sys_Dept))]
public record Sys_Dept : VersionEntity, IFieldEnabled, IFieldSummary, IFieldSort public record Sys_Dept : VersionEntity, IFieldEnabled, IFieldSummary, IFieldSort
{ {
/// <summary> /// <summary>

View File

@ -5,7 +5,7 @@ namespace NetAdmin.Domain.DbMaps.Sys;
/// <summary> /// <summary>
/// 字典目录表 /// 字典目录表
/// </summary> /// </summary>
[Table(Name = Chars.FLG_TABLE_NAME_PREFIX + nameof(Sys_DicCatalog))] [Table(Name = Chars.FLG_DB_TABLE_NAME_PREFIX + nameof(Sys_DicCatalog))]
[Index($"idx_{{tablename}}_{nameof(Code)}", nameof(Code), true)] [Index($"idx_{{tablename}}_{nameof(Code)}", nameof(Code), true)]
public record Sys_DicCatalog : VersionEntity public record Sys_DicCatalog : VersionEntity
{ {

View File

@ -5,7 +5,7 @@ namespace NetAdmin.Domain.DbMaps.Sys;
/// <summary> /// <summary>
/// 字典内容表 /// 字典内容表
/// </summary> /// </summary>
[Table(Name = Chars.FLG_TABLE_NAME_PREFIX + nameof(Sys_DicContent))] [Table(Name = Chars.FLG_DB_TABLE_NAME_PREFIX + nameof(Sys_DicContent))]
[Index($"idx_{{tablename}}_{nameof(CatalogId)}_{nameof(Key)}", $"{nameof(CatalogId)},{nameof(Key)}", true)] [Index($"idx_{{tablename}}_{nameof(CatalogId)}_{nameof(Key)}", $"{nameof(CatalogId)},{nameof(Key)}", true)]
[Index($"idx_{{tablename}}_{nameof(CatalogId)}_{nameof(Value)}", $"{nameof(CatalogId)},{nameof(Value)}", true)] [Index($"idx_{{tablename}}_{nameof(CatalogId)}_{nameof(Value)}", $"{nameof(CatalogId)},{nameof(Value)}", true)]
public record Sys_DicContent : VersionEntity public record Sys_DicContent : VersionEntity

View File

@ -8,7 +8,7 @@ namespace NetAdmin.Domain.DbMaps.Sys;
/// <summary> /// <summary>
/// 计划作业表 /// 计划作业表
/// </summary> /// </summary>
[Table(Name = Chars.FLG_TABLE_NAME_PREFIX + nameof(Sys_Job))] [Table(Name = Chars.FLG_DB_TABLE_NAME_PREFIX + nameof(Sys_Job))]
public record Sys_Job : VersionEntity, IFieldEnabled, IFieldSummary public record Sys_Job : VersionEntity, IFieldEnabled, IFieldSummary
{ {
/// <inheritdoc cref="IFieldEnabled.Enabled" /> /// <inheritdoc cref="IFieldEnabled.Enabled" />

View File

@ -6,7 +6,7 @@ namespace NetAdmin.Domain.DbMaps.Sys;
/// <summary> /// <summary>
/// 计划作业执行记录表 /// 计划作业执行记录表
/// </summary> /// </summary>
[Table(Name = Chars.FLG_TABLE_NAME_PREFIX + nameof(Sys_JobRecord))] [Table(Name = Chars.FLG_DB_TABLE_NAME_PREFIX + nameof(Sys_JobRecord))]
[Index($"idx_{{tablename}}_{nameof(JobId)}_{nameof(TimeId)}", $"{nameof(JobId)},{nameof(TimeId)}", true)] [Index($"idx_{{tablename}}_{nameof(JobId)}_{nameof(TimeId)}", $"{nameof(JobId)},{nameof(TimeId)}", true)]
public record Sys_JobRecord : LiteImmutableEntity public record Sys_JobRecord : LiteImmutableEntity
{ {

View File

@ -7,7 +7,7 @@ namespace NetAdmin.Domain.DbMaps.Sys;
/// <summary> /// <summary>
/// 菜单表 /// 菜单表
/// </summary> /// </summary>
[Table(Name = Chars.FLG_TABLE_NAME_PREFIX + nameof(Sys_Menu))] [Table(Name = Chars.FLG_DB_TABLE_NAME_PREFIX + nameof(Sys_Menu))]
[Index($"idx_{{tablename}}_{nameof(Name)}", nameof(Name), true)] [Index($"idx_{{tablename}}_{nameof(Name)}", nameof(Name), true)]
public record Sys_Menu : VersionEntity, IFieldSort public record Sys_Menu : VersionEntity, IFieldSort
{ {

View File

@ -6,7 +6,9 @@ namespace NetAdmin.Domain.DbMaps.Sys;
/// <summary> /// <summary>
/// 请求日志表 /// 请求日志表
/// </summary> /// </summary>
[Table(Name = Chars.FLG_TABLE_NAME_PREFIX + nameof(Sys_RequestLog))] [Table(Name = Chars.FLG_DB_TABLE_NAME_PREFIX + nameof(Sys_RequestLog))]
[Index($"idx_{{tablename}}_{nameof(ApiId)}", nameof(ApiId), false)]
[Index($"idx_{{tablename}}_{nameof(CreatedTime)}", nameof(CreatedTime), false)]
public record Sys_RequestLog : ImmutableEntity, IFieldCreatedClient public record Sys_RequestLog : ImmutableEntity, IFieldCreatedClient
{ {
/// <summary> /// <summary>

View File

@ -8,7 +8,7 @@ namespace NetAdmin.Domain.DbMaps.Sys;
/// <summary> /// <summary>
/// 角色表 /// 角色表
/// </summary> /// </summary>
[Table(Name = Chars.FLG_TABLE_NAME_PREFIX + nameof(Sys_Role))] [Table(Name = Chars.FLG_DB_TABLE_NAME_PREFIX + nameof(Sys_Role))]
[Index("idx_{tablename}_01", nameof(Name), true)] [Index("idx_{tablename}_01", nameof(Name), true)]
public record Sys_Role : VersionEntity, IFieldSort, IFieldEnabled, IFieldSummary, IRegister public record Sys_Role : VersionEntity, IFieldSort, IFieldEnabled, IFieldSummary, IRegister
{ {

View File

@ -5,7 +5,7 @@ namespace NetAdmin.Domain.DbMaps.Sys;
/// <summary> /// <summary>
/// 角色-接口映射表 /// 角色-接口映射表
/// </summary> /// </summary>
[Table(Name = Chars.FLG_TABLE_NAME_PREFIX + nameof(Sys_RoleApi))] [Table(Name = Chars.FLG_DB_TABLE_NAME_PREFIX + nameof(Sys_RoleApi))]
public record Sys_RoleApi : ImmutableEntity public record Sys_RoleApi : ImmutableEntity
{ {
/// <summary> /// <summary>

View File

@ -5,7 +5,7 @@ namespace NetAdmin.Domain.DbMaps.Sys;
/// <summary> /// <summary>
/// 角色-部门映射表 /// 角色-部门映射表
/// </summary> /// </summary>
[Table(Name = Chars.FLG_TABLE_NAME_PREFIX + nameof(Sys_RoleDept))] [Table(Name = Chars.FLG_DB_TABLE_NAME_PREFIX + nameof(Sys_RoleDept))]
[Index($"idx_{{tablename}}_{nameof(RoleId)}_{nameof(DeptId)}", $"{nameof(RoleId)},{nameof(DeptId)}", true)] [Index($"idx_{{tablename}}_{nameof(RoleId)}_{nameof(DeptId)}", $"{nameof(RoleId)},{nameof(DeptId)}", true)]
public record Sys_RoleDept : ImmutableEntity public record Sys_RoleDept : ImmutableEntity
{ {

View File

@ -5,7 +5,7 @@ namespace NetAdmin.Domain.DbMaps.Sys;
/// <summary> /// <summary>
/// 角色-菜单映射表 /// 角色-菜单映射表
/// </summary> /// </summary>
[Table(Name = Chars.FLG_TABLE_NAME_PREFIX + nameof(Sys_RoleMenu))] [Table(Name = Chars.FLG_DB_TABLE_NAME_PREFIX + nameof(Sys_RoleMenu))]
[Index($"idx_{{tablename}}_{nameof(RoleId)}_{nameof(MenuId)}", $"{nameof(RoleId)},{nameof(MenuId)}", true)] [Index($"idx_{{tablename}}_{nameof(RoleId)}_{nameof(MenuId)}", $"{nameof(RoleId)},{nameof(MenuId)}", true)]
public record Sys_RoleMenu : ImmutableEntity public record Sys_RoleMenu : ImmutableEntity
{ {

View File

@ -8,7 +8,7 @@ namespace NetAdmin.Domain.DbMaps.Sys;
/// <summary> /// <summary>
/// 站内信表 /// 站内信表
/// </summary> /// </summary>
[Table(Name = Chars.FLG_TABLE_NAME_PREFIX + nameof(Sys_SiteMsg))] [Table(Name = Chars.FLG_DB_TABLE_NAME_PREFIX + nameof(Sys_SiteMsg))]
public record Sys_SiteMsg : VersionEntity, IRegister, IFieldSummary public record Sys_SiteMsg : VersionEntity, IRegister, IFieldSummary
{ {
/// <summary> /// <summary>

View File

@ -5,7 +5,7 @@ namespace NetAdmin.Domain.DbMaps.Sys;
/// <summary> /// <summary>
/// 站内信-部门映射表 /// 站内信-部门映射表
/// </summary> /// </summary>
[Table(Name = Chars.FLG_TABLE_NAME_PREFIX + nameof(Sys_SiteMsgDept))] [Table(Name = Chars.FLG_DB_TABLE_NAME_PREFIX + nameof(Sys_SiteMsgDept))]
[Index($"idx_{{tablename}}_{nameof(DeptId)}_{nameof(SiteMsgId)}", $"{nameof(DeptId)},{nameof(SiteMsgId)}", true)] [Index($"idx_{{tablename}}_{nameof(DeptId)}_{nameof(SiteMsgId)}", $"{nameof(DeptId)},{nameof(SiteMsgId)}", true)]
public record Sys_SiteMsgDept : ImmutableEntity public record Sys_SiteMsgDept : ImmutableEntity
{ {

View File

@ -6,7 +6,7 @@ namespace NetAdmin.Domain.DbMaps.Sys;
/// <summary> /// <summary>
/// 站内信标记表 /// 站内信标记表
/// </summary> /// </summary>
[Table(Name = Chars.FLG_TABLE_NAME_PREFIX + nameof(Sys_SiteMsgFlag))] [Table(Name = Chars.FLG_DB_TABLE_NAME_PREFIX + nameof(Sys_SiteMsgFlag))]
[Index($"idx_{{tablename}}_{nameof(SiteMsgId)}_{nameof(UserId)}", $"{nameof(SiteMsgId)},{nameof(UserId)}", true)] [Index($"idx_{{tablename}}_{nameof(SiteMsgId)}_{nameof(UserId)}", $"{nameof(SiteMsgId)},{nameof(UserId)}", true)]
public record Sys_SiteMsgFlag : MutableEntity public record Sys_SiteMsgFlag : MutableEntity
{ {

View File

@ -5,7 +5,7 @@ namespace NetAdmin.Domain.DbMaps.Sys;
/// <summary> /// <summary>
/// 站内信-角色映射表 /// 站内信-角色映射表
/// </summary> /// </summary>
[Table(Name = Chars.FLG_TABLE_NAME_PREFIX + nameof(Sys_SiteMsgRole))] [Table(Name = Chars.FLG_DB_TABLE_NAME_PREFIX + nameof(Sys_SiteMsgRole))]
[Index($"idx_{{tablename}}_{nameof(RoleId)}_{nameof(SiteMsgId)}", $"{nameof(RoleId)},{nameof(SiteMsgId)}", true)] [Index($"idx_{{tablename}}_{nameof(RoleId)}_{nameof(SiteMsgId)}", $"{nameof(RoleId)},{nameof(SiteMsgId)}", true)]
public record Sys_SiteMsgRole : ImmutableEntity public record Sys_SiteMsgRole : ImmutableEntity
{ {

View File

@ -5,7 +5,7 @@ namespace NetAdmin.Domain.DbMaps.Sys;
/// <summary> /// <summary>
/// 站内信-用户映射表 /// 站内信-用户映射表
/// </summary> /// </summary>
[Table(Name = Chars.FLG_TABLE_NAME_PREFIX + nameof(Sys_SiteMsgUser))] [Table(Name = Chars.FLG_DB_TABLE_NAME_PREFIX + nameof(Sys_SiteMsgUser))]
[Index($"idx_{{tablename}}_{nameof(UserId)}_{nameof(SiteMsgId)}", $"{nameof(UserId)},{nameof(SiteMsgId)}", true)] [Index($"idx_{{tablename}}_{nameof(UserId)}_{nameof(SiteMsgId)}", $"{nameof(UserId)},{nameof(SiteMsgId)}", true)]
public record Sys_SiteMsgUser : ImmutableEntity public record Sys_SiteMsgUser : ImmutableEntity
{ {

View File

@ -7,7 +7,7 @@ namespace NetAdmin.Domain.DbMaps.Sys;
/// <summary> /// <summary>
/// 用户基本信息表 /// 用户基本信息表
/// </summary> /// </summary>
[Table(Name = Chars.FLG_TABLE_NAME_PREFIX + nameof(Sys_User))] [Table(Name = Chars.FLG_DB_TABLE_NAME_PREFIX + nameof(Sys_User))]
[Index($"idx_{{tablename}}_{nameof(UserName)}", nameof(UserName), true)] [Index($"idx_{{tablename}}_{nameof(UserName)}", nameof(UserName), true)]
[Index($"idx_{{tablename}}_{nameof(Mobile)}", nameof(Mobile), true)] [Index($"idx_{{tablename}}_{nameof(Mobile)}", nameof(Mobile), true)]
[Index($"idx_{{tablename}}_{nameof(Email)}", nameof(Email), true)] [Index($"idx_{{tablename}}_{nameof(Email)}", nameof(Email), true)]

View File

@ -6,7 +6,7 @@ namespace NetAdmin.Domain.DbMaps.Sys;
/// <summary> /// <summary>
/// 用户档案表 /// 用户档案表
/// </summary> /// </summary>
[Table(Name = Chars.FLG_TABLE_NAME_PREFIX + nameof(Sys_UserProfile))] [Table(Name = Chars.FLG_DB_TABLE_NAME_PREFIX + nameof(Sys_UserProfile))]
public record Sys_UserProfile : VersionEntity, IRegister public record Sys_UserProfile : VersionEntity, IRegister
{ {
/// <summary> /// <summary>

View File

@ -5,7 +5,7 @@ namespace NetAdmin.Domain.DbMaps.Sys;
/// <summary> /// <summary>
/// 用户-角色映射表 /// 用户-角色映射表
/// </summary> /// </summary>
[Table(Name = Chars.FLG_TABLE_NAME_PREFIX + nameof(Sys_UserRole))] [Table(Name = Chars.FLG_DB_TABLE_NAME_PREFIX + nameof(Sys_UserRole))]
public record Sys_UserRole : VersionEntity public record Sys_UserRole : VersionEntity
{ {
/// <summary> /// <summary>

View File

@ -6,7 +6,7 @@ namespace NetAdmin.Domain.DbMaps.Sys;
/// <summary> /// <summary>
/// 验证码表 /// 验证码表
/// </summary> /// </summary>
[Table(Name = Chars.FLG_TABLE_NAME_PREFIX + nameof(Sys_VerifyCode))] [Table(Name = Chars.FLG_DB_TABLE_NAME_PREFIX + nameof(Sys_VerifyCode))]
public record Sys_VerifyCode : VersionEntity public record Sys_VerifyCode : VersionEntity
{ {
/// <summary> /// <summary>

View File

@ -5,5 +5,5 @@ namespace NetAdmin.Domain.DbMaps.Tpl;
/// <summary> /// <summary>
/// 示例表 /// 示例表
/// </summary> /// </summary>
[Table(Name = Chars.FLG_TABLE_NAME_PREFIX + nameof(Tpl_Example))] [Table(Name = Chars.FLG_DB_TABLE_NAME_PREFIX + nameof(Tpl_Example))]
public record Tpl_Example : VersionEntity; public record Tpl_Example : VersionEntity;

View File

@ -11,6 +11,6 @@ public sealed record BulkReq<T> : DataAbstraction
/// </summary> /// </summary>
[Required(ErrorMessageResourceType = typeof(Ln), ErrorMessageResourceName = nameof(Ln.请求对象不能为空))] [Required(ErrorMessageResourceType = typeof(Ln), ErrorMessageResourceName = nameof(Ln.请求对象不能为空))]
[MinLength(1)] [MinLength(1)]
[MaxLength(Numbers.BULK_REQ_LIMIT)] [MaxLength(Numbers.MAX_LIMIT_BULK_REQ)]
public IEnumerable<T> Items { get; init; } public IEnumerable<T> Items { get; init; }
} }

View File

@ -7,10 +7,10 @@ public sealed record PagedQueryReq<T> : QueryReq<T>, IPagedInfo
where T : DataAbstraction, new() where T : DataAbstraction, new()
{ {
/// <inheritdoc cref="IPagedInfo.Page" /> /// <inheritdoc cref="IPagedInfo.Page" />
[Range(1, Numbers.QUERY_MAX_PAGE_NO)] [Range(1, Numbers.MAX_LIMIT_QUERY_PAGE_NO)]
public int Page { get; init; } = 1; public int Page { get; init; } = 1;
/// <inheritdoc cref="IPagedInfo.PageSize" /> /// <inheritdoc cref="IPagedInfo.PageSize" />
[Range(1, Numbers.QUERY_MAX_PAGE_SIZE)] [Range(1, Numbers.MAX_LIMIT_QUERY_PAGE_SIZE)]
public int PageSize { get; init; } = Numbers.QUERY_DEF_PAGE_SIZE; public int PageSize { get; init; } = Numbers.DEF_PAGE_SIZE_QUERY;
} }

View File

@ -9,8 +9,8 @@ public record QueryReq<T> : DataAbstraction
/// <summary> /// <summary>
/// 取前n条 /// 取前n条
/// </summary> /// </summary>
[Range(1, Numbers.QUERY_LIMIT)] [Range(1, Numbers.MAX_LIMIT_QUERY)]
public int Count { get; init; } = Numbers.QUERY_LIMIT; public int Count { get; init; } = Numbers.MAX_LIMIT_QUERY;
/// <summary> /// <summary>
/// 动态查询条件 /// 动态查询条件

View File

@ -21,6 +21,16 @@ public sealed record GetAllEntriesRsp : DataAbstraction
Data = data; Data = data;
} }
/// <summary>
/// 绝对过期时间
/// </summary>
public DateTime? AbsExpTime => AbsExp == -1 ? null : DateTime.FromBinary(AbsExp).ToLocalTime();
/// <summary>
/// 滑动过期时间
/// </summary>
public DateTime? SldExpTime => SldExp == -1 ? null : DateTime.FromBinary(SldExp).ToLocalTime();
/// <summary> /// <summary>
/// 绝对过期时间 /// 绝对过期时间
/// </summary> /// </summary>

View File

@ -10,6 +10,10 @@ namespace NetAdmin.Domain.Dto.Sys.Config;
/// </summary> /// </summary>
public sealed record QueryConfigRsp : Sys_Config public sealed record QueryConfigRsp : Sys_Config
{ {
/// <inheritdoc cref="IFieldCreatedTime.CreatedTime" />
[JsonIgnore(Condition = JsonIgnoreCondition.Never)]
public override DateTime CreatedTime { get; init; }
/// <inheritdoc cref="IFieldEnabled.Enabled" /> /// <inheritdoc cref="IFieldEnabled.Enabled" />
[JsonIgnore(Condition = JsonIgnoreCondition.Never)] [JsonIgnore(Condition = JsonIgnoreCondition.Never)]
public override bool Enabled { get; init; } public override bool Enabled { get; init; }

View File

@ -17,7 +17,7 @@ public record CreateSiteMsgReq : Sys_SiteMsg
/// 部门编号列表 /// 部门编号列表
/// </summary> /// </summary>
[MinLength(1)] [MinLength(1)]
[MaxLength(Numbers.BULK_REQ_LIMIT)] [MaxLength(Numbers.MAX_LIMIT_BULK_REQ)]
public IReadOnlyCollection<long> DeptIds { get; init; } public IReadOnlyCollection<long> DeptIds { get; init; }
/// <inheritdoc cref="Sys_SiteMsg.MsgType" /> /// <inheritdoc cref="Sys_SiteMsg.MsgType" />
@ -30,7 +30,7 @@ public record CreateSiteMsgReq : Sys_SiteMsg
/// 角色编号列表 /// 角色编号列表
/// </summary> /// </summary>
[MinLength(1)] [MinLength(1)]
[MaxLength(Numbers.BULK_REQ_LIMIT)] [MaxLength(Numbers.MAX_LIMIT_BULK_REQ)]
public IReadOnlyCollection<long> RoleIds { get; init; } public IReadOnlyCollection<long> RoleIds { get; init; }
/// <inheritdoc cref="Sys_SiteMsg.Title" /> /// <inheritdoc cref="Sys_SiteMsg.Title" />
@ -42,6 +42,6 @@ public record CreateSiteMsgReq : Sys_SiteMsg
/// 用户编号列表 /// 用户编号列表
/// </summary> /// </summary>
[MinLength(1)] [MinLength(1)]
[MaxLength(Numbers.BULK_REQ_LIMIT)] [MaxLength(Numbers.MAX_LIMIT_BULK_REQ)]
public IReadOnlyCollection<long> UserIds { get; init; } public IReadOnlyCollection<long> UserIds { get; init; }
} }

View File

@ -21,6 +21,10 @@ public sealed record QuerySiteMsgRsp : Sys_SiteMsg
[JsonIgnore(Condition = JsonIgnoreCondition.Never)] [JsonIgnore(Condition = JsonIgnoreCondition.Never)]
public override DateTime CreatedTime { get; init; } public override DateTime CreatedTime { get; init; }
/// <inheritdoc cref="IFieldCreatedUser.CreatedUserName" />
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public override string CreatedUserName { get; init; }
/// <inheritdoc cref="Sys_SiteMsg.Depts" /> /// <inheritdoc cref="Sys_SiteMsg.Depts" />
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public new IEnumerable<QueryDeptRsp> Depts { get; init; } public new IEnumerable<QueryDeptRsp> Depts { get; init; }

View File

@ -43,7 +43,7 @@ public abstract record CreateUpdateUserReq : Sys_User
/// </summary> /// </summary>
[Required(ErrorMessageResourceType = typeof(Ln), ErrorMessageResourceName = nameof(Ln.角色编号列表不能为空))] [Required(ErrorMessageResourceType = typeof(Ln), ErrorMessageResourceName = nameof(Ln.角色编号列表不能为空))]
[MinLength(1)] [MinLength(1)]
[MaxLength(Numbers.BULK_REQ_LIMIT)] [MaxLength(Numbers.MAX_LIMIT_BULK_REQ)]
public IReadOnlyCollection<long> RoleIds { get; init; } public IReadOnlyCollection<long> RoleIds { get; init; }
/// <inheritdoc cref="Sys_User.Summary" /> /// <inheritdoc cref="Sys_User.Summary" />

View File

@ -21,7 +21,7 @@ public sealed record LoginRsp : DataAbstraction
public void SetToRspHeader() public void SetToRspHeader()
{ {
// 设置响应报文头 // 设置响应报文头
App.HttpContext.Response.Headers[Chars.FLG_ACCESS_TOKEN] = AccessToken; App.HttpContext.Response.Headers[Chars.FLG_HTTP_HEADER_VALUE_ACCESS_TOKEN] = AccessToken;
App.HttpContext.Response.Headers[Chars.FLG_X_ACCESS_TOKEN] = RefreshToken; App.HttpContext.Response.Headers[Chars.FLG_HTTP_HEADER_KEY_X_ACCESS_TOKEN] = RefreshToken;
} }
} }

View File

@ -24,6 +24,7 @@ public sealed record SqlCommandAfterEvent : SqlCommandBeforeEvent
/// <inheritdoc /> /// <inheritdoc />
public override string ToString() public override string ToString()
{ {
return string.Format(CultureInfo.InvariantCulture, "SQL-{0}: {2} ms {1}", Id, Sql, ElapsedMicroseconds / 1000); return string.Format(CultureInfo.InvariantCulture, "SQL-{0}: {2} ms {1}", Id
, Sql?.Sub(0, Numbers.MAX_LIMIT_PRINT_LEN_SQL), ElapsedMicroseconds / 1000);
} }
} }

View File

@ -40,9 +40,9 @@ public abstract class WorkBase<TLogger>
/// </summary> /// </summary>
protected Task<IRedLock> GetLockerAsync(string lockId) protected Task<IRedLock> GetLockerAsync(string lockId)
{ {
return _redLocker.RedLockFactory.CreateLockAsync(lockId, TimeSpan.FromSeconds(Numbers.RED_LOCK_EXPIRY_TIME_SECS) return _redLocker.RedLockFactory.CreateLockAsync(lockId, TimeSpan.FromSeconds(Numbers.SECS_RED_LOCK_EXPIRY)
, TimeSpan.FromSeconds(Numbers.RED_LOCK_WAIT_TIME_SECS) , TimeSpan.FromSeconds(Numbers.SECS_RED_LOCK_WAIT)
, TimeSpan.FromSeconds(Numbers.RED_LOCK_RETRY_TIME_SECS)); , TimeSpan.FromSeconds(Numbers.SECS_RED_LOCK_RETRY));
} }
/// <summary> /// <summary>

View File

@ -6,7 +6,7 @@ namespace NetAdmin.Host.Controllers;
/// <summary> /// <summary>
/// 控制器基类 /// 控制器基类
/// </summary> /// </summary>
public abstract class ControllerBase<TCache, TService>(TCache cache) : IDynamicApiController public abstract class ControllerBase<TCache, TService>(TCache cache = default) : IDynamicApiController
where TCache : ICache<IDistributedCache, TService> // where TCache : ICache<IDistributedCache, TService> //
where TService : IService where TService : IService
{ {

View File

@ -1,24 +0,0 @@
using NetAdmin.Application.Services;
using NetAdmin.Cache;
namespace NetAdmin.Host.Controllers;
/// <summary>
/// 健康控制器
/// </summary>
[ApiDescriptionSettings("Health")]
public sealed class HealthController(ICache<IDistributedCache, IService> cache)
: ControllerBase<ICache<IDistributedCache, IService>, IService>(cache)
{
/// <summary>
/// 健康检查
/// </summary>
[AllowAnonymous]
[HttpGet]
#pragma warning disable CA1822, S3400
public string Check()
#pragma warning restore S3400, CA1822
{
return GlobalStatic.ProductVersion;
}
}

View File

@ -0,0 +1,28 @@
using NetAdmin.Application.Services;
using NetAdmin.Cache;
using NetAdmin.Host.Middlewares;
namespace NetAdmin.Host.Controllers;
/// <summary>
/// 探针组件
/// </summary>
[ApiDescriptionSettings("Probe")]
public sealed class ProbeController : ControllerBase<ICache<IDistributedCache, IService>, IService>
{
/// <summary>
/// 健康检查
/// </summary>
[AllowAnonymous]
[HttpGet]
#pragma warning disable CA1822, S3400
public object HealthCheck()
#pragma warning restore S3400, CA1822
{
return new {
HostName = Environment.MachineName
, CurrentConnections = SafetyShopHostMiddleware.Connections
, GlobalStatic.ProductVersion
};
}
}

View File

@ -13,7 +13,7 @@ public static class HttpContextExtensions
public static async Task RemoveJsonNodeWithNullValueAsync(this HttpContext me) public static async Task RemoveJsonNodeWithNullValueAsync(this HttpContext me)
{ {
// 非json格式退出 // 非json格式退出
if (!(me.Response.ContentType?.Contains(Chars.FLG_APPLICATION_JSON) ?? false)) { if (!(me.Response.ContentType?.Contains(Chars.FLG_HTTP_HEADER_VALUE_APPLICATION_JSON) ?? false)) {
return; return;
} }

View File

@ -1,4 +1,3 @@
using Microsoft.AspNetCore.HttpOverrides;
#if DEBUG #if DEBUG
using IGeekFan.AspNetCore.Knife4jUI; using IGeekFan.AspNetCore.Knife4jUI;
@ -42,16 +41,4 @@ public static class IApplicationBuilderExtensions
}); });
} }
#endif #endif
/// <summary>
/// 获取客户端真实Ip
/// </summary>
public static IApplicationBuilder UseRealIp(this IApplicationBuilder me)
{
return me.UseForwardedHeaders(new ForwardedHeadersOptions //
{
ForwardedHeaders = ForwardedHeaders.XForwardedFor |
ForwardedHeaders.XForwardedProto
});
}
} }

View File

@ -105,8 +105,7 @@ public static class ServiceCollectionExtensions
public static IServiceCollection AddConsoleFormatter(this IServiceCollection me) public static IServiceCollection AddConsoleFormatter(this IServiceCollection me)
{ {
return me.AddConsoleFormatter(options => { return me.AddConsoleFormatter(options => {
var logLevels = Enum.GetValues<LogLevels>() var logLevels = Enum.GetValues<LogLevels>().ToDictionary(x => x, x => x.GetDisplay());
.ToDictionary(x => x, x => x.GetDisplay());
#if DEBUG #if DEBUG
options.WriteHandler = (message, _, _, _, _) => { options.WriteHandler = (message, _, _, _, _) => {
@ -242,11 +241,6 @@ public static class ServiceCollectionExtensions
, LogMessage message // , LogMessage message //
, Dictionary<LogLevels, DisplayAttribute> logLevels) , Dictionary<LogLevels, DisplayAttribute> logLevels)
{ {
// 日志过长
if (msg.Length > Numbers.CONSOLE_LINE_LEN_LIMIT) {
msg = $"{Ln.日志长度超过限制} {Numbers.CONSOLE_LINE_LEN_LIMIT}";
}
msg = _consoleColors.Aggregate( // msg = _consoleColors.Aggregate( //
msg, (current, regex) => regex.Key.Replace(current, regex.Value)); msg, (current, regex) => regex.Key.Replace(current, regex.Value));
msg = msg.ReplaceLineEndings(string.Empty); msg = msg.ReplaceLineEndings(string.Empty);

View File

@ -23,12 +23,12 @@ public abstract class ApiResultHandler<T>
/// </summary> /// </summary>
public IActionResult OnException(ExceptionContext context, ExceptionMetadata metadata) public IActionResult OnException(ExceptionContext context, ExceptionMetadata metadata)
{ {
var lineException = context.Exception switch { NetAdminException ex => ex, _ => null }; var naException = context.Exception switch { NetAdminException ex => ex, _ => null };
var errorCode = lineException?.Code ?? ErrorCodes.Unhandled; var errorCode = naException?.Code ?? ErrorCodes.Unhandled;
var result = RestfulResult(errorCode, metadata.Data var result = RestfulResult(errorCode, metadata.Data
, lineException is NetAdminValidateException vEx , naException is NetAdminValidateException vEx
? vEx.ValidateResults ? vEx.ValidateResults
: lineException?.Message ?? errorCode.ResDesc<ErrorCodes>()); : naException?.Message ?? errorCode.ResDesc<ErrorCodes>());
SetErrorCodeToHeader(context.HttpContext, errorCode); SetErrorCodeToHeader(context.HttpContext, errorCode);

View File

@ -8,7 +8,12 @@ public sealed class GlobalExceptionHandler(ILogger<GlobalExceptionHandler> logge
/// <inheritdoc /> /// <inheritdoc />
public Task OnExceptionAsync(ExceptionContext context) public Task OnExceptionAsync(ExceptionContext context)
{ {
if (context.Exception is NetAdminException and not NetAdminUnexpectedException) {
logger.Warn(context.Exception);
}
else {
logger.Error(context.Exception); logger.Error(context.Exception);
}
// 将异常设置到HttpContext.Features中 以便中间件能获取到他 // 将异常设置到HttpContext.Features中 以便中间件能获取到他
context.HttpContext.Features.Set<IExceptionHandlerFeature>( context.HttpContext.Features.Set<IExceptionHandlerFeature>(

View File

@ -5,9 +5,6 @@ namespace NetAdmin.Host.Middlewares;
/// <summary> /// <summary>
/// 请求审计中间件 /// 请求审计中间件
/// </summary> /// </summary>
/// <remarks>
/// 放在所有中间件最前面
/// </remarks>
public sealed class RequestAuditMiddleware( public sealed class RequestAuditMiddleware(
RequestDelegate next RequestDelegate next
, IOptions<DynamicApiControllerSettingsOptions> dynamicApiControllerSettingsOptions , IOptions<DynamicApiControllerSettingsOptions> dynamicApiControllerSettingsOptions
@ -17,7 +14,7 @@ public sealed class RequestAuditMiddleware(
= new($"/{dynamicApiControllerSettingsOptions.Value.DefaultRoutePrefix}"); = new($"/{dynamicApiControllerSettingsOptions.Value.DefaultRoutePrefix}");
private readonly PathString _healthCheckRoutePrefix private readonly PathString _healthCheckRoutePrefix
= new($"/{dynamicApiControllerSettingsOptions.Value.DefaultRoutePrefix}/health/check"); = new($"/{dynamicApiControllerSettingsOptions.Value.DefaultRoutePrefix}/probe/health.check");
/// <summary> /// <summary>
/// 主函数 /// 主函数

View File

@ -0,0 +1,44 @@
namespace NetAdmin.Host.Middlewares;
/// <summary>
/// 安全停机中间件
/// </summary>
/// <remarks>
/// 放在所有中间件最前面
/// </remarks>
public sealed class SafetyShopHostMiddleware(RequestDelegate next)
{
private static long _connections;
private static bool _hostStopping;
/// <summary>
/// 当前连接数
/// </summary>
public static long Connections => Interlocked.Read(ref _connections);
/// <summary>
/// 停机处理
/// </summary>
public static void OnStopping()
{
Volatile.Write(ref _hostStopping, true);
while (Interlocked.Read(ref _connections) > 0) {
Thread.Sleep(10);
}
}
/// <summary>
/// 主函数
/// </summary>
public async Task InvokeAsync(HttpContext context)
{
if (Volatile.Read(ref _hostStopping)) {
context.Response.StatusCode = (int)HttpStatusCode.ServiceUnavailable;
return;
}
_ = Interlocked.Increment(ref _connections);
await next(context).ConfigureAwait(false);
_ = Interlocked.Decrement(ref _connections);
}
}

View File

@ -36,10 +36,12 @@ public sealed class RequestLogger(
_textContentTypes _textContentTypes
, x => context.Request.ContentType?.Contains( , x => context.Request.ContentType?.Contains(
x, StringComparison.OrdinalIgnoreCase) ?? false) x, StringComparison.OrdinalIgnoreCase) ?? false)
? await context.ReadBodyContentAsync().ConfigureAwait(false) ? (await context.ReadBodyContentAsync().ConfigureAwait(false))
?.Sub(0, Numbers.MAX_LIMIT_PRINT_LEN_CONTENT)
: string.Empty : string.Empty
, RequestUrl = context.Request.GetRequestUrlAddress() , RequestUrl = context.Request.GetRequestUrlAddress()
, ResponseBody = responseBody , ResponseBody
= responseBody?.Sub(0, Numbers.MAX_LIMIT_PRINT_LEN_CONTENT)
, ServerIp = context.GetLocalIpAddressToIPv4()?.IpV4ToInt32() , ServerIp = context.GetLocalIpAddressToIPv4()?.IpV4ToInt32()
, ApiId = context.Request.Path.Value?.TrimStart('/') , ApiId = context.Request.Path.Value?.TrimStart('/')
, RequestHeaders = context.Request.Headers.Json() , RequestHeaders = context.Request.Headers.Json()
@ -51,7 +53,10 @@ public sealed class RequestLogger(
, CreatedUserId = associatedUser?.UserId , CreatedUserId = associatedUser?.UserId
, CreatedUserName = associatedUser?.UserName , CreatedUserName = associatedUser?.UserName
, CreatedUserAgent = context.Request.Headers.UserAgent.ToString() , CreatedUserAgent = context.Request.Headers.UserAgent.ToString()
, CreatedClientIp = context.GetRemoteIpAddressToIPv4()?.IpV4ToInt32() , CreatedClientIp = context.GetRealIpAddress()
?.MapToIPv4()
.ToString()
.IpV4ToInt32()
}; };
// 打印日志 // 打印日志

View File

@ -59,7 +59,7 @@ public sealed class SqlAuditor : ISingleton
private static void SetCreatedClientIp(AuditValueEventArgs e) private static void SetCreatedClientIp(AuditValueEventArgs e)
{ {
if (e.Value is null or 0) { if (e.Value is null or 0) {
e.Value = App.HttpContext?.GetRemoteIpAddressToIPv4().IpV4ToInt32(); e.Value = App.HttpContext?.GetRealIpAddress()?.MapToIPv4().ToString().IpV4ToInt32();
} }
} }
@ -80,7 +80,7 @@ public sealed class SqlAuditor : ISingleton
private static void SetCreatedUserAgent(AuditValueEventArgs e) private static void SetCreatedUserAgent(AuditValueEventArgs e)
{ {
if (e.Value is null or "") { if (e.Value is null or "") {
e.Value = App.HttpContext?.Request.Headers[Chars.FLG_HTTP_HEADER_USER_AGENT].ToString(); e.Value = App.HttpContext?.Request.Headers[Chars.FLG_HTTP_HEADER_KEY_USER_AGENT].ToString();
} }
} }

View File

@ -14,8 +14,8 @@ public sealed record CaptchaOptions : OptionAbstraction
{ {
var rtn = new char[32]; var rtn = new char[32];
for (var i = 0; i != 32; i++) { for (var i = 0; i != 32; i++) {
rtn[i] = Chars.FLG_VISIBLE_ASCIIS[ rtn[i] = Chars.FLGL_VISIBLE_ASCIIS[
(int)(Math.Abs(Math.Sin(_seed * (i + 1))) * Chars.FLG_VISIBLE_ASCIIS.Length)]; (int)(Math.Abs(Math.Sin(_seed * (i + 1))) * Chars.FLGL_VISIBLE_ASCIIS.Length)];
} }
SecretKey = new string(rtn); SecretKey = new string(rtn);

View File

@ -10,18 +10,21 @@ namespace NetAdmin.Infrastructure.Constant;
/// </remarks> /// </remarks>
public static class Chars public static class Chars
{ {
public const string FLG_ACCESS_TOKEN = "ACCESS-TOKEN";
public const string FLG_ACCESS_TOKEN_HEADER_KEY = "Authorization";
public const string FLG_APPLICATION_JSON = "application/json";
public const string FLG_AUTH_SCHEMA = "Bearer";
public const string FLG_CONSUL_REG_HOSTNAME = "CONSUL_REG_HOSTNAME";
public const string FLG_CONSUL_REG_PORT = "CONSUL_REG_PORT";
public const string FLG_CONTEXT_MEMBER_INFO = nameof(FLG_CONTEXT_MEMBER_INFO); public const string FLG_CONTEXT_MEMBER_INFO = nameof(FLG_CONTEXT_MEMBER_INFO);
public const string FLG_CONTEXT_OWNER_DEPT_ID = nameof(FLG_CONTEXT_OWNER_DEPT_ID); public const string FLG_CONTEXT_OWNER_DEPT_ID = nameof(FLG_CONTEXT_OWNER_DEPT_ID);
public const string FLG_CONTEXT_USER_ID = nameof(FLG_CONTEXT_USER_ID); public const string FLG_CONTEXT_USER_ID = nameof(FLG_CONTEXT_USER_ID);
public const string FLG_CONTEXT_USER_INFO = nameof(FLG_CONTEXT_USER_INFO); public const string FLG_CONTEXT_USER_INFO = nameof(FLG_CONTEXT_USER_INFO);
public const string FLG_DB_EXCEPTION_PRIVATE_KEY_CONFLICT = "PRIMARY KEY";
public const string FLG_DB_FIELD_TYPE_NVARCHAR = "nvarchar"; public const string FLG_DB_FIELD_TYPE_NVARCHAR = "nvarchar";
public const string FLG_DB_FIELD_TYPE_NVARCHAR_1022 = "nvarchar(1022)";
public const string FLG_DB_FIELD_TYPE_NVARCHAR_127 = "nvarchar(127)";
public const string FLG_DB_FIELD_TYPE_NVARCHAR_15 = "nvarchar(15)";
public const string FLG_DB_FIELD_TYPE_NVARCHAR_255 = "nvarchar(255)"; public const string FLG_DB_FIELD_TYPE_NVARCHAR_255 = "nvarchar(255)";
public const string FLG_DB_FIELD_TYPE_NVARCHAR_31 = "nvarchar(31)";
public const string FLG_DB_FIELD_TYPE_NVARCHAR_4094 = "nvarchar(4094)";
public const string FLG_DB_FIELD_TYPE_NVARCHAR_510 = "nvarchar(510)";
public const string FLG_DB_FIELD_TYPE_NVARCHAR_63 = "nvarchar(63)";
public const string FLG_DB_FIELD_TYPE_NVARCHAR_7 = "nvarchar(7)";
public const string FLG_DB_FIELD_TYPE_NVARCHAR_MAX = "nvarchar(max)"; public const string FLG_DB_FIELD_TYPE_NVARCHAR_MAX = "nvarchar(max)";
public const string FLG_DB_FIELD_TYPE_SMALL_INT = "smallint"; public const string FLG_DB_FIELD_TYPE_SMALL_INT = "smallint";
public const string FLG_DB_FIELD_TYPE_TEXT = "text"; public const string FLG_DB_FIELD_TYPE_TEXT = "text";
@ -36,14 +39,23 @@ public static class Chars
public const string FLG_DB_FIELD_TYPE_VARCHAR_63 = "varchar(63)"; public const string FLG_DB_FIELD_TYPE_VARCHAR_63 = "varchar(63)";
public const string FLG_DB_FIELD_TYPE_VARCHAR_7 = "varchar(7)"; public const string FLG_DB_FIELD_TYPE_VARCHAR_7 = "varchar(7)";
public const string FLG_DB_FIELD_TYPE_VARCHAR_MAX = "varchar(max)"; public const string FLG_DB_FIELD_TYPE_VARCHAR_MAX = "varchar(max)";
public const string FLG_GLOBAL_FILTER_DATA = nameof(FLG_GLOBAL_FILTER_DATA); public const string FLG_DB_TABLE_NAME_PREFIX = "";
public const string FLG_GLOBAL_FILTER_DELETE = nameof(FLG_GLOBAL_FILTER_DELETE); public const string FLG_FREE_SQL_GLOBAL_FILTER_DATA = nameof(FLG_FREE_SQL_GLOBAL_FILTER_DATA);
public const string FLG_GLOBAL_FILTER_MEMBER = nameof(FLG_GLOBAL_FILTER_MEMBER); public const string FLG_FREE_SQL_GLOBAL_FILTER_DELETE = nameof(FLG_FREE_SQL_GLOBAL_FILTER_DELETE);
public const string FLG_GLOBAL_FILTER_SELF = nameof(FLG_GLOBAL_FILTER_SELF); public const string FLG_FREE_SQL_GLOBAL_FILTER_MEMBER = nameof(FLG_FREE_SQL_GLOBAL_FILTER_MEMBER);
public const string FLG_GLOBAL_FILTER_TENANT = nameof(FLG_GLOBAL_FILTER_TENANT); public const string FLG_FREE_SQL_GLOBAL_FILTER_SELF = nameof(FLG_FREE_SQL_GLOBAL_FILTER_SELF);
public const string FLG_HEALTH_CHECK_PATH_PREFIX = "health/check"; public const string FLG_FREE_SQL_GLOBAL_FILTER_TENANT = nameof(FLG_FREE_SQL_GLOBAL_FILTER_TENANT);
public const string FLG_HTTP_HEADER_REFERER = "Referer"; public const string FLG_HTTP_HEADER_KEY_AUTHORIZATION = "Authorization";
public const string FLG_HTTP_HEADER_USER_AGENT = "User-Agent"; public const string FLG_HTTP_HEADER_KEY_REFERER = "Referer";
public const string FLG_HTTP_HEADER_KEY_USER_AGENT = "User-Agent";
public const string FLG_HTTP_HEADER_KEY_X_ACCESS_TOKEN = "X-ACCESS-TOKEN";
public const string FLG_HTTP_HEADER_KEY_X_ACCESS_TOKEN_HEADER_KEY = "X-Authorization";
public const string FLG_HTTP_HEADER_KEY_X_FORWARDED_FOR = "X-Forwarded-For";
public const string FLG_HTTP_HEADER_KEY_X_REAL_IP = "X-Real-IP";
public const string FLG_HTTP_HEADER_VALUE_ACCESS_TOKEN = "ACCESS-TOKEN";
public const string FLG_HTTP_HEADER_VALUE_APPLICATION_JSON = "application/json";
public const string FLG_HTTP_HEADER_VALUE_APPLICATION_URLENCODED = "application/x-www-form-urlencoded";
public const string FLG_HTTP_HEADER_VALUE_AUTH_SCHEMA = "Bearer";
public const string FLG_HTTP_METHOD_CONNECT = "CONNECT"; public const string FLG_HTTP_METHOD_CONNECT = "CONNECT";
public const string FLG_HTTP_METHOD_DELETE = "DELETE"; public const string FLG_HTTP_METHOD_DELETE = "DELETE";
public const string FLG_HTTP_METHOD_GET = "GET"; public const string FLG_HTTP_METHOD_GET = "GET";
@ -53,37 +65,23 @@ public static class Chars
public const string FLG_HTTP_METHOD_POST = "POST"; public const string FLG_HTTP_METHOD_POST = "POST";
public const string FLG_HTTP_METHOD_PUT = "PUT"; public const string FLG_HTTP_METHOD_PUT = "PUT";
public const string FLG_HTTP_METHOD_TRACE = "TRACE"; public const string FLG_HTTP_METHOD_TRACE = "TRACE";
public const string FLG_PATH_PREFIX_HEALTH_CHECK = "probe/health.check";
public const string FLG_RANDOM_UNAME_PWD = "VcXlp7WY"; public const string FLG_RANDOM_UNAME_PWD = "VcXlp7WY";
public const string FLG_REDIS_INSTANCE_DATA_CACHE = "DataCache"; public const string FLG_REDIS_INSTANCE_DATA_CACHE = "DataCache";
public const string FLG_SNOWFLAKE_WORK_ID = "SNOWFLAKE_WORK_ID"; public const string FLG_SNOWFLAKE_WORK_ID = "SNOWFLAKE_WORK_ID";
public const string FLG_SYSTEM_PREFIX = "sc_"; public const string FLG_SYSTEM_PREFIX = "sc_";
public const string FLG_TABLE_NAME_PREFIX = "";
public const string FLG_UA_MOBILE public const string FLGL_HTTP_HEADER_VALUE_UA_MOBILE
= "Mozilla/5.0 (Linux; Android 9; Redmi Note 8 Pro Build/PPR1.180610.011; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/78.0.3904.96 Mobile Safari/537.36"; = "Mozilla/5.0 (Linux; Android 9; Redmi Note 8 Pro Build/PPR1.180610.011; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/78.0.3904.96 Mobile Safari/537.36";
public const string FLG_UA_PC public const string FLGL_HTTP_HEADER_VALUE_UA_PC
= "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36"; = "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36";
public const string FLG_VISIBLE_ASCIIS public const string FLGL_VISIBLE_ASCIIS
= """!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~"""; = """!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~""";
public const string FLG_X_ACCESS_TOKEN = "X-ACCESS-TOKEN";
public const string FLG_X_ACCESS_TOKEN_HEADER_KEY = "X-Authorization";
public const string RGX_CERTIFICATE = "^[a-zA-Z0-9-_]+$"; public const string RGX_CERTIFICATE = "^[a-zA-Z0-9-_]+$";
public const string RGX_CHINESE_NAME
= """^(?:赵|钱|孙|李|周|吴|郑|王|冯|陈|褚|卫|蒋|沈|韩|杨|朱|秦|尤|许|何|吕|施|张|孔|曹|严|华|金|魏|陶|姜|戚|谢|邹|喻|柏|水|窦|章|云|苏|潘|葛|奚|范|彭|郎|鲁|韦|昌|马|苗|凤|花|方|俞|任|袁|柳|酆|鲍|史|唐|费|廉|岑|薛|雷|贺|倪|汤|滕|殷|罗|毕|郝|邬|安|常|乐|于|时|傅|皮|卞|齐|康|伍|余|元|卜|顾|孟|平|黄|和|穆|萧|尹|姚|邵|湛|汪|祁|毛|禹|狄|米|贝|明|臧|计|伏|成|戴|谈|宋|茅|庞|熊|纪|舒|屈|项|祝|董|梁|杜|阮|蓝|闵|席|季|麻|强|贾|路|娄|危|江|童|颜|郭|梅|盛|林|刁|钟|徐|邱|骆|高|夏|蔡|田|樊|胡|凌|霍|虞|万|支|柯|昝|管|卢|莫|经|房|裘|缪|干|解|应|宗|丁|宣|贲|邓|郁|单|杭|洪|包|诸|左|石|崔|吉|钮|龚|程|嵇|邢|滑|裴|陆|荣|翁|荀|羊|於|惠|甄|曲|家|封|芮|羿|储|靳|汲|邴|糜|松|井|段|富|巫|乌|焦|巴|弓|牧|隗|山|谷|车|侯|宓|蓬|全|郗|班|仰|秋|仲|伊|宫|宁|仇|栾|暴|甘|钭|厉|戎|祖|武|符|刘|景|詹|束|龙|叶|幸|司|韶|郜|黎|蓟|薄|印|宿|白|怀|蒲|邰|从|鄂|索|咸|籍|赖|卓|蔺|屠|蒙|池|乔|阴|胥|能|苍|双|闻|莘|党|翟|谭|贡|劳|逄|姬|申|扶|堵|冉|宰|郦|雍|郤|璩|桑|桂|濮|牛|寿|通|边|扈|燕|冀|郏|浦|尚|农|温|别|庄|晏|柴|瞿|阎|充|慕|连|茹|习|宦|艾|鱼|容|向|古|易|慎|戈|廖|庾|终|暨|居|衡|步|都|耿|满|弘|匡|国|文|寇|广|禄|阙|东|欧|殳|沃|利|蔚|越|夔|隆|师|巩|厍|聂|晁|勾|敖|融|冷|訾|辛|阚|那|简|饶|空|曾|毋|沙|乜|养|鞠|须|丰|巢|关|蒯|相|查|後|荆|红|游|竺|权|逯|盖|益|桓|公|万俟|司马|上官|欧阳|夏侯|诸葛|闻人|东方|赫连|皇甫|尉迟|公羊|澹台|公冶|宗政|濮阳|淳于|单于|太叔|申屠|公孙|仲孙|轩辕|令狐|钟离|宇文|长孙|慕容|鲜于|闾丘|司徒|司空|亓官|司寇|仉|督|子车|颛孙|端木|巫马|公西|漆雕|乐正|壤驷|公良|拓跋|夹谷|宰父|谷梁|晋|楚|闫|法|汝|鄢|涂|钦|段干|百里|东郭|南门|呼延|归|海|羊舌|微生|岳|帅|缑|亢|况|后|有|琴|梁丘|左丘|东门|西门|商|牟|佘|佴|伯|赏|南宫|墨|哈|谯|笪|年|爱|阳|佟|第五|言|福)[\u4e00-\u9fa5]{1,3}$""";
public const string RGX_CRON
= "^\\s*($|#|\\w+\\s*=|(\\?|\\*|(?:[0-5]?\\d)(?:(?:-|\\/|\\,)(?:[0-5]?\\d))?(?:,(?:[0-5]?\\d)(?:(?:-|\\/|\\,)(?:[0-5]?\\d))?)*)\\s+(\\?|\\*|(?:[0-5]?\\d)(?:(?:-|\\/|\\,)(?:[0-5]?\\d))?(?:,(?:[0-5]?\\d)(?:(?:-|\\/|\\,)(?:[0-5]?\\d))?)*)\\s+(\\?|\\*|(?:[01]?\\d|2[0-3])(?:(?:-|\\/|\\,)(?:[01]?\\d|2[0-3]))?(?:,(?:[01]?\\d|2[0-3])(?:(?:-|\\/|\\,)(?:[01]?\\d|2[0-3]))?)*)\\s+(\\?|\\*|(?:0?[1-9]|[12]\\d|3[01])(?:(?:-|\\/|\\,)(?:0?[1-9]|[12]\\d|3[01]))?(?:,(?:0?[1-9]|[12]\\d|3[01])(?:(?:-|\\/|\\,)(?:0?[1-9]|[12]\\d|3[01]))?)*)\\s+(\\?|\\*|(?:[1-9]|1[012])(?:(?:-|\\/|\\,)(?:[1-9]|1[012]))?(?:L|W)?(?:,(?:[1-9]|1[012])(?:(?:-|\\/|\\,)(?:[1-9]|1[012]))?(?:L|W)?)*|\\?|\\*|(?:JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC)(?:(?:-)(?:JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC))?(?:,(?:JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC)(?:(?:-)(?:JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC))?)*)\\s+(\\?|\\*|(?:[0-6])(?:(?:-|\\/|\\,|#)(?:[0-6]))?(?:L)?(?:,(?:[0-6])(?:(?:-|\\/|\\,|#)(?:[0-6]))?(?:L)?)*|\\?|\\*|(?:MON|TUE|WED|THU|FRI|SAT|SUN)(?:(?:-)(?:MON|TUE|WED|THU|FRI|SAT|SUN))?(?:,(?:MON|TUE|WED|THU|FRI|SAT|SUN)(?:(?:-)(?:MON|TUE|WED|THU|FRI|SAT|SUN))?)*)(|\\s)+(\\?|\\*|(?:|\\d{4})(?:(?:-|\\/|\\,)(?:|\\d{4}))?(?:,(?:|\\d{4})(?:(?:-|\\/|\\,)(?:|\\d{4}))?)*))$";
public const string RGX_EMAIL
= """^((([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))$""";
public const string RGX_INVITE_CODE = """^\d{8}$"""; public const string RGX_INVITE_CODE = """^\d{8}$""";
public const string RGX_MOBILE = """^1(3\d|4[5-9]|5[0-35-9]|6[6]|7[2-8]|8\d|9[0-35-9])\d{8}$"""; public const string RGX_MOBILE = """^1(3\d|4[5-9]|5[0-35-9]|6[6]|7[2-8]|8\d|9[0-35-9])\d{8}$""";
public const string RGX_PASSWORD = "^(?![0-9]+$)(?![a-zA-Z]+$).{8,16}$"; public const string RGX_PASSWORD = "^(?![0-9]+$)(?![a-zA-Z]+$).{8,16}$";
public const string RGX_PAY_PASSWORD = """^\d{6}$"""; public const string RGX_PAY_PASSWORD = """^\d{6}$""";
@ -93,6 +91,18 @@ public static class Chars
public const string RGX_USERNAME = "^[a-zA-Z0-9_]{4,16}$"; public const string RGX_USERNAME = "^[a-zA-Z0-9_]{4,16}$";
public const string RGX_VERIFY_CODE = """^\d{4}$"""; public const string RGX_VERIFY_CODE = """^\d{4}$""";
public const string RGXL_CHINESE_NAME
= """^(?:赵|钱|孙|李|周|吴|郑|王|冯|陈|褚|卫|蒋|沈|韩|杨|朱|秦|尤|许|何|吕|施|张|孔|曹|严|华|金|魏|陶|姜|戚|谢|邹|喻|柏|水|窦|章|云|苏|潘|葛|奚|范|彭|郎|鲁|韦|昌|马|苗|凤|花|方|俞|任|袁|柳|酆|鲍|史|唐|费|廉|岑|薛|雷|贺|倪|汤|滕|殷|罗|毕|郝|邬|安|常|乐|于|时|傅|皮|卞|齐|康|伍|余|元|卜|顾|孟|平|黄|和|穆|萧|尹|姚|邵|湛|汪|祁|毛|禹|狄|米|贝|明|臧|计|伏|成|戴|谈|宋|茅|庞|熊|纪|舒|屈|项|祝|董|梁|杜|阮|蓝|闵|席|季|麻|强|贾|路|娄|危|江|童|颜|郭|梅|盛|林|刁|钟|徐|邱|骆|高|夏|蔡|田|樊|胡|凌|霍|虞|万|支|柯|昝|管|卢|莫|经|房|裘|缪|干|解|应|宗|丁|宣|贲|邓|郁|单|杭|洪|包|诸|左|石|崔|吉|钮|龚|程|嵇|邢|滑|裴|陆|荣|翁|荀|羊|於|惠|甄|曲|家|封|芮|羿|储|靳|汲|邴|糜|松|井|段|富|巫|乌|焦|巴|弓|牧|隗|山|谷|车|侯|宓|蓬|全|郗|班|仰|秋|仲|伊|宫|宁|仇|栾|暴|甘|钭|厉|戎|祖|武|符|刘|景|詹|束|龙|叶|幸|司|韶|郜|黎|蓟|薄|印|宿|白|怀|蒲|邰|从|鄂|索|咸|籍|赖|卓|蔺|屠|蒙|池|乔|阴|胥|能|苍|双|闻|莘|党|翟|谭|贡|劳|逄|姬|申|扶|堵|冉|宰|郦|雍|郤|璩|桑|桂|濮|牛|寿|通|边|扈|燕|冀|郏|浦|尚|农|温|别|庄|晏|柴|瞿|阎|充|慕|连|茹|习|宦|艾|鱼|容|向|古|易|慎|戈|廖|庾|终|暨|居|衡|步|都|耿|满|弘|匡|国|文|寇|广|禄|阙|东|欧|殳|沃|利|蔚|越|夔|隆|师|巩|厍|聂|晁|勾|敖|融|冷|訾|辛|阚|那|简|饶|空|曾|毋|沙|乜|养|鞠|须|丰|巢|关|蒯|相|查|後|荆|红|游|竺|权|逯|盖|益|桓|公|万俟|司马|上官|欧阳|夏侯|诸葛|闻人|东方|赫连|皇甫|尉迟|公羊|澹台|公冶|宗政|濮阳|淳于|单于|太叔|申屠|公孙|仲孙|轩辕|令狐|钟离|宇文|长孙|慕容|鲜于|闾丘|司徒|司空|亓官|司寇|仉|督|子车|颛孙|端木|巫马|公西|漆雕|乐正|壤驷|公良|拓跋|夹谷|宰父|谷梁|晋|楚|闫|法|汝|鄢|涂|钦|段干|百里|东郭|南门|呼延|归|海|羊舌|微生|岳|帅|缑|亢|况|后|有|琴|梁丘|左丘|东门|西门|商|牟|佘|佴|伯|赏|南宫|墨|哈|谯|笪|年|爱|阳|佟|第五|言|福)[\u4e00-\u9fa5]{1,3}$""";
public const string RGXL_CRON
= "^\\s*($|#|\\w+\\s*=|(\\?|\\*|(?:[0-5]?\\d)(?:(?:-|\\/|\\,)(?:[0-5]?\\d))?(?:,(?:[0-5]?\\d)(?:(?:-|\\/|\\,)(?:[0-5]?\\d))?)*)\\s+(\\?|\\*|(?:[0-5]?\\d)(?:(?:-|\\/|\\,)(?:[0-5]?\\d))?(?:,(?:[0-5]?\\d)(?:(?:-|\\/|\\,)(?:[0-5]?\\d))?)*)\\s+(\\?|\\*|(?:[01]?\\d|2[0-3])(?:(?:-|\\/|\\,)(?:[01]?\\d|2[0-3]))?(?:,(?:[01]?\\d|2[0-3])(?:(?:-|\\/|\\,)(?:[01]?\\d|2[0-3]))?)*)\\s+(\\?|\\*|(?:0?[1-9]|[12]\\d|3[01])(?:(?:-|\\/|\\,)(?:0?[1-9]|[12]\\d|3[01]))?(?:,(?:0?[1-9]|[12]\\d|3[01])(?:(?:-|\\/|\\,)(?:0?[1-9]|[12]\\d|3[01]))?)*)\\s+(\\?|\\*|(?:[1-9]|1[012])(?:(?:-|\\/|\\,)(?:[1-9]|1[012]))?(?:L|W)?(?:,(?:[1-9]|1[012])(?:(?:-|\\/|\\,)(?:[1-9]|1[012]))?(?:L|W)?)*|\\?|\\*|(?:JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC)(?:(?:-)(?:JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC))?(?:,(?:JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC)(?:(?:-)(?:JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC))?)*)\\s+(\\?|\\*|(?:[0-6])(?:(?:-|\\/|\\,|#)(?:[0-6]))?(?:L)?(?:,(?:[0-6])(?:(?:-|\\/|\\,|#)(?:[0-6]))?(?:L)?)*|\\?|\\*|(?:MON|TUE|WED|THU|FRI|SAT|SUN)(?:(?:-)(?:MON|TUE|WED|THU|FRI|SAT|SUN))?(?:,(?:MON|TUE|WED|THU|FRI|SAT|SUN)(?:(?:-)(?:MON|TUE|WED|THU|FRI|SAT|SUN))?)*)(|\\s)+(\\?|\\*|(?:|\\d{4})(?:(?:-|\\/|\\,)(?:|\\d{4}))?(?:,(?:|\\d{4})(?:(?:-|\\/|\\,)(?:|\\d{4}))?)*))$";
public const string RGXL_EMAIL
= """^((([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))$""";
public const string RGXL_IP_V4
= @"^(25[0-5]|2[0-4][0-9]|[0-1]?[0-9]{1,2})(\.(25[0-5]|2[0-4][0-9]|[0-1]?[0-9]{1,2})){3}$";
public const string TPL_DATE_HH_MM_SS_FFFFFF = "HH:mm:ss.ffffff"; public const string TPL_DATE_HH_MM_SS_FFFFFF = "HH:mm:ss.ffffff";
public const string TPL_DATE_YYYY_MM_DD = "yyyy-MM-dd"; public const string TPL_DATE_YYYY_MM_DD = "yyyy-MM-dd";
public const string TPL_DATE_YYYY_MM_DD_HH_MM_SS = "yyyy-MM-dd HH:mm:ss"; public const string TPL_DATE_YYYY_MM_DD_HH_MM_SS = "yyyy-MM-dd HH:mm:ss";

View File

@ -10,17 +10,22 @@ namespace NetAdmin.Infrastructure.Constant;
/// </remarks> /// </remarks>
public static class Numbers public static class Numbers
{ {
public const int BULK_REQ_LIMIT = 100; // 批量请求允许的最大数量 public const int DEF_PAGE_SIZE_QUERY = 20; // 分页查询默认的页容量
public const int CONSOLE_LINE_LEN_LIMIT = 8192; // 控制台输出的最大长度
public const long DEF_SORT_VAL = 100; // 排序默认值 public const long DEF_SORT_VAL = 100; // 排序默认值
public const long DIC_CATALOG_ID_GEO_AREA = 379794295185413; // 字典目录编号-行政区划字典
public const int HTTP_STATUS_BIZ_FAIL = 900; // Http状态码-业务异常 public const int HTTP_STATUS_BIZ_FAIL = 900; // Http状态码-业务异常
public const int QUERY_DEF_PAGE_SIZE = 20; // 分页查询默认的页容量 public const long ID_DIC_CATALOG_GEO_AREA = 379794295185413; // 唯一编号:字典目录-行政区划字典
public const int QUERY_LIMIT = 100; // 非分页查询允许返回的最大条数
public const int QUERY_MAX_PAGE_NO = 1000; // 分页查询允许最大的页码 public const int MAX_LIMIT_BULK_REQ = 100; // 最大限制:批量请求数
public const int QUERY_MAX_PAGE_SIZE = 100; // 分页查询允许最大的页容量 public const int MAX_LIMIT_PRINT_LEN_CONTENT = 4096; // 最大限制打印长度HTTP 内容)
public const int RED_LOCK_EXPIRY_TIME_SECS = 30; // red lock 锁锁定过期时间,锁区域内的逻辑执行如果超过过期时间,锁将被释放 public const int MAX_LIMIT_PRINT_LEN_SQL = 4096; // 最大限制打印长度SQL 语句)
public const int RED_LOCK_RETRY_TIME_SECS = 1; // red lock 锁等待时间内,多久尝试获取一次 public const int MAX_LIMIT_QUERY = 1000; // 最大限制:非分页查询条数
public const int RED_LOCK_WAIT_TIME_SECS = 10; // red lock 锁等待时间,相同的 resource 如果当前的锁被其他线程占用,最多等待时间 public const int MAX_LIMIT_QUERY_PAGE_NO = 10000; // 最大限制:分页查询页码
public const int TIMEOUT_SECS_JOB = 600; // 超时时间:作业 public const int MAX_LIMIT_QUERY_PAGE_SIZE = 100; // 最大限制:分页查询页容量
public const int SECS_CACHE_DEFAULT = 60; // 秒:缓存时间-默认
public const int SECS_RED_LOCK_EXPIRY = 30; // 秒RedLock-锁过期时间,锁区域内的逻辑执行如果超过过期时间,锁将被释放
public const int SECS_RED_LOCK_RETRY = 1; // 秒RedLock-锁等待时间内,多久尝试获取一次
public const int SECS_RED_LOCK_WAIT = 10; // 秒RedLock-锁等待时间,相同的 resource 如果当前的锁被其他线程占用,最多等待时间
public const int SECS_TIMEOUT_JOB = 600; // 秒:超时时间-作业
} }

View File

@ -19,4 +19,12 @@ public enum Orders
/// </summary> /// </summary>
[ResourceDescription<Ln>(nameof(Ln.倒序排序))] [ResourceDescription<Ln>(nameof(Ln.倒序排序))]
Descending = 2 Descending = 2
,
/// <summary>
/// 随机排序
/// </summary>
[ResourceDescription<Ln>(nameof(Ln.随机排序))]
Random = 3
} }

View File

@ -4,5 +4,5 @@ namespace NetAdmin.Infrastructure.Exceptions;
/// 加锁失败异常 /// 加锁失败异常
/// </summary> /// </summary>
#pragma warning disable RCS1194 #pragma warning disable RCS1194
public sealed class NetAdminGetLockerException : NetAdminUnexpectedException; public sealed class NetAdminGetLockerException : NetAdminException;
#pragma warning restore RCS1194 #pragma warning restore RCS1194

View File

@ -0,0 +1,25 @@
namespace NetAdmin.Infrastructure.Extensions;
/// <summary>
/// HttpContext 扩展方法
/// </summary>
public static class HttpContextExtensions
{
/// <summary>
/// 获取客户端真实IP
/// </summary>
public static IPAddress GetRealIpAddress(this HttpContext me)
{
#pragma warning disable IDE0046
if (me.Request.Headers.TryGetValue(Chars.FLG_HTTP_HEADER_KEY_X_FORWARDED_FOR, out var ips1) &&
#pragma warning restore IDE0046
IPAddress.TryParse(ips1.FirstOrDefault()?.Split(',').FirstOrDefault(), out var ip1)) {
return ip1;
}
return me.Request.Headers.TryGetValue(Chars.FLG_HTTP_HEADER_KEY_X_REAL_IP, out var ips2) &&
IPAddress.TryParse(ips2.FirstOrDefault()?.Split(',').FirstOrDefault(), out var ip2)
? ip2
: me.Connection.RemoteIpAddress;
}
}

View File

@ -19,7 +19,8 @@ public static class HttpRequestMessageExtensions
/// </summary> /// </summary>
public static async Task<HttpRequestMessage> LogAsync<T>(this HttpRequestMessage me, ILogger<T> logger) public static async Task<HttpRequestMessage> LogAsync<T>(this HttpRequestMessage me, ILogger<T> logger)
{ {
logger.Info($"HTTP Request: {await me.BuildJsonAsync().ConfigureAwait(false)}"); logger.Info(
$"HTTP Request: {(await me.BuildJsonAsync().ConfigureAwait(false))?.Sub(0, Numbers.MAX_LIMIT_PRINT_LEN_CONTENT)}");
return me; return me;
} }
} }

View File

@ -11,7 +11,9 @@ public static class HttpResponseMessageExtensions
public static async Task LogAsync<T>(this HttpResponseMessage me, ILogger<T> logger public static async Task LogAsync<T>(this HttpResponseMessage me, ILogger<T> logger
, Func<string, string> bodyPreHandle = null) , Func<string, string> bodyPreHandle = null)
{ {
logger.Info(await me.BuildJsonAsync(bodyPreHandle).ConfigureAwait(false)); logger.Info(
(await me.BuildJsonAsync(bodyPreHandle).ConfigureAwait(false))?.Sub(
0, Numbers.MAX_LIMIT_PRINT_LEN_CONTENT));
} }
/// <summary> /// <summary>
@ -20,7 +22,8 @@ public static class HttpResponseMessageExtensions
public static async Task LogExceptionAsync<T>(this HttpResponseMessage me, string errors, ILogger<T> logger public static async Task LogExceptionAsync<T>(this HttpResponseMessage me, string errors, ILogger<T> logger
, Func<string, string> bodyHandle = null) , Func<string, string> bodyHandle = null)
{ {
logger.Warn($"{errors}: {await me.BuildJsonAsync(bodyHandle).ConfigureAwait(false)}"); logger.Warn(
$"{errors}: {(await me.BuildJsonAsync(bodyHandle).ConfigureAwait(false))?.Sub(0, Numbers.MAX_LIMIT_PRINT_LEN_CONTENT)}");
} }
/// <summary> /// <summary>

View File

@ -7,12 +7,12 @@
<Import Project="$(SolutionDir)/build/prebuild.targets"/> <Import Project="$(SolutionDir)/build/prebuild.targets"/>
<ItemGroup> <ItemGroup>
<PackageReference Include="Cronos" Version="0.8.4"/> <PackageReference Include="Cronos" Version="0.8.4"/>
<PackageReference Include="FreeSql.DbContext.NS" Version="3.2.813-preview20240208-ns1"/> <PackageReference Include="FreeSql.DbContext.NS" Version="3.2.821-ns1"/>
<PackageReference Include="FreeSql.Provider.Sqlite.NS" Version="3.2.813-preview20240208-ns1"/> <PackageReference Include="FreeSql.Provider.Sqlite.NS" Version="3.2.821-ns1"/>
<PackageReference Include="Furion.Extras.Authentication.JwtBearer" Version="4.9.1.31"/> <PackageReference Include="Furion.Extras.Authentication.JwtBearer" Version="4.9.2.19"/>
<PackageReference Include="Furion.Extras.ObjectMapper.Mapster.NS" Version="4.9.1.31-ns2"/> <PackageReference Include="Furion.Extras.ObjectMapper.Mapster.NS" Version="4.9.2.19-ns3"/>
<PackageReference Include="Furion.Pure.NS" Version="4.9.1.31-ns2"/> <PackageReference Include="Furion.Pure.NS" Version="4.9.2.19-ns3"/>
<PackageReference Include="Microsoft.Extensions.Caching.StackExchangeRedis" Version="9.0.0-preview.1.24081.5"/> <PackageReference Include="Microsoft.Extensions.Caching.StackExchangeRedis" Version="8.0.1"/>
<PackageReference Include="Minio" Version="6.0.2"/> <PackageReference Include="Minio" Version="6.0.2"/>
<PackageReference Include="NSExt" Version="2.1.0"/> <PackageReference Include="NSExt" Version="2.1.0"/>
<PackageReference Include="RedLock.net" Version="2.3.2"/> <PackageReference Include="RedLock.net" Version="2.3.2"/>

View File

@ -315,8 +315,9 @@ public sealed class UserAgentParser
private bool SetPlatform() private bool SetPlatform()
{ {
var kv = _platforms.First(x => // var kv = _platforms.FirstOrDefault(x => //
Regex.IsMatch(_agent, $"{Regex.Escape(x.Key)}", RegexOptions.IgnoreCase)); Regex.IsMatch(_agent, $"{Regex.Escape(x.Key)}"
, RegexOptions.IgnoreCase));
if (kv.Key == null) { if (kv.Key == null) {
Platform = "Unknown Platform"; Platform = "Unknown Platform";

View File

@ -297,8 +297,8 @@
// //
{ {
"Name": "DataCache", "Name": "DataCache",
"ConnStr": "localhost:6379", "ConnStr": "localhost:6379,abortConnect=false",
"Database": 0 "DataBase": 0,
} }
] ]
}, },

View File

@ -24,10 +24,10 @@ public sealed class Startup : Host.Startup
/// <summary> /// <summary>
/// 配置应用程序中间件 /// 配置应用程序中间件
/// </summary> /// </summary>
public void Configure(IApplicationBuilder app) public void Configure(IApplicationBuilder app, IHostApplicationLifetime lifeTime)
{ {
_ = app // _ = app //
.UseRealIp() // 使用RealIp中间件用于获取真实客户端IP地址 .UseMiddleware<SafetyShopHostMiddleware>() // 安全停机中间件
.EnableBuffering() // 启用请求体缓冲,允许多次读取请求体 .EnableBuffering() // 启用请求体缓冲,允许多次读取请求体
.UseMiddleware<RequestAuditMiddleware>() // 使用RequestAuditMiddleware中间件执行请求审计 .UseMiddleware<RequestAuditMiddleware>() // 使用RequestAuditMiddleware中间件执行请求审计
#if DEBUG #if DEBUG
@ -41,6 +41,7 @@ public sealed class Startup : Host.Startup
.UseRouting() // 使用Routing中间件配置路由映射 .UseRouting() // 使用Routing中间件配置路由映射
.UseMiddleware<RemoveNullNodeMiddleware>() // 使用RemoveNullNodeMiddleware中间件删除JSON中的空节点 .UseMiddleware<RemoveNullNodeMiddleware>() // 使用RemoveNullNodeMiddleware中间件删除JSON中的空节点
.UseEndpoints(); // 配置端点以处理请求 .UseEndpoints(); // 配置端点以处理请求
_ = lifeTime.ApplicationStopping.Register(SafetyShopHostMiddleware.OnStopping);
} }
/// <summary> /// <summary>

View File

@ -21,6 +21,13 @@ public sealed class ApiService(
throw new NotImplementedException(); throw new NotImplementedException();
} }
/// <inheritdoc />
public Task<long> CountAsync(QueryReq<QueryApiReq> req)
{
req.ThrowIfInvalid();
return QueryInternal(req).CountAsync();
}
/// <inheritdoc /> /// <inheritdoc />
public Task<QueryApiRsp> CreateAsync(CreateApiReq req) public Task<QueryApiRsp> CreateAsync(CreateApiReq req)
{ {
@ -140,9 +147,12 @@ public sealed class ApiService(
private ISelect<Sys_Api> QueryInternal(QueryReq<QueryApiReq> req) private ISelect<Sys_Api> QueryInternal(QueryReq<QueryApiReq> req)
{ {
var ret = Rpo.Select.WhereDynamicFilter(req.DynamicFilter) var ret = Rpo.Select.WhereDynamicFilter(req.DynamicFilter).WhereDynamic(req.Filter);
.WhereDynamic(req.Filter) if (req.Order == Orders.Random) {
.OrderByPropertyNameIf(req.Prop?.Length > 0, req.Prop, req.Order == Orders.Ascending); return ret.OrderByRandom();
}
ret = ret.OrderByPropertyNameIf(req.Prop?.Length > 0, req.Prop, req.Order == Orders.Ascending);
if (!req.Prop?.Equals(nameof(req.Filter.CreatedTime), StringComparison.OrdinalIgnoreCase) ?? true) { if (!req.Prop?.Equals(nameof(req.Filter.CreatedTime), StringComparison.OrdinalIgnoreCase) ?? true) {
ret = ret.OrderByDescending(a => a.CreatedTime); ret = ret.OrderByDescending(a => a.CreatedTime);

View File

@ -10,11 +10,21 @@ namespace NetAdmin.SysComponent.Application.Services.Sys;
public sealed class CacheService(IConnectionMultiplexer connectionMultiplexer) // public sealed class CacheService(IConnectionMultiplexer connectionMultiplexer) //
: ServiceBase<ICacheService>, ICacheService : ServiceBase<ICacheService>, ICacheService
{ {
private readonly InstanceNode _redisInstance;
/// <summary>
/// Initializes a new instance of the <see cref="CacheService" /> class.
/// </summary>
public CacheService(IConnectionMultiplexer connectionMultiplexer, IOptions<RedisOptions> redisOptions) //
: this(connectionMultiplexer) //
{
_redisInstance = redisOptions.Value.Instances.First(x => x.Name == Chars.FLG_REDIS_INSTANCE_DATA_CACHE);
}
/// <inheritdoc /> /// <inheritdoc />
public async Task<CacheStatisticsRsp> CacheStatisticsAsync() public async Task<CacheStatisticsRsp> CacheStatisticsAsync()
{ {
var database = connectionMultiplexer.GetDatabase(); var database = connectionMultiplexer.GetDatabase(_redisInstance.Database);
return new CacheStatisticsRsp((string)await database.ExecuteAsync("info").ConfigureAwait(false)) { return new CacheStatisticsRsp((string)await database.ExecuteAsync("info").ConfigureAwait(false)) {
DbSize = (long)await database.ExecuteAsync("dbSize").ConfigureAwait(false) DbSize = (long)await database.ExecuteAsync("dbSize").ConfigureAwait(false)
}; };
@ -24,7 +34,7 @@ public sealed class CacheService(IConnectionMultiplexer connectionMultiplexer) /
public async Task<PagedQueryRsp<GetAllEntriesRsp>> GetAllEntriesAsync(PagedQueryReq<GetAllEntriesReq> req) public async Task<PagedQueryRsp<GetAllEntriesRsp>> GetAllEntriesAsync(PagedQueryReq<GetAllEntriesReq> req)
{ {
req.ThrowIfInvalid(); req.ThrowIfInvalid();
var database = connectionMultiplexer.GetDatabase((int?)req.Filter?.DbIndex ?? 0); var database = connectionMultiplexer.GetDatabase(_redisInstance.Database);
var redisResults = (RedisResult[])await database var redisResults = (RedisResult[])await database
.ExecuteAsync("scan", (req.Page - 1) * req.PageSize, "count" .ExecuteAsync("scan", (req.Page - 1) * req.PageSize, "count"
, req.PageSize) , req.PageSize)

View File

@ -26,6 +26,13 @@ public sealed class ConfigService(DefaultRepository<Sys_Config> rpo) //
return ret; return ret;
} }
/// <inheritdoc />
public Task<long> CountAsync(QueryReq<QueryConfigReq> req)
{
req.ThrowIfInvalid();
return QueryInternal(req).CountAsync();
}
/// <inheritdoc /> /// <inheritdoc />
public async Task<QueryConfigRsp> CreateAsync(CreateConfigReq req) public async Task<QueryConfigRsp> CreateAsync(CreateConfigReq req)
{ {
@ -113,8 +120,12 @@ public sealed class ConfigService(DefaultRepository<Sys_Config> rpo) //
.Include(a => a.UserRegisterRole) .Include(a => a.UserRegisterRole)
.WhereDynamicFilter(req.DynamicFilter) .WhereDynamicFilter(req.DynamicFilter)
.WhereIf( // .WhereIf( //
req.Filter?.Enabled.HasValue ?? false, a => a.Enabled == req.Filter.Enabled.Value) req.Filter?.Enabled.HasValue ?? false, a => a.Enabled == req.Filter.Enabled.Value);
.OrderByPropertyNameIf(req.Prop?.Length > 0, req.Prop, req.Order == Orders.Ascending); if (req.Order == Orders.Random) {
return ret.OrderByRandom();
}
ret = ret.OrderByPropertyNameIf(req.Prop?.Length > 0, req.Prop, req.Order == Orders.Ascending);
if (!req.Prop?.Equals(nameof(req.Filter.Id), StringComparison.OrdinalIgnoreCase) ?? true) { if (!req.Prop?.Equals(nameof(req.Filter.Id), StringComparison.OrdinalIgnoreCase) ?? true) {
ret = ret.OrderByDescending(a => a.Id); ret = ret.OrderByDescending(a => a.Id);
} }

View File

@ -18,7 +18,7 @@ public sealed class ConstantService : ServiceBase<IConstantService>, IConstantSe
/// <inheritdoc /> /// <inheritdoc />
public IDictionary<string, Dictionary<string, string[]>> GetEnums() public IDictionary<string, Dictionary<string, string[]>> GetEnums()
{ {
return App.EffectiveTypes.Where(x => x.IsEnum && x.GetCustomAttribute<ExportAttribute>(false) != null) var ret = App.EffectiveTypes.Where(x => x.IsEnum && x.GetCustomAttribute<ExportAttribute>(false) != null)
.ToDictionary(x => x.Name, x => // .ToDictionary(x => x.Name, x => //
x.GetEnumValues() x.GetEnumValues()
.Cast<Enum>() .Cast<Enum>()
@ -29,6 +29,17 @@ public sealed class ConstantService : ServiceBase<IConstantService>, IConstantSe
.ToString(CultureInfo.InvariantCulture) .ToString(CultureInfo.InvariantCulture)
, y.ResDesc<Ln>() , y.ResDesc<Ln>()
})); }));
ret.Add($"{nameof(HttpStatusCode)}s", Enum.GetNames<HttpStatusCode>()
.ToDictionary( //
x => x, x => new[] {
Convert.ToInt64( //
Enum.Parse<HttpStatusCode>(x)
, CultureInfo.InvariantCulture)
.ToString(CultureInfo.InvariantCulture)
, x
}));
return ret;
} }
/// <inheritdoc /> /// <inheritdoc />

View File

@ -25,6 +25,13 @@ public sealed class DeptService(DefaultRepository<Sys_Dept> rpo) //
return ret; return ret;
} }
/// <inheritdoc />
public Task<long> CountAsync(QueryReq<QueryDeptReq> req)
{
req.ThrowIfInvalid();
return QueryInternal(req).CountAsync();
}
/// <inheritdoc /> /// <inheritdoc />
/// <exception cref="NetAdminInvalidOperationException">Parent_department_does_not_exist</exception> /// <exception cref="NetAdminInvalidOperationException">Parent_department_does_not_exist</exception>
public async Task<QueryDeptRsp> CreateAsync(CreateDeptReq req) public async Task<QueryDeptRsp> CreateAsync(CreateDeptReq req)
@ -88,12 +95,11 @@ public sealed class DeptService(DefaultRepository<Sys_Dept> rpo) //
} }
/// <inheritdoc /> /// <inheritdoc />
/// <exception cref="NetAdminUnexpectedException">NetAdminUnexpectedException</exception>
public async Task<QueryDeptRsp> UpdateAsync(UpdateDeptReq req) public async Task<QueryDeptRsp> UpdateAsync(UpdateDeptReq req)
{ {
req.ThrowIfInvalid(); req.ThrowIfInvalid();
return await Rpo.UpdateDiy.SetSource(req).ExecuteAffrowsAsync().ConfigureAwait(false) <= 0 return await Rpo.UpdateDiy.SetSource(req).ExecuteAffrowsAsync().ConfigureAwait(false) <= 0
? throw new NetAdminUnexpectedException() ? null
: (await QueryInternal(new QueryReq<QueryDeptReq> { Filter = new QueryDeptReq { Id = req.Id } }, true) : (await QueryInternal(new QueryReq<QueryDeptReq> { Filter = new QueryDeptReq { Id = req.Id } }, true)
.ToTreeListAsync() .ToTreeListAsync()
.ConfigureAwait(false))[0] .ConfigureAwait(false))[0]
@ -118,6 +124,10 @@ public sealed class DeptService(DefaultRepository<Sys_Dept> rpo) //
ret = ret.AsTreeCte(); ret = ret.AsTreeCte();
} }
if (req.Order == Orders.Random) {
return ret.OrderByRandom();
}
ret = ret.OrderByPropertyNameIf(req.Prop?.Length > 0, req.Prop, req.Order == Orders.Ascending); ret = ret.OrderByPropertyNameIf(req.Prop?.Length > 0, req.Prop, req.Order == Orders.Ascending);
if (!req.Prop?.Equals(nameof(req.Filter.Sort), StringComparison.OrdinalIgnoreCase) ?? true) { if (!req.Prop?.Equals(nameof(req.Filter.Sort), StringComparison.OrdinalIgnoreCase) ?? true) {

View File

@ -25,6 +25,13 @@ public sealed class DicCatalogService(DefaultRepository<Sys_DicCatalog> rpo) //
return ret; return ret;
} }
/// <inheritdoc />
public Task<long> CountAsync(QueryReq<QueryDicCatalogReq> req)
{
req.ThrowIfInvalid();
return QueryInternal(req).CountAsync();
}
/// <inheritdoc /> /// <inheritdoc />
/// <exception cref="NetAdminInvalidOperationException">The_parent_node_does_not_exist</exception> /// <exception cref="NetAdminInvalidOperationException">The_parent_node_does_not_exist</exception>
public async Task<QueryDicCatalogRsp> CreateAsync(CreateDicCatalogReq req) public async Task<QueryDicCatalogRsp> CreateAsync(CreateDicCatalogReq req)
@ -88,7 +95,6 @@ public sealed class DicCatalogService(DefaultRepository<Sys_DicCatalog> rpo) //
/// <inheritdoc /> /// <inheritdoc />
/// <exception cref="NetAdminInvalidOperationException">The_parent_node_does_not_exist</exception> /// <exception cref="NetAdminInvalidOperationException">The_parent_node_does_not_exist</exception>
/// <exception cref="NetAdminUnexpectedException">NetAdminUnexpectedException</exception>
public async Task<QueryDicCatalogRsp> UpdateAsync(UpdateDicCatalogReq req) public async Task<QueryDicCatalogRsp> UpdateAsync(UpdateDicCatalogReq req)
{ {
req.ThrowIfInvalid(); req.ThrowIfInvalid();
@ -98,7 +104,7 @@ public sealed class DicCatalogService(DefaultRepository<Sys_DicCatalog> rpo) //
} }
if (await Rpo.UpdateDiy.SetSource(req).ExecuteAffrowsAsync().ConfigureAwait(false) <= 0) { if (await Rpo.UpdateDiy.SetSource(req).ExecuteAffrowsAsync().ConfigureAwait(false) <= 0) {
throw new NetAdminUnexpectedException(); return null;
} }
var ret = await Rpo.Where(a => a.Id == req.Id).ToOneAsync().ConfigureAwait(false); var ret = await Rpo.Where(a => a.Id == req.Id).ToOneAsync().ConfigureAwait(false);
@ -113,9 +119,12 @@ public sealed class DicCatalogService(DefaultRepository<Sys_DicCatalog> rpo) //
private ISelect<Sys_DicCatalog> QueryInternal(QueryReq<QueryDicCatalogReq> req) private ISelect<Sys_DicCatalog> QueryInternal(QueryReq<QueryDicCatalogReq> req)
{ {
var ret = Rpo.Select.WhereDynamicFilter(req.DynamicFilter) var ret = Rpo.Select.WhereDynamicFilter(req.DynamicFilter).WhereDynamic(req.Filter);
.WhereDynamic(req.Filter) if (req.Order == Orders.Random) {
.OrderByPropertyNameIf(req.Prop?.Length > 0, req.Prop, req.Order == Orders.Ascending); return ret.OrderByRandom();
}
ret = ret.OrderByPropertyNameIf(req.Prop?.Length > 0, req.Prop, req.Order == Orders.Ascending);
if (!req.Prop?.Equals(nameof(req.Filter.Id), StringComparison.OrdinalIgnoreCase) ?? true) { if (!req.Prop?.Equals(nameof(req.Filter.Id), StringComparison.OrdinalIgnoreCase) ?? true) {
ret = ret.OrderByDescending(a => a.Id); ret = ret.OrderByDescending(a => a.Id);
} }

View File

@ -25,6 +25,13 @@ public sealed class DicContentService(DefaultRepository<Sys_DicContent> rpo) //
return ret; return ret;
} }
/// <inheritdoc />
public Task<long> CountAsync(QueryReq<QueryDicContentReq> req)
{
req.ThrowIfInvalid();
return QueryInternal(req).CountAsync();
}
/// <inheritdoc /> /// <inheritdoc />
/// <exception cref="NetAdminInvalidOperationException">Dictionary_directory_does_not_exist</exception> /// <exception cref="NetAdminInvalidOperationException">Dictionary_directory_does_not_exist</exception>
public async Task<QueryDicContentRsp> CreateAsync(CreateDicContentReq req) public async Task<QueryDicContentRsp> CreateAsync(CreateDicContentReq req)
@ -90,7 +97,6 @@ public sealed class DicContentService(DefaultRepository<Sys_DicContent> rpo) //
/// <inheritdoc /> /// <inheritdoc />
/// <exception cref="NetAdminInvalidOperationException">Dictionary_directory_does_not_exist</exception> /// <exception cref="NetAdminInvalidOperationException">Dictionary_directory_does_not_exist</exception>
/// <exception cref="NetAdminUnexpectedException">NetAdminUnexpectedException</exception>
public async Task<QueryDicContentRsp> UpdateAsync(UpdateDicContentReq req) public async Task<QueryDicContentRsp> UpdateAsync(UpdateDicContentReq req)
{ {
req.ThrowIfInvalid(); req.ThrowIfInvalid();
@ -103,7 +109,7 @@ public sealed class DicContentService(DefaultRepository<Sys_DicContent> rpo) //
} }
if (await Rpo.UpdateDiy.SetSource(req).ExecuteAffrowsAsync().ConfigureAwait(false) <= 0) { if (await Rpo.UpdateDiy.SetSource(req).ExecuteAffrowsAsync().ConfigureAwait(false) <= 0) {
throw new NetAdminUnexpectedException(); return null;
} }
var ret = await Rpo.Where(a => a.Id == req.Id).ToOneAsync().ConfigureAwait(false); var ret = await Rpo.Where(a => a.Id == req.Id).ToOneAsync().ConfigureAwait(false);
@ -118,9 +124,12 @@ public sealed class DicContentService(DefaultRepository<Sys_DicContent> rpo) //
private ISelect<Sys_DicContent> QueryInternal(QueryReq<QueryDicContentReq> req) private ISelect<Sys_DicContent> QueryInternal(QueryReq<QueryDicContentReq> req)
{ {
var ret = Rpo.Select.WhereDynamicFilter(req.DynamicFilter) var ret = Rpo.Select.WhereDynamicFilter(req.DynamicFilter).WhereDynamic(req.Filter);
.WhereDynamic(req.Filter) if (req.Order == Orders.Random) {
.OrderByPropertyNameIf(req.Prop?.Length > 0, req.Prop, req.Order == Orders.Ascending); return ret.OrderByRandom();
}
ret = ret.OrderByPropertyNameIf(req.Prop?.Length > 0, req.Prop, req.Order == Orders.Ascending);
if (!req.Prop?.Equals(nameof(req.Filter.Id), StringComparison.OrdinalIgnoreCase) ?? true) { if (!req.Prop?.Equals(nameof(req.Filter.Id), StringComparison.OrdinalIgnoreCase) ?? true) {
ret = ret.OrderByDescending(a => a.Id); ret = ret.OrderByDescending(a => a.Id);
} }

View File

@ -26,6 +26,13 @@ public sealed class JobRecordService(DefaultRepository<Sys_JobRecord> rpo) //
return ret; return ret;
} }
/// <inheritdoc />
public Task<long> CountAsync(QueryReq<QueryJobRecordReq> req)
{
req.ThrowIfInvalid();
return QueryInternal(req).CountAsync();
}
/// <inheritdoc /> /// <inheritdoc />
public async Task<QueryJobRecordRsp> CreateAsync(CreateJobRecordReq req) public async Task<QueryJobRecordRsp> CreateAsync(CreateJobRecordReq req)
{ {
@ -106,8 +113,12 @@ public sealed class JobRecordService(DefaultRepository<Sys_JobRecord> rpo) //
.WhereDynamic(req.Filter) .WhereDynamic(req.Filter)
.WhereIf( // .WhereIf( //
req.Keywords?.Length > 0 req.Keywords?.Length > 0
, a => a.JobId == req.Keywords.Int64Try(0) || a.Id == req.Keywords.Int64Try(0)) , a => a.JobId == req.Keywords.Int64Try(0) || a.Id == req.Keywords.Int64Try(0));
.OrderByPropertyNameIf(req.Prop?.Length > 0, req.Prop, req.Order == Orders.Ascending); if (req.Order == Orders.Random) {
return ret.OrderByRandom();
}
ret = ret.OrderByPropertyNameIf(req.Prop?.Length > 0, req.Prop, req.Order == Orders.Ascending);
if (!req.Prop?.Equals(nameof(req.Filter.Id), StringComparison.OrdinalIgnoreCase) ?? true) { if (!req.Prop?.Equals(nameof(req.Filter.Id), StringComparison.OrdinalIgnoreCase) ?? true) {
ret = ret.OrderByDescending(a => a.Id); ret = ret.OrderByDescending(a => a.Id);
} }

View File

@ -29,6 +29,13 @@ public sealed class JobService(DefaultRepository<Sys_Job> rpo, IJobRecordService
return ret; return ret;
} }
/// <inheritdoc />
public Task<long> CountAsync(QueryReq<QueryJobReq> req)
{
req.ThrowIfInvalid();
return QueryInternal(req).CountAsync();
}
/// <inheritdoc /> /// <inheritdoc />
public async Task<QueryJobRsp> CreateAsync(CreateJobReq req) public async Task<QueryJobRsp> CreateAsync(CreateJobReq req)
{ {
@ -119,7 +126,8 @@ public sealed class JobService(DefaultRepository<Sys_Job> rpo, IJobRecordService
} }
] ]
}; };
var job = await QueryInternal(new QueryReq<QueryJobReq> { DynamicFilter = df, Count = 1 }, true) var job
= await QueryInternal(new QueryReq<QueryJobReq> { DynamicFilter = df, Count = 1, Order = Orders.Random })
.Where(a => !Rpo.Orm.Select<Sys_JobRecord>() .Where(a => !Rpo.Orm.Select<Sys_JobRecord>()
.As("b") .As("b")
.Where(b => b.JobId == a.Id && b.TimeId == a.NextTimeId) .Where(b => b.JobId == a.Id && b.TimeId == a.NextTimeId)
@ -175,7 +183,7 @@ public sealed class JobService(DefaultRepository<Sys_Job> rpo, IJobRecordService
{ {
return Rpo.UpdateDiy.Set(a => a.Status == JobStatues.Idle) return Rpo.UpdateDiy.Set(a => a.Status == JobStatues.Idle)
.Where(a => a.Status == JobStatues.Running && .Where(a => a.Status == JobStatues.Running &&
a.LastExecTime < DateTime.Now.AddSeconds(-Numbers.TIMEOUT_SECS_JOB)) a.LastExecTime < DateTime.Now.AddSeconds(-Numbers.SECS_TIMEOUT_JOB))
.ExecuteAffrowsAsync(); .ExecuteAffrowsAsync();
} }
@ -211,17 +219,23 @@ public sealed class JobService(DefaultRepository<Sys_Job> rpo, IJobRecordService
.GetNextOccurrence(DateTime.UtcNow, TimeZoneInfo.Utc); .GetNextOccurrence(DateTime.UtcNow, TimeZoneInfo.Utc);
} }
private ISelect<Sys_Job> QueryInternal(QueryReq<QueryJobReq> req, bool orderByRandom = false) private ISelect<Sys_Job> QueryInternal(QueryReq<QueryJobReq> req)
{ {
var ret = Rpo.Select.Include(a => a.User) var ret = Rpo.Select.Include(a => a.User)
.WhereDynamicFilter(req.DynamicFilter) .WhereDynamicFilter(req.DynamicFilter)
.WhereDynamic(req.Filter) .WhereDynamic(req.Filter)
.WhereIf( // .WhereIf( //
req.Keywords?.Length > 0 req.Keywords?.Length > 0
, a => a.Id == req.Keywords.Int64Try(0) || a.JobName.Contains(req.Keywords)) , a => a.Id == req.Keywords.Int64Try(0) || a.JobName.Contains(req.Keywords));
.OrderByPropertyNameIf(req.Prop?.Length > 0, req.Prop, req.Order == Orders.Ascending); if (req.Order == Orders.Random) {
return !orderByRandom && (!req.Prop?.Equals(nameof(req.Filter.Id), StringComparison.OrdinalIgnoreCase) ?? true) return ret.OrderByRandom();
? ret.OrderByDescending(a => a.LastExecTime) }
: ret.OrderByRandom();
ret = ret.OrderByPropertyNameIf(req.Prop?.Length > 0, req.Prop, req.Order == Orders.Ascending);
if (!req.Prop?.Equals(nameof(req.Filter.LastExecTime), StringComparison.OrdinalIgnoreCase) ?? true) {
ret = ret.OrderByDescending(a => a.LastExecTime);
}
return ret;
} }
} }

View File

@ -25,6 +25,13 @@ public sealed class MenuService(DefaultRepository<Sys_Menu> rpo, IUserService us
return ret; return ret;
} }
/// <inheritdoc />
public Task<long> CountAsync(QueryReq<QueryMenuReq> req)
{
req.ThrowIfInvalid();
return QueryInternal(req).CountAsync();
}
/// <inheritdoc /> /// <inheritdoc />
public async Task<QueryMenuRsp> CreateAsync(CreateMenuReq req) public async Task<QueryMenuRsp> CreateAsync(CreateMenuReq req)
{ {
@ -37,12 +44,12 @@ public sealed class MenuService(DefaultRepository<Sys_Menu> rpo, IUserService us
public async Task<int> DeleteAsync(DelReq req) public async Task<int> DeleteAsync(DelReq req)
{ {
req.ThrowIfInvalid(); req.ThrowIfInvalid();
var effect = await Rpo.DeleteAsync(a => a.Id == req.Id).ConfigureAwait(false); var ret = await Rpo.DeleteAsync(a => a.Id == req.Id).ConfigureAwait(false);
effect += await Rpo.Orm.Delete<Sys_RoleMenu>() _ = await Rpo.Orm.Delete<Sys_RoleMenu>()
.Where(a => a.MenuId == req.Id) .Where(a => a.MenuId == req.Id)
.ExecuteAffrowsAsync() .ExecuteAffrowsAsync()
.ConfigureAwait(false); .ConfigureAwait(false);
return effect; return ret;
} }
/// <inheritdoc /> /// <inheritdoc />
@ -76,12 +83,11 @@ public sealed class MenuService(DefaultRepository<Sys_Menu> rpo, IUserService us
} }
/// <inheritdoc /> /// <inheritdoc />
/// <exception cref="NetAdminUnexpectedException">NetAdminUnexpectedException</exception>
public async Task<QueryMenuRsp> UpdateAsync(UpdateMenuReq req) public async Task<QueryMenuRsp> UpdateAsync(UpdateMenuReq req)
{ {
req.ThrowIfInvalid(); req.ThrowIfInvalid();
if (await Rpo.UpdateDiy.SetSource(req).ExecuteAffrowsAsync().ConfigureAwait(false) <= 0) { if (await Rpo.UpdateDiy.SetSource(req).ExecuteAffrowsAsync().ConfigureAwait(false) <= 0) {
throw new NetAdminUnexpectedException(); return null;
} }
var ret = await Rpo.Where(a => a.Id == req.Id).ToOneAsync().ConfigureAwait(false); var ret = await Rpo.Where(a => a.Id == req.Id).ToOneAsync().ConfigureAwait(false);
@ -124,9 +130,10 @@ public sealed class MenuService(DefaultRepository<Sys_Menu> rpo, IUserService us
private ISelect<Sys_Menu> QueryInternal(QueryReq<QueryMenuReq> req) private ISelect<Sys_Menu> QueryInternal(QueryReq<QueryMenuReq> req)
{ {
return Rpo.Select.WhereDynamicFilter(req.DynamicFilter) var ret = Rpo.Select.WhereDynamicFilter(req.DynamicFilter).WhereDynamic(req.Filter);
.WhereDynamic(req.Filter) return req.Order == Orders.Random
.OrderByPropertyNameIf(req.Prop?.Length > 0, req.Prop, req.Order == Orders.Ascending) ? ret.OrderByRandom()
: ret.OrderByPropertyNameIf(req.Prop?.Length > 0, req.Prop, req.Order == Orders.Ascending)
.OrderByDescending(a => a.Sort) .OrderByDescending(a => a.Sort)
.OrderBy(a => a.Name) .OrderBy(a => a.Name)
.OrderBy(a => a.Id); .OrderBy(a => a.Id);

View File

@ -25,6 +25,13 @@ public sealed class RequestLogService(DefaultRepository<Sys_RequestLog> rpo) //
return ret; return ret;
} }
/// <inheritdoc />
public Task<long> CountAsync(QueryReq<QueryRequestLogReq> req)
{
req.ThrowIfInvalid();
return QueryInternal(req).CountAsync();
}
/// <inheritdoc /> /// <inheritdoc />
public async Task<QueryRequestLogRsp> CreateAsync(CreateRequestLogReq req) public async Task<QueryRequestLogRsp> CreateAsync(CreateRequestLogReq req)
{ {
@ -106,10 +113,12 @@ public sealed class RequestLogService(DefaultRepository<Sys_RequestLog> rpo) //
private ISelect<Sys_RequestLog> QueryInternal(QueryReq<QueryRequestLogReq> req) private ISelect<Sys_RequestLog> QueryInternal(QueryReq<QueryRequestLogReq> req)
{ {
var ret = Rpo.Select.Include(a => a.Api) var ret = Rpo.Select.Include(a => a.Api).WhereDynamicFilter(req.DynamicFilter).WhereDynamic(req.Filter);
.WhereDynamicFilter(req.DynamicFilter) if (req.Order == Orders.Random) {
.WhereDynamic(req.Filter) return ret.OrderByRandom();
.OrderByPropertyNameIf(req.Prop?.Length > 0, req.Prop, req.Order == Orders.Ascending); }
ret = ret.OrderByPropertyNameIf(req.Prop?.Length > 0, req.Prop, req.Order == Orders.Ascending);
if (!req.Prop?.Equals(nameof(req.Filter.CreatedTime), StringComparison.OrdinalIgnoreCase) ?? true) { if (!req.Prop?.Equals(nameof(req.Filter.CreatedTime), StringComparison.OrdinalIgnoreCase) ?? true) {
ret = ret.OrderByDescending(a => a.CreatedTime); ret = ret.OrderByDescending(a => a.CreatedTime);

View File

@ -25,6 +25,13 @@ public sealed class RoleService(DefaultRepository<Sys_Role> rpo) //
return ret; return ret;
} }
/// <inheritdoc />
public Task<long> CountAsync(QueryReq<QueryRoleReq> req)
{
req.ThrowIfInvalid();
return QueryInternal(req).CountAsync();
}
/// <inheritdoc /> /// <inheritdoc />
public async Task<QueryRoleRsp> CreateAsync(CreateRoleReq req) public async Task<QueryRoleRsp> CreateAsync(CreateRoleReq req)
{ {
@ -116,8 +123,12 @@ public sealed class RoleService(DefaultRepository<Sys_Role> rpo) //
.WhereIf( // .WhereIf( //
req.Keywords?.Length > 0 req.Keywords?.Length > 0
, a => a.Id == req.Keywords.Int64Try(0) || a.Name.Contains(req.Keywords) || , a => a.Id == req.Keywords.Int64Try(0) || a.Name.Contains(req.Keywords) ||
a.Summary.Contains(req.Keywords)) a.Summary.Contains(req.Keywords));
.OrderByPropertyNameIf(req.Prop?.Length > 0, req.Prop, req.Order == Orders.Ascending); if (req.Order == Orders.Random) {
return ret.OrderByRandom();
}
ret = ret.OrderByPropertyNameIf(req.Prop?.Length > 0, req.Prop, req.Order == Orders.Ascending);
if (!req.Prop?.Equals(nameof(req.Filter.Sort), StringComparison.OrdinalIgnoreCase) ?? true) { if (!req.Prop?.Equals(nameof(req.Filter.Sort), StringComparison.OrdinalIgnoreCase) ?? true) {
ret = ret.OrderByDescending(a => a.Sort); ret = ret.OrderByDescending(a => a.Sort);

View File

@ -26,6 +26,13 @@ public sealed class SiteMsgDeptService(DefaultRepository<Sys_SiteMsgDept> rpo) /
return ret; return ret;
} }
/// <inheritdoc />
public Task<long> CountAsync(QueryReq<QuerySiteMsgDeptReq> req)
{
req.ThrowIfInvalid();
return QueryInternal(req).CountAsync();
}
/// <inheritdoc /> /// <inheritdoc />
public async Task<QuerySiteMsgDeptRsp> CreateAsync(CreateSiteMsgDeptReq req) public async Task<QuerySiteMsgDeptRsp> CreateAsync(CreateSiteMsgDeptReq req)
{ {
@ -102,9 +109,12 @@ public sealed class SiteMsgDeptService(DefaultRepository<Sys_SiteMsgDept> rpo) /
private ISelect<Sys_SiteMsgDept> QueryInternal(QueryReq<QuerySiteMsgDeptReq> req) private ISelect<Sys_SiteMsgDept> QueryInternal(QueryReq<QuerySiteMsgDeptReq> req)
{ {
var ret = Rpo.Select.WhereDynamicFilter(req.DynamicFilter) var ret = Rpo.Select.WhereDynamicFilter(req.DynamicFilter).WhereDynamic(req.Filter);
.WhereDynamic(req.Filter) if (req.Order == Orders.Random) {
.OrderByPropertyNameIf(req.Prop?.Length > 0, req.Prop, req.Order == Orders.Ascending); return ret.OrderByRandom();
}
ret = ret.OrderByPropertyNameIf(req.Prop?.Length > 0, req.Prop, req.Order == Orders.Ascending);
if (!req.Prop?.Equals(nameof(req.Filter.Id), StringComparison.OrdinalIgnoreCase) ?? true) { if (!req.Prop?.Equals(nameof(req.Filter.Id), StringComparison.OrdinalIgnoreCase) ?? true) {
ret = ret.OrderByDescending(a => a.Id); ret = ret.OrderByDescending(a => a.Id);
} }

View File

@ -26,6 +26,13 @@ public sealed class SiteMsgFlagService(DefaultRepository<Sys_SiteMsgFlag> rpo) /
return ret; return ret;
} }
/// <inheritdoc />
public Task<long> CountAsync(QueryReq<QuerySiteMsgFlagReq> req)
{
req.ThrowIfInvalid();
return QueryInternal(req).CountAsync();
}
/// <inheritdoc /> /// <inheritdoc />
public async Task<QuerySiteMsgFlagRsp> CreateAsync(CreateSiteMsgFlagReq req) public async Task<QuerySiteMsgFlagRsp> CreateAsync(CreateSiteMsgFlagReq req)
{ {
@ -108,9 +115,12 @@ public sealed class SiteMsgFlagService(DefaultRepository<Sys_SiteMsgFlag> rpo) /
private ISelect<Sys_SiteMsgFlag> QueryInternal(QueryReq<QuerySiteMsgFlagReq> req) private ISelect<Sys_SiteMsgFlag> QueryInternal(QueryReq<QuerySiteMsgFlagReq> req)
{ {
var ret = Rpo.Select.WhereDynamicFilter(req.DynamicFilter) var ret = Rpo.Select.WhereDynamicFilter(req.DynamicFilter).WhereDynamic(req.Filter);
.WhereDynamic(req.Filter) if (req.Order == Orders.Random) {
.OrderByPropertyNameIf(req.Prop?.Length > 0, req.Prop, req.Order == Orders.Ascending); return ret.OrderByRandom();
}
ret = ret.OrderByPropertyNameIf(req.Prop?.Length > 0, req.Prop, req.Order == Orders.Ascending);
if (!req.Prop?.Equals(nameof(req.Filter.Id), StringComparison.OrdinalIgnoreCase) ?? true) { if (!req.Prop?.Equals(nameof(req.Filter.Id), StringComparison.OrdinalIgnoreCase) ?? true) {
ret = ret.OrderByDescending(a => a.Id); ret = ret.OrderByDescending(a => a.Id);
} }

View File

@ -26,6 +26,13 @@ public sealed class SiteMsgRoleService(DefaultRepository<Sys_SiteMsgRole> rpo) /
return ret; return ret;
} }
/// <inheritdoc />
public Task<long> CountAsync(QueryReq<QuerySiteMsgRoleReq> req)
{
req.ThrowIfInvalid();
return QueryInternal(req).CountAsync();
}
/// <inheritdoc /> /// <inheritdoc />
public async Task<QuerySiteMsgRoleRsp> CreateAsync(CreateSiteMsgRoleReq req) public async Task<QuerySiteMsgRoleRsp> CreateAsync(CreateSiteMsgRoleReq req)
{ {
@ -102,9 +109,12 @@ public sealed class SiteMsgRoleService(DefaultRepository<Sys_SiteMsgRole> rpo) /
private ISelect<Sys_SiteMsgRole> QueryInternal(QueryReq<QuerySiteMsgRoleReq> req) private ISelect<Sys_SiteMsgRole> QueryInternal(QueryReq<QuerySiteMsgRoleReq> req)
{ {
var ret = Rpo.Select.WhereDynamicFilter(req.DynamicFilter) var ret = Rpo.Select.WhereDynamicFilter(req.DynamicFilter).WhereDynamic(req.Filter);
.WhereDynamic(req.Filter) if (req.Order == Orders.Random) {
.OrderByPropertyNameIf(req.Prop?.Length > 0, req.Prop, req.Order == Orders.Ascending); return ret.OrderByRandom();
}
ret = ret.OrderByPropertyNameIf(req.Prop?.Length > 0, req.Prop, req.Order == Orders.Ascending);
if (!req.Prop?.Equals(nameof(req.Filter.Id), StringComparison.OrdinalIgnoreCase) ?? true) { if (!req.Prop?.Equals(nameof(req.Filter.Id), StringComparison.OrdinalIgnoreCase) ?? true) {
ret = ret.OrderByDescending(a => a.Id); ret = ret.OrderByDescending(a => a.Id);
} }

View File

@ -12,7 +12,9 @@ using NetAdmin.SysComponent.Application.Services.Sys.Dependency;
namespace NetAdmin.SysComponent.Application.Services.Sys; namespace NetAdmin.SysComponent.Application.Services.Sys;
/// <inheritdoc cref="ISiteMsgService" /> /// <inheritdoc cref="ISiteMsgService" />
public sealed class SiteMsgService(DefaultRepository<Sys_SiteMsg> rpo, ContextUserInfo contextUserInfo public sealed class SiteMsgService(
DefaultRepository<Sys_SiteMsg> rpo
, ContextUserInfo contextUserInfo
, ISiteMsgFlagService siteMsgFlagService) // , ISiteMsgFlagService siteMsgFlagService) //
: RepositoryService<Sys_SiteMsg, ISiteMsgService>(rpo), ISiteMsgService : RepositoryService<Sys_SiteMsg, ISiteMsgService>(rpo), ISiteMsgService
{ {
@ -30,6 +32,13 @@ public sealed class SiteMsgService(DefaultRepository<Sys_SiteMsg> rpo, ContextUs
return ret; return ret;
} }
/// <inheritdoc />
public Task<long> CountAsync(QueryReq<QuerySiteMsgReq> req)
{
req.ThrowIfInvalid();
return QueryInternal(req).CountAsync();
}
/// <inheritdoc /> /// <inheritdoc />
public async Task<QuerySiteMsgRsp> CreateAsync(CreateSiteMsgReq req) public async Task<QuerySiteMsgRsp> CreateAsync(CreateSiteMsgReq req)
{ {
@ -109,7 +118,7 @@ public sealed class SiteMsgService(DefaultRepository<Sys_SiteMsg> rpo, ContextUs
.Count(out var total) .Count(out var total)
.ToListAsync(a => new { .ToListAsync(a => new {
a.CreatedTime a.CreatedTime
, a.Creator , a.CreatedUserName
, a.Id , a.Id
, a.MsgType , a.MsgType
, a.Summary , a.Summary
@ -275,8 +284,12 @@ public sealed class SiteMsgService(DefaultRepository<Sys_SiteMsg> rpo, ContextUs
.WhereIf( // .WhereIf( //
req.Keywords?.Length > 0 req.Keywords?.Length > 0
, a => a.Id == req.Keywords.Int64Try(0) || a.Title.Contains(req.Keywords) || , a => a.Id == req.Keywords.Int64Try(0) || a.Title.Contains(req.Keywords) ||
a.Summary.Contains(req.Keywords)) a.Summary.Contains(req.Keywords));
.OrderByPropertyNameIf(req.Prop?.Length > 0, req.Prop, req.Order == Orders.Ascending); if (req.Order == Orders.Random) {
return ret.OrderByRandom();
}
ret = ret.OrderByPropertyNameIf(req.Prop?.Length > 0, req.Prop, req.Order == Orders.Ascending);
if (!req.Prop?.Equals(nameof(req.Filter.Id), StringComparison.OrdinalIgnoreCase) ?? true) { if (!req.Prop?.Equals(nameof(req.Filter.Id), StringComparison.OrdinalIgnoreCase) ?? true) {
ret = ret.OrderByDescending(a => a.Id); ret = ret.OrderByDescending(a => a.Id);
} }
@ -300,9 +313,9 @@ public sealed class SiteMsgService(DefaultRepository<Sys_SiteMsg> rpo, ContextUs
.WhereDynamicFilter(req.DynamicFilter) .WhereDynamicFilter(req.DynamicFilter)
.Where((a, _, c, d, e, f) => .Where((a, _, c, d, e, f) =>
(SqlExt.EqualIsNull(f.UserSiteMsgStatus) || (SqlExt.EqualIsNull(f.UserSiteMsgStatus) ||
f.UserSiteMsgStatus != UserSiteMsgStatues.Deleted) && (a.MsgType == SiteMsgTypes.Public || f.UserSiteMsgStatus != UserSiteMsgStatues.Deleted) &&
c.DeptId == contextUserInfo.DeptId || roleIds.Contains(d.RoleId) || (a.MsgType == SiteMsgTypes.Public || c.DeptId == contextUserInfo.DeptId ||
e.UserId == contextUserInfo.Id)) roleIds.Contains(d.RoleId) || e.UserId == contextUserInfo.Id))
.GroupBy((a, _, _, _, _, _) => a.Id); .GroupBy((a, _, _, _, _, _) => a.Id);
} }
} }

View File

@ -26,6 +26,13 @@ public sealed class SiteMsgUserService(DefaultRepository<Sys_SiteMsgUser> rpo) /
return ret; return ret;
} }
/// <inheritdoc />
public Task<long> CountAsync(QueryReq<QuerySiteMsgUserReq> req)
{
req.ThrowIfInvalid();
return QueryInternal(req).CountAsync();
}
/// <inheritdoc /> /// <inheritdoc />
public async Task<QuerySiteMsgUserRsp> CreateAsync(CreateSiteMsgUserReq req) public async Task<QuerySiteMsgUserRsp> CreateAsync(CreateSiteMsgUserReq req)
{ {
@ -102,9 +109,12 @@ public sealed class SiteMsgUserService(DefaultRepository<Sys_SiteMsgUser> rpo) /
private ISelect<Sys_SiteMsgUser> QueryInternal(QueryReq<QuerySiteMsgUserReq> req) private ISelect<Sys_SiteMsgUser> QueryInternal(QueryReq<QuerySiteMsgUserReq> req)
{ {
var ret = Rpo.Select.WhereDynamicFilter(req.DynamicFilter) var ret = Rpo.Select.WhereDynamicFilter(req.DynamicFilter).WhereDynamic(req.Filter);
.WhereDynamic(req.Filter) if (req.Order == Orders.Random) {
.OrderByPropertyNameIf(req.Prop?.Length > 0, req.Prop, req.Order == Orders.Ascending); return ret.OrderByRandom();
}
ret = ret.OrderByPropertyNameIf(req.Prop?.Length > 0, req.Prop, req.Order == Orders.Ascending);
if (!req.Prop?.Equals(nameof(req.Filter.Id), StringComparison.OrdinalIgnoreCase) ?? true) { if (!req.Prop?.Equals(nameof(req.Filter.Id), StringComparison.OrdinalIgnoreCase) ?? true) {
ret = ret.OrderByDescending(a => a.Id); ret = ret.OrderByDescending(a => a.Id);
} }

View File

@ -27,6 +27,13 @@ public sealed class UserProfileService(DefaultRepository<Sys_UserProfile> rpo) /
return ret; return ret;
} }
/// <inheritdoc />
public Task<long> CountAsync(QueryReq<QueryUserProfileReq> req)
{
req.ThrowIfInvalid();
return QueryInternal(req).CountAsync();
}
/// <inheritdoc /> /// <inheritdoc />
public async Task<QueryUserProfileRsp> CreateAsync(CreateUserProfileReq req) public async Task<QueryUserProfileRsp> CreateAsync(CreateUserProfileReq req)
{ {
@ -146,17 +153,20 @@ public sealed class UserProfileService(DefaultRepository<Sys_UserProfile> rpo) /
QueryReq<QueryUserProfileReq> req) QueryReq<QueryUserProfileReq> req)
{ {
#pragma warning disable CA1305 #pragma warning disable CA1305
return Rpo.Orm.Select<Sys_UserProfile, Sys_DicContent, Sys_DicContent, Sys_DicContent, Sys_DicContent>() var ret = Rpo.Orm.Select<Sys_UserProfile, Sys_DicContent, Sys_DicContent, Sys_DicContent, Sys_DicContent>()
.LeftJoin((a, b, _, __, ___) => .LeftJoin((a, b, _, __, ___) =>
a.NationArea.ToString() == b.Value && b.CatalogId == Numbers.DIC_CATALOG_ID_GEO_AREA) a.NationArea.ToString() == b.Value && b.CatalogId == Numbers.ID_DIC_CATALOG_GEO_AREA)
.LeftJoin((a, _, c, __, ___) => .LeftJoin((a, _, c, __, ___) =>
a.CompanyArea.ToString() == c.Value && c.CatalogId == Numbers.DIC_CATALOG_ID_GEO_AREA) a.CompanyArea.ToString() == c.Value &&
c.CatalogId == Numbers.ID_DIC_CATALOG_GEO_AREA)
.LeftJoin((a, _, __, d, ___) => .LeftJoin((a, _, __, d, ___) =>
a.HomeArea.ToString() == d.Value && d.CatalogId == Numbers.DIC_CATALOG_ID_GEO_AREA) a.HomeArea.ToString() == d.Value && d.CatalogId == Numbers.ID_DIC_CATALOG_GEO_AREA)
.LeftJoin((a, _, __, ___, e) => a.EmergencyContactArea.ToString() == e.Value && .LeftJoin((a, _, __, ___, e) => a.EmergencyContactArea.ToString() == e.Value &&
e.CatalogId == Numbers.DIC_CATALOG_ID_GEO_AREA) e.CatalogId == Numbers.ID_DIC_CATALOG_GEO_AREA)
.WhereDynamicFilter(req.DynamicFilter) .WhereDynamicFilter(req.DynamicFilter);
.OrderByPropertyNameIf(req.Prop?.Length > 0, req.Prop, req.Order == Orders.Ascending) return req.Order == Orders.Random
? ret.OrderByRandom()
: ret.OrderByPropertyNameIf(req.Prop?.Length > 0, req.Prop, req.Order == Orders.Ascending)
.OrderByDescending((a, _, __, ___, ____) => a.Id); .OrderByDescending((a, _, __, ___, ____) => a.Id);
#pragma warning restore CA1305 #pragma warning restore CA1305
} }

View File

@ -13,7 +13,8 @@ using NetAdmin.SysComponent.Application.Services.Sys.Dependency;
namespace NetAdmin.SysComponent.Application.Services.Sys; namespace NetAdmin.SysComponent.Application.Services.Sys;
/// <inheritdoc cref="IUserService" /> /// <inheritdoc cref="IUserService" />
public sealed class UserService(DefaultRepository<Sys_User> rpo // public sealed class UserService(
DefaultRepository<Sys_User> rpo //
, IUserProfileService userProfileService // , IUserProfileService userProfileService //
, IVerifyCodeService verifyCodeService // , IVerifyCodeService verifyCodeService //
, IEventPublisher eventPublisher) // , IEventPublisher eventPublisher) //
@ -63,6 +64,15 @@ public sealed class UserService(DefaultRepository<Sys_User> rpo /
.ConfigureAwait(false); .ConfigureAwait(false);
} }
/// <inheritdoc />
public Task<long> CountAsync(QueryReq<QueryUserReq> req)
{
req.ThrowIfInvalid();
#pragma warning disable VSTHRD103
return QueryInternal(req).CountAsync();
#pragma warning restore VSTHRD103
}
/// <inheritdoc /> /// <inheritdoc />
public async Task<QueryUserRsp> CreateAsync(CreateUserReq req) public async Task<QueryUserRsp> CreateAsync(CreateUserReq req)
{ {
@ -88,20 +98,17 @@ public sealed class UserService(DefaultRepository<Sys_User> rpo /
public async Task<int> DeleteAsync(DelReq req) public async Task<int> DeleteAsync(DelReq req)
{ {
req.ThrowIfInvalid(); req.ThrowIfInvalid();
var effect = 0;
// 删除主表 // 删除主表
effect += await Rpo.DeleteAsync(req.Id).ConfigureAwait(false); var ret = await Rpo.DeleteAsync(req.Id).ConfigureAwait(false);
// 删除分表 // 删除分表
effect += await Rpo.Orm.Delete<Sys_UserRole>(new { UserId = req.Id }) _ = await Rpo.Orm.Delete<Sys_UserRole>(new { UserId = req.Id }).ExecuteAffrowsAsync().ConfigureAwait(false);
.ExecuteAffrowsAsync()
.ConfigureAwait(false);
// 删除档案表 // 删除档案表
effect += await userProfileService.DeleteAsync(req).ConfigureAwait(false); _ = await userProfileService.DeleteAsync(req).ConfigureAwait(false);
return effect; return ret;
} }
/// <inheritdoc /> /// <inheritdoc />
@ -255,7 +262,7 @@ public sealed class UserService(DefaultRepository<Sys_User> rpo /
.UpdateColumns(a => a.Avatar) .UpdateColumns(a => a.Avatar)
.ExecuteAffrowsAsync() .ExecuteAffrowsAsync()
.ConfigureAwait(false) <= 0) { .ConfigureAwait(false) <= 0) {
throw new NetAdminUnexpectedException(); return null;
} }
var ret = (await QueryAsync(new QueryReq<QueryUserReq> { Filter = new QueryUserReq { Id = UserToken.Id } }) var ret = (await QueryAsync(new QueryReq<QueryUserReq> { Filter = new QueryUserReq { Id = UserToken.Id } })
@ -289,7 +296,7 @@ public sealed class UserService(DefaultRepository<Sys_User> rpo /
.UpdateColumns(a => a.Email) .UpdateColumns(a => a.Email)
.ExecuteAffrowsAsync() .ExecuteAffrowsAsync()
.ConfigureAwait(false) <= 0) { .ConfigureAwait(false) <= 0) {
throw new NetAdminUnexpectedException(); return null;
} }
var ret = (await QueryAsync(new QueryReq<QueryUserReq> { Filter = new QueryUserReq { Id = UserToken.Id } }) var ret = (await QueryAsync(new QueryReq<QueryUserReq> { Filter = new QueryUserReq { Id = UserToken.Id } })
@ -341,7 +348,7 @@ public sealed class UserService(DefaultRepository<Sys_User> rpo /
.UpdateColumns(a => a.Mobile) .UpdateColumns(a => a.Mobile)
.ExecuteAffrowsAsync() .ExecuteAffrowsAsync()
.ConfigureAwait(false) <= 0) { .ConfigureAwait(false) <= 0) {
throw new NetAdminUnexpectedException(); return null;
} }
var ret = (await QueryAsync(new QueryReq<QueryUserReq> { Filter = new QueryUserReq { Id = UserToken.Id } }) var ret = (await QueryAsync(new QueryReq<QueryUserReq> { Filter = new QueryUserReq { Id = UserToken.Id } })
@ -370,7 +377,7 @@ public sealed class UserService(DefaultRepository<Sys_User> rpo /
.UpdateColumns(a => a.Password) .UpdateColumns(a => a.Password)
.ExecuteAffrowsAsync() .ExecuteAffrowsAsync()
.ConfigureAwait(false); .ConfigureAwait(false);
return ret <= 0 ? throw new NetAdminUnexpectedException() : (uint)ret; return (uint)ret;
} }
/// <inheritdoc /> /// <inheritdoc />
@ -478,9 +485,12 @@ public sealed class UserService(DefaultRepository<Sys_User> rpo /
private ISelect<Sys_User> QueryInternal(QueryReq<QueryUserReq> req) private ISelect<Sys_User> QueryInternal(QueryReq<QueryUserReq> req)
{ {
var ret = Rpo.Select.WhereDynamicFilter(req.DynamicFilter) var ret = Rpo.Select.WhereDynamicFilter(req.DynamicFilter).WhereDynamic(req.Filter);
.WhereDynamic(req.Filter) if (req.Order == Orders.Random) {
.OrderByPropertyNameIf(req.Prop?.Length > 0, req.Prop, req.Order == Orders.Ascending); return ret.OrderByRandom();
}
ret = ret.OrderByPropertyNameIf(req.Prop?.Length > 0, req.Prop, req.Order == Orders.Ascending);
if (!req.Prop?.Equals(nameof(req.Filter.Id), StringComparison.OrdinalIgnoreCase) ?? true) { if (!req.Prop?.Equals(nameof(req.Filter.Id), StringComparison.OrdinalIgnoreCase) ?? true) {
ret = ret.OrderByDescending(a => a.Id); ret = ret.OrderByDescending(a => a.Id);
} }
@ -511,8 +521,12 @@ public sealed class UserService(DefaultRepository<Sys_User> rpo /
req.Keywords?.Length > 0 req.Keywords?.Length > 0
, a => a.Id == req.Keywords.Int64Try(0) || a.UserName.Contains(req.Keywords) || , a => a.Id == req.Keywords.Int64Try(0) || a.UserName.Contains(req.Keywords) ||
a.Mobile.Contains(req.Keywords) || a.Email.Contains(req.Keywords) || a.Mobile.Contains(req.Keywords) || a.Email.Contains(req.Keywords) ||
a.Summary.Contains(req.Keywords)) a.Summary.Contains(req.Keywords));
.OrderByPropertyNameIf(req.Prop?.Length > 0, req.Prop, req.Order == Orders.Ascending); if (req.Order == Orders.Random) {
return ret.OrderByRandom();
}
ret = ret.OrderByPropertyNameIf(req.Prop?.Length > 0, req.Prop, req.Order == Orders.Ascending);
if (!req.Prop?.Equals(nameof(req.Filter.CreatedTime), StringComparison.OrdinalIgnoreCase) ?? true) { if (!req.Prop?.Equals(nameof(req.Filter.CreatedTime), StringComparison.OrdinalIgnoreCase) ?? true) {
ret = ret.OrderByDescending(a => a.CreatedTime); ret = ret.OrderByDescending(a => a.CreatedTime);

View File

@ -30,6 +30,13 @@ public sealed class VerifyCodeService(DefaultRepository<Sys_VerifyCode> rpo, IEv
return ret; return ret;
} }
/// <inheritdoc />
public Task<long> CountAsync(QueryReq<QueryVerifyCodeReq> req)
{
req.ThrowIfInvalid();
return QueryInternal(req).CountAsync();
}
/// <inheritdoc /> /// <inheritdoc />
public async Task<QueryVerifyCodeRsp> CreateAsync(CreateVerifyCodeReq req) public async Task<QueryVerifyCodeRsp> CreateAsync(CreateVerifyCodeReq req)
{ {
@ -180,9 +187,12 @@ public sealed class VerifyCodeService(DefaultRepository<Sys_VerifyCode> rpo, IEv
private ISelect<Sys_VerifyCode> QueryInternal(QueryReq<QueryVerifyCodeReq> req) private ISelect<Sys_VerifyCode> QueryInternal(QueryReq<QueryVerifyCodeReq> req)
{ {
var ret = Rpo.Select.WhereDynamicFilter(req.DynamicFilter) var ret = Rpo.Select.WhereDynamicFilter(req.DynamicFilter).WhereDynamic(req.Filter);
.WhereDynamic(req.Filter) if (req.Order == Orders.Random) {
.OrderByPropertyNameIf(req.Prop?.Length > 0, req.Prop, req.Order == Orders.Ascending); return ret.OrderByRandom();
}
ret = ret.OrderByPropertyNameIf(req.Prop?.Length > 0, req.Prop, req.Order == Orders.Ascending);
if (!req.Prop?.Equals(nameof(req.Filter.Id), StringComparison.OrdinalIgnoreCase) ?? true) { if (!req.Prop?.Equals(nameof(req.Filter.Id), StringComparison.OrdinalIgnoreCase) ?? true) {
ret = ret.OrderByDescending(a => a.Id); ret = ret.OrderByDescending(a => a.Id);
} }

View File

@ -26,6 +26,13 @@ public sealed class ExampleService(DefaultRepository<Tpl_Example> rpo) //
return ret; return ret;
} }
/// <inheritdoc />
public Task<long> CountAsync(QueryReq<QueryExampleReq> req)
{
req.ThrowIfInvalid();
return QueryInternal(req).CountAsync();
}
/// <inheritdoc /> /// <inheritdoc />
public async Task<QueryExampleRsp> CreateAsync(CreateExampleReq req) public async Task<QueryExampleRsp> CreateAsync(CreateExampleReq req)
{ {
@ -102,9 +109,12 @@ public sealed class ExampleService(DefaultRepository<Tpl_Example> rpo) //
private ISelect<Tpl_Example> QueryInternal(QueryReq<QueryExampleReq> req) private ISelect<Tpl_Example> QueryInternal(QueryReq<QueryExampleReq> req)
{ {
var ret = Rpo.Select.WhereDynamicFilter(req.DynamicFilter) var ret = Rpo.Select.WhereDynamicFilter(req.DynamicFilter).WhereDynamic(req.Filter);
.WhereDynamic(req.Filter) if (req.Order == Orders.Random) {
.OrderByPropertyNameIf(req.Prop?.Length > 0, req.Prop, req.Order == Orders.Ascending); return ret.OrderByRandom();
}
ret = ret.OrderByPropertyNameIf(req.Prop?.Length > 0, req.Prop, req.Order == Orders.Ascending);
if (!req.Prop?.Equals(nameof(req.Filter.Id), StringComparison.OrdinalIgnoreCase) ?? true) { if (!req.Prop?.Equals(nameof(req.Filter.Id), StringComparison.OrdinalIgnoreCase) ?? true) {
ret = ret.OrderByDescending(a => a.Id); ret = ret.OrderByDescending(a => a.Id);
} }

View File

@ -16,6 +16,12 @@ public sealed class ApiCache(IDistributedCache cache, IApiService service) //
return Service.BulkDeleteAsync(req); return Service.BulkDeleteAsync(req);
} }
/// <inheritdoc />
public Task<long> CountAsync(QueryReq<QueryApiReq> req)
{
return Service.CountAsync(req);
}
/// <inheritdoc /> /// <inheritdoc />
public Task<QueryApiRsp> CreateAsync(CreateApiReq req) public Task<QueryApiRsp> CreateAsync(CreateApiReq req)
{ {

View File

@ -15,7 +15,7 @@ public sealed class CacheCache(IDistributedCache cache, ICacheService service) /
{ {
#if !DEBUG #if !DEBUG
return GetOrCreateAsync( // return GetOrCreateAsync( //
GetCacheKey(string.Empty), Service.CacheStatisticsAsync, TimeSpan.FromMinutes(1)); GetCacheKey(string.Empty), Service.CacheStatisticsAsync, TimeSpan.FromSeconds(Numbers.CACHE_SECS_DEFAULT));
#else #else
return Service.CacheStatisticsAsync(); return Service.CacheStatisticsAsync();
#endif #endif

View File

@ -14,7 +14,7 @@ public sealed class CaptchaCache(IDistributedCache cache, ICaptchaService servic
{ {
var captchaRsp = await Service.GetCaptchaImageAsync().ConfigureAwait(false); var captchaRsp = await Service.GetCaptchaImageAsync().ConfigureAwait(false);
await CreateAsync(GetCacheKey(captchaRsp.Id, nameof(CaptchaCache)), captchaRsp.SawOffsetX await CreateAsync(GetCacheKey(captchaRsp.Id, nameof(CaptchaCache)), captchaRsp.SawOffsetX
, TimeSpan.FromMinutes(1)) , TimeSpan.FromSeconds(Numbers.SECS_CACHE_DEFAULT))
.ConfigureAwait(false); .ConfigureAwait(false);
return captchaRsp; return captchaRsp;
} }

Some files were not shown because too many files have changed in this diff Show More