init commit.

This commit is contained in:
2025-11-11 11:07:25 +08:00
commit 7a5fb889c5
4 changed files with 567 additions and 0 deletions

211
www/app.js Normal file
View File

@@ -0,0 +1,211 @@
// 日历状态管理
class CalendarApp {
constructor() {
this.currentDate = new Date();
this.markedDates = this.loadData();
this.init();
}
init() {
this.renderCalendar();
this.bindEvents();
}
// 获取月份的第一天是星期几0=周日, 1=周一...
getFirstDayOfMonth(date) {
const firstDay = new Date(date.getFullYear(), date.getMonth(), 1);
return firstDay.getDay();
}
// 获取月份的天数
getDaysInMonth(date) {
return new Date(date.getFullYear(), date.getMonth() + 1, 0).getDate();
}
// 格式化日期为 YYYY-MM-DD
formatDate(date) {
const year = date.getFullYear();
const month = String(date.getMonth() + 1).padStart(2, '0');
const day = String(date.getDate()).padStart(2, '0');
return `${year}-${month}-${day}`;
}
// 检查是否为今天
isToday(date) {
const today = new Date();
return date.getDate() === today.getDate() &&
date.getMonth() === today.getMonth() &&
date.getFullYear() === today.getFullYear();
}
// 获取日期标记状态
getDateStatus(date) {
const dateStr = this.formatDate(date);
return this.markedDates[dateStr] || 'none';
}
// 切换日期标记状态
toggleDateStatus(date) {
const dateStr = this.formatDate(date);
const currentStatus = this.markedDates[dateStr] || 'none';
// 状态循环: none -> completed -> partial -> none
let newStatus;
switch (currentStatus) {
case 'none':
newStatus = 'completed';
break;
case 'completed':
newStatus = 'partial';
break;
case 'partial':
newStatus = 'none';
break;
default:
newStatus = 'none';
}
if (newStatus === 'none') {
delete this.markedDates[dateStr];
} else {
this.markedDates[dateStr] = newStatus;
}
this.saveData();
this.renderCalendar();
}
// 渲染日历
renderCalendar() {
const calendar = document.getElementById('calendar');
calendar.innerHTML = '';
// 星期标题
const weekdays = ['日', '一', '二', '三', '四', '五', '六'];
weekdays.forEach(day => {
const weekdayEl = document.createElement('div');
weekdayEl.className = 'weekday';
weekdayEl.textContent = day;
calendar.appendChild(weekdayEl);
});
// 更新月份显示
const monthNames = ['一月', '二月', '三月', '四月', '五月', '六月',
'七月', '八月', '九月', '十月', '十一月', '十二月'];
const monthDisplay = document.getElementById('currentMonth');
monthDisplay.textContent = `${this.currentDate.getFullYear()}${monthNames[this.currentDate.getMonth()]}`;
// 获取月份信息
const firstDay = this.getFirstDayOfMonth(this.currentDate);
const daysInMonth = this.getDaysInMonth(this.currentDate);
const today = new Date();
// 添加上个月的日期(填充空白)
const prevMonth = new Date(this.currentDate.getFullYear(), this.currentDate.getMonth() - 1, 0);
const daysInPrevMonth = prevMonth.getDate();
for (let i = firstDay - 1; i >= 0; i--) {
const day = daysInPrevMonth - i;
const date = new Date(this.currentDate.getFullYear(), this.currentDate.getMonth() - 1, day);
this.createDayElement(calendar, date, day, true);
}
// 添加当前月的日期
for (let day = 1; day <= daysInMonth; day++) {
const date = new Date(this.currentDate.getFullYear(), this.currentDate.getMonth(), day);
this.createDayElement(calendar, date, day, false);
}
// 添加下个月的日期(填充到完整周)
const totalCells = calendar.children.length - 7; // 减去星期标题
const remainingCells = 42 - totalCells; // 6行 x 7列 = 42
for (let day = 1; day <= remainingCells; day++) {
const date = new Date(this.currentDate.getFullYear(), this.currentDate.getMonth() + 1, day);
this.createDayElement(calendar, date, day, true);
}
}
// 创建日期元素
createDayElement(container, date, dayNumber, isOtherMonth) {
const dayEl = document.createElement('div');
dayEl.className = 'day';
if (isOtherMonth) {
dayEl.classList.add('other-month');
}
if (this.isToday(date)) {
dayEl.classList.add('today');
}
const status = this.getDateStatus(date);
if (status !== 'none') {
dayEl.classList.add(status);
}
const dayNumberEl = document.createElement('div');
dayNumberEl.className = 'day-number';
dayNumberEl.textContent = dayNumber;
dayEl.appendChild(dayNumberEl);
if (status !== 'none') {
const markEl = document.createElement('div');
markEl.className = 'day-mark';
markEl.textContent = status === 'completed' ? '✓' : '○';
dayEl.appendChild(markEl);
}
// 添加点击事件
dayEl.addEventListener('click', () => {
if (!isOtherMonth) {
this.toggleDateStatus(date);
}
});
container.appendChild(dayEl);
}
// 绑定事件
bindEvents() {
document.getElementById('prevMonth').addEventListener('click', () => {
this.currentDate.setMonth(this.currentDate.getMonth() - 1);
this.renderCalendar();
});
document.getElementById('nextMonth').addEventListener('click', () => {
this.currentDate.setMonth(this.currentDate.getMonth() + 1);
this.renderCalendar();
});
document.getElementById('todayBtn').addEventListener('click', () => {
this.currentDate = new Date();
this.renderCalendar();
});
}
// 保存数据到 localStorage
saveData() {
try {
localStorage.setItem('calendarMarkedDates', JSON.stringify(this.markedDates));
} catch (e) {
console.error('保存数据失败:', e);
}
}
// 从 localStorage 加载数据
loadData() {
try {
const data = localStorage.getItem('calendarMarkedDates');
return data ? JSON.parse(data) : {};
} catch (e) {
console.error('加载数据失败:', e);
return {};
}
}
}
// 初始化应用
document.addEventListener('DOMContentLoaded', () => {
new CalendarApp();
});