本页给出一个 Calendar 排期面板示例,演示 Calendar、DateBadge、Alert、Button 的组合用法。适合设备维保、课程安排、项目里程碑、值班计划等按日期组织的业务界面。
示例仍采用 aardio 推荐模式:在 /*DSG{{*/ ... /*}}*/ 中放置多个语义化 custom 宿主,再用 AntdUI.Control(winform.host) 自然嵌入控件。这样窗口缩放、DPI 缩放和边距固定由 aardio 设计器维护,不需要在 .NET 控件内部手写大量 SetBounds。
import win.ui;
import dotNet.AntdUI;
import System;
import System.Drawing;
/*DSG{{*/
var winform = win.form(text="项目排期日历";right=920;bottom=600;bgcolor=0xF7F8FA)
winform.add(
calendarHost={cls="custom";left=20;top=20;right=610;bottom=560;db=1;dl=1;dt=1;edge=1;z=1};
detailHost={cls="custom";left=630;top=20;right=900;bottom=190;dl=1;dr=1;dt=1;frame=1;z=2};
legendHost={cls="custom";left=630;top=410;right=900;bottom=560;db=1;dl=1;dr=1;dt=1;z=7};
nextHost={cls="custom";text="下一项";left=820;top=350;right=900;bottom=386;dr=1;dt=1;frame=1;z=6};
prevHost={cls="custom";text="上一项";left=630;top=350;right=710;bottom=386;dl=1;dt=1;frame=1;z=4};
summaryHost={cls="custom";left=630;top=205;right=900;bottom=330;dl=1;dr=1;dt=1;frame=1;z=3};
todayHost={cls="custom";text="今天";left=725;top=350;right=805;bottom=386;dl=1;dt=1;frame=1;z=5}
)
/*}}*/
// 业务数据使用普通 aardio 数组保存;Calendar 只负责展示与选择日期。
var plans = [
{date="2026-07-06"; type="巡检"; title="核心机房巡检"; desc="检查 UPS、温湿度、告警面板和备份链路。"; color=0xFF1677FF},
{date="2026-07-09"; type="保养"; title="冷却系统保养"; desc="更换滤网,复核冷却水压力与风机状态。"; color=0xFF52C41A},
{date="2026-07-15"; type="评审"; title="月度容量评审"; desc="评估存储、带宽和计算资源的增长趋势。"; color=0xFFFAAD14},
{date="2026-07-21"; type="发布"; title="网关策略发布"; desc="灰度发布新访问策略,观察 30 分钟后扩大范围。"; color=0xFF722ED1},
{date="2026-07-28"; type="演练"; title="灾备切换演练"; desc="按预案切换到备站,并记录恢复时间。"; color=0xFFF5222D}
];
var parseDateText = function(dateText){
var y,m,d = string.match(dateText,"^(\d+)-(\d+)-(\d+)$");
if(!y) return System.DateTime.Now.Date;
//tonumber 返回 2 个值,这样实际传了 4 个参数,会因参数类型不匹配找不到方法
//System.DateTime(tonumber(y),tonumber(m),tonumber(d))
y,m,d = tonumber(y),tonumber(m),tonumber(d)
return System.DateTime(y,m,d);
}
var calendar = AntdUI.Calendar(winform.calendarHost);
calendar.Full = true;
calendar.ShowChinese = true;
calendar.ShowButtonToDay = true;
calendar.Radius = 8;
calendar.SetMinMax(System.DateTime(2026,7,1), System.DateTime(2026,7,31));
var detail = AntdUI.Alert(winform.detailHost);
detail.TextTitle = "选中日期";
detail.Text = "请选择日历中的日期查看安排。";
detail.Icon = AntdUI.TType.Info;
detail.CloseIcon = false;
detail.Radius = 8;
detail.BorderWidth = 1;
var summary = AntdUI.Alert(winform.summaryHost);
summary.TextTitle = "本月计划";
summary.Text = "共 " + #plans + " 项排期,徽标颜色表示不同类型。";
summary.Icon = AntdUI.TType.Success;
summary.CloseIcon = false;
summary.Radius = 8;
var btnPrev = AntdUI.Button(winform.prevHost);
btnPrev.Type = AntdUI.TTypeMini.Default;
var btnToday = AntdUI.Button(winform.todayHost);
btnToday.Type = AntdUI.TTypeMini.Primary;
var btnNext = AntdUI.Button(winform.nextHost);
btnNext.Type = AntdUI.TTypeMini.Default;
var legend = AntdUI.Alert(winform.legendHost);
legend.TextTitle = "图例";
legend.Text = '蓝色:巡检\r\n绿色:保养\r\n黄色:评审\r\n紫色:发布\r\n红色:演练';
legend.Icon = AntdUI.TType.Info;
legend.CloseIcon = false;
legend.Radius = 8;
var buildBadges = function(){
var badges = dotNet.list("AntdUI.DateBadge");
for i,item in plans {
// DateBadge 的 date 参数使用 yyyy-MM-dd 字符串,content 是显示在日期上的徽标文本。
var badge = AntdUI.DateBadge(item.date,item.type,item.color);
badge.Radius = 4;
badge.Size = 0.6; //相对 Calendar 字体的缩放比例,不是像素字号
badges.Add(badge);
}
return badges;
}
calendar.SetBadge(buildBadges());
calendar.LoadBadge();
var findPlansByDate = function(dateText){
var found = [];
for i,item in plans {
if(item.date == dateText) table.push(found,item);
}
return found;
}
var renderDate = function(dateText){
var found = findPlansByDate(dateText);
if(#found){
var lines = [];
for i,item in found {
table.push(lines,item.type + " · " + item.title ++ '\r\n' ++ item.desc);
}
detail.Icon = AntdUI.TType.Success;
detail.TextTitle = dateText + " · " + #found + " 项安排";
detail.Text = string.join(lines,'\r\n\r\n');
}
else{
detail.Icon = AntdUI.TType.Info;
detail.TextTitle = dateText + " · 无安排";
detail.Text = "这一天没有排期,可作为缓冲或临时维护窗口。";
}
}
var currentPlanIndex = 1;
var jumpToPlan = function(index){
if(index < 1) index = #plans;
if(index > #plans) index = 1;
currentPlanIndex = index;
var item = plans[currentPlanIndex];
calendar.SetDate(parseDateText(item.date));
renderDate(item.date);
}
calendar.DateChanged = function(sender,value){
renderDate(value.ToString("yyyy-MM-dd"));
}
btnPrev.Click = function(sender,e){
jumpToPlan(currentPlanIndex - 1);
}
btnNext.Click = function(sender,e){
jumpToPlan(currentPlanIndex + 1);
}
btnToday.Click = function(sender,e){
var todayText = System.DateTime.Now.ToString("yyyy-MM-dd");
calendar.SetDate(System.DateTime.Now.Date);
renderDate(todayText);
}
jumpToPlan(1);
winform.show();
win.loopMessage();
不要把业务数据塞进控件内部再从控件反推业务状态。示例中 plans 保存真实数据,DateBadge 只是把重要日期视觉化:
var badge = AntdUI.DateBadge(item.date,item.type,item.color);
badges.Add(badge);
calendar.SetBadge(badges);
当前 DLL 验证的 DateBadge 常用构造函数使用 yyyy-MM-dd 字符串作为日期参数,例如:
var badge = AntdUI.DateBadge("2026-07-06","巡检",0xFF1677FF);
badge.Radius = 4;
badge.Size = 0.6; //相对 Calendar 字体的缩放比例,不是像素字号
DateBadge 常用属性包括:
Date:日期字符串。Content:徽标文本或数值内容。Fill:徽标颜色;aardio 中直接使用 0xAARRGGBB 数值。Round / Radius:圆形或圆角样式。Align:徽标相对日期单元格的对齐位置。Size:徽标字体相对于 Calendar.Font 的缩放比例,默认值为 0.6,不是像素字号;一般使用 0.5~0.8,也可以不设置而沿用默认值。误设为 11 会得到基础字体 11 倍的超大徽标,在高 DPI 屏幕上尤其明显。OffsetX / OffsetY:徽标相对日期单元格的横向与纵向偏移。用户选择日期后,DateChanged 传入 System.DateTime,常用 value.ToString("yyyy-MM-dd") 转成业务 key:
calendar.DateChanged = function(sender,value){
renderDate(value.ToString("yyyy-MM-dd"));
}
如果在代码中调用 calendar.SetDate(...) 后需要立即更新右侧详情,建议像示例一样主动调用 renderDate(dateText),不要依赖事件是否同步触发。
calendar.SetMinMax(System.DateTime(2026,7,1), System.DateTime(2026,7,31));
calendar.ShowChinese = true;
calendar.ShowButtonToDay = true;
ShowChinese 适合排班、节假日、课程表等场景;如果是全球化业务系统,应根据用户区域决定是否启用。