日期范围选择组件

This commit is contained in:
2025-09-25 00:10:24 +08:00
parent dd1136d1e6
commit d99d3d87a9
4 changed files with 374 additions and 258 deletions

View File

@@ -5,6 +5,7 @@ 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[]
@@ -16,7 +17,8 @@ interface NutUICalendarProps {
}
export interface CalendarUIRef {
jumpTo: (year: number, month: number) => void
jumpTo: (year: number, month: number) => void,
gotoMonth: (delta: number) => void,
}
const NutUICalendar = React.forwardRef<CalendarUIRef, NutUICalendarProps>(({
@@ -28,27 +30,27 @@ const NutUICalendar = React.forwardRef<CalendarUIRef, NutUICalendarProps>(({
onHeaderClick
}, ref) => {
// 根据类型初始化选中值
// const getInitialValue = (): Date | Date[] => {
// console.log(value,defaultValue,'today')
// 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
// }
// 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[]>()
@@ -59,23 +61,25 @@ const NutUICalendar = React.forwardRef<CalendarUIRef, NutUICalendarProps>(({
// 当外部 value 变化时更新内部状态
useEffect(() => {
if (Array.isArray(value) && value.length > 0) {
setSelectedValue(value.map(item => new Date(item)))
setCurrent(new Date(value[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))
setSelectedValue(new Date(value))
setCurrent(new Date(value))
}
}, [value])
useImperativeHandle(ref, () => ({
jumpTo: (year: number, month: number) => {
calendarRef.current?.jumpTo(year, month)
},
gotoMonth: (delta: number) => {
gotoMonth(delta)
}
}))
const handleDateChange = (newValue: any) => {
console.log('xxxxxxxxxxxxxxxxxxxxxx', newValue)
setSelectedValue(newValue)
onChange?.(newValue as any)
}
@@ -87,6 +91,7 @@ const NutUICalendar = React.forwardRef<CalendarUIRef, NutUICalendarProps>(({
}
const gotoMonth = (delta: number) => {
console.log('aaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbb', delta)
const base = current instanceof Date ? new Date(current) : new Date()
base.setMonth(base.getMonth() + delta)
const next = startOfMonth(base)
@@ -101,6 +106,7 @@ const NutUICalendar = React.forwardRef<CalendarUIRef, NutUICalendarProps>(({
}
const handleHeaderClick = () => {
console.log('handleHeaderClick', current)
onHeaderClick && onHeaderClick(current)
setvisible(true)
}
@@ -115,11 +121,11 @@ const NutUICalendar = React.forwardRef<CalendarUIRef, NutUICalendarProps>(({
}
}
const renderDay = (day: any) => {
const { date, month, year} = day;
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">
<View className="day-container">
{date}
</View>
)
@@ -160,12 +166,21 @@ const NutUICalendar = React.forwardRef<CalendarUIRef, NutUICalendarProps>(({
{
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['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'] : ''}`}>
{
type === 'range' && (
<View className={styles['date-range-container']}>
<Text className={`${styles['date-text-placeholder']} ${value?.[0] ? styles['date-text'] : ''}`}>{value?.[0] ? dayjs(value?.[0] as Date).format('YYYY-MM-DD') : '起始时间'}</Text>
<Text></Text>
<Text className={`${styles['date-text-placeholder']} ${value?.[1] ? styles['date-text'] : ''}`}>{value?.[1] ? dayjs(value?.[1] as Date).format('YYYY-MM-DD') : '结束时间'}</Text>
</View>
)
}
{/* 自定义头部显示周一到周日 */}
<View className={styles['header']}>
<View className={styles['header-left']} onClick={handleHeaderClick}>
@@ -173,16 +188,16 @@ const NutUICalendar = React.forwardRef<CalendarUIRef, NutUICalendarProps>(({
<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 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) => (
{['周日', '周一', '周二', '周三', '周四', '周五', '周六'].map((day) => (
<Text key={day} className={styles['week-day']}>
{day}
</Text>
@@ -199,12 +214,12 @@ const NutUICalendar = React.forwardRef<CalendarUIRef, NutUICalendarProps>(({
onPageChange={handlePageChange}
/>
</View>
{ visible && <PopupPicker
visible={visible}
setvisible={setvisible}
value={[current.getFullYear(), current.getMonth() + 1]}
type="month"
onChange={(value) => handleMonthChange(value)}/> }
{visible && <PopupPicker
visible={visible}
setvisible={setvisible}
value={[current.getFullYear(), current.getMonth() + 1]}
type="month"
onChange={(value) => handleMonthChange(value)} />}
</View>
)
})