公司动态

CSharp: 万年历

📅 2026/8/29 4:33:03
CSharp: 万年历
存动态数据不是JS数据。项目结构sql:-- -- 日历节日配置表支持4种节日类型公历、农历、第N周、星期节日支持单日、多日、整周节日 -- CREATE TABLE dbo.Calendar_Festival ( Id INT IDENTITY(1,1) PRIMARY KEY, FestivalName NVARCHAR(64) NOT NULL, --节日名称 FestivalKind NVARCHAR(16) NOT NULL, --Solar公历|Lunar农历|WeekIndex第N周|WeekDay星期节日 RangeType NVARCHAR(16) NOT NULL, --Single单日|MultiDays连续多日|WholeWeek整周 IsVacation BIT NOT NULL DEFAULT 0, --是否放假 Remark NVARCHAR(128) NULL, --备注说明 FoundYear INT NULL, -- 创立年份 SolarMonth INT NULL, --公历月(公历节日用) SolarDay INT NULL, --公历日(公历节日用) LunarMonth INT NULL, --农历月(农历节日用) LunarDay INT NULL, --农历日(农历节日用) WeekIndex INT NULL, --第N周(WeekIndex类型5月第2周则WeekIndex2) TargetWeekDay INT NULL, --目标星期1周一~7周日 MonthOfYear INT NULL, --对应月份5代表5月 StartOffsetDay INT NULL, --多日持续起始偏移 LastDays INT NULL, --多日持续天数WholeWeek固定7天 IsEnabled BIT NOT NULL DEFAULT 1, CreateTime DATETIME DEFAULT GETDATE() ); GO -- -- 黄历宜忌配置表模拟多条样本 -- CREATE TABLE dbo.Calendar_Almanac ( Id INT IDENTITY(1,1) PRIMARY KEY, Yi NVARCHAR(200) NOT NULL, Ji NVARCHAR(200) NOT NULL, IsEnabled BIT NOT NULL DEFAULT 1, CreateTime DATETIME DEFAULT GETDATE() ); GO -- -- 二十四节气表基准数据生产可替换高精度节气时刻 -- CREATE TABLE dbo.Calendar_SolarTerm ( Id INT IDENTITY(1,1) PRIMARY KEY, Month TINYINT NOT NULL, Day TINYINT NOT NULL, TermName NVARCHAR(16) NOT NULL ); GO CREATE TABLE dbo.Calendar_HuangLi ( Id INT IDENTITY(1,1) PRIMARY KEY, HuangLiYear INT NOT NULL, HuangLiMonth INT NOT NULL, HuangLiDay INT NOT NULL, Yi NVARCHAR(MAX) NULL, Ji NVARCHAR(MAX) NULL, Chong NVARCHAR(32) NULL, Sha NVARCHAR(8) NULL, JianChu NVARCHAR(8) NULL, ZhengChong NVARCHAR(32) NULL, TaiShen NVARCHAR(64) NULL, CONSTRAINT UQ_Calendar_HuangLi_YearMD UNIQUE (HuangLiYear, HuangLiMonth, HuangLiDay) ); CREATE TABLE dbo.Calendar_HolidayAdjust ( Id INT IDENTITY(1,1) PRIMARY KEY, HolidayYear INT NOT NULL, HolidayMonth INT NOT NULL, HolidayDay INT NOT NULL, AdjustType INT NOT NULL, Remark NVARCHAR(64) NULL, CONSTRAINT UQ_Calendar_HolidayAdjust_YearMD UNIQUE (HolidayYear, HolidayMonth, HolidayDay) );using Application.Services; using Infrastructur.Cache; using Infrastructur.Logger; using Infrastructur.Repository; using Infrastructur.Services; using Newtonsoft.Json; using System; using System.Collections.Generic; using System.Configuration; using System.Linq; using System.Web; using System.Web.SessionState; namespace ChineseCalendar { /// summary /// CalendarApi /// geovindu /// /summary public class CalendarApi : IHttpHandler { /// summary /// /// /summary /// param namecontext/param public void ProcessRequest(HttpContext context) { ILogger logger ChineseCalendar.Global.GlobalLogger; DateTime startTime DateTime.Now; try { context.Response.ContentType application/json; context.Response.Charset utf-8; int year, month; if (!int.TryParse(context.Request.QueryString[year], out year)) year DateTime.Now.Year; if (!int.TryParse(context.Request.QueryString[month], out month)) month DateTime.Now.Month; logger.Info(string.Format(开始生成日历{0}年{1}月, year, month)); // 组合根仓储 - 缓存装饰 - 领域服务 - 应用服务 string connStr ConfigurationManager.ConnectionStrings[CalendarDb].ConnectionString; ICalendarRepository repo new SqlServerCalendarRepository(connStr); ICalendarCacheService cache new HttpRuntimeCalendarCache(repo); var lunarProvider new Infrastructur.Services.LunarCalendarProvider(repo); //cache var appSvc new Infrastructur.Services.CalendarApplicationService(lunarProvider); // 放假调休数据接口数据库驱动替代前端 workTime.js string action context.Request.QueryString[action] ?? ; if (action holidays) { var holidays appSvc.GetHolidayAdjusts(year); string hJson JsonConvert.SerializeObject(holidays, Formatting.Indented); context.Response.Write(hJson); logger.Info(string.Format(放假调休接口完成{0}年共{1}条, year, holidays.Count)); return; } // 黄历宜忌接口数据库驱动替代前端 js/huangli/YYYY.js if (action huangli) { var huangli appSvc.GetHuangLi(year); string hlJson JsonConvert.SerializeObject(huangli, Formatting.Indented); context.Response.Write(hlJson); logger.Info(string.Format(黄历宜忌接口完成{0}年共{1}条, year, huangli.Days.Count)); return; } var result appSvc.GetCalendar(year, month); string json JsonConvert.SerializeObject(result, Formatting.Indented); context.Response.Write(json); double ms (DateTime.Now - startTime).TotalMilliseconds; logger.Info(string.Format(日历生成完成{0}年{1}月耗时{2}ms, year, month, ms)); } catch (Exception ex) { logger.Error(日历接口异常, ex); context.Response.StatusCode 500; context.Response.Write({\error\:\服务器内部错误\}); } } public bool IsReusable { get { return false; } } } }% Page LanguageC# AutoEventWireuptrue CodeBehindCalendarView.aspx.cs InheritsChineseCalendar.CalendarView % !DOCTYPE html html xmlnshttp://www.w3.org/1999/xhtml head meta http-equivContent-Type contenttext/html; charsetutf-8/ meta nameviewport contentwidthdevice-width, initial-scale1, viewport-fitcover/ titleDDD万年历‑悬停详情版/title meta nameKeywords content塗聚文,涂聚文,Geovin Du,geovindu,捷為工作室万年历,万年历查询,黄历,黄历查询,塗聚文,捷為工作室 / meta nameDescription content塗聚文,涂聚文,Geovin Du,geovindu,捷為工作室信息流,物流,人力资源流,资本流的系统解决方案的开发与设计. / meta nameauthor contentgeovindu,塗聚文,Geovin Du,涂聚文 / link relshortcut icon hreffavicon.ico typeimage/x-icon / link relicon hreffavicon.ico typeimage/ico / link relbookmark hreffavicon.ico / script srcjs/jquery-3.6.0.min.js/script style *{box-sizing:border-box;} body{font-family:Microsoft YaHei,Arial,sans-serif;background:#fff;margin:0;padding:10px;} table.calendar{border-collapse:collapse;width:100%;max-width:980px;margin:0 auto;table-layout:fixed;} table.calendar th,table.calendar td{border:1px solid #bbbbbb;padding:6px;vertical-align:top;height:96px;width:140px;} table.calendar th{background:#f2f2f2;text-align:center;} table.calendar td{cursor:pointer;position:relative;} table.calendar td:hover{background:#fffbe8;outline:1px solid #e0a800;outline-offset:-1px;} .cell-other-month{color:#999999;} .cell-today{background:#eaf4ff;outline:2px solid #2a6ec9;outline-offset:-2px;} .day-num{font-size:20px;font-weight:bold;line-height:1.1;} .cell-other-month .day-num{color:#999999;} .text-festival{color:#c81010;font-size:12px;} .text-term{color:#00701a;font-size:12px;font-weight:bold;} .text-lunar{font-size:12px;color:#333;} .text-week{font-size:10px;color:#888;} .tool-bar{margin:12px auto;max-width:980px;display:flex;flex-wrap:wrap;align-items:center;gap:6px 10px;} .tool-bar button{margin:0;} button{padding:4px 12px;margin:0 6px;} /* 放假/上班角标仿参考页 rest / workN */ .badge-rest,.badge-work{ position:absolute;top:3px;right:3px;font-size:10px;line-height:1; padding:2px 3px;border-radius:2px;color:#fff; } .badge-rest{background:#c81010;} .badge-work{background:#5b7db1;} /* 悬停弹出详情层仿 chinesecalendar.html detailDialog */ #dayPopup{ display:none;position:absolute;z-index:999;width:min(360px,92vw); background:#fff;border:1px solid #c9a34e;border-radius:6px; box-shadow:0 4px 16px rgba(0,0,0,.25);overflow:hidden; font-size:12px;color:#333; } #dayPopup .pop-header{background:linear-gradient(#fdf6e3,#f6e7c1);padding:10px 12px;border-bottom:1px solid #c9a34e;} #dayPopup .pop-day{font-size:34px;font-weight:bold;color:#c81010;float:left;line-height:1;margin-right:10px;min-width:44px;text-align:center;} #dayPopup .pop-solar{font-size:14px;font-weight:bold;} #dayPopup .pop-sub{color:#666;margin-top:3px;} #dayPopup .pop-body{padding:10px 12px;} #dayPopup .pop-row{margin-bottom:6px;line-height:1.7;} #dayPopup .pop-label{color:#8a6d3b;font-weight:bold;margin-right:4px;} #dayPopup .pop-lunar{color:#1d7d46;} #dayPopup .pop-term{color:#00701a;font-weight:bold;} #dayPopup .pop-fest{color:#c81010;} #dayPopup .pop-ann{color:#c81010;font-weight:bold;} #dayPopup .pop-vacation{display:inline-block;background:#c81010;color:#fff;border-radius:3px;padding:0 4px;font-size:10px;margin-left:4px;} #dayPopup .pop-remark{color:#888;margin-left:2px;} #dayPopup .pop-work{background:#fff8e8;border:1px dashed #d9a94f;border-radius:4px;padding:4px 8px;color:#8a5a00;} #dayPopup .pop-yiji{overflow:hidden;border-top:1px dashed #ddd;padding-top:8px;} #dayPopup .pop-yi,.pop-ji{float:left;width:50%;box-sizing:border-box;} #dayPopup .pop-ji{border-left:1px dashed #ddd;padding-left:10px;} #dayPopup .pop-yi .t{color:#1d7d46;font-weight:bold;margin-bottom:4px;} #dayPopup .pop-ji .t{color:#c81010;font-weight:bold;margin-bottom:4px;} #dayPopup .pop-footer{clear:both;background:#fafafa;border-top:1px solid #eee;padding:5px 12px;color:#aaa;font-size:10px;} /* 触摸端底部抽屉式弹出宽度自适应点击空白处关闭 */ #dayPopup.mobile-pop{ position:fixed;left:50%;top:auto;bottom:12px;transform:translateX(-50%); width:92vw;max-width:360px;max-height:80vh;overflow:auto; } /* 响应式平板 / 手机自适应 */ media (max-width:768px){ body{padding:6px 8px;} .tool-bar span{font-size:11px;margin-left:0 !important;} table.calendar th,table.calendar td{padding:3px;height:auto;min-height:62px;} .day-num{font-size:17px;} .text-festival,.text-term,.text-lunar{font-size:10px;} .text-week{font-size:9px;} .badge-rest,.badge-work{font-size:9px;padding:1px 2px;top:2px;right:2px;} } media (max-width:480px){ table.calendar th{font-size:11px;padding:2px 1px;} table.calendar td{min-height:54px;padding:2px;} .day-num{font-size:15px;} .text-festival,.text-term,.text-lunar{font-size:9px;} .text-week{display:none;} } /style /head body div classtool-bar button idbtnPrev上一月/button span idpageTitle/span button idbtnNext下一月/button span stylecolor:#888;font-size:12px;margin-left:16px;鼠标移过日期查看公历/农历详情、宜忌、节日周年、放假调休安排/span /div table classcalendar thead tr th星期一/th th星期二/th th星期三/th th星期四/th th星期五/th th星期六/th th星期日/th /tr /thead tbody idtbContainer/tbody /table !-- 悬停弹出详情层 -- div iddayPopup div classpop-header div classpop-day idpopDay26/div div classpop-solar idpopSolar2026年8月26日 星期三/div div classpop-sub idpopSub第35周/div div styleclear:both;/div /div div classpop-body div classpop-rowspan classpop-label农历/spanspan classpop-lunar idpopLunar/span/div div classpop-row idpopTermRow styledisplay:none;span classpop-label节气/spanspan classpop-term idpopTerm/span/div div classpop-row idpopFestRow styledisplay:none;span classpop-label节日/spanspan idpopFest/span/div div classpop-row idpopWorkRow styledisplay:none;span classpop-label放假安排/spanspan classpop-work idpopWork/span/div div classpop-yiji div classpop-yidiv classt宜/divdiv idpopYi/div/div div classpop-jidiv classt忌/divdiv idpopJi/div/div /div /div div classpop-footerDDD万年历 · 悬停查看详情/div /div script var curYear,curMonth; var cellData[]; //所有单元格数据td通过data-idx索引 var hideTimernull; //延迟隐藏计时器 var weekText[日,一,二,三,四,五,六]; //是否触摸设备无 hover 能力触摸端改用点击 底部抽屉弹出 var isTouch (window.matchMedia window.matchMedia((hover: none)).matches) || (ontouchstart in window) || (navigator.maxTouchPoints0); $(function(){ var nownew Date(); curYearnow.getFullYear(); curMonthnow.getMonth()1; loadCalendar(curYear,curMonth); $(#btnPrev).on(click,function(){ curMonth--; if(curMonth1){curMonth12;curYear--;} loadCalendar(curYear,curMonth); }); $(#btnNext).on(click,function(){ curMonth; if(curMonth12){curMonth1;curYear;} loadCalendar(curYear,curMonth); }); //交互桌面用悬停触摸端用点击底部抽屉并点击空白处关闭 if(!isTouch){ //事件委托td悬停显示详情移出延迟隐藏鼠标移到弹层上不隐藏 $(#tbContainer).on(mouseenter,td,function(){ if(hideTimer){clearTimeout(hideTimer);hideTimernull;} var idx$(this).data(idx); if(idxundefined)return; showPopup(cellData[idx],$(this)); }).on(mouseleave,td,function(){ delayHide(); }); $(#dayPopup).on(mouseenter,function(){ if(hideTimer){clearTimeout(hideTimer);hideTimernull;} }).on(mouseleave,function(){ delayHide(); }); }else{ //触摸端点击单元格显示详情点击弹层外区域关闭 $(#tbContainer).on(click,td,function(){ var idx$(this).data(idx); if(idxundefined)return; showPopup(cellData[idx],$(this)); }); $(document).on(click touchstart,function(e){ var $t$(e.target); if($t.closest(#dayPopup).length || $t.closest(td).length)return; if(hideTimer){clearTimeout(hideTimer);hideTimernull;} $(#dayPopup).hide(); }); } }); function loadCalendar(y,m){ //放假调休数据走数据库接口/CalendarApi.ashx?actionholidaysyearY按年缓存 ensureHolidays(y,function(){ $.getJSON(CalendarApi.ashx,{year:y,month:m},function(res){ $(#pageTitle).text(res.SolarYear年res.SolarMonth月 res.LunarTitle); var html; cellData[]; var todaynew Date(); $.each(res.Rows,function(rIdx,rowData){ htmltr; $.each(rowData,function(cIdx,cell){ var idxcellData.length; cellData.push(cell); var cssClasscell.IsCurrentMonthCell?:cell-other-month; if(cell.SolarYeartoday.getFullYear()cell.SolarMonth(today.getMonth()1)cell.SolarDaytoday.getDate()){ cssClass cell-today; } //放假/上班角标数据库放假调休数据 var badge; var wtdayWorkStatus(cell.SolarYear,cell.SolarMonth,cell.SolarDay); if(wt放假){ badgespan classbadge-rest休/span; }else if(wt上班){ badgespan classbadge-work班/span; } var innerdiv classday-numcell.SolarDay/divbadge; if(cell.FestivalMergeText){ innerdiv classtext-festivalcell.FestivalMergeText/div; } if(cell.SolarTerm){ innerdiv classtext-termcell.SolarTerm/div; } innerdiv classtext-lunarcell.LunarDayText/div; innerdiv classtext-week第cell.YearWeek周/div; htmltd classcssClass />