修改日历组件
This commit is contained in:
211
src/components/Picker/CalendarUI/CalendarUI.tsx
Normal file
211
src/components/Picker/CalendarUI/CalendarUI.tsx
Normal file
@@ -0,0 +1,211 @@
|
||||
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'
|
||||
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
|
||||
}
|
||||
|
||||
const NutUICalendar = React.forwardRef<CalendarUIRef, NutUICalendarProps>(({
|
||||
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<Date | Date[]>()
|
||||
const [current, setCurrent] = useState<Date>(startOfMonth(new Date()))
|
||||
const calendarRef = useRef<any>(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]))
|
||||
}
|
||||
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)
|
||||
}
|
||||
}))
|
||||
|
||||
const handleDateChange = (newValue: any) => {
|
||||
setSelectedValue(newValue)
|
||||
onChange?.(newValue as any)
|
||||
}
|
||||
const formatHeader = (date: Date) => `${getMonth(date)}`
|
||||
|
||||
const handlePageChange = (data: { year: number; month: number }) => {
|
||||
// 月份切换时的处理逻辑,如果需要的话
|
||||
console.log('月份切换:', data)
|
||||
}
|
||||
|
||||
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 (
|
||||
<View class="day-container">
|
||||
{date}
|
||||
</View>
|
||||
)
|
||||
}
|
||||
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 (
|
||||
<View>
|
||||
{/* 快速操作行 */}
|
||||
{
|
||||
showQuickActions &&
|
||||
<View className={styles['quick-actions']}>
|
||||
<View className={styles['quick-action']} onClick={selectWeekend}>本周末</View>
|
||||
<View className={styles['quick-action']} onClick={selectWeek}>一周内</View>
|
||||
<View className={styles['quick-action']} onClick={selectMonth}>一个月</View>
|
||||
</View>
|
||||
}
|
||||
<View className={`${styles['calendar-card']} ${isBorder ? styles['border'] : ''}`}>
|
||||
{/* 自定义头部显示周一到周日 */}
|
||||
<View className={styles['header']}>
|
||||
<View className={styles['header-left']} onClick={handleHeaderClick}>
|
||||
<Text className={styles['header-text']}>{formatHeader(current as Date)}</Text>
|
||||
<Image src={images.ICON_RIGHT_MAX} className={`${styles['month-arrow']}`} onClick={() => gotoMonth(1)} />
|
||||
</View>
|
||||
<View className={styles['header-actions']}>
|
||||
<View className={styles['arrow-left-container']} onClick={() => gotoMonth(-1)}>
|
||||
<Image src={images.ICON_RIGHT_MAX} className={`${styles['arrow']} ${styles['left']}`} />
|
||||
</View>
|
||||
<View className={styles['arrow-right-container']} onClick={() => gotoMonth(1)}>
|
||||
<Image src={images.ICON_RIGHT_MAX} className={`${styles['arrow']}`} />
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
<View className={styles['week-header']}>
|
||||
{[ '周日', '周一', '周二', '周三', '周四', '周五', '周六'].map((day) => (
|
||||
<Text key={day} className={styles['week-day']}>
|
||||
{day}
|
||||
</Text>
|
||||
))}
|
||||
</View>
|
||||
|
||||
{/* NutUI CalendarCard 组件 */}
|
||||
<CalendarCard
|
||||
ref={calendarRef}
|
||||
type={type}
|
||||
value={selectedValue}
|
||||
renderDay={renderDay}
|
||||
onChange={handleDateChange}
|
||||
onPageChange={handlePageChange}
|
||||
/>
|
||||
</View>
|
||||
{ visible && <PopupPicker
|
||||
visible={visible}
|
||||
setvisible={setvisible}
|
||||
value={[current.getFullYear(), current.getMonth() + 1]}
|
||||
type="month"
|
||||
onChange={(value) => handleMonthChange(value)}/> }
|
||||
</View>
|
||||
)
|
||||
})
|
||||
|
||||
export default NutUICalendar
|
||||
Reference in New Issue
Block a user