Last active
December 25, 2024 15:02
-
-
Save ekibun/d7c5b564fe94a2f4b3178459aa53cc66 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!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