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,
///
/// 按年显示。
///