import React, { useState, useEffect, useRef, useImperativeHandle } from "react"; import { CalendarCard } from "@nutui/nutui-react-taro"; import { View, Text, Image } from "@tarojs/components"; import images from "@/config/images"; import styles from "./index.module.scss"; import { getMonth, getWeekend, getWeekendOfCurrentWeek, } from "@/utils/timeUtils"; import { PopupPicker } from "@/components/Picker/index"; import dayjs from "dayjs"; interface NutUICalendarProps { type?: "single" | "range" | "multiple"; value?: string | Date | String[] | Date[]; defaultValue?: string | string[]; onChange?: (value: Date | Date[]) => void; isBorder?: boolean; showQuickActions?: boolean; onHeaderClick?: (date: Date) => void; } export interface CalendarUIRef { jumpTo: (year: number, month: number) => void; gotoMonth: (delta: number) => void; } const NutUICalendar = React.forwardRef( ( { type = "single", value, onChange, isBorder = false, showQuickActions = true, onHeaderClick, }, ref ) => { // 根据类型初始化选中值 // const getInitialValue = (): Date | Date[] => { // console.log(value,defaultValue,'today') // if (typeof value === 'string' && value) { // return new Date(value) // } // if (Array.isArray(value) && value.length > 0) { // return value.map(item => new Date(item)) // } // if (typeof defaultValue === 'string' && defaultValue) { // return new Date(defaultValue) // } // if (Array.isArray(defaultValue) && defaultValue.length > 0) { // return defaultValue.map(item => new Date(item)) // } // const today = new Date(); // if (type === 'multiple') { // return [today] // } // return today // } const startOfMonth = (date: Date) => new Date(date.getFullYear(), date.getMonth(), 1); const [selectedValue, setSelectedValue] = useState(); const [current, setCurrent] = useState(startOfMonth(new Date())); const calendarRef = useRef(null); const [visible, setvisible] = useState(false); console.log("current", current); // 当外部 value 变化时更新内部状态 useEffect(() => { if (Array.isArray(value) && value.length > 0) { setSelectedValue(value.map((item) => new Date(item))); setCurrent(new Date(value[0] as Date)); } if ((typeof value === "string" || value instanceof Date) && value) { setSelectedValue(new Date(value)); setCurrent(new Date(value)); } }, [value]); useImperativeHandle(ref, () => ({ jumpTo: (year: number, month: number) => { calendarRef.current?.jumpTo(year, month); }, gotoMonth, })); const handleDateChange = (newValue: any) => { if (type === "range") return; setSelectedValue(newValue); onChange?.(newValue as any); }; const formatHeader = (date: Date) => `${getMonth(date)}`; const handlePageChange = (data: { year: number; month: number }) => { // 月份切换时的处理逻辑,如果需要的话 console.log("月份切换:", data); }; const handleDayClick = (day: any) => { const { type, year, month, date } = day; if (type === "next") return; onChange?.([new Date(year, month - 1, date)]); }; const gotoMonth = (delta: number) => { const base = current instanceof Date ? new Date(current) : new Date(); base.setMonth(base.getMonth() + delta); const next = startOfMonth(base); setCurrent(next); // 同步底部 CalendarCard 的月份 try { calendarRef.current?.jump?.(delta); } catch (e) { console.warn("CalendarCardRef jump 调用失败", e); } handlePageChange({ year: next.getFullYear(), month: next.getMonth() + 1, }); }; const handleHeaderClick = () => { onHeaderClick && onHeaderClick(current); setvisible(true); }; const syncMonthTo = (anchor: Date) => { // 计算从 current 到目标 anchor 所在月份的偏移,调用 jump(delta) const monthsDelta = (anchor.getFullYear() - current.getFullYear()) * 12 + (anchor.getMonth() - current.getMonth()); if (monthsDelta !== 0) { gotoMonth(monthsDelta); } }; const renderDay = (day: any) => { const { date, month, year } = day; const today = new Date(); if ( date === today.getDate() && month === today.getMonth() + 1 && year === today.getFullYear() ) { return {date}; } return date; }; const selectWeekend = () => { const [start, end] = getWeekend(); setSelectedValue([start, end]); syncMonthTo(start); onChange?.([start, end]); }; const selectWeek = () => { const dayList = getWeekendOfCurrentWeek(7); setSelectedValue(dayList); syncMonthTo(dayList[0]); onChange?.(dayList); }; const selectMonth = () => { const dayList = getWeekendOfCurrentWeek(30); setSelectedValue(dayList); syncMonthTo(dayList[0]); onChange?.(dayList); }; const handleMonthChange = (value: any) => { const [year, month] = value; const newDate = new Date(year, month - 1, 1); setCurrent(newDate); calendarRef.current?.jumpTo(year, month); }; return ( {/* 快速操作行 */} {showQuickActions && ( 本周末 一周内 一个月 )} {type === "range" && ( {(value as Date[]).length === 2 ? dayjs(value?.[0] as Date).format("YYYY-MM-DD") : "起始时间"} {(value as Date[]).length === 2 ? dayjs(value?.[1] as Date).format("YYYY-MM-DD") : "结束时间"} )} {/* 自定义头部显示周一到周日 */} {formatHeader(current as Date)} gotoMonth(1)} /> gotoMonth(-1)} > gotoMonth(1)} > {["周日", "周一", "周二", "周三", "周四", "周五", "周六"].map( (day) => ( {day} ) )} {/* NutUI CalendarCard 组件 */} {visible && ( handleMonthChange(value)} /> )} ); } ); export default NutUICalendar;