"use client"; import * as React from "react"; import { CalendarIcon } from "lucide-react"; import { format, parse, isValid } from "date-fns"; import { cn } from "@/lib/utils"; import { Button } from "@/components/ui/button"; import { Calendar } from "@/components/ui/calendar"; import { Input } from "@/components/ui/input"; import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover"; interface DateTimePickerProps { value?: Date; onChange?: (date: Date | undefined) => void; placeholder?: string; disabled?: boolean; className?: string; } function DateTimePicker({ value, onChange, placeholder = "选择日期和时间", disabled = false, className, }: DateTimePickerProps) { const [open, setOpen] = React.useState(false); // 获取初始默认时间 const getDefaultDate = React.useCallback(() => { const now = new Date(); now.setSeconds(0); now.setMilliseconds(0); return now; }, []); const [selectedDate, setSelectedDate] = React.useState(() => { return value ?? getDefaultDate(); }); const [inputValue, setInputValue] = React.useState(() => { return format(value ?? getDefaultDate(), "yyyy-MM-dd HH:mm"); }); // 组件挂载时,如果没有外部值,设置当前时间为默认值 const initialized = React.useRef(false); React.useEffect(() => { if (!initialized.current && !value && onChange) { initialized.current = true; const defaultDate = getDefaultDate(); onChange(defaultDate); } }, [value, onChange, getDefaultDate]); // Sync with external value React.useEffect(() => { if (value) { setSelectedDate(value); setInputValue(format(value, "yyyy-MM-dd HH:mm")); } }, [value]); const handleDateSelect = (date: Date | undefined) => { setSelectedDate(date); if (date && onChange) { const newDate = new Date(date); // 如果已有时间值,保留原来的时分;否则使用当前时间 if (value) { newDate.setHours(value.getHours()); newDate.setMinutes(value.getMinutes()); } else { const now = new Date(); newDate.setHours(now.getHours()); newDate.setMinutes(now.getMinutes()); } newDate.setSeconds(0); newDate.setMilliseconds(0); onChange(newDate); } }; const handleInputChange = (e: React.ChangeEvent) => { const newValue = e.target.value; setInputValue(newValue); }; const handleInputBlur = () => { if (!inputValue.trim()) { onChange?.(undefined); setSelectedDate(undefined); return; } // Try to parse the input value with time const parsed = parse(inputValue, "yyyy-MM-dd HH:mm", new Date()); if (isValid(parsed)) { setSelectedDate(parsed); parsed.setSeconds(0); parsed.setMilliseconds(0); onChange?.(parsed); } else { // If invalid, reset to the current value if (value) { setInputValue(format(value, "yyyy-MM-dd HH:mm")); } else { setInputValue(""); } } }; return (
e.preventDefault()} onCloseAutoFocus={(e) => e.preventDefault()} >
{ // 阻止点击事件冒泡到 Dialog e.stopPropagation(); }} onPointerDown={(e) => { // 阻止指针按下事件冒泡 e.stopPropagation(); }} >
); } export { DateTimePicker };