diff --git a/doc/TDesign.Docs.ServerSide/TDesign.xml b/doc/TDesign.Docs.ServerSide/TDesign.xml index bf1d127d..4f9f91f7 100644 --- a/doc/TDesign.Docs.ServerSide/TDesign.xml +++ b/doc/TDesign.Docs.ServerSide/TDesign.xml @@ -3748,6 +3748,11 @@ 按照日历形式展示数据或日期的容器。 + + + 是否隐藏控制面板。 + + 使用卡片模式。 @@ -3760,7 +3765,7 @@ - 是否显示周末。 有效。 + 是否显示周末。 有效。 @@ -3783,6 +3788,26 @@ 周几算第一天。 + + + 年月的开始范围。 + + + + + 年月的结束范围。 + + + + + 设置标题。 + + + + + 设置标题的任意代码片段。 + + 星期对应的文本。 @@ -3798,18 +3823,21 @@ 当前月。 - + - 构建日历的头部。 + 切换月年模式。 - - + - 是否跳过周末 + 切换周末是否显示。 - - + + + + 构建日历的头部。 + + @@ -3832,13 +3860,6 @@ - - - 关闭上一个 tr 并开始新的 tr。用于动态换行。 - - - - 构建单元格。 @@ -3848,12 +3869,26 @@ + + + 是否跳过周末 + + + + + + + 关闭上一个 tr 并开始新的 tr。用于动态换行。 + + + + 日历模式。 - + 按月显示。 diff --git a/doc/TDesign.Docs.Shared/Pages/Components/Data/CalendarPage.razor b/doc/TDesign.Docs.Shared/Pages/Components/Data/CalendarPage.razor index 12de16cf..3e7b0d3e 100644 --- a/doc/TDesign.Docs.Shared/Pages/Components/Data/CalendarPage.razor +++ b/doc/TDesign.Docs.Shared/Pages/Components/Data/CalendarPage.razor @@ -9,7 +9,6 @@ 在日期中可显示事项的日期显示容器。常用于有足够空间,且需要承载或显示事项信息时使用。 - @Code.Create(@" diff --git a/doc/TDesign.Docs.WebAssembly/wwwroot/TDesign.xml b/doc/TDesign.Docs.WebAssembly/wwwroot/TDesign.xml index bf1d127d..4f9f91f7 100644 --- a/doc/TDesign.Docs.WebAssembly/wwwroot/TDesign.xml +++ b/doc/TDesign.Docs.WebAssembly/wwwroot/TDesign.xml @@ -3748,6 +3748,11 @@ 按照日历形式展示数据或日期的容器。 + + + 是否隐藏控制面板。 + + 使用卡片模式。 @@ -3760,7 +3765,7 @@ - 是否显示周末。 有效。 + 是否显示周末。 有效。 @@ -3783,6 +3788,26 @@ 周几算第一天。 + + + 年月的开始范围。 + + + + + 年月的结束范围。 + + + + + 设置标题。 + + + + + 设置标题的任意代码片段。 + + 星期对应的文本。 @@ -3798,18 +3823,21 @@ 当前月。 - + - 构建日历的头部。 + 切换月年模式。 - - + - 是否跳过周末 + 切换周末是否显示。 - - + + + + 构建日历的头部。 + + @@ -3832,13 +3860,6 @@ - - - 关闭上一个 tr 并开始新的 tr。用于动态换行。 - - - - 构建单元格。 @@ -3848,12 +3869,26 @@ + + + 是否跳过周末 + + + + + + + 关闭上一个 tr 并开始新的 tr。用于动态换行。 + + + + 日历模式。 - + 按月显示。 diff --git a/src/TDesign/Components/TCalendar.cs b/src/TDesign/Components/TCalendar.cs index 25c4de87..14514343 100644 --- a/src/TDesign/Components/TCalendar.cs +++ b/src/TDesign/Components/TCalendar.cs @@ -1,20 +1,26 @@ -namespace TDesign; +using TDesign.Specifications; + +namespace TDesign; /// /// 按照日历形式展示数据或日期的容器。 /// [CssClass("t-calendar")] -public class TCalendar : TDesignComponentBase +public class TCalendar : TDesignComponentBase,IHasTitleText,IHasTitleFragment { #region Parameters /// + /// 是否隐藏控制面板。 + /// + [Parameter] public bool HideController { get; set; } + /// /// 使用卡片模式。 /// [Parameter][BooleanCssClass("t-calendar--card","t-calendar--full")]public bool Card { get; set; } /// /// 日历的模式。 /// - [Parameter] public CalendarMode Mode { get; set; } = CalendarMode.Mounth; + [Parameter] public CalendarMode Mode { get; set; } = CalendarMode.Month; /// /// 是否显示周末。 有效。 @@ -36,6 +42,23 @@ public class TCalendar : TDesignComponentBase /// 周几算第一天。 /// [Parameter] public DayOfWeek FirstDayOfWeek { get; set; } = DayOfWeek.Monday; + /// + /// 年月的开始范围。 + /// + [Parameter]public DateTime? Start { get; set; } + /// + /// 年月的结束范围。 + /// + [Parameter] public DateTime? End { get; set; } + /// + /// 设置标题。 + /// + [Parameter] public string? TitleText { get; set; } + /// + /// 设置标题的任意代码片段。 + /// + [Parameter] public RenderFragment? TitleContent { get; set; } + #endregion #region Internal @@ -73,6 +96,37 @@ public class TCalendar : TDesignComponentBase /// 当前月。 /// int CurrentMonth { get; set; } + + #endregion + + #region Callback Function + /// + /// 切换月年模式。 + /// + Task SwitchCalendarMode(CalendarMode mode) + { + Mode = mode; + StateHasChanged(); + return Task.CompletedTask; + } + + /// + /// 切换周末是否显示。 + /// + Task SwitchWeekend() + { + ShowWeekend = !ShowWeekend; + StateHasChanged(); + return Task.CompletedTask; + } + + Task ChangeDate(int year, int month) + { + CurrentYear = Year = year; + CurrentMonth = Month = month; + StateHasChanged(); + return Task.CompletedTask; + } #endregion protected override void OnParametersSet() @@ -82,6 +136,14 @@ protected override void OnParametersSet() CurrentYear = Year; CurrentMonth = Month; + Start ??= new DateTime(CurrentYear - 10, 1, 1); + End ??= new DateTime(CurrentYear + 10, 12, 1); + + if ( Start >= End ) + { + throw new InvalidOperationException($"{nameof(Start)} 不能大于 {nameof(End)}"); + } + #region 调整第一天是周几的顺序 var theFirstDayIndex = DayOfWeekList.FindIndex(m => m == FirstDayOfWeek); var orderRange = DayOfWeekList.GetRange(theFirstDayIndex, DayOfWeekList.Count - theFirstDayIndex); @@ -92,6 +154,8 @@ protected override void OnParametersSet() protected override void AddContent(RenderTreeBuilder builder, int sequence) { + BuildControl(builder); + builder.Div("t-calendar__panel") .Class(Mode.GetCssClass("t-calendar__panel--")) .Content(BuildCalendarTable) @@ -115,7 +179,7 @@ void BuildCalendarTable(RenderTreeBuilder builder) /// void BuildCalendarHeader(RenderTreeBuilder builder) { - if(Mode!= CalendarMode.Mounth ) + if(Mode!= CalendarMode.Month ) { return; } @@ -145,13 +209,6 @@ void BuildCalendarHeader(RenderTreeBuilder builder) .Close(); } - /// - /// 是否跳过周末 - /// - /// - /// - bool IsSkipWeekend(DayOfWeek day) => !ShowWeekend && new[] { DayOfWeek.Saturday, DayOfWeek.Sunday }.Contains(day); - /// /// 构建日历的主体。 /// @@ -161,7 +218,7 @@ void BuildCalendarBody(RenderTreeBuilder builder) builder.Element("tbody", "t-calendar__table-body") .Content(body => { - if(Mode== CalendarMode.Mounth ) + if(Mode== CalendarMode.Month ) { BuildMonthBody(body); } @@ -246,7 +303,10 @@ void BuildMonthBody(RenderTreeBuilder builder) } var today = DateTime.Today; - BuildBodyCell(builder, day.ToString(), false, today == currentDateTime); + + var completeDayString = FiilWithZero && day < 10 ? day.ToString().PadLeft(2, '0') : day.ToString(); + + BuildBodyCell(builder, completeDayString, false, today == currentDateTime); if ( (i + firstDayOfWeekIndex) % 7 == 0 ) { @@ -278,16 +338,115 @@ void BuildMonthBody(RenderTreeBuilder builder) builder.CloseElement(); } - /// - /// 关闭上一个 tr 并开始新的 tr。用于动态换行。 - /// - /// - /// - private static void ClosePrevRowAndBuildNewRow(RenderTreeBuilder builder, int sequence) + void BuildControl(RenderTreeBuilder builder) { - builder.CloseElement(); - builder.OpenElement(sequence, "tr"); - builder.AddAttribute(sequence + 1, "class", "t-calendar__table-body-row"); + builder.Div("t-calendar__control", !HideController) + .Content(control => + { + control.Div("t-calendar__title").Content(TitleContent).Close(); + control.Div("t-calendar__control-section") + .Content(selection => + { + //年 下拉菜单 + BuildSelectionCell(selection, year => + { + year.Component>() + .Attribute(m => m.Value, Year) + .Attribute(m => m.ValueExpression, () => Year) + .Attribute(m => m.ValueChanged, HtmlHelper.Instance.Callback().Create(this, value => ChangeDate(value, Month))) + .Content(options => + { + for ( int i = Start!.Value.Year; i <= End!.Value.Year; i++ ) + { + options.Component>() + .Attribute(m => m.Value, i) + .Attribute(m => m.Label, $"{i}年") + .Close(); + } + }) + .Close(); + }); + //月 下拉菜单 + BuildSelectionCell(selection, month => + { + month.Component>() + .Attribute(m => m.Value, Month) + .Attribute(m => m.ValueExpression, () => Month) + .Attribute(m => m.ValueChanged, HtmlHelper.Instance.Callback().Create(this, value => ChangeDate(Year, value))) + .Content(options => + { + for ( int i = 1; i <= 12; i++ ) + { + options.Component>() + .Attribute(m => m.Value, i) + .Attribute(m => m.Label, $"{i}月") + .Attribute(m => m.Disabled, i <= 6 && i < Start!.Value.Month) + .Attribute(m => m.Disabled, i > 6 && i > End!.Value.Month) + .Close(); + } + }) + .Close(); + }, Mode == CalendarMode.Month); + //年月切换 + BuildSelectionCell(selection, mode => + { + mode.Component>() + .Attribute(m=>m.Value,Mode) + .Attribute(m=>m.ValueExpression,()=>Mode) + .Attribute(m=>m.ValueChanged,HtmlHelper.Instance.Callback().Create(this,SwitchCalendarMode)) + .Attribute(m=>m.ButtonStyle, RadioButtonStyle.Filled) + .Content(radio => + { + radio.Component>() + .Attribute(m=>m.Value,CalendarMode.Month) + .Content("月") + .Close(); + + radio.Component>() + .Attribute(m => m.Value, CalendarMode.Year) + .Content("年") + .Close(); + }) + .Close(); + }); + //切换周末显示 + BuildSelectionCell(selection, weekend => + { + var theme = Theme.Primary; + var text = "显示周末"; + + if ( !ShowWeekend ) + { + theme = Theme.Default; + text = "隐藏周末"; + } + weekend.Component() + .Attribute(m => m.Theme, theme) + .Attribute(m => m.OnClick, HtmlHelper.Instance.Callback().Create(this, SwitchWeekend)) + .Content(text) + .Close(); + }, Mode == CalendarMode.Month); + + //回到今天/本月 + BuildSelectionCell(selection, now => + { + var today = DateTime.Now; + + now.Component() + .Attribute(m => m.Theme, Theme.Primary) + .Attribute(m => m.OnClick, HtmlHelper.Instance.Callback().Create(this, () => ChangeDate(today.Year, today.Month))) + .Content(Mode == CalendarMode.Year ? "本月" : "今天") + .Close(); + }); + }) + .Close(); + }) + .Close(); + + void BuildSelectionCell(RenderTreeBuilder selection,RenderFragment content,Condition? condition=default) + { + selection.Div("t-calendar__control-section-cell", condition).Content(content).Close(); + } } /// @@ -319,6 +478,24 @@ static void BuildBodyCell(RenderTreeBuilder builder,string content,bool disabled .Close(); }); } + + /// + /// 是否跳过周末 + /// + /// + /// + bool IsSkipWeekend(DayOfWeek day) => !ShowWeekend && new[] { DayOfWeek.Saturday, DayOfWeek.Sunday }.Contains(day); + /// + /// 关闭上一个 tr 并开始新的 tr。用于动态换行。 + /// + /// + /// + private static void ClosePrevRowAndBuildNewRow(RenderTreeBuilder builder, int sequence) + { + builder.CloseElement(); + builder.OpenElement(sequence, "tr"); + builder.AddAttribute(sequence + 1, "class", "t-calendar__table-body-row"); + } } /// @@ -329,7 +506,7 @@ public enum CalendarMode /// /// 按月显示。 /// - Mounth, + Month, /// /// 按年显示。 ///