mirror of
https://gitee.com/element-plus/element-plus.git
synced 2024-12-04 20:27:44 +08:00
refactor(components): [time-picker] panel-time-pick (#8115)
* Refactor `panel-time-pick` to script setup. Co-authored-by: JeremyWuuuuu <15975785+JeremyWuuuuu@users.noreply.github.com>
This commit is contained in:
parent
364014a35a
commit
207baf89c4
@ -37,8 +37,8 @@
|
||||
</transition>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { computed, defineComponent, inject, ref } from 'vue'
|
||||
<script lang="ts" setup>
|
||||
import { computed, inject, ref } from 'vue'
|
||||
import dayjs from 'dayjs'
|
||||
import { EVENT_CODE } from '@element-plus/constants'
|
||||
import { useLocale, useNamespace } from '@element-plus/hooks'
|
||||
@ -49,179 +49,161 @@ import { getAvailableArrs, useOldValue } from './useTimePicker'
|
||||
|
||||
import type { Dayjs } from 'dayjs'
|
||||
|
||||
export default defineComponent({
|
||||
components: {
|
||||
TimeSpinner,
|
||||
},
|
||||
const props = defineProps(panelTimePickerProps)
|
||||
const emit = defineEmits(['pick', 'select-range', 'set-picker-option'])
|
||||
|
||||
props: panelTimePickerProps,
|
||||
|
||||
emits: ['pick', 'select-range', 'set-picker-option'],
|
||||
|
||||
setup(props, ctx) {
|
||||
const ns = useNamespace('time')
|
||||
const { t, lang } = useLocale()
|
||||
// data
|
||||
const selectionRange = ref([0, 2])
|
||||
const oldValue = useOldValue(props)
|
||||
// computed
|
||||
const transitionName = computed(() => {
|
||||
return isUndefined(props.actualVisible)
|
||||
? `${ns.namespace.value}-zoom-in-top`
|
||||
: ''
|
||||
})
|
||||
const showSeconds = computed(() => {
|
||||
return props.format.includes('ss')
|
||||
})
|
||||
const amPmMode = computed(() => {
|
||||
if (props.format.includes('A')) return 'A'
|
||||
if (props.format.includes('a')) return 'a'
|
||||
return ''
|
||||
})
|
||||
// method
|
||||
const isValidValue = (_date: Dayjs) => {
|
||||
const parsedDate = dayjs(_date).locale(lang.value)
|
||||
const result = getRangeAvailableTime(parsedDate)
|
||||
return parsedDate.isSame(result)
|
||||
}
|
||||
const handleCancel = () => {
|
||||
ctx.emit('pick', oldValue.value, false)
|
||||
}
|
||||
const handleConfirm = (visible = false, first = false) => {
|
||||
if (first) return
|
||||
ctx.emit('pick', props.parsedValue, visible)
|
||||
}
|
||||
const handleChange = (_date: Dayjs) => {
|
||||
// visible avoids edge cases, when use scrolls during panel closing animation
|
||||
if (!props.visible) {
|
||||
return
|
||||
}
|
||||
const result = getRangeAvailableTime(_date).millisecond(0)
|
||||
ctx.emit('pick', result, true)
|
||||
}
|
||||
|
||||
const setSelectionRange = (start, end) => {
|
||||
ctx.emit('select-range', start, end)
|
||||
selectionRange.value = [start, end]
|
||||
}
|
||||
|
||||
const changeSelectionRange = (step: number) => {
|
||||
const list = [0, 3].concat(showSeconds.value ? [6] : [])
|
||||
const mapping = ['hours', 'minutes'].concat(
|
||||
showSeconds.value ? ['seconds'] : []
|
||||
)
|
||||
const index = list.indexOf(selectionRange.value[0])
|
||||
const next = (index + step + list.length) % list.length
|
||||
timePickerOptions['start_emitSelectRange'](mapping[next])
|
||||
}
|
||||
|
||||
const handleKeydown = (event: KeyboardEvent) => {
|
||||
const code = event.code
|
||||
|
||||
if (code === EVENT_CODE.left || code === EVENT_CODE.right) {
|
||||
const step = code === EVENT_CODE.left ? -1 : 1
|
||||
changeSelectionRange(step)
|
||||
event.preventDefault()
|
||||
return
|
||||
}
|
||||
|
||||
if (code === EVENT_CODE.up || code === EVENT_CODE.down) {
|
||||
const step = code === EVENT_CODE.up ? -1 : 1
|
||||
timePickerOptions['start_scrollDown'](step)
|
||||
event.preventDefault()
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
const getRangeAvailableTime = (date: Dayjs) => {
|
||||
const availableMap = {
|
||||
hour: getAvailableHours,
|
||||
minute: getAvailableMinutes,
|
||||
second: getAvailableSeconds,
|
||||
}
|
||||
let result = date
|
||||
;['hour', 'minute', 'second'].forEach((_) => {
|
||||
if (availableMap[_]) {
|
||||
let availableArr
|
||||
const method = availableMap[_]
|
||||
if (_ === 'minute') {
|
||||
availableArr = method(result.hour(), props.datetimeRole)
|
||||
} else if (_ === 'second') {
|
||||
availableArr = method(
|
||||
result.hour(),
|
||||
result.minute(),
|
||||
props.datetimeRole
|
||||
)
|
||||
} else {
|
||||
availableArr = method(props.datetimeRole)
|
||||
}
|
||||
if (
|
||||
availableArr &&
|
||||
availableArr.length &&
|
||||
!availableArr.includes(result[_]())
|
||||
) {
|
||||
result = result[_](availableArr[0])
|
||||
}
|
||||
}
|
||||
})
|
||||
return result
|
||||
}
|
||||
|
||||
const parseUserInput = (value: Dayjs) => {
|
||||
if (!value) return null
|
||||
return dayjs(value, props.format).locale(lang.value)
|
||||
}
|
||||
|
||||
const formatToString = (value: Dayjs) => {
|
||||
if (!value) return null
|
||||
return value.format(props.format)
|
||||
}
|
||||
|
||||
const getDefaultValue = () => {
|
||||
return dayjs(defaultValue).locale(lang.value)
|
||||
}
|
||||
|
||||
ctx.emit('set-picker-option', ['isValidValue', isValidValue])
|
||||
ctx.emit('set-picker-option', ['formatToString', formatToString])
|
||||
ctx.emit('set-picker-option', ['parseUserInput', parseUserInput])
|
||||
ctx.emit('set-picker-option', ['handleKeydownInput', handleKeydown])
|
||||
ctx.emit('set-picker-option', [
|
||||
'getRangeAvailableTime',
|
||||
getRangeAvailableTime,
|
||||
])
|
||||
ctx.emit('set-picker-option', ['getDefaultValue', getDefaultValue])
|
||||
const timePickerOptions = {} as any
|
||||
const onSetOption = (e) => {
|
||||
timePickerOptions[e[0]] = e[1]
|
||||
}
|
||||
const pickerBase = inject('EP_PICKER_BASE') as any
|
||||
const {
|
||||
arrowControl,
|
||||
disabledHours,
|
||||
disabledMinutes,
|
||||
disabledSeconds,
|
||||
defaultValue,
|
||||
} = pickerBase.props
|
||||
const { getAvailableHours, getAvailableMinutes, getAvailableSeconds } =
|
||||
getAvailableArrs(disabledHours, disabledMinutes, disabledSeconds)
|
||||
|
||||
return {
|
||||
ns,
|
||||
|
||||
transitionName,
|
||||
arrowControl,
|
||||
onSetOption,
|
||||
t,
|
||||
handleConfirm,
|
||||
handleChange,
|
||||
setSelectionRange,
|
||||
amPmMode,
|
||||
showSeconds,
|
||||
handleCancel,
|
||||
disabledHours,
|
||||
disabledMinutes,
|
||||
disabledSeconds,
|
||||
}
|
||||
},
|
||||
const ns = useNamespace('time')
|
||||
const { t, lang } = useLocale()
|
||||
// data
|
||||
const selectionRange = ref([0, 2])
|
||||
const oldValue = useOldValue(props)
|
||||
// computed
|
||||
const transitionName = computed(() => {
|
||||
return isUndefined(props.actualVisible)
|
||||
? `${ns.namespace.value}-zoom-in-top`
|
||||
: ''
|
||||
})
|
||||
const showSeconds = computed(() => {
|
||||
return props.format.includes('ss')
|
||||
})
|
||||
const amPmMode = computed(() => {
|
||||
if (props.format.includes('A')) return 'A'
|
||||
if (props.format.includes('a')) return 'a'
|
||||
return ''
|
||||
})
|
||||
// method
|
||||
const isValidValue = (_date: Dayjs) => {
|
||||
const parsedDate = dayjs(_date).locale(lang.value)
|
||||
const result = getRangeAvailableTime(parsedDate)
|
||||
return parsedDate.isSame(result)
|
||||
}
|
||||
const handleCancel = () => {
|
||||
emit('pick', oldValue.value, false)
|
||||
}
|
||||
const handleConfirm = (visible = false, first = false) => {
|
||||
if (first) return
|
||||
emit('pick', props.parsedValue, visible)
|
||||
}
|
||||
const handleChange = (_date: Dayjs) => {
|
||||
// visible avoids edge cases, when use scrolls during panel closing animation
|
||||
if (!props.visible) {
|
||||
return
|
||||
}
|
||||
const result = getRangeAvailableTime(_date).millisecond(0)
|
||||
emit('pick', result, true)
|
||||
}
|
||||
|
||||
const setSelectionRange = (start: number, end: number) => {
|
||||
emit('select-range', start, end)
|
||||
selectionRange.value = [start, end]
|
||||
}
|
||||
|
||||
const changeSelectionRange = (step: number) => {
|
||||
const list = [0, 3].concat(showSeconds.value ? [6] : [])
|
||||
const mapping = ['hours', 'minutes'].concat(
|
||||
showSeconds.value ? ['seconds'] : []
|
||||
)
|
||||
const index = list.indexOf(selectionRange.value[0])
|
||||
const next = (index + step + list.length) % list.length
|
||||
timePickerOptions['start_emitSelectRange'](mapping[next])
|
||||
}
|
||||
|
||||
const handleKeydown = (event: KeyboardEvent) => {
|
||||
const code = event.code
|
||||
|
||||
if (code === EVENT_CODE.left || code === EVENT_CODE.right) {
|
||||
const step = code === EVENT_CODE.left ? -1 : 1
|
||||
changeSelectionRange(step)
|
||||
event.preventDefault()
|
||||
return
|
||||
}
|
||||
|
||||
if (code === EVENT_CODE.up || code === EVENT_CODE.down) {
|
||||
const step = code === EVENT_CODE.up ? -1 : 1
|
||||
timePickerOptions['start_scrollDown'](step)
|
||||
event.preventDefault()
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
const getRangeAvailableTime = (date: Dayjs) => {
|
||||
const availableTimeGetters = {
|
||||
hour: getAvailableHours,
|
||||
minute: getAvailableMinutes,
|
||||
second: getAvailableSeconds,
|
||||
} as const
|
||||
let result = date
|
||||
;(['hour', 'minute', 'second'] as const).forEach((type) => {
|
||||
if (availableTimeGetters[type]) {
|
||||
let availableTimeSlots
|
||||
const method = availableTimeGetters[type]
|
||||
switch (type) {
|
||||
case 'minute': {
|
||||
availableTimeSlots = (method as typeof getAvailableMinutes)(
|
||||
result.hour(),
|
||||
props.datetimeRole
|
||||
)
|
||||
break
|
||||
}
|
||||
case 'second': {
|
||||
availableTimeSlots = (method as typeof getAvailableSeconds)(
|
||||
result.hour(),
|
||||
result.minute(),
|
||||
props.datetimeRole
|
||||
)
|
||||
break
|
||||
}
|
||||
default: {
|
||||
availableTimeSlots = (method as typeof getAvailableHours)(
|
||||
props.datetimeRole
|
||||
)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if (
|
||||
availableTimeSlots?.length &&
|
||||
!availableTimeSlots.includes(result[type]())
|
||||
) {
|
||||
result = result[type](availableTimeSlots[0]) as unknown as Dayjs
|
||||
}
|
||||
}
|
||||
})
|
||||
return result
|
||||
}
|
||||
|
||||
const parseUserInput = (value: Dayjs) => {
|
||||
if (!value) return null
|
||||
return dayjs(value, props.format).locale(lang.value)
|
||||
}
|
||||
|
||||
const formatToString = (value: Dayjs) => {
|
||||
if (!value) return null
|
||||
return value.format(props.format)
|
||||
}
|
||||
|
||||
const getDefaultValue = () => {
|
||||
return dayjs(defaultValue).locale(lang.value)
|
||||
}
|
||||
|
||||
emit('set-picker-option', ['isValidValue', isValidValue])
|
||||
emit('set-picker-option', ['formatToString', formatToString])
|
||||
emit('set-picker-option', ['parseUserInput', parseUserInput])
|
||||
emit('set-picker-option', ['handleKeydownInput', handleKeydown])
|
||||
emit('set-picker-option', ['getRangeAvailableTime', getRangeAvailableTime])
|
||||
emit('set-picker-option', ['getDefaultValue', getDefaultValue])
|
||||
const timePickerOptions = {} as any
|
||||
const onSetOption = (e: [string, number]) => {
|
||||
timePickerOptions[e[0]] = e[1]
|
||||
}
|
||||
const pickerBase = inject('EP_PICKER_BASE') as any
|
||||
const {
|
||||
arrowControl,
|
||||
disabledHours,
|
||||
disabledMinutes,
|
||||
disabledSeconds,
|
||||
defaultValue,
|
||||
} = pickerBase.props
|
||||
const { getAvailableHours, getAvailableMinutes, getAvailableSeconds } =
|
||||
getAvailableArrs(disabledHours, disabledMinutes, disabledSeconds)
|
||||
</script>
|
||||
|
Loading…
Reference in New Issue
Block a user