2 Commits

Author SHA1 Message Date
mac
5ef340cb08 v2.1.0 — 日历三级选择:年→月→周,4个月格+4周格 2026-07-24 17:34:52 +08:00
mac
073b570681 fix: 更新fmtWeek支持和calMonth渲染逻辑 2026-07-24 17:34:15 +08:00
3 changed files with 112 additions and 45 deletions

View File

@@ -6,7 +6,8 @@
State
================================================================ */
var calendarStatus = {}; // { "2026-W30": "pass", ... }
var calYear; // 日历显示的年
var calYear;
var calMonth = new Date().getMonth(); // 月份索引 0-11
var activePanel = 'daily';
var weekOffset = 0;
var lastSavedData = null;
@@ -145,45 +146,61 @@
renderCalendar();
};
/** 渲染周历4周一行 + 月份分组) */
/** 选择月份 */
window.selectCalMonth = function(mIdx) {
calMonth = mIdx;
renderCalendar();
};
/** 渲染年-月-周选择器 */
function renderCalendar() {
document.getElementById('cal-year-label').textContent = calYear + '年';
var yearStart = new Date(calYear, 0, 1);
var yearEnd = new Date(calYear, 11, 31);
var weeks = [];
var d = new Date(yearStart);
d.setDate(d.getDate() - d.getDay() + (d.getDay() === 0 ? -6 : 1));
var lastMonth = -1;
var monthsList = ['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'];
while (d <= yearEnd) {
var wk = fmtWeek(d);
var mon = new Date(d);
var mIdx = mon.getMonth();
var isMonthStart = (mIdx !== lastMonth && mon.getDate() <= 7);
weeks.push({ wk: wk, monthLabel: isMonthStart ? monthsList[mIdx] : '' });
lastMonth = mIdx;
d.setDate(d.getDate() + 7);
// 月份标签
var monthsList = ['1月','2月','3月','4月','5月','6月','7月','8月','9月','10月','11月','12月'];
var today = new Date();
var todayMonth = today.getFullYear() === calYear ? today.getMonth() : -1;
var mHtml = '';
for (var i = 0; i < 12; i++) {
var mc = 'cal-month-btn';
if (i === calMonth) mc += ' active';
if (i === todayMonth) mc += ' today';
mHtml += '<button class="' + mc + '" onclick="selectCalMonth(' + i + ')">' + monthsList[i] + '</button>';
}
document.getElementById('cal-months').innerHTML = mHtml;
// 计算该月包含的周
var firstDay = new Date(calYear, calMonth, 1);
var lastDay = new Date(calYear, calMonth + 1, 0);
var monday = new Date(firstDay);
monday.setDate(monday.getDate() - monday.getDay() + (monday.getDay() === 0 ? -6 : 1));
var weeks = [];
while (monday <= lastDay) {
weeks.push(fmtWeek(monday));
monday.setDate(monday.getDate() + 7);
}
// 确保至少有4周显示
while (weeks.length < 4) {
var w = fmtWeek(monday);
if (weeks.indexOf(w) < 0) weeks.push(w);
monday.setDate(monday.getDate() + 7);
}
var todayWk = fmtWeek(new Date());
var el = document.getElementById('cal-week-list');
var html = '';
for (var i = 0; i < weeks.length; i++) {
var we = weeks[i];
var w = we.wk;
var wHtml = '';
for (var i2 = 0; i2 < weeks.length; i2++) {
var w = weeks[i2];
var cls = 'cal-week-cell';
var status = calendarStatus[w];
if (status) cls += ' ' + status;
if (w === todayWk) cls += ' today';
if (w === selectedWeek) cls += ' selected';
if (we.monthLabel) cls += ' month-start';
var wkNum = w.split('-W')[1].replace(/^0/, '');
html += '<div class="' + cls + '" data-week="' + w + '" data-month="' + we.monthLabel + '" title="' + w + '">' +
'<span class="wk-num">W' + wkNum + '</span>' +
'<span class="wk-dot"></span>' +
'</div>';
wHtml += '<div class="' + cls + '" data-week="' + w + '" title="' + w + '">' +
'W' + w.split('-W')[1].replace(/^0/, '') + '</div>';
}
el.innerHTML = html;
el.querySelectorAll('.cal-week-cell').forEach(function(cell) {
var we = document.getElementById('cal-weeks');
we.innerHTML = wHtml;
we.querySelectorAll('.cal-week-cell').forEach(function(cell) {
cell.addEventListener('click', function() {
var wk = this.dataset.week;
if (wk) navigateToWeek(wk);
@@ -200,10 +217,11 @@
}
window.goToCurrentWeek = function() {
var now = fmtWeek(new Date());
calYear = new Date().getFullYear();
var now = new Date();
calYear = now.getFullYear();
calMonth = now.getMonth();
renderCalendar();
navigateToWeek(now);
navigateToWeek(fmtWeek(now));
};
/* ================================================================

View File

@@ -208,12 +208,62 @@ body {
color: var(--text-dim);
}
.cal-nav:hover { background: var(--bg); color: var(--text); }
.cal-week-list {
/* 月份按钮 */
.cal-months {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 6px 4px;
padding: 0 14px;
gap: 3px;
padding: 0 14px 8px;
}
.cal-month-btn {
padding: 4px 0;
border: 1px solid transparent;
border-radius: 6px;
background: var(--card);
font-size: 11px;
font-weight: 500;
color: var(--text-dim);
cursor: pointer;
text-align: center;
transition: all 0.15s;
font-family: inherit;
}
.cal-month-btn:hover { border-color: var(--border); color: var(--text); }
.cal-month-btn.active { background: var(--primary); color: #FFF; }
.cal-month-btn.today { border-color: var(--primary); }
.cal-month-btn.today:not(.active) { color: var(--primary); }
/* 周选择 */
.cal-weeks {
display: flex;
gap: 8px;
padding: 8px 14px 10px;
justify-content: center;
}
.cal-week-cell {
width: 44px;
height: 44px;
display: flex;
align-items: center;
justify-content: center;
font-size: 13px;
font-weight: 600;
border-radius: 8px;
color: var(--text-dim);
cursor: pointer;
transition: all 0.15s;
border: 1.5px solid var(--border);
background: var(--card);
}
.cal-week-cell:hover { border-color: var(--primary); color: var(--primary); }
.cal-week-cell.pass { background: var(--success-light); border-color: var(--success); color: var(--success); }
.cal-week-cell.fail { background: var(--danger-light); border-color: var(--danger); color: var(--danger); }
.cal-week-cell.today { border-color: var(--primary); box-shadow: 0 0 0 2px var(--primary-light); }
.cal-week-cell.selected { background: var(--primary); color: #FFF; border-color: var(--primary); }
/* 旧样式清理 */
.cal-week-list { display: none; }
.cal-week-cell .wk-num, .cal-week-cell .wk-dot { display: none; }
.cal-header {
display: flex;

View File

@@ -106,17 +106,16 @@
</div>
<div class="calendar-widget inline">
<div class="cal-header">
<button class="cal-nav" onclick="changeCalYear(-1)">
<svg class="icon-sm"><use href="#icon-chevron-left"/></svg>
</button>
<span class="cal-month-label" id="cal-year-label">2026年</span>
<div class="cal-nav-group">
<button class="cal-nav" onclick="changeCalYear(-1)">
<svg class="icon-sm"><use href="#icon-chevron-left"/></svg>
</button>
<button class="cal-nav" onclick="changeCalYear(1)">
<svg class="icon-sm"><use href="#icon-chevron-right"/></svg>
</button>
</div>
<button class="cal-nav" onclick="changeCalYear(1)">
<svg class="icon-sm"><use href="#icon-chevron-right"/></svg>
</button>
</div>
<div class="cal-week-list" id="cal-week-list"></div>
<div class="cal-months" id="cal-months"></div>
<div class="cal-weeks" id="cal-weeks"></div>
</div>
</div>
<!-- 右侧Tab + 内容 -->