260 lines
7.2 KiB
JavaScript
260 lines
7.2 KiB
JavaScript
import React, { useState, useEffect } from 'react';
|
||
import { Calendar, Clock } from 'lucide-react';
|
||
import './DateTimePicker.css';
|
||
|
||
const DateTimePicker = ({ value, onChange, placeholder = "选择会议时间" }) => {
|
||
const [date, setDate] = useState('');
|
||
const [time, setTime] = useState('');
|
||
const [showQuickSelect, setShowQuickSelect] = useState(false);
|
||
const [isInitialized, setIsInitialized] = useState(false);
|
||
|
||
// 组件卸载时清理状态
|
||
useEffect(() => {
|
||
return () => {
|
||
setShowQuickSelect(false);
|
||
};
|
||
}, []);
|
||
|
||
// 初始化时间值
|
||
useEffect(() => {
|
||
if (value && !isInitialized) {
|
||
const dateObj = new Date(value);
|
||
if (!isNaN(dateObj.getTime())) {
|
||
// 转换为本地时间字符串
|
||
const timeZoneOffset = dateObj.getTimezoneOffset() * 60000;
|
||
const localDate = new Date(dateObj.getTime() - timeZoneOffset);
|
||
const isoString = localDate.toISOString();
|
||
|
||
setDate(isoString.split('T')[0]);
|
||
setTime(isoString.split('T')[1].slice(0, 5));
|
||
}
|
||
setIsInitialized(true);
|
||
} else if (!value && !isInitialized) {
|
||
setDate('');
|
||
setTime('');
|
||
setIsInitialized(true);
|
||
}
|
||
}, [value, isInitialized]);
|
||
|
||
// 当日期或时间改变时,更新父组件的值
|
||
useEffect(() => {
|
||
// 只在初始化完成后才触发onChange
|
||
if (!isInitialized) return;
|
||
|
||
if (date && time) {
|
||
const dateTimeString = `${date}T${time}`;
|
||
onChange?.(dateTimeString);
|
||
} else if (!date && !time) {
|
||
onChange?.('');
|
||
}
|
||
}, [date, time, isInitialized]); // 移除onChange依赖
|
||
|
||
// 快速选择时间的选项
|
||
const timeOptions = [
|
||
{ label: '09:00', value: '09:00' },
|
||
{ label: '10:00', value: '10:00' },
|
||
{ label: '11:00', value: '11:00' },
|
||
{ label: '14:00', value: '14:00' },
|
||
{ label: '15:00', value: '15:00' },
|
||
{ label: '16:00', value: '16:00' },
|
||
{ label: '17:00', value: '17:00' },
|
||
];
|
||
|
||
// 快速选择日期的选项
|
||
const getQuickDateOptions = () => {
|
||
const today = new Date();
|
||
const options = [];
|
||
|
||
// 今天
|
||
options.push({
|
||
label: '今天',
|
||
value: today.toISOString().split('T')[0]
|
||
});
|
||
|
||
// 明天
|
||
const tomorrow = new Date(today);
|
||
tomorrow.setDate(today.getDate() + 1);
|
||
options.push({
|
||
label: '明天',
|
||
value: tomorrow.toISOString().split('T')[0]
|
||
});
|
||
|
||
// 后天
|
||
const dayAfterTomorrow = new Date(today);
|
||
dayAfterTomorrow.setDate(today.getDate() + 2);
|
||
options.push({
|
||
label: '后天',
|
||
value: dayAfterTomorrow.toISOString().split('T')[0]
|
||
});
|
||
|
||
return options;
|
||
};
|
||
|
||
const quickDateOptions = getQuickDateOptions();
|
||
|
||
const formatDisplayText = () => {
|
||
if (!date && !time) return placeholder;
|
||
|
||
if (date && time) {
|
||
const dateObj = new Date(`${date}T${time}`);
|
||
return dateObj.toLocaleString('zh-CN', {
|
||
year: 'numeric',
|
||
month: 'long',
|
||
day: 'numeric',
|
||
hour: '2-digit',
|
||
minute: '2-digit'
|
||
});
|
||
}
|
||
|
||
if (date) {
|
||
const dateObj = new Date(date);
|
||
return dateObj.toLocaleDateString('zh-CN', {
|
||
year: 'numeric',
|
||
month: 'long',
|
||
day: 'numeric'
|
||
});
|
||
}
|
||
|
||
return placeholder;
|
||
};
|
||
|
||
const clearDateTime = () => {
|
||
setDate('');
|
||
setTime('');
|
||
// 重置初始化状态,允许后续值的设定
|
||
setIsInitialized(false);
|
||
onChange?.('');
|
||
};
|
||
|
||
return (
|
||
<div className="datetime-picker">
|
||
<div className="datetime-display" onClick={(e) => {
|
||
e.stopPropagation();
|
||
setShowQuickSelect(!showQuickSelect);
|
||
}}>
|
||
<Calendar size={18} />
|
||
<span className={`display-text ${(!date && !time) ? 'placeholder' : ''}`}>
|
||
{formatDisplayText()}
|
||
</span>
|
||
{(date || time) && (
|
||
<button
|
||
type="button"
|
||
className="clear-btn"
|
||
onClick={(e) => {
|
||
e.preventDefault();
|
||
e.stopPropagation();
|
||
clearDateTime();
|
||
}}
|
||
>
|
||
×
|
||
</button>
|
||
)}
|
||
</div>
|
||
|
||
{showQuickSelect && (
|
||
<div className="datetime-picker-panel">
|
||
<div className="picker-section">
|
||
<h4>选择日期</h4>
|
||
<div className="quick-date-options">
|
||
{quickDateOptions.map((option) => (
|
||
<button
|
||
key={option.value}
|
||
type="button"
|
||
className={`quick-option ${date === option.value ? 'selected' : ''}`}
|
||
onClick={(e) => {
|
||
e.preventDefault();
|
||
e.stopPropagation();
|
||
setDate(option.value);
|
||
}}
|
||
>
|
||
{option.label}
|
||
</button>
|
||
))}
|
||
</div>
|
||
<div className="custom-date-input">
|
||
<input
|
||
type="date"
|
||
value={date}
|
||
onChange={(e) => {
|
||
e.preventDefault();
|
||
e.stopPropagation();
|
||
setDate(e.target.value);
|
||
}}
|
||
onClick={(e) => e.stopPropagation()}
|
||
className="date-input"
|
||
/>
|
||
</div>
|
||
</div>
|
||
|
||
<div className="picker-section">
|
||
<h4>选择时间</h4>
|
||
<div className="quick-time-options">
|
||
{timeOptions.map((option) => (
|
||
<button
|
||
key={option.value}
|
||
type="button"
|
||
className={`quick-option ${time === option.value ? 'selected' : ''}`}
|
||
onClick={(e) => {
|
||
e.preventDefault();
|
||
e.stopPropagation();
|
||
setTime(option.value);
|
||
}}
|
||
>
|
||
{option.label}
|
||
</button>
|
||
))}
|
||
</div>
|
||
<div className="custom-time-input">
|
||
<Clock size={16} />
|
||
<input
|
||
type="time"
|
||
value={time}
|
||
onChange={(e) => {
|
||
e.preventDefault();
|
||
e.stopPropagation();
|
||
setTime(e.target.value);
|
||
}}
|
||
onClick={(e) => e.stopPropagation()}
|
||
className="time-input"
|
||
/>
|
||
</div>
|
||
</div>
|
||
|
||
<div className="picker-actions">
|
||
<button
|
||
type="button"
|
||
className="action-btn cancel"
|
||
onClick={(e) => {
|
||
e.preventDefault();
|
||
e.stopPropagation();
|
||
setShowQuickSelect(false);
|
||
}}
|
||
>
|
||
取消
|
||
</button>
|
||
<button
|
||
type="button"
|
||
className="action-btn confirm"
|
||
onClick={(e) => {
|
||
e.preventDefault();
|
||
e.stopPropagation();
|
||
setShowQuickSelect(false);
|
||
}}
|
||
>
|
||
确认
|
||
</button>
|
||
</div>
|
||
</div>
|
||
)}
|
||
|
||
{showQuickSelect && (
|
||
<div
|
||
className="datetime-picker-overlay"
|
||
onClick={() => setShowQuickSelect(false)}
|
||
/>
|
||
)}
|
||
</div>
|
||
);
|
||
};
|
||
|
||
export default DateTimePicker; |