diff --git a/framework/src/Volo.Abp.BlazoriseUI/BlazoriseUiObjectExtensionPropertyInfoExtensions.cs b/framework/src/Volo.Abp.BlazoriseUI/BlazoriseUiObjectExtensionPropertyInfoExtensions.cs index 5794021488..b8a31d6a54 100644 --- a/framework/src/Volo.Abp.BlazoriseUI/BlazoriseUiObjectExtensionPropertyInfoExtensions.cs +++ b/framework/src/Volo.Abp.BlazoriseUI/BlazoriseUiObjectExtensionPropertyInfoExtensions.cs @@ -211,7 +211,7 @@ public static class BlazoriseUiObjectExtensionPropertyInfoExtensions { foreach (var attribute in propertyInfo.Attributes) { - var inputTypeByAttribute = GetInputTypeFromAttributeOrNull(attribute); + var inputTypeByAttribute = GetInputTypeFromAttributeOrNull(attribute, propertyInfo.Type); if (inputTypeByAttribute != null) { return inputTypeByAttribute; @@ -226,7 +226,7 @@ public static class BlazoriseUiObjectExtensionPropertyInfoExtensions return propertyInfo.Type.IsEnum || TypeHelper.IsNullableEnum(propertyInfo.Type); } - private static Type? GetInputTypeFromAttributeOrNull(Attribute attribute) + private static Type? GetInputTypeFromAttributeOrNull(Attribute attribute, Type propertyType) { var hasTextEditSupport = TextEditSupportedAttributeTypes.Any(t => t == attribute.GetType()); @@ -235,7 +235,6 @@ public static class BlazoriseUiObjectExtensionPropertyInfoExtensions return typeof(TextExtensionProperty<,>); } - if (attribute is DataTypeAttribute dataTypeAttribute) { switch (dataTypeAttribute.DataType) @@ -247,7 +246,9 @@ public static class BlazoriseUiObjectExtensionPropertyInfoExtensions return typeof(TextExtensionProperty<,>); case DataType.Date: case DataType.DateTime: - return typeof(DateTimeExtensionProperty<,>); + return propertyType == typeof(DateTimeOffset) || propertyType == typeof(DateTimeOffset?) + ? typeof(DateTimeOffsetExtensionProperty<,>) + : typeof(DateTimeExtensionProperty<,>); case DataType.Time: return typeof(TimeExtensionProperty<,>); case DataType.MultilineText: @@ -265,11 +266,16 @@ public static class BlazoriseUiObjectExtensionPropertyInfoExtensions return typeof(CheckExtensionProperty<,>); } - if (type == typeof(DateTime)) + if (type == typeof(DateTime) || type == typeof(DateTime?)) { return typeof(DateTimeExtensionProperty<,>); } + if (type == typeof(DateTimeOffset) || type == typeof(DateTimeOffset?)) + { + return typeof(DateTimeOffsetExtensionProperty<,>); + } + if (NumberTypes.Contains(type)) { return typeof(TextExtensionProperty<,>); diff --git a/framework/src/Volo.Abp.BlazoriseUI/Components/AbpExtensibleDataGrid.razor b/framework/src/Volo.Abp.BlazoriseUI/Components/AbpExtensibleDataGrid.razor index 6417902c57..6f1a82df5d 100644 --- a/framework/src/Volo.Abp.BlazoriseUI/Components/AbpExtensibleDataGrid.razor +++ b/framework/src/Volo.Abp.BlazoriseUI/Components/AbpExtensibleDataGrid.razor @@ -92,7 +92,7 @@ { if (!ExtensionPropertiesRegex.IsMatch(column.Data)) { - @if (column.ValueConverter == null) + @if (column.ValueConverter == null && !IsDateTimeColumn(column)) { : ComponentBase [Inject] public IStringLocalizer UiLocalizer { get; set; } = default!; + [Inject] + public IClock Clock { get; set; } = default!; + protected virtual RenderFragment RenderCustomTableColumnComponent(Type type, object data) { return (builder) => @@ -57,13 +62,67 @@ public partial class AbpExtensibleDataGrid : ComponentBase protected virtual string GetConvertedFieldValue(TItem item, TableColumn columnDefinition) { - var convertedValue = columnDefinition.ValueConverter!.Invoke(item!); + if (columnDefinition.ValueConverter != null) + { + var convertedValue = columnDefinition.ValueConverter.Invoke(item!); + if (!columnDefinition.DisplayFormat.IsNullOrEmpty()) + { + return string.Format(columnDefinition.DisplayFormatProvider, columnDefinition.DisplayFormat!, convertedValue); + } + + return convertedValue; + } + + var propertyInfo = item!.GetType().GetProperty(columnDefinition.Data); + return GetConvertedFieldValue(propertyInfo?.GetValue(item), columnDefinition); + } + + protected virtual string GetConvertedFieldValue(object? value, TableColumn columnDefinition) + { + if (value is DateTime dateTime) + { + var converted = Clock.ConvertToUserTime(dateTime); + if (!columnDefinition.DisplayFormat.IsNullOrEmpty()) + { + return string.Format(columnDefinition.DisplayFormatProvider, columnDefinition.DisplayFormat!, converted); + } + + return converted.ToString(columnDefinition.DisplayFormatProvider as CultureInfo ?? CultureInfo.CurrentCulture); + } + + if (value is DateTimeOffset dateTimeOffset) + { + var converted = Clock.ConvertToUserTime(dateTimeOffset); + if (!columnDefinition.DisplayFormat.IsNullOrEmpty()) + { + return string.Format(columnDefinition.DisplayFormatProvider, columnDefinition.DisplayFormat!, converted); + } + + return converted.ToString(columnDefinition.DisplayFormatProvider as CultureInfo ?? CultureInfo.CurrentCulture); + } + + if (value == null) + { + return string.Empty; + } + if (!columnDefinition.DisplayFormat.IsNullOrEmpty()) { - return string.Format(columnDefinition.DisplayFormatProvider, columnDefinition.DisplayFormat!, - convertedValue); + return string.Format(columnDefinition.DisplayFormatProvider, columnDefinition.DisplayFormat!, value); + } + + return value.ToString() ?? string.Empty; + } + + protected virtual bool IsDateTimeColumn(TableColumn columnDefinition) + { + var propertyInfo = typeof(TItem).GetProperty(columnDefinition.Data); + if (propertyInfo == null) + { + return false; } - return convertedValue; + var propertyType = Nullable.GetUnderlyingType(propertyInfo.PropertyType) ?? propertyInfo.PropertyType; + return propertyType == typeof(DateTime) || propertyType == typeof(DateTimeOffset); } } diff --git a/framework/src/Volo.Abp.BlazoriseUI/Components/ObjectExtending/DateTimeOffsetExtensionProperty.razor b/framework/src/Volo.Abp.BlazoriseUI/Components/ObjectExtending/DateTimeOffsetExtensionProperty.razor new file mode 100644 index 0000000000..045928fffa --- /dev/null +++ b/framework/src/Volo.Abp.BlazoriseUI/Components/ObjectExtending/DateTimeOffsetExtensionProperty.razor @@ -0,0 +1,24 @@ +@typeparam TEntity +@typeparam TResourceType +@using Volo.Abp.BlazoriseUI +@using Volo.Abp.Localization +@using Volo.Abp.ObjectExtending +@inherits ExtensionPropertyComponentBase + +@if (PropertyInfo != null && Entity != null) +{ + + + @PropertyInfo.GetLocalizedDisplayName(StringLocalizerFactory) + + + + + + + +} diff --git a/framework/src/Volo.Abp.BlazoriseUI/Components/ObjectExtending/DateTimeOffsetExtensionProperty.razor.cs b/framework/src/Volo.Abp.BlazoriseUI/Components/ObjectExtending/DateTimeOffsetExtensionProperty.razor.cs new file mode 100644 index 0000000000..41488c0ea8 --- /dev/null +++ b/framework/src/Volo.Abp.BlazoriseUI/Components/ObjectExtending/DateTimeOffsetExtensionProperty.razor.cs @@ -0,0 +1,29 @@ +using System; +using Volo.Abp.Data; + +namespace Volo.Abp.BlazoriseUI.Components.ObjectExtending; + +public partial class DateTimeOffsetExtensionProperty + where TEntity : IHasExtraProperties +{ + protected DateTimeOffset? Value { + get { + var raw = Entity.GetProperty(PropertyInfo.Name); + return raw switch + { + null => null, + DateTimeOffset dto => dto, + DateTime dt => dt.Kind switch + { + DateTimeKind.Utc => new DateTimeOffset(dt, TimeSpan.Zero), + DateTimeKind.Local => new DateTimeOffset(dt), + _ => new DateTimeOffset(DateTime.SpecifyKind(dt, DateTimeKind.Utc), TimeSpan.Zero) + }, + _ => null + }; + } + set { + Entity.SetProperty(PropertyInfo.Name, value, false); + } + } +}