349 lines
12 KiB
JavaScript
349 lines
12 KiB
JavaScript
|
/**
|
|||
|
* 日期时间选择对话框模块
|
|||
|
* @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-6,0表示周日
|
|||
|
|
|||
|
// 生成月份选项
|
|||
|
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">×</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}`;
|
|||
|
}
|
|||
|
}
|