Skip to content

Instantly share code, notes, and snippets.

@ekibun
Last active December 25, 2024 15:02
Show Gist options
  • Save ekibun/d7c5b564fe94a2f4b3178459aa53cc66 to your computer and use it in GitHub Desktop.
Save ekibun/d7c5b564fe94a2f4b3178459aa53cc66 to your computer and use it in GitHub Desktop.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<style>
table {
border-collapse: collapse;
width: 100%;
table-layout: fixed;
}
th, td {
border: 1px solid #ddd;
padding: 2px;
text-align: center;
white-space: nowrap;
text-overflow: clip;
overflow: hidden;
}
@media print {
@page {
size: landscape;
}
.noprint {
user-select: none;
display: none;
}
}
</style>
</head>
<body>
<div class="noprint">
<label for="year-select">选择年份: </label>
<select id="year-select" onchange="updateCalendar()">
<script>
for (let year = 2000; year <= 2050; year++) {
document.write(`<option value="${year}" ${year === 2024 ? 'selected' : ''}>${year}</option>`);
}
</script>
</select>
<button onclick="window.print()">打印</button>
<button onclick="copyFullHTML()">复制表格</button>
<script>
async function copyFullHTML() {
try {
const table = document.getElementById('calendar-table');
await navigator.clipboard.write([
new ClipboardItem({
"text/html": new Blob([table.outerHTML], { type: "text/html" }),
"text/plain": new Blob([table.innerText], { type: "text/plain" })
})
]);
alert('表格内容已复制到剪贴板!');
} catch (err) {
alert('复制失败:' + err);
}
}
</script>
</div>
<table id="calendar-table">
<colgroup id="colgroup"></colgroup>
<thead>
<tr>
<th colspan="29" id="header"></th>
</tr>
<tr id="months-header"></tr>
</thead>
<tbody id="calendar-body"></tbody>
</table>
<script>
const months = ["一月", "二月", "三月", "四月", "五月", "六月", "七月", "八月", "九月", "十月", "十一月", "十二月"];
const daysOfWeek = ["日", "一", "二", "三", "四", "五", "六"];
async function fetchHolidays(year) {
const response = await fetch(`https://cdn.jsdelivr.net/gh/NateScarlet/holiday-cn@master/${year}.json`);
if (response.ok) {
const data = await response.json();
return data.days.reduce((acc, holiday) => {
acc[holiday.date] = holiday;
return acc;
}, {});
} else {
console.error('Failed to fetch holiday data');
return {};
}
}
function createElementCol(width) {
const col = document.createElement('col');
col.setAttribute('style', `width: ${width}%`);
return col;
}
async function generateCalendar(year) {
const header = document.getElementById('header');
header.innerHTML = `${year}年竖式日历`;
const colgroup = document.getElementById('colgroup');
colgroup.innerHTML = '';
const monthsHeader = document.getElementById('months-header');
monthsHeader.innerHTML = '';
months.forEach((month, index) => {
if (index % 3 == 0) {
monthsHeader.appendChild(document.createElement('th'));
colgroup.appendChild(createElementCol(1));
}
const th = document.createElement('th');
th.setAttribute('colspan', 2);
th.textContent = month;
monthsHeader.appendChild(th);
colgroup.appendChild(createElementCol(1));
colgroup.appendChild(createElementCol(4));
});
monthsHeader.appendChild(document.createElement('th'));
colgroup.appendChild(createElementCol(1));
const calendarBody = document.getElementById('calendar-body');
calendarBody.innerHTML = '';
const holidays = await fetchHolidays(year);
const maxDays = Math.max(...months.map((_, index) => new Date(year, index + 1, 0).getDate()));
for (let day = 1; day <= maxDays; day++) {
let row = document.createElement('tr');
months.forEach((_, index) => {
let date = new Date(year, index, day);
// 按季度写日期
if (index % 3 == 0) {
const dayCell = document.createElement('th');
dayCell.textContent = day;
row.appendChild(dayCell);
}
if (date.getMonth() !== index) {
let td = document.createElement('td');
td.setAttribute('colspan', 2);
td.textContent = 'x';
row.appendChild(td);
} else {
const dateString = `${year}-${String(index + 1).padStart(2, '0')}-${String(day).padStart(2, '0')}`;
const weekdayCell = document.createElement('td');
const weekday = date.getDay();
weekdayCell.textContent = daysOfWeek[date.getDay()];
row.appendChild(weekdayCell);
const holidayCell = document.createElement('td');
let cellstyle = 'text-align: left;';
if (holidays[dateString]) {
const holiday = holidays[dateString];
if (holiday.isOffDay) {
cellstyle += 'background-color: #fadade;'
const firstholiday = Object.values(holidays).find((v) => v.date.startsWith(year) && v.name == holiday.name && v.isOffDay);
holidayCell.textContent = (firstholiday == holiday) ? holiday.name : '休';
} else {
cellstyle += 'background-color: #ddb7ff;'
holidayCell.textContent = '班'
}
} else if (weekday == 0) {
cellstyle += 'background-color: #a2e7e2;'
} else if (weekday == 6) {
cellstyle += 'background-color: #d2f4f2;'
}
holidayCell.setAttribute('style', cellstyle);
row.appendChild(holidayCell);
}
});
// 最后一列日期
const dayCell = document.createElement('th');
dayCell.textContent = day;
row.appendChild(dayCell);
calendarBody.appendChild(row);
}
}
function updateCalendar() {
const year = document.getElementById('year-select').value;
generateCalendar(year);
}
generateCalendar(2024);
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment