2025-04-28 12:25:20 +08:00

349 lines
12 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* 日期时间选择对话框模块
* @type {module}
*/
export class DateTimeDialog {
/**
* 显示日期时间选择对话框
* @param {HTMLElement} parentElement - 父元素,用于挂载对话框
* @param {HTMLInputElement} inputElement - 日期时间输入框
* @param {Function} onConfirm - 确认回调函数
*/
static show(parentElement, inputElement, onConfirm) {
// 解析当前日期和时间
let currentDate = new Date();
let currentTime = '00:00:00';
if (inputElement.value) {
try {
const parts = inputElement.value.split(' ');
if (parts.length >= 1) {
const dateParts = parts[0].split('-');
if (dateParts.length === 3) {
const year = parseInt(dateParts[0]);
const month = parseInt(dateParts[1]) - 1; // 月份从0开始
const day = parseInt(dateParts[2]);
currentDate = new Date(year, month, day);
}
}
if (parts.length >= 2) {
currentTime = parts[1];
}
} catch (error) {
console.error('解析日期时间失败:', error);
currentDate = new Date();
}
}
// 创建模态框
const modal = document.createElement('div');
modal.className = 'modal';
modal.id = 'dateTimeModal';
// 获取年、月、日
const year = currentDate.getFullYear();
const month = currentDate.getMonth(); // 0-11
const day = currentDate.getDate();
// 生成日历
const daysInMonth = new Date(year, month + 1, 0).getDate();
const firstDay = new Date(year, month, 1).getDay(); // 0-60表示周日
// 生成月份选项
let monthOptions = '';
const monthNames = ['一月', '二月', '三月', '四月', '五月', '六月', '七月', '八月', '九月', '十月', '十一月', '十二月'];
monthNames.forEach((name, idx) => {
monthOptions += `<option value="${idx}" ${idx === month ? 'selected' : ''}>${name}</option>`;
});
// 生成年份选项
let yearOptions = '';
const currentYear = new Date().getFullYear();
for (let y = currentYear - 10; y <= currentYear + 10; y++) {
yearOptions += `<option value="${y}" ${y === year ? 'selected' : ''}>${y}</option>`;
}
// 生成日历表格
let calendarRows = '';
let dayCount = 1;
// 添加表头
calendarRows += '<tr>';
['日', '一', '二', '三', '四', '五', '六'].forEach(dayName => {
calendarRows += `<th>${dayName}</th>`;
});
calendarRows += '</tr>';
// 计算行数
const totalCells = firstDay + daysInMonth;
const rowCount = Math.ceil(totalCells / 7);
// 添加日期行
for (let i = 0; i < rowCount; i++) {
calendarRows += '<tr>';
for (let j = 0; j < 7; j++) {
if ((i === 0 && j < firstDay) || dayCount > daysInMonth) {
calendarRows += '<td></td>';
} else {
const isToday = dayCount === day;
calendarRows += `<td class="calendar-day ${isToday ? 'selected' : ''}" data-day="${dayCount}">${dayCount}</td>`;
dayCount++;
}
}
calendarRows += '</tr>';
}
modal.innerHTML = `
<div class="modal-content">
<div class="modal-header">
<div class="modal-title">选择日期和时间</div>
<span class="close">&times;</span>
</div>
<div class="modal-body">
<div class="calendar-container">
<div class="calendar-header">
<select id="calendarMonth" class="form-control" style="max-width: 120px;">${monthOptions}</select>
<select id="calendarYear" class="form-control" style="max-width: 100px;">${yearOptions}</select>
</div>
<table class="calendar-table">
<thead>
${calendarRows}
</thead>
</table>
</div>
<div class="time-container" style="margin-top: 15px;">
<label for="timeInput">时间:</label>
<input type="time" id="timeInput" class="form-control" step="1" value="${currentTime}">
</div>
</div>
<div class="modal-footer">
<button id="cancelDateTime" class="action-button secondary">取消</button>
<button id="confirmDateTime" class="action-button">确定</button>
</div>
</div>
<style>
.modal {
display: block;
position: fixed;
z-index: 1000;
left: 0;
top: 0;
width: 100%;
height: 100%;
overflow: auto;
background-color: rgba(0,0,0,0.4);
}
.modal-content {
background-color: #fefefe;
margin: 10% auto;
padding: 20px;
border: 1px solid #888;
width: 50%;
max-width: 500px;
border-radius: 5px;
box-shadow: 0 4px 8px rgba(0,0,0,0.1);
}
.modal-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 15px;
}
.modal-title {
font-weight: bold;
font-size: 18px;
}
.close {
color: #aaa;
font-size: 28px;
font-weight: bold;
cursor: pointer;
}
.close:hover {
color: black;
}
.modal-footer {
display: flex;
justify-content: flex-end;
gap: 10px;
margin-top: 15px;
}
.calendar-container {
width: 100%;
}
.calendar-header {
display: flex;
justify-content: space-between;
margin-bottom: 10px;
}
.calendar-header select {
padding: 5px;
border: 1px solid #ddd;
border-radius: 4px;
}
.calendar-table {
width: 100%;
border-collapse: collapse;
margin-top: 10px;
}
.calendar-table th,
.calendar-table td {
padding: 8px;
text-align: center;
border: 1px solid #ddd;
}
.calendar-day {
cursor: pointer;
}
.calendar-day:hover {
background-color: #f0f0f0;
}
.calendar-day.selected {
background-color: #7986E7;
color: white;
}
.form-control {
width: 100%;
padding: 8px;
box-sizing: border-box;
border: 1px solid #ccc;
border-radius: 4px;
}
.action-button {
background-color: #7986E7;
color: white;
border: none;
border-radius: 4px;
padding: 6px 12px;
cursor: pointer;
font-size: 14px;
transition: background-color 0.3s;
}
.action-button:hover {
background-color: #6875D6;
}
.action-button.secondary {
background-color: #f0f0f0;
color: #333;
}
.action-button.secondary:hover {
background-color: #e0e0e0;
}
</style>
`;
// 添加到父元素
parentElement.appendChild(modal);
// 事件处理
const closeBtn = modal.querySelector('.close');
const cancelBtn = modal.querySelector('#cancelDateTime');
const confirmBtn = modal.querySelector('#confirmDateTime');
const calendarMonth = modal.querySelector('#calendarMonth');
const calendarYear = modal.querySelector('#calendarYear');
const calendarDays = modal.querySelectorAll('.calendar-day');
const timeInput = modal.querySelector('#timeInput');
// 选择日期事件
calendarDays.forEach(cell => {
cell.addEventListener('click', (e) => {
// 移除所有选中状态
calendarDays.forEach(day => day.classList.remove('selected'));
// 添加新选中状态
e.target.classList.add('selected');
});
});
// 月份和年份变化时重新渲染日历
const updateCalendar = () => {
const selectedYear = parseInt(calendarYear.value);
const selectedMonth = parseInt(calendarMonth.value);
// 关闭当前对话框
closeModal();
// 更新日期参数并重新显示对话框
currentDate = new Date(selectedYear, selectedMonth, 1);
DateTimeDialog.show(parentElement, inputElement, onConfirm);
};
calendarMonth.addEventListener('change', updateCalendar);
calendarYear.addEventListener('change', updateCalendar);
const closeModal = () => {
if (parentElement.contains(modal)) {
parentElement.removeChild(modal);
}
};
closeBtn.addEventListener('click', closeModal);
cancelBtn.addEventListener('click', closeModal);
confirmBtn.addEventListener('click', () => {
// 获取选中的日期
const selectedDay = modal.querySelector('.calendar-day.selected');
if (!selectedDay) {
closeModal();
return;
}
const day = selectedDay.dataset.day;
const month = parseInt(calendarMonth.value) + 1; // 月份从0开始显示时+1
const year = calendarYear.value;
// 格式化日期
const formattedDate = `${year}-${month.toString().padStart(2, '0')}-${day.toString().padStart(2, '0')}`;
// 获取时间
const time = timeInput.value || '00:00:00';
// 更新输入框值
const dateTimeValue = `${formattedDate} ${time}`;
// 调用确认回调
if (onConfirm) {
onConfirm(dateTimeValue);
}
closeModal();
});
// 点击模态窗口外部关闭
modal.addEventListener('click', (event) => {
if (event.target === modal) {
closeModal();
}
});
}
/**
* 获取当前格式化的日期时间
* @returns {string} 格式化的日期时间字符串
*/
static getCurrentDateTime() {
const now = new Date();
const dateStr = now.toISOString().split('T')[0];
const timeStr = now.toTimeString().split(' ')[0];
return `${dateStr} ${timeStr}`;
}
}