diff --git a/build/version.props b/build/version.props
index 16bc9019..288ea347 100644
--- a/build/version.props
+++ b/build/version.props
@@ -2,7 +2,7 @@
7
1
- 35
+ 36
$(VersionMajor).$(VersionMinor).$(VersionPatch)
diff --git a/src/Util.Data.EntityFrameworkCore/UnitOfWorkBase.cs b/src/Util.Data.EntityFrameworkCore/UnitOfWorkBase.cs
index 89486e17..921cb3cc 100644
--- a/src/Util.Data.EntityFrameworkCore/UnitOfWorkBase.cs
+++ b/src/Util.Data.EntityFrameworkCore/UnitOfWorkBase.cs
@@ -640,6 +640,7 @@ public abstract class UnitOfWorkBase : DbContext, IUnitOfWork, IFilterSwitch {
if ( value != null )
result.Add( value );
} );
+ continue;
}
var changeValue = GetPropertyChangeValue( property, propertyEntry );
if ( changeValue == null )
diff --git a/src/Util.Ui.Angular/Configs/AngularConst.cs b/src/Util.Ui.Angular/Configs/AngularConst.cs
index 3db86a2f..e00ce437 100644
--- a/src/Util.Ui.Angular/Configs/AngularConst.cs
+++ b/src/Util.Ui.Angular/Configs/AngularConst.cs
@@ -77,6 +77,22 @@ public static class AngularConst {
///
public const string BindFixed = "bind-fixed";
///
+ /// 行数
+ ///
+ public const string BindLines = "bind-lines";
+ ///
+ /// 长度
+ ///
+ public const string BindLength = "bind-length";
+ ///
+ /// 全宽识别
+ ///
+ public const string BindFullWidthRecognition = "bind-full-width-recognition";
+ ///
+ /// 尾巴
+ ///
+ public const string BindTail = "bind-tail";
+ ///
/// 名称
///
public const string BindName = "bind-name";
@@ -101,6 +117,10 @@ public static class AngularConst {
///
public const string BindValue = "bind-value";
///
+ /// 工具提示
+ ///
+ public const string BindTooltip = "bind-tooltip";
+ ///
/// 提示
///
public const string BindPlaceholder = "bind-placeholder";
diff --git a/src/Util.Ui.NgAlain/Components/Ellipsis/Builders/EllipsisBuilder.cs b/src/Util.Ui.NgAlain/Components/Ellipsis/Builders/EllipsisBuilder.cs
new file mode 100644
index 00000000..62c5c332
--- /dev/null
+++ b/src/Util.Ui.NgAlain/Components/Ellipsis/Builders/EllipsisBuilder.cs
@@ -0,0 +1,79 @@
+using Util.Ui.Angular.Builders;
+using Util.Ui.Angular.Configs;
+using Util.Ui.Configs;
+
+namespace Util.Ui.NgAlain.Components.Ellipsis.Builders;
+
+///
+/// 文本省略标签生成器
+///
+public class EllipsisBuilder : AngularTagBuilder {
+ ///
+ /// 配置
+ ///
+ private readonly Config _config;
+ ///
+ /// 初始化文本省略标签生成器
+ ///
+ /// 配置
+ public EllipsisBuilder( Config config ) : base( config, "ellipsis" ) {
+ _config = config;
+ }
+
+ ///
+ /// 配置工具提示
+ ///
+ public EllipsisBuilder Tooltip() {
+ AttributeIfNotEmpty( "[tooltip]", _config.GetBoolValue( UiConst.Tooltip ) );
+ AttributeIfNotEmpty( "[tooltip]", _config.GetValue( AngularConst.BindTooltip ) );
+ return this;
+ }
+
+ ///
+ /// 配置文本最大长度
+ ///
+ public EllipsisBuilder Length() {
+ AttributeIfNotEmpty( "length", _config.GetValue( UiConst.Length ) );
+ AttributeIfNotEmpty( "[length]", _config.GetValue( AngularConst.BindLength ) );
+ return this;
+ }
+
+ ///
+ /// 配置文本最大行数
+ ///
+ public EllipsisBuilder Lines() {
+ AttributeIfNotEmpty( "lines", _config.GetValue( UiConst.Lines ) );
+ AttributeIfNotEmpty( "[lines]", _config.GetValue( AngularConst.BindLines ) );
+ return this;
+ }
+
+ ///
+ /// 配置是否将全角字符的长度视为2来计算字符串长度
+ ///
+ public EllipsisBuilder FullWidthRecognition() {
+ AttributeIfNotEmpty( "[fullWidthRecognition]", _config.GetBoolValue( UiConst.FullWidthRecognition ) );
+ AttributeIfNotEmpty( "[fullWidthRecognition]", _config.GetValue( AngularConst.BindFullWidthRecognition ) );
+ return this;
+ }
+
+ ///
+ /// 配置溢出尾巴
+ ///
+ public EllipsisBuilder Tail() {
+ AttributeIfNotEmpty( "tail", _config.GetValue( UiConst.Tail ) );
+ AttributeIfNotEmpty( "[tail]", _config.GetValue( AngularConst.BindTail ) );
+ return this;
+ }
+
+ ///
+ /// 配置
+ ///
+ public override void Config() {
+ base.Config();
+ Tooltip().Length().Lines().FullWidthRecognition().Tail();
+ var value = _config.GetValue( UiConst.Value );
+ if ( value.IsEmpty() )
+ return;
+ AppendContent( "{{" + value + "}}" );
+ }
+}
\ No newline at end of file
diff --git a/src/Util.Ui.NgAlain/Components/Ellipsis/EllipsisTagHelper.cs b/src/Util.Ui.NgAlain/Components/Ellipsis/EllipsisTagHelper.cs
new file mode 100644
index 00000000..62c928c7
--- /dev/null
+++ b/src/Util.Ui.NgAlain/Components/Ellipsis/EllipsisTagHelper.cs
@@ -0,0 +1,77 @@
+using Microsoft.AspNetCore.Mvc.ViewFeatures;
+using Microsoft.AspNetCore.Razor.TagHelpers;
+using Util.Ui.Angular.TagHelpers;
+using Util.Ui.Configs;
+using Util.Ui.NgAlain.Components.Ellipsis.Helpers;
+using Util.Ui.NgAlain.Components.Ellipsis.Renders;
+using Util.Ui.Renders;
+
+namespace Util.Ui.NgAlain.Components.Ellipsis;
+
+///
+/// 文本省略组件,生成的标签为<ellipsis></ellipsis>
+///
+[HtmlTargetElement( "util-ellipsis" )]
+public class EllipsisTagHelper : AngularTagHelperBase {
+ ///
+ /// 配置
+ ///
+ private Config _config;
+ ///
+ /// 属性表达式
+ ///
+ public ModelExpression For { get; set; }
+ ///
+ /// [tooltip],移动到文本展示完整内容的提示,默认值: false
+ ///
+ public bool Tooltip { get; set; }
+ ///
+ /// [tooltip],移动到文本展示完整内容的提示,默认值: false
+ ///
+ public string BindTooltip { get; set; }
+ ///
+ /// length,在按照长度截取下的文本最大字符数,超过则截取省略
+ ///
+ public int Length { get; set; }
+ ///
+ /// [length],在按照长度截取下的文本最大字符数,超过则截取省略
+ ///
+ public string BindLength { get; set; }
+ ///
+ /// lines,在按照行数截取下最大的行数,超过则截取省略
+ ///
+ public int Lines { get; set; }
+ ///
+ /// [lines],在按照行数截取下最大的行数,超过则截取省略
+ ///
+ public string BindLines { get; set; }
+ ///
+ /// [fullWidthRecognition],是否将全角字符的长度视为2来计算字符串长度,默认值: false
+ ///
+ public bool FullWidthRecognition { get; set; }
+ ///
+ /// [fullWidthRecognition],是否将全角字符的长度视为2来计算字符串长度,默认值: false
+ ///
+ public string BindFullWidthRecognition { get; set; }
+ ///
+ /// tail,指定溢出尾巴,默认值: ...
+ ///
+ public string Tail { get; set; }
+ ///
+ /// [tail],指定溢出尾巴,默认值: ...
+ ///
+ public string BindTail { get; set; }
+
+ ///
+ protected override void ProcessBefore( TagHelperContext context, TagHelperOutput output ) {
+ _config = new Config( context, output );
+ var loader = new EllipsisExpressionLoader();
+ loader.Load( _config );
+ }
+
+ ///
+ protected override IRender GetRender( TagHelperContext context, TagHelperOutput output, TagHelperContent content ) {
+ _config.Content = content;
+ return new EllipsisRender( _config );
+ }
+}
\ No newline at end of file
diff --git a/src/Util.Ui.NgAlain/Components/Ellipsis/Helpers/EllipsisExpressionLoader.cs b/src/Util.Ui.NgAlain/Components/Ellipsis/Helpers/EllipsisExpressionLoader.cs
new file mode 100644
index 00000000..39ca0260
--- /dev/null
+++ b/src/Util.Ui.NgAlain/Components/Ellipsis/Helpers/EllipsisExpressionLoader.cs
@@ -0,0 +1,19 @@
+using Util.Ui.Configs;
+using Util.Ui.Expressions;
+using Util.Ui.NgZorro.Expressions;
+
+namespace Util.Ui.NgAlain.Components.Ellipsis.Helpers;
+
+///
+/// 文本省略表达式加载器
+///
+public class EllipsisExpressionLoader : NgZorroExpressionLoaderBase {
+ ///
+ /// 加载模型信息
+ ///
+ /// 配置
+ /// 模型表达式信息
+ protected override void Load( Config config, ModelExpressionInfo info ) {
+ config.SetAttribute( UiConst.Value, info.SafePropertyName, false );
+ }
+}
\ No newline at end of file
diff --git a/src/Util.Ui.NgAlain/Components/Ellipsis/Renders/EllipsisRender.cs b/src/Util.Ui.NgAlain/Components/Ellipsis/Renders/EllipsisRender.cs
new file mode 100644
index 00000000..b52834e9
--- /dev/null
+++ b/src/Util.Ui.NgAlain/Components/Ellipsis/Renders/EllipsisRender.cs
@@ -0,0 +1,38 @@
+using Util.Ui.Builders;
+using Util.Ui.Configs;
+using Util.Ui.NgAlain.Components.Ellipsis.Builders;
+using Util.Ui.Renders;
+
+namespace Util.Ui.NgAlain.Components.Ellipsis.Renders;
+
+///
+/// 文本省略渲染器
+///
+public class EllipsisRender : RenderBase {
+ ///
+ /// 配置
+ ///
+ private readonly Config _config;
+
+ ///
+ /// 初始化文本省略渲染器
+ ///
+ /// 配置
+ public EllipsisRender( Config config ) {
+ _config = config;
+ }
+
+ ///
+ /// 获取标签生成器
+ ///
+ protected override TagBuilder GetTagBuilder() {
+ var builder = new EllipsisBuilder( _config );
+ builder.Config();
+ return builder;
+ }
+
+ ///
+ public override IHtmlContent Clone() {
+ return new EllipsisBuilder( _config.Copy() );
+ }
+}
\ No newline at end of file
diff --git a/src/Util.Ui.NgAlain/Components/PageHeaders/Builders/PageHeaderBuilder.cs b/src/Util.Ui.NgAlain/Components/PageHeaders/Builders/PageHeaderBuilder.cs
index c30fdde7..0f7c268a 100644
--- a/src/Util.Ui.NgAlain/Components/PageHeaders/Builders/PageHeaderBuilder.cs
+++ b/src/Util.Ui.NgAlain/Components/PageHeaders/Builders/PageHeaderBuilder.cs
@@ -213,8 +213,7 @@ public class PageHeaderBuilder : AngularTagBuilder {
///
public override void Config() {
base.Config();
- Title()
- .AutoTitle().SyncTitle()
+ Title().AutoTitle().SyncTitle()
.Home().HomeLink().HomeI18n()
.AutoBreadcrumb().RecursiveBreadcrumb()
.Loading().Wide().Fixed().FixedOffsetTop()
diff --git a/src/Util.Ui.NgZorro/Components/Display/Helpers/DisplayExpressionLoader.cs b/src/Util.Ui.NgZorro/Components/Display/Helpers/DisplayExpressionLoader.cs
index 75895c70..c5d8b2e9 100644
--- a/src/Util.Ui.NgZorro/Components/Display/Helpers/DisplayExpressionLoader.cs
+++ b/src/Util.Ui.NgZorro/Components/Display/Helpers/DisplayExpressionLoader.cs
@@ -39,7 +39,6 @@ public class DisplayExpressionLoader : NgZorroExpressionLoaderBase {
return true;
return false;
}
-
///
/// 加载值
diff --git a/src/Util.Ui/Configs/UiConst.cs b/src/Util.Ui/Configs/UiConst.cs
index c837fd21..b31b4dde 100644
--- a/src/Util.Ui/Configs/UiConst.cs
+++ b/src/Util.Ui/Configs/UiConst.cs
@@ -45,6 +45,10 @@ public static class UiConst {
///
public const string DropdownRender = "dropdown-render";
///
+ /// 行数
+ ///
+ public const string Lines = "lines";
+ ///
/// 访问控制
///
public const string Acl = "acl";
@@ -57,6 +61,10 @@ public static class UiConst {
///
public const string AclElseTemplateId = "acl-else-template-id";
///
+ /// 尾巴
+ ///
+ public const string Tail = "tail";
+ ///
/// 类型
///
public const string Type = "type";
@@ -429,6 +437,10 @@ public static class UiConst {
///
public const string MinLengthMessage = "min-length-message";
///
+ /// 长度
+ ///
+ public const string Length = "length";
+ ///
/// 最大长度
///
public const string MaxLength = "max-length";
@@ -461,6 +473,10 @@ public static class UiConst {
///
public const string Tooltip = "tooltip";
///
+ /// 全宽识别
+ ///
+ public const string FullWidthRecognition = "full-width-recognition";
+ ///
/// 链接
///
public const string Link = "link";
diff --git a/test/Util.Ui.NgAlain.Tests/Ellipsis/EllipsisTagHelperTest.Expression.cs b/test/Util.Ui.NgAlain.Tests/Ellipsis/EllipsisTagHelperTest.Expression.cs
new file mode 100644
index 00000000..529ef6c9
--- /dev/null
+++ b/test/Util.Ui.NgAlain.Tests/Ellipsis/EllipsisTagHelperTest.Expression.cs
@@ -0,0 +1,22 @@
+using System.Text;
+using Xunit;
+
+namespace Util.Ui.NgAlain.Tests.Ellipsis {
+ ///
+ /// 文本省略组件测试
+ ///
+ public partial class EllipsisTagHelperTest {
+ ///
+ /// 测试解析表达式属性for
+ ///
+ [Fact]
+ public void TestFor_1() {
+ _wrapper.SetExpression( t => t.Code );
+ var result = new StringBuilder();
+ result.Append( "" );
+ result.Append( "{{model.code}}" );
+ result.Append( "" );
+ Assert.Equal( result.ToString(), GetResult() );
+ }
+ }
+}
\ No newline at end of file
diff --git a/test/Util.Ui.NgAlain.Tests/Ellipsis/EllipsisTagHelperTest.cs b/test/Util.Ui.NgAlain.Tests/Ellipsis/EllipsisTagHelperTest.cs
new file mode 100644
index 00000000..c3aae3d8
--- /dev/null
+++ b/test/Util.Ui.NgAlain.Tests/Ellipsis/EllipsisTagHelperTest.cs
@@ -0,0 +1,172 @@
+using System.Text;
+using Util.Ui.Angular.Configs;
+using Util.Ui.Configs;
+using Util.Ui.NgAlain.Components.Ellipsis;
+using Util.Ui.NgAlain.Tests.Samples;
+using Util.Ui.TagHelpers;
+using Xunit;
+using Xunit.Abstractions;
+
+namespace Util.Ui.NgAlain.Tests.Ellipsis {
+ ///
+ /// 文本省略组件测试
+ ///
+ public partial class EllipsisTagHelperTest {
+ ///
+ /// 输出工具
+ ///
+ private readonly ITestOutputHelper _output;
+ ///
+ /// TagHelper包装器
+ ///
+ private readonly TagHelperWrapper _wrapper;
+
+ ///
+ /// 测试初始化
+ ///
+ public EllipsisTagHelperTest( ITestOutputHelper output ) {
+ _output = output;
+ _wrapper = new EllipsisTagHelper().ToWrapper();
+ }
+
+ ///
+ /// 获取结果
+ ///
+ private string GetResult() {
+ var result = _wrapper.GetResult();
+ _output.WriteLine( result );
+ return result;
+ }
+
+ ///
+ /// 测试默认输出
+ ///
+ [Fact]
+ public void TestDefault() {
+ var result = new StringBuilder();
+ result.Append( "" );
+ Assert.Equal( result.ToString(), GetResult() );
+ }
+
+ ///
+ /// 测试工具提示
+ ///
+ [Fact]
+ public void TestTooltip() {
+ _wrapper.SetContextAttribute( UiConst.Tooltip, true );
+ var result = new StringBuilder();
+ result.Append( "" );
+ Assert.Equal( result.ToString(), GetResult() );
+ }
+
+ ///
+ /// 测试工具提示
+ ///
+ [Fact]
+ public void TestBindTooltip() {
+ _wrapper.SetContextAttribute( AngularConst.BindTooltip, "true" );
+ var result = new StringBuilder();
+ result.Append( "" );
+ Assert.Equal( result.ToString(), GetResult() );
+ }
+
+ ///
+ /// 测试文本最大长度
+ ///
+ [Fact]
+ public void TestLength() {
+ _wrapper.SetContextAttribute( UiConst.Length, 2 );
+ var result = new StringBuilder();
+ result.Append( "" );
+ Assert.Equal( result.ToString(), GetResult() );
+ }
+
+ ///
+ /// 测试文本最大长度
+ ///
+ [Fact]
+ public void TestBindLength() {
+ _wrapper.SetContextAttribute( AngularConst.BindLength, "2" );
+ var result = new StringBuilder();
+ result.Append( "" );
+ Assert.Equal( result.ToString(), GetResult() );
+ }
+
+ ///
+ /// 测试文本最大行数
+ ///
+ [Fact]
+ public void TestLines() {
+ _wrapper.SetContextAttribute( UiConst.Lines, 2 );
+ var result = new StringBuilder();
+ result.Append( "" );
+ Assert.Equal( result.ToString(), GetResult() );
+ }
+
+ ///
+ /// 测试文本最大行数
+ ///
+ [Fact]
+ public void TestBindLines() {
+ _wrapper.SetContextAttribute( AngularConst.BindLines, "2" );
+ var result = new StringBuilder();
+ result.Append( "" );
+ Assert.Equal( result.ToString(), GetResult() );
+ }
+
+ ///
+ /// 测试是否将全角字符的长度视为2来计算字符串长度
+ ///
+ [Fact]
+ public void TestFullWidthRecognition() {
+ _wrapper.SetContextAttribute( UiConst.FullWidthRecognition, true );
+ var result = new StringBuilder();
+ result.Append( "" );
+ Assert.Equal( result.ToString(), GetResult() );
+ }
+
+ ///
+ /// 测试是否将全角字符的长度视为2来计算字符串长度
+ ///
+ [Fact]
+ public void TestBindFullWidthRecognition() {
+ _wrapper.SetContextAttribute( AngularConst.BindFullWidthRecognition, "true" );
+ var result = new StringBuilder();
+ result.Append( "" );
+ Assert.Equal( result.ToString(), GetResult() );
+ }
+
+ ///
+ /// 测试溢出尾巴
+ ///
+ [Fact]
+ public void TestTail() {
+ _wrapper.SetContextAttribute( UiConst.Tail, "a" );
+ var result = new StringBuilder();
+ result.Append( "" );
+ Assert.Equal( result.ToString(), GetResult() );
+ }
+
+ ///
+ /// 测试溢出尾巴
+ ///
+ [Fact]
+ public void TestBindTail() {
+ _wrapper.SetContextAttribute( AngularConst.BindTail, "a" );
+ var result = new StringBuilder();
+ result.Append( "" );
+ Assert.Equal( result.ToString(), GetResult() );
+ }
+
+ ///
+ /// 测试内容
+ ///
+ [Fact]
+ public void TestAppendContent() {
+ _wrapper.AppendContent( "a" );
+ var result = new StringBuilder();
+ result.Append( "a" );
+ Assert.Equal( result.ToString(), GetResult() );
+ }
+ }
+}
\ No newline at end of file