173 lines
4.9 KiB
TypeScript
173 lines
4.9 KiB
TypeScript
import type { IDatePickerProps } from '@yz1311/react-native-wheel-picker'
|
|
import SegmentedControl from '@react-native-segmented-control/segmented-control'
|
|
import { DatePicker } from '@yz1311/react-native-wheel-picker'
|
|
import dayjs from 'dayjs'
|
|
import React, { useEffect, useRef, useState } from 'react'
|
|
import { Animated, Modal, StyleSheet, Text, TouchableOpacity, View } from 'react-native'
|
|
import { toDate } from '@/utils/time'
|
|
|
|
// 定义 mode 类型
|
|
export type DatePickerMode = 'year' | 'month' | 'date' | 'time' | 'datetime'
|
|
|
|
// 定义 format 类型
|
|
export type DateFormatType = 'YYYY' | 'YYYY-MM' | 'YYYY-MM-DD' | 'HH:mm:ss' | 'YYYY-MM-DD HH:mm:ss'
|
|
|
|
interface ADatePickerProps extends Omit<IDatePickerProps, 'date'> {
|
|
date?: Date | string
|
|
show?: boolean
|
|
onClose?: () => void
|
|
onConfirm?: (value: string) => void
|
|
mode?: DatePickerMode
|
|
format?: DateFormatType
|
|
}
|
|
|
|
const defaultFormatMap: Record<DatePickerMode, DateFormatType> = {
|
|
year: 'YYYY',
|
|
month: 'YYYY-MM',
|
|
date: 'YYYY-MM-DD',
|
|
time: 'HH:mm:ss',
|
|
datetime: 'YYYY-MM-DD HH:mm:ss',
|
|
}
|
|
|
|
export default function ADatePicker({
|
|
date,
|
|
show = false,
|
|
onClose,
|
|
onConfirm,
|
|
format,
|
|
...restProps
|
|
}: ADatePickerProps) {
|
|
const fadeAnim = useRef(new Animated.Value(0)).current
|
|
const slideAnim = useRef(new Animated.Value(300)).current
|
|
const [visible, setVisible] = useState(show)
|
|
const [index, setIndex] = useState(0)
|
|
const [mode, setMode] = useState<DatePickerMode>('month')
|
|
|
|
// 使用传入 format 或默认 format
|
|
const finalFormat = format || defaultFormatMap[mode]
|
|
|
|
useEffect(() => {
|
|
if (show) {
|
|
setVisible(true)
|
|
fadeAnim.setValue(0)
|
|
slideAnim.setValue(300)
|
|
Animated.parallel([
|
|
Animated.timing(fadeAnim, { toValue: 1, duration: 250, useNativeDriver: true }),
|
|
Animated.timing(slideAnim, { toValue: 0, duration: 250, useNativeDriver: true }),
|
|
]).start()
|
|
}
|
|
else {
|
|
Animated.parallel([
|
|
Animated.timing(fadeAnim, { toValue: 0, duration: 250, useNativeDriver: true }),
|
|
Animated.timing(slideAnim, { toValue: 280, duration: 250, useNativeDriver: true }),
|
|
]).start(() => setVisible(false))
|
|
}
|
|
}, [show])
|
|
|
|
const handleCancel = () => onClose?.()
|
|
|
|
const handleConfirm = (date: Date) => {
|
|
const value = dayjs(date).format(finalFormat)
|
|
onConfirm?.(value)
|
|
}
|
|
|
|
if (!visible)
|
|
return null
|
|
|
|
return (
|
|
<Modal transparent visible={visible} animationType="none">
|
|
<Animated.View style={[styles.overlay, { opacity: fadeAnim }]}>
|
|
<TouchableOpacity style={{ flex: 1 }} activeOpacity={1} onPress={handleCancel} />
|
|
</Animated.View>
|
|
|
|
<Animated.View
|
|
style={[styles.pickerContainer, { transform: [{ translateY: slideAnim }] }]}
|
|
>
|
|
<View className="px-3 pt-2 flex flex-col gap-2">
|
|
<View className="w-full">
|
|
<Text>快速选择</Text>
|
|
{/* <ATab
|
|
data={[
|
|
{
|
|
label: '自定义',
|
|
key: '自定义',
|
|
},
|
|
{
|
|
label: '不限',
|
|
key: '不限',
|
|
},
|
|
{
|
|
label: '今天',
|
|
key: '今天',
|
|
},
|
|
{
|
|
label: '本月',
|
|
key: '本月',
|
|
},
|
|
{
|
|
label: '本年',
|
|
key: '本年',
|
|
},
|
|
{
|
|
label: '范围',
|
|
key: '范围',
|
|
},
|
|
]}
|
|
onChange={(key) => {
|
|
setMode('datetime')
|
|
}}
|
|
/> */}
|
|
</View>
|
|
|
|
<View className="w-full">
|
|
<Text>选择模式</Text>
|
|
<SegmentedControl
|
|
values={['日', '月', '年', '时间', '日期']}
|
|
selectedIndex={index}
|
|
style={{ borderRadius: 2, width: '100%' }}
|
|
sliderStyle={{
|
|
borderRadius: 2,
|
|
}}
|
|
|
|
onChange={(event: any) => setIndex(event.nativeEvent.selectedSegmentIndex)}
|
|
/>
|
|
</View>
|
|
|
|
</View>
|
|
|
|
<DatePicker
|
|
{...restProps}
|
|
date={toDate(date)}
|
|
mode={mode}
|
|
isModal={false}
|
|
onPickerCancel={handleCancel}
|
|
onPickerConfirm={handleConfirm}
|
|
showHeader={false}
|
|
onDateChange={(value) => {
|
|
console.log(value)
|
|
}}
|
|
/>
|
|
|
|
<View className="flex flex-row gap-4 px-3 pb-1 v">
|
|
{/* <AButton variant="outline" className="flex-1">取消</AButton>
|
|
<AButton className="flex-1">确认</AButton> */}
|
|
</View>
|
|
</Animated.View>
|
|
</Modal>
|
|
)
|
|
}
|
|
|
|
const styles = StyleSheet.create({
|
|
overlay: {
|
|
...StyleSheet.absoluteFillObject,
|
|
backgroundColor: 'rgba(0,0,0,0.5)',
|
|
},
|
|
pickerContainer: {
|
|
backgroundColor: '#fff',
|
|
overflow: 'hidden',
|
|
position: 'absolute',
|
|
bottom: 0,
|
|
width: '100%',
|
|
},
|
|
})
|