238 lines
6.7 KiB
TypeScript
238 lines
6.7 KiB
TypeScript
import React, { useState, useEffect, useRef } from "react";
|
||
import CommonPopup from "@/components/CommonPopup";
|
||
import { View } from "@tarojs/components";
|
||
import Taro from "@tarojs/taro";
|
||
import CalendarUI, {
|
||
CalendarUIRef,
|
||
} from "@/components/Picker/CalendarUI/CalendarUI";
|
||
import { PickerCommon, PickerCommonRef } from "@/components/Picker";
|
||
import dayjs from "dayjs";
|
||
import styles from "./index.module.scss";
|
||
export interface DialogCalendarCardProps {
|
||
value?: Date | Date[];
|
||
searchType?: "single" | "range" | "multiple";
|
||
onChange?: (date: Date | Date[]) => void;
|
||
visible: boolean;
|
||
onClose: () => void;
|
||
title?: React.ReactNode;
|
||
}
|
||
|
||
const DialogCalendarCard: React.FC<DialogCalendarCardProps> = ({
|
||
visible,
|
||
searchType,
|
||
onClose,
|
||
title,
|
||
value,
|
||
onChange,
|
||
}) => {
|
||
const [selected, setSelected] = useState<Date | Date[]>(value || new Date());
|
||
const [selectedBackup, setSelectedBackup] = useState<Date[]>(
|
||
Array.isArray(value) ? [...(value as Date[])] : [value as Date]
|
||
);
|
||
const [current, setCurrent] = useState<Date>(new Date());
|
||
const [delta, setDelta] = useState(0);
|
||
const calendarRef = useRef<CalendarUIRef>(null);
|
||
const [type, setType] = useState<"year" | "month" | "time">("year");
|
||
const [selectedHour, setSelectedHour] = useState(8);
|
||
const [selectedMinute, setSelectedMinute] = useState(0);
|
||
const pickerRef = useRef<PickerCommonRef>(null);
|
||
const hourMinutePickerRef = useRef<PickerCommonRef>(null);
|
||
const [pendingJump, setPendingJump] = useState<{
|
||
year: number;
|
||
month: number;
|
||
} | null>(null);
|
||
const handleConfirm = () => {
|
||
if (type === "year") {
|
||
if (searchType === "range") {
|
||
if (onChange) onChange(selected);
|
||
onClose();
|
||
return;
|
||
}
|
||
if (!selected) {
|
||
Taro.showToast({
|
||
title: '请选择日期',
|
||
icon: "none",
|
||
});
|
||
return;
|
||
}
|
||
// 年份选择完成后,进入月份选择
|
||
setType("time");
|
||
} else if (type === "month") {
|
||
// 月份选择完成后,进入时间选择
|
||
const value = pickerRef.current?.getValue();
|
||
if (value) {
|
||
const year = value[0] as number;
|
||
const month = value[1] as number;
|
||
setPendingJump({ year, month });
|
||
setType("year");
|
||
if (searchType === "range") {
|
||
calculateMonthDifference(
|
||
current,
|
||
new Date(year, month - 1, 1)
|
||
);
|
||
|
||
return;
|
||
}
|
||
setSelected(new Date(year, month - 1, 1));
|
||
}
|
||
} else if (type === "time") {
|
||
// 时间选择完成后,调用onNext回调
|
||
const value = hourMinutePickerRef.current?.getValue();
|
||
if (value) {
|
||
const hour = value[0] as number;
|
||
const minute = value[1] as number;
|
||
setSelectedHour(hour);
|
||
setSelectedMinute(minute);
|
||
const hours = hour.toString().padStart(2, "0");
|
||
const minutes = minute.toString().padStart(2, "0");
|
||
const finalDate = new Date(
|
||
dayjs(selected as Date).format("YYYY-MM-DD") +
|
||
" " +
|
||
hours +
|
||
":" +
|
||
minutes
|
||
);
|
||
if (onChange) onChange(finalDate);
|
||
}
|
||
onClose();
|
||
}
|
||
};
|
||
const dialogClose = () => {
|
||
setType("year");
|
||
onClose();
|
||
}
|
||
const calculateMonthDifference = (date1, date2) => {
|
||
if (!(date1 instanceof Date) || !(date2 instanceof Date)) {
|
||
throw new Error("Both arguments must be Date objects");
|
||
}
|
||
setCurrent(date1)
|
||
let months = (date2.getFullYear() - date1.getFullYear()) * 12;
|
||
months -= date1.getMonth();
|
||
months += date2.getMonth();
|
||
setDelta(months);
|
||
};
|
||
|
||
const handleChange = (d: Date | Date[]) => {
|
||
if (searchType === "range") {
|
||
if (Array.isArray(d)) {
|
||
if (d.length === 2) {
|
||
return;
|
||
} else if (d.length === 1) {
|
||
if (selectedBackup.length === 0 || selectedBackup.length === 2) {
|
||
setSelected([...d]);
|
||
setSelectedBackup([...d]);
|
||
} else {
|
||
setSelected(
|
||
[...selectedBackup, d[0]].sort(
|
||
(a, b) => a.getTime() - b.getTime()
|
||
)
|
||
);
|
||
setSelectedBackup([]);
|
||
}
|
||
}
|
||
return;
|
||
}
|
||
}
|
||
if (Array.isArray(d)) {
|
||
setSelected(d[0]);
|
||
} else {
|
||
setSelected(d);
|
||
}
|
||
};
|
||
const onHeaderClick = (date: Date) => {
|
||
console.log("onHeaderClick", date);
|
||
setSelected(date);
|
||
setType("month");
|
||
};
|
||
const getConfirmText = () => {
|
||
if (type === "time" || type === "month" || searchType === "range")
|
||
return "完成";
|
||
return "下一步";
|
||
};
|
||
const handleDateTimePickerChange = (value: (string | number)[]) => {
|
||
const year = value[0] as number;
|
||
const month = value[1] as number;
|
||
setSelected(new Date(year, month - 1, 1));
|
||
};
|
||
const onCancel = () => {
|
||
if (type === "month") {
|
||
setType("year");
|
||
} else if (type === "time") {
|
||
setType("year");
|
||
} else {
|
||
onClose();
|
||
}
|
||
};
|
||
useEffect(() => {
|
||
calendarRef.current?.gotoMonth(delta);
|
||
}, [delta])
|
||
|
||
useEffect(() => {
|
||
if (visible && value) {
|
||
setSelected(value || new Date());
|
||
setSelectedHour(value ? dayjs(value as Date).hour() : 8);
|
||
setSelectedMinute(value ? dayjs(value as Date).minute() : 0);
|
||
}
|
||
}, [value, visible]);
|
||
|
||
useEffect(() => {
|
||
if (type === "year" && pendingJump && calendarRef.current) {
|
||
calendarRef.current.jumpTo(pendingJump.year, pendingJump.month);
|
||
setPendingJump(null);
|
||
}
|
||
}, [type, pendingJump]);
|
||
|
||
console.log([selectedHour, selectedMinute], visible,type, "selectedHour, selectedMinute");
|
||
|
||
return (
|
||
<CommonPopup
|
||
visible={visible}
|
||
onClose={dialogClose}
|
||
onCancel={onCancel}
|
||
showHeader={!!title}
|
||
title={title}
|
||
hideFooter={false}
|
||
cancelText="取消"
|
||
confirmText={getConfirmText()}
|
||
onConfirm={handleConfirm}
|
||
className={styles["calendar-popup"]}
|
||
position="bottom"
|
||
round
|
||
zIndex={1000}
|
||
>
|
||
{type === "year" && (
|
||
<View className={styles["calendar-container"]}>
|
||
<CalendarUI
|
||
ref={calendarRef}
|
||
type={searchType}
|
||
value={selected}
|
||
onChange={handleChange}
|
||
showQuickActions={false}
|
||
onHeaderClick={onHeaderClick}
|
||
/>
|
||
</View>
|
||
)}
|
||
{type === "month" && (
|
||
<PickerCommon
|
||
ref={pickerRef}
|
||
onChange={handleDateTimePickerChange}
|
||
type="month"
|
||
value={[
|
||
(selected as Date).getFullYear(),
|
||
(selected as Date).getMonth() + 1,
|
||
]}
|
||
/>
|
||
)}
|
||
{type === "time" && (
|
||
<PickerCommon
|
||
ref={hourMinutePickerRef}
|
||
type="hour"
|
||
value={[selectedHour, selectedMinute]}
|
||
/>
|
||
)}
|
||
</CommonPopup>
|
||
);
|
||
};
|
||
|
||
export default DialogCalendarCard;
|