前端技术(26) : 全年排班日历

来源: 通义千问

效果图

代码

<!DOCTYPE html>
<html lang="zh-CN">
	<head>
		<meta charset="UTF-8">
		<title>年度日历</title>
		<style>
			body {
				font-family: Arial, sans-serif;
			}

			.calendar-container {
				margin: 20px auto;
				width: 90%;
				max-width: 1000px;
			}

			h1,
			h2 {
				text-align: center;
				color: #4a148c;
			}

			table {
				width: 100%;
				border-collapse: collapse;
				margin-bottom: 20px;
			}

			th,
			td {
				padding: 10px;
				text-align: center;
				border: 1px solid #ddd;

				position: relative;
			}

			th {
				background-color: #e0e0e0;
				color: #4a148c;
			}

			.workday {
				background-color: #ffffcc;
			}

			/* 浅黄色 */
			.holiday,
			.off-day {
				background-color: white;
			}

			/* 默认白色 */
			.makeup-workday {
				background-color: #ffffcc;
			}

			/* 调休补班时为浅黄色 */
			.special-date {
				background-color: #6a1b9a;
				color: white;
			}

			/* 紫色 */
			.service-day {
				border: 2px solid #42a5f5 !important;
			}

			/* 蓝色 */
			.today {
				background-color: #fff25d;
			}

			/* 当天日期为紫色边框 */
			.month-separator {
				border-top: 2px solid #4a148c;
				margin: 20px 0;
			}

			.today-display {
				text-align: center;
				color: #4a148c;
				margin-bottom: 20px;
			}

			.top-right-corner {
				position: absolute;
				top: 0;
				right: 0;
				background-color: #e3e3e3;
				/* 确保文字背景与单元格背景一致 */
				padding: 2px 5px;
				/* 根据需要调整内边距 */
				font-size: 0.8em;
				/* 调整字体大小 */
			}
		</style>
	</head>
	<body>

		<div class="calendar-container">
			<div class="today-display" id="todayDisplay"></div>
			<h1 id="yearTitle">2024年日历</h1>
			<input type="number" id="yearInput" value="2024">
			<button onclick="updateCalendar()">更新日历</button>
			<div style="float: right;">
				<table style="width: 300px;">
					<tbody>
						<tr>
							<td class="workday" style="width: 100px;">工作日</td>
							<td class="service-day workday" style="width: 100px;">服务日</td>
							<td class="workday" style="width: 100px;">驻场'<span class="top-right-corner">上海</span>'</td>
						</tr>
					</tbody>
				</table>

			</div>

			<div id="calendarContainer"></div>
		</div>

		<script>
			// 法定节假日列表
			const holidays = [
				/// 2024年
				'2024-01-01', // 元旦
				'2024-02-10', '2024-02-11', '2024-02-12', '2024-02-13', '2024-02-14', '2024-02-15', '2024-02-16',
				'2024-02-17', // 春节
				'2024-04-04', '2024-04-05', '2024-04-06', // 清明节
				'2024-05-01', '2024-05-02', '2024-05-03', '2024-05-04', '2024-05-05', // 劳动节
				'2024-06-08', '2024-06-09', '2024-06-10', // 端午节
				'2024-09-15', '2024-09-16', '2024-09-17', // 中秋节
				'2024-10-01', '2024-10-02', '2024-10-03', '2024-10-04', '2024-10-05', '2024-10-06', '2024-10-07', // 国庆节

				/// 2025年
				'2025-01-01', // 元旦
				'2025-01-28', '2025-01-29', '2025-01-30', '2024-01-31', '2025-02-02', '2025-02-03', '2025-02-04', // 春节
				'2025-04-04', '2025-04-05', '2025-04-06', // 清明节
				'2025-05-01', '2025-05-02', '2025-05-03', '2025-05-04', '2025-05-05', // 劳动节
				'2025-05-31', '2024-06-01', '2024-06-02', // 端午节
				'2025-10-01', '2025-10-02', '2025-10-03', '2025-10-04', '2025-10-05', '2025-10-06', '2025-10-07',
				'2025-10-08', // 国庆节中秋节

			];

			// 调休补班列表()
			const makeupDays = [
				/// 2024年
				'2024-02-04', '2024-02-18', // 春节调休补班
				'2024-04-07', // 清明节调休补班
				'2024-04-28', '2024-05-11', // 劳动节调休补班
				'2024-09-14', // 中秋节调休补班
				'2024-09-29', '2024-10-12', // 国庆节调休补班

				/// 2025年
				'2025-01-26', '2025-02-08', // 春节调休补班
				'2025-04-27', // 劳动节调休补班
				'2025-09-28', // 中秋节调休补班
				'2025-10-11', // 国庆节调休补班
			];

			// 驻场的日期
			const inSceneDates = [
				// 2024
				['2024-08-11', '2024-08-30'],
				['2024-09-02', '2024-09-14'],
				['2024-09-18', '2024-09-30'],
				['2024-10-08', '2024-10-25'],
				['2024-10-28', '2024-11-15'],
				['2024-12-02', '2024-12-20'],
				// 2025
				['2025-01-06', '2025-01-17'],
				['2025-02-17', '2025-03-07'],
				['2025-03-24', '2025-04-03'],
				['2025-04-21', '2025-04-30'],
				['2025-05-19', '2025-05-30'],
				['2025-06-16', '2025-07-04'],
				['2025-07-21', '2025-08-08'],
			]
			const finalInSceneDates = flattenDateRanges(inSceneDates);

			// 服务开始日期和天数
			const serviceStartDate = '2024-08-12'; // 示例:服务从3月1日开始
			const serviceWorkdaysCount = 7 * 30; // 示例:20个工作日
			var serviceWorkdaysPassed = 0;
			const serviceDays = []



			function updateCalendar() {
				const year = document.getElementById('yearInput').value;
				document.getElementById('yearTitle').innerText = `${year}年日历`;
				document.getElementById('calendarContainer').innerHTML = ''; // 清空旧日历

				for (let month = 1; month <= 12; month++) {
					if (month > 1) {
						document.getElementById('calendarContainer').insertAdjacentHTML('beforeend',
							'<hr class="month-separator">');
					}
					createMonthCalendar(year, month);
				}

				// 更新今天日期显示
				const today = new Date();
				document.getElementById('todayDisplay').textContent = `今天是:${today.toLocaleDateString()}`;
			}

			function createMonthCalendar(year, month) {
				const container = document.getElementById('calendarContainer');
				const table = document.createElement('table');
				const thead = document.createElement('thead');
				const tbody = document.createElement('tbody');

				// Create header row with days of week
				const headerRow = document.createElement('tr');
				const daysOfWeek = ['周日', '周一', '周二', '周三', '周四', '周五', '周六'];
				daysOfWeek.forEach(day => {
					const th = document.createElement('th');
					th.textContent = day;
					headerRow.appendChild(th);
				});
				thead.appendChild(headerRow);
				table.appendChild(thead);

				// Fill in calendar days
				const date = new Date(year, month - 1, 1);
				const lastDay = new Date(year, month, 0).getDate();
				const startDay = date.getDay(); // Get the first day of the week (0=Sun, 1=Mon, ...)

				let day = 1;
					for (let i = 0;; i++) {
						for (let j = 0; j < 7; j++) {
							if (i === 0 && j < startDay || day > lastDay) {
							} else {
								const currentDate = `${year}-${String(month).padStart(2, '0')}-${String(day).padStart(2, '0')}`;
								const isHoliday = holidays.includes(currentDate);
								const isMakeupDay = makeupDays.includes(currentDate);
								const isWorkday = !isHoliday && ((j >= 1 && j <= 5) || isMakeupDay);
								let isServiceDay = false

								if (isWorkday) {

									if (serviceDays.includes(currentDate)) {
										isServiceDay = true
										serviceDays.push(currentDate)
									} else {
										if (new Date(currentDate) >= new Date(serviceStartDate)) {
											if (isWorkday) {
												serviceWorkdaysPassed++;
												if (serviceWorkdaysPassed <= serviceWorkdaysCount) {
													isServiceDay = true
													serviceDays.push(currentDate)
												}
											}
										}
									}
								}
								day++;
							}
						}
						if (day > lastDay) break;
					}

				let endServiceDay = getMaxDate(serviceDays)
				console.log(endServiceDay)

				day = 1;
				for (let i = 0;; i++) {
					const row = document.createElement('tr');
					for (let j = 0; j < 7; j++) {
						if (i === 0 && j < startDay || day > lastDay) {
							row.appendChild(document.createElement('td'));
						} else {
							const cell = document.createElement('td');

							const currentDate = `${year}-${String(month).padStart(2, '0')}-${String(day).padStart(2, '0')}`;
							const isHoliday = holidays.includes(currentDate);
							const isMakeupDay = makeupDays.includes(currentDate);
							const isInSceneDay = finalInSceneDates.includes(currentDate);
							const isWorkday = !isHoliday && ((j >= 1 && j <= 5) || isMakeupDay);
							const today = new Date().toJSON().slice(0, 10) === currentDate;
							let isServiceDay = false

							if (isWorkday) {
								cell.classList.add('workday');

								// Check if this is a service workday
								if (serviceDays.includes(currentDate)) {
									isServiceDay = true
									cell.classList.add('service-day');
								} else {
									if (new Date(currentDate) >= new Date(serviceStartDate)) {
										if (isWorkday) {
											serviceWorkdaysPassed++;
											if (serviceWorkdaysPassed <= serviceWorkdaysCount) {
												isServiceDay = true
												cell.classList.add('service-day');
												serviceDays.push(currentDate)
											}
										}
									}
								}
							} else {
								cell.classList.add('holiday');
							}
							let remake = ''
							if (isInSceneDay) {
								if (endServiceDay != null && new Date(currentDate) <= new Date(endServiceDay)) {
									remake += '<span class="top-right-corner">上海</span>'
								}
							}

							if (today) {
								cell.classList.add('today'); // Add purple border to today's date
							}

							cell.innerHTML = day + remake;
							day++;
							row.appendChild(cell);
						}
					}
					tbody.appendChild(row);
					if (day > lastDay) break;
				}
				table.appendChild(tbody);

				// Add month title
				const monthTitle = document.createElement('h2');
				const monthNames = ['一月', '二月', '三月', '四月', '五月', '六月', '七月', '八月', '九月', '十月', '十一月', '十二月'];
				monthTitle.textContent = monthNames[month - 1];
				container.appendChild(monthTitle);

				container.appendChild(table);
			}

			// Initialize the calendar on page load
			window.onload = function() {
				updateCalendar();
			};

			function generateDateRange(startDate, endDate) {
				const dateArray = [];
				let currentDate = new Date(startDate);
				const end = new Date(endDate);

				while (currentDate <= end) {
					dateArray.push(currentDate.toISOString().split('T')[0]);
					currentDate.setDate(currentDate.getDate() + 1);
				}

				return dateArray;
			}

			function flattenDateRanges(dateRanges) {
				return dateRanges.reduce((acc, [start, end]) => {
					acc.push(...generateDateRange(start, end));
					return acc;
				}, []);
			}

			function getMaxDate(dateArray) {
				if (dateArray.length === 0) return null;

				// 将日期字符串数组映射为时间戳数组,并找到最大值
				const maxTimestamp = Math.max(...dateArray.map(dateStr => Date.parse(dateStr)));

				// 将最大时间戳转换回日期字符串
				const maxDate = new Date(maxTimestamp).toISOString().split('T')[0];

				return maxDate;
			}
		</script>

	</body>
</html>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值