mirror of
https://gitee.com/element-plus/element-plus.git
synced 2024-12-04 20:27:44 +08:00
refactor(components): [time-picker] script setup (#8128)
* refactor(components): [time-picker] panel-time-range * Refactor `panel-time-range` to script setup. * refactor(components): [time-picker] panel-time-range * Fix typing issues in `panel-time-range`. * Extract common code to `use-time-panel`. * refactor(components): [time-picker] panel-time-picker * Replace duplicated logic with `use-time-panel`. Co-authored-by: JeremyWuuuuu <15975785+JeremyWuuuuu@users.noreply.github.com>
This commit is contained in:
parent
f8547411e5
commit
beacaf6ce4
@ -0,0 +1,86 @@
|
||||
import type { Dayjs } from 'dayjs'
|
||||
|
||||
type UseTimePanelProps = {
|
||||
getAvailableHours: (role: string, compare?: Dayjs) => number[]
|
||||
getAvailableMinutes: (hour: number, role: string, compare?: Dayjs) => number[]
|
||||
getAvailableSeconds: (
|
||||
hour: number,
|
||||
minute: number,
|
||||
role: string,
|
||||
compare?: Dayjs
|
||||
) => number[]
|
||||
}
|
||||
|
||||
export const useTimePanel = ({
|
||||
getAvailableHours,
|
||||
getAvailableMinutes,
|
||||
getAvailableSeconds,
|
||||
}: UseTimePanelProps) => {
|
||||
const getAvailableTime = (
|
||||
date: Dayjs,
|
||||
role: string,
|
||||
first: boolean,
|
||||
compareDate?: 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(),
|
||||
role,
|
||||
compareDate
|
||||
)
|
||||
break
|
||||
}
|
||||
case 'second': {
|
||||
availableTimeSlots = (method as typeof getAvailableSeconds)(
|
||||
result.hour(),
|
||||
result.minute(),
|
||||
role,
|
||||
compareDate
|
||||
)
|
||||
break
|
||||
}
|
||||
default: {
|
||||
availableTimeSlots = (method as typeof getAvailableHours)(
|
||||
role,
|
||||
compareDate
|
||||
)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if (
|
||||
availableTimeSlots?.length &&
|
||||
!availableTimeSlots.includes(result[type]())
|
||||
) {
|
||||
const pos = first ? 0 : availableTimeSlots.length - 1
|
||||
result = result[type](availableTimeSlots[pos]) as unknown as Dayjs
|
||||
}
|
||||
}
|
||||
})
|
||||
return result
|
||||
}
|
||||
|
||||
const timePickerOptions: Record<string, (...args: any[]) => void> = {}
|
||||
|
||||
const onSetOption = ([key, val]: [string, (...args: any[]) => void]) => {
|
||||
timePickerOptions[key] = val
|
||||
}
|
||||
|
||||
return {
|
||||
timePickerOptions,
|
||||
|
||||
getAvailableTime,
|
||||
onSetOption,
|
||||
}
|
||||
}
|
@ -19,17 +19,17 @@ export const basicTimeSpinnerProps = buildProps({
|
||||
arrowControl: Boolean,
|
||||
amPmMode: {
|
||||
// 'a': am/pm; 'A': AM/PM
|
||||
type: definePropType<'a' | 'A'>(String),
|
||||
type: definePropType<'a' | 'A' | ''>(String),
|
||||
default: '',
|
||||
},
|
||||
disabledHours: {
|
||||
type: definePropType<(role: string, comparingDate?: Dayjs) => boolean[]>(
|
||||
type: definePropType<(role: string, comparingDate?: Dayjs) => number[]>(
|
||||
Function
|
||||
),
|
||||
},
|
||||
disabledMinutes: {
|
||||
type: definePropType<
|
||||
(hour: number, role: string, comparingDate?: Dayjs) => boolean[]
|
||||
(hour: number, role: string, comparingDate?: Dayjs) => number[]
|
||||
>(Function),
|
||||
},
|
||||
disabledSeconds: {
|
||||
@ -39,7 +39,7 @@ export const basicTimeSpinnerProps = buildProps({
|
||||
minute: number,
|
||||
role: string,
|
||||
comparingDate?: Dayjs
|
||||
) => boolean[]
|
||||
) => number[]
|
||||
>(Function),
|
||||
},
|
||||
} as const)
|
||||
|
@ -11,7 +11,7 @@ export const panelTimePickerProps = buildProps({
|
||||
},
|
||||
datetimeRole: String,
|
||||
parsedValue: {
|
||||
type: definePropType<string | Dayjs>([Object, String]),
|
||||
type: definePropType<Dayjs>(Object),
|
||||
},
|
||||
format: {
|
||||
type: String,
|
||||
|
@ -7,7 +7,7 @@ export const panelTimeRangeProps = buildProps({
|
||||
visible: Boolean,
|
||||
actualVisible: Boolean,
|
||||
parsedValue: {
|
||||
type: definePropType<Dayjs[]>(Array),
|
||||
type: definePropType<[Dayjs, Dayjs]>(Array),
|
||||
},
|
||||
format: {
|
||||
type: String,
|
||||
|
@ -8,7 +8,7 @@
|
||||
:arrow-control="arrowControl"
|
||||
:show-seconds="showSeconds"
|
||||
:am-pm-mode="amPmMode"
|
||||
:spinner-date="parsedValue"
|
||||
:spinner-date="(parsedValue as any)"
|
||||
:disabled-hours="disabledHours"
|
||||
:disabled-minutes="disabledMinutes"
|
||||
:disabled-seconds="disabledSeconds"
|
||||
@ -44,6 +44,7 @@ import { EVENT_CODE } from '@element-plus/constants'
|
||||
import { useLocale, useNamespace } from '@element-plus/hooks'
|
||||
import { isUndefined } from '@element-plus/utils'
|
||||
import { panelTimePickerProps } from '../props/panel-time-picker'
|
||||
import { useTimePanel } from '../composables/use-time-panel'
|
||||
import TimeSpinner from './basic-time-spinner.vue'
|
||||
import { getAvailableArrs, useOldValue } from './useTimePicker'
|
||||
|
||||
@ -52,6 +53,18 @@ import type { Dayjs } from 'dayjs'
|
||||
const props = defineProps(panelTimePickerProps)
|
||||
const emit = defineEmits(['pick', 'select-range', 'set-picker-option'])
|
||||
|
||||
// Injections
|
||||
const pickerBase = inject('EP_PICKER_BASE') as any
|
||||
const {
|
||||
arrowControl,
|
||||
disabledHours,
|
||||
disabledMinutes,
|
||||
disabledSeconds,
|
||||
defaultValue,
|
||||
} = pickerBase.props
|
||||
const { getAvailableHours, getAvailableMinutes, getAvailableSeconds } =
|
||||
getAvailableArrs(disabledHours, disabledMinutes, disabledSeconds)
|
||||
|
||||
const ns = useNamespace('time')
|
||||
const { t, lang } = useLocale()
|
||||
// data
|
||||
@ -111,65 +124,31 @@ const changeSelectionRange = (step: number) => {
|
||||
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
|
||||
const { left, right, up, down } = EVENT_CODE
|
||||
|
||||
if ([left, right].includes(code)) {
|
||||
const step = 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
|
||||
if ([up, down].includes(code)) {
|
||||
const step = 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
|
||||
}
|
||||
}
|
||||
const { timePickerOptions, onSetOption, getAvailableTime } = useTimePanel({
|
||||
getAvailableHours,
|
||||
getAvailableMinutes,
|
||||
getAvailableSeconds,
|
||||
})
|
||||
|
||||
if (
|
||||
availableTimeSlots?.length &&
|
||||
!availableTimeSlots.includes(result[type]())
|
||||
) {
|
||||
result = result[type](availableTimeSlots[0]) as unknown as Dayjs
|
||||
}
|
||||
}
|
||||
})
|
||||
return result
|
||||
const getRangeAvailableTime = (date: Dayjs) => {
|
||||
return getAvailableTime(date, props.datetimeRole || '', true)
|
||||
}
|
||||
|
||||
const parseUserInput = (value: Dayjs) => {
|
||||
@ -192,18 +171,4 @@ 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>
|
||||
|
@ -22,7 +22,7 @@
|
||||
:show-seconds="showSeconds"
|
||||
:am-pm-mode="amPmMode"
|
||||
:arrow-control="arrowControl"
|
||||
:spinner-date="minDate"
|
||||
:spinner-date="startTime"
|
||||
:disabled-hours="disabledHours_"
|
||||
:disabled-minutes="disabledMinutes_"
|
||||
:disabled-seconds="disabledSeconds_"
|
||||
@ -50,7 +50,7 @@
|
||||
:show-seconds="showSeconds"
|
||||
:am-pm-mode="amPmMode"
|
||||
:arrow-control="arrowControl"
|
||||
:spinner-date="maxDate"
|
||||
:spinner-date="endTime"
|
||||
:disabled-hours="disabledHours_"
|
||||
:disabled-minutes="disabledMinutes_"
|
||||
:disabled-seconds="disabledSeconds_"
|
||||
@ -81,18 +81,23 @@
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { computed, defineComponent, inject, ref } from 'vue'
|
||||
<script lang="ts" setup>
|
||||
import { computed, inject, ref, unref } from 'vue'
|
||||
import dayjs from 'dayjs'
|
||||
import { union } from 'lodash-unified'
|
||||
import { useLocale, useNamespace } from '@element-plus/hooks'
|
||||
import { isArray } from '@element-plus/utils'
|
||||
import { EVENT_CODE } from '@element-plus/constants'
|
||||
import { panelTimeRangeProps } from '../props/panel-time-range'
|
||||
import { useTimePanel } from '../composables/use-time-panel'
|
||||
import TimeSpinner from './basic-time-spinner.vue'
|
||||
import { getAvailableArrs, useOldValue } from './useTimePicker'
|
||||
|
||||
import type { Dayjs } from 'dayjs'
|
||||
|
||||
const props = defineProps(panelTimeRangeProps)
|
||||
const emit = defineEmits(['pick', 'select-range', 'set-picker-option'])
|
||||
|
||||
const makeSelectRange = (start: number, end: number) => {
|
||||
const result = []
|
||||
for (let i = start; i <= end; i++) {
|
||||
@ -100,274 +105,204 @@ const makeSelectRange = (start: number, end: number) => {
|
||||
}
|
||||
return result
|
||||
}
|
||||
export default defineComponent({
|
||||
components: { TimeSpinner },
|
||||
|
||||
props: panelTimeRangeProps,
|
||||
const { t, lang } = useLocale()
|
||||
const nsTime = useNamespace('time')
|
||||
const nsPicker = useNamespace('picker')
|
||||
const pickerBase = inject('EP_PICKER_BASE') as any
|
||||
const {
|
||||
arrowControl,
|
||||
disabledHours,
|
||||
disabledMinutes,
|
||||
disabledSeconds,
|
||||
defaultValue,
|
||||
} = pickerBase.props
|
||||
|
||||
emits: ['pick', 'select-range', 'set-picker-option'],
|
||||
|
||||
setup(props, ctx) {
|
||||
const { t, lang } = useLocale()
|
||||
const nsTime = useNamespace('time')
|
||||
const nsPicker = useNamespace('picker')
|
||||
const minDate = computed(() => props.parsedValue[0])
|
||||
const maxDate = computed(() => props.parsedValue[1])
|
||||
const oldValue = useOldValue(props)
|
||||
const handleCancel = () => {
|
||||
ctx.emit('pick', oldValue.value, false)
|
||||
}
|
||||
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 ''
|
||||
})
|
||||
|
||||
const minSelectableRange = ref([])
|
||||
const maxSelectableRange = ref([])
|
||||
|
||||
const handleConfirm = (visible = false) => {
|
||||
ctx.emit('pick', [minDate.value, maxDate.value], visible)
|
||||
}
|
||||
|
||||
const handleMinChange = (date) => {
|
||||
handleChange(date.millisecond(0), maxDate.value)
|
||||
}
|
||||
const handleMaxChange = (date) => {
|
||||
handleChange(minDate.value, date.millisecond(0))
|
||||
}
|
||||
|
||||
const isValidValue = (_date: Dayjs[]) => {
|
||||
const parsedDate = _date.map((_) => dayjs(_).locale(lang.value))
|
||||
const result = getRangeAvailableTime(parsedDate)
|
||||
return parsedDate[0].isSame(result[0]) && parsedDate[1].isSame(result[1])
|
||||
}
|
||||
|
||||
const handleChange = (_minDate, _maxDate) => {
|
||||
// todo getRangeAvailableTime(_date).millisecond(0)
|
||||
ctx.emit('pick', [_minDate, _maxDate], true)
|
||||
}
|
||||
const btnConfirmDisabled = computed(() => {
|
||||
return minDate.value > maxDate.value
|
||||
})
|
||||
|
||||
const selectionRange = ref([0, 2])
|
||||
const setMinSelectionRange = (start, end) => {
|
||||
ctx.emit('select-range', start, end, 'min')
|
||||
selectionRange.value = [start, end]
|
||||
}
|
||||
|
||||
const offset = computed(() => (showSeconds.value ? 11 : 8))
|
||||
const setMaxSelectionRange = (start, end) => {
|
||||
ctx.emit('select-range', start, end, 'max')
|
||||
selectionRange.value = [start + offset.value, end + offset.value]
|
||||
}
|
||||
|
||||
const changeSelectionRange = (step) => {
|
||||
const list = showSeconds.value ? [0, 3, 6, 11, 14, 17] : [0, 3, 8, 11]
|
||||
const mapping = ['hours', 'minutes'].concat(
|
||||
showSeconds.value ? ['seconds'] : []
|
||||
)
|
||||
const index = list.indexOf(selectionRange.value[0])
|
||||
const next = (index + step + list.length) % list.length
|
||||
const half = list.length / 2
|
||||
if (next < half) {
|
||||
timePickerOptions['start_emitSelectRange'](mapping[next])
|
||||
} else {
|
||||
timePickerOptions['end_emitSelectRange'](mapping[next - half])
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
const role = selectionRange.value[0] < offset.value ? 'start' : 'end'
|
||||
timePickerOptions[`${role}_scrollDown`](step)
|
||||
event.preventDefault()
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
const disabledHours_ = (role, compare) => {
|
||||
const defaultDisable = disabledHours ? disabledHours(role) : []
|
||||
const isStart = role === 'start'
|
||||
const compareDate = compare || (isStart ? maxDate.value : minDate.value)
|
||||
const compareHour = compareDate.hour()
|
||||
const nextDisable = isStart
|
||||
? makeSelectRange(compareHour + 1, 23)
|
||||
: makeSelectRange(0, compareHour - 1)
|
||||
return union(defaultDisable, nextDisable)
|
||||
}
|
||||
const disabledMinutes_ = (hour, role, compare) => {
|
||||
const defaultDisable = disabledMinutes ? disabledMinutes(hour, role) : []
|
||||
const isStart = role === 'start'
|
||||
const compareDate = compare || (isStart ? maxDate.value : minDate.value)
|
||||
const compareHour = compareDate.hour()
|
||||
if (hour !== compareHour) {
|
||||
return defaultDisable
|
||||
}
|
||||
const compareMinute = compareDate.minute()
|
||||
const nextDisable = isStart
|
||||
? makeSelectRange(compareMinute + 1, 59)
|
||||
: makeSelectRange(0, compareMinute - 1)
|
||||
return union(defaultDisable, nextDisable)
|
||||
}
|
||||
const disabledSeconds_ = (hour, minute, role, compare) => {
|
||||
const defaultDisable = disabledSeconds
|
||||
? disabledSeconds(hour, minute, role)
|
||||
: []
|
||||
const isStart = role === 'start'
|
||||
const compareDate = compare || (isStart ? maxDate.value : minDate.value)
|
||||
const compareHour = compareDate.hour()
|
||||
const compareMinute = compareDate.minute()
|
||||
if (hour !== compareHour || minute !== compareMinute) {
|
||||
return defaultDisable
|
||||
}
|
||||
const compareSecond = compareDate.second()
|
||||
const nextDisable = isStart
|
||||
? makeSelectRange(compareSecond + 1, 59)
|
||||
: makeSelectRange(0, compareSecond - 1)
|
||||
return union(defaultDisable, nextDisable)
|
||||
}
|
||||
|
||||
const getRangeAvailableTime = (dates: Array<Dayjs>) => {
|
||||
return dates.map((_, index) =>
|
||||
getRangeAvailableTimeEach(
|
||||
dates[0],
|
||||
dates[1],
|
||||
index === 0 ? 'start' : 'end'
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
const { getAvailableHours, getAvailableMinutes, getAvailableSeconds } =
|
||||
getAvailableArrs(disabledHours_, disabledMinutes_, disabledSeconds_)
|
||||
|
||||
const getRangeAvailableTimeEach = (
|
||||
startDate: Dayjs,
|
||||
endDate: Dayjs,
|
||||
role
|
||||
) => {
|
||||
const availableMap = {
|
||||
hour: getAvailableHours,
|
||||
minute: getAvailableMinutes,
|
||||
second: getAvailableSeconds,
|
||||
}
|
||||
const isStart = role === 'start'
|
||||
let result = isStart ? startDate : endDate
|
||||
const compareDate = isStart ? endDate : startDate
|
||||
;['hour', 'minute', 'second'].forEach((_) => {
|
||||
if (availableMap[_]) {
|
||||
let availableArr
|
||||
const method = availableMap[_]
|
||||
if (_ === 'minute') {
|
||||
availableArr = method(result.hour(), role, compareDate)
|
||||
} else if (_ === 'second') {
|
||||
availableArr = method(
|
||||
result.hour(),
|
||||
result.minute(),
|
||||
role,
|
||||
compareDate
|
||||
)
|
||||
} else {
|
||||
availableArr = method(role, compareDate)
|
||||
}
|
||||
if (
|
||||
availableArr &&
|
||||
availableArr.length &&
|
||||
!availableArr.includes(result[_]())
|
||||
) {
|
||||
const pos = isStart ? 0 : availableArr.length - 1
|
||||
result = result[_](availableArr[pos])
|
||||
}
|
||||
}
|
||||
})
|
||||
return result
|
||||
}
|
||||
|
||||
const parseUserInput = (value: Dayjs[] | Dayjs) => {
|
||||
if (!value) return null
|
||||
if (Array.isArray(value)) {
|
||||
return value.map((_) => dayjs(_, props.format).locale(lang.value))
|
||||
}
|
||||
return dayjs(value, props.format).locale(lang.value)
|
||||
}
|
||||
|
||||
const formatToString = (value: Dayjs[] | Dayjs) => {
|
||||
if (!value) return null
|
||||
if (Array.isArray(value)) {
|
||||
return value.map((_) => _.format(props.format))
|
||||
}
|
||||
return value.format(props.format)
|
||||
}
|
||||
|
||||
const getDefaultValue = () => {
|
||||
if (Array.isArray(defaultValue)) {
|
||||
return defaultValue.map((_) => dayjs(_).locale(lang.value))
|
||||
}
|
||||
const defaultDay = dayjs(defaultValue).locale(lang.value)
|
||||
return [defaultDay, defaultDay.add(60, 'm')]
|
||||
}
|
||||
|
||||
ctx.emit('set-picker-option', ['formatToString', formatToString])
|
||||
ctx.emit('set-picker-option', ['parseUserInput', parseUserInput])
|
||||
ctx.emit('set-picker-option', ['isValidValue', isValidValue])
|
||||
ctx.emit('set-picker-option', ['handleKeydownInput', handleKeydown])
|
||||
ctx.emit('set-picker-option', ['getDefaultValue', getDefaultValue])
|
||||
ctx.emit('set-picker-option', [
|
||||
'getRangeAvailableTime',
|
||||
getRangeAvailableTime,
|
||||
])
|
||||
|
||||
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
|
||||
|
||||
return {
|
||||
nsTime,
|
||||
nsPicker,
|
||||
arrowControl,
|
||||
onSetOption,
|
||||
setMaxSelectionRange,
|
||||
setMinSelectionRange,
|
||||
btnConfirmDisabled,
|
||||
handleCancel,
|
||||
handleConfirm,
|
||||
t,
|
||||
showSeconds,
|
||||
minDate,
|
||||
maxDate,
|
||||
amPmMode,
|
||||
handleMinChange,
|
||||
handleMaxChange,
|
||||
minSelectableRange,
|
||||
maxSelectableRange,
|
||||
disabledHours_,
|
||||
disabledMinutes_,
|
||||
disabledSeconds_,
|
||||
}
|
||||
},
|
||||
const startTime = computed(() => props.parsedValue![0])
|
||||
const endTime = computed(() => props.parsedValue![1])
|
||||
const oldValue = useOldValue(props)
|
||||
const handleCancel = () => {
|
||||
emit('pick', oldValue.value, false)
|
||||
}
|
||||
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 ''
|
||||
})
|
||||
|
||||
const handleConfirm = (visible = false) => {
|
||||
emit('pick', [startTime.value, endTime.value], visible)
|
||||
}
|
||||
|
||||
const handleMinChange = (date: Dayjs) => {
|
||||
handleChange(date.millisecond(0), endTime.value)
|
||||
}
|
||||
const handleMaxChange = (date: Dayjs) => {
|
||||
handleChange(startTime.value, date.millisecond(0))
|
||||
}
|
||||
|
||||
const isValidValue = (_date: Dayjs[]) => {
|
||||
const parsedDate = _date.map((_) => dayjs(_).locale(lang.value))
|
||||
const result = getRangeAvailableTime(parsedDate)
|
||||
return parsedDate[0].isSame(result[0]) && parsedDate[1].isSame(result[1])
|
||||
}
|
||||
|
||||
const handleChange = (start: Dayjs, end: Dayjs) => {
|
||||
// todo getRangeAvailableTime(_date).millisecond(0)
|
||||
emit('pick', [start, end], true)
|
||||
}
|
||||
const btnConfirmDisabled = computed(() => {
|
||||
return startTime.value > endTime.value
|
||||
})
|
||||
|
||||
const selectionRange = ref([0, 2])
|
||||
const setMinSelectionRange = (start: number, end: number) => {
|
||||
emit('select-range', start, end, 'min')
|
||||
selectionRange.value = [start, end]
|
||||
}
|
||||
|
||||
const offset = computed(() => (showSeconds.value ? 11 : 8))
|
||||
const setMaxSelectionRange = (start: number, end: number) => {
|
||||
emit('select-range', start, end, 'max')
|
||||
const _offset = unref(offset)
|
||||
selectionRange.value = [start + _offset, end + _offset]
|
||||
}
|
||||
|
||||
const changeSelectionRange = (step: number) => {
|
||||
const list = showSeconds.value ? [0, 3, 6, 11, 14, 17] : [0, 3, 8, 11]
|
||||
const mapping = ['hours', 'minutes'].concat(
|
||||
showSeconds.value ? ['seconds'] : []
|
||||
)
|
||||
const index = list.indexOf(selectionRange.value[0])
|
||||
const next = (index + step + list.length) % list.length
|
||||
const half = list.length / 2
|
||||
if (next < half) {
|
||||
timePickerOptions['start_emitSelectRange'](mapping[next])
|
||||
} else {
|
||||
timePickerOptions['end_emitSelectRange'](mapping[next - half])
|
||||
}
|
||||
}
|
||||
|
||||
const handleKeydown = (event: KeyboardEvent) => {
|
||||
const code = event.code
|
||||
|
||||
const { left, right, up, down } = EVENT_CODE
|
||||
|
||||
if ([left, right].includes(code)) {
|
||||
const step = code === left ? -1 : 1
|
||||
changeSelectionRange(step)
|
||||
event.preventDefault()
|
||||
return
|
||||
}
|
||||
|
||||
if ([up, down].includes(code)) {
|
||||
const step = code === up ? -1 : 1
|
||||
const role = selectionRange.value[0] < offset.value ? 'start' : 'end'
|
||||
timePickerOptions[`${role}_scrollDown`](step)
|
||||
event.preventDefault()
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
const disabledHours_ = (role: string, compare?: Dayjs) => {
|
||||
const defaultDisable = disabledHours ? disabledHours(role) : []
|
||||
const isStart = role === 'start'
|
||||
const compareDate = compare || (isStart ? endTime.value : startTime.value)
|
||||
const compareHour = compareDate.hour()
|
||||
const nextDisable = isStart
|
||||
? makeSelectRange(compareHour + 1, 23)
|
||||
: makeSelectRange(0, compareHour - 1)
|
||||
return union(defaultDisable, nextDisable)
|
||||
}
|
||||
const disabledMinutes_ = (hour: number, role: string, compare?: Dayjs) => {
|
||||
const defaultDisable = disabledMinutes ? disabledMinutes(hour, role) : []
|
||||
const isStart = role === 'start'
|
||||
const compareDate = compare || (isStart ? endTime.value : startTime.value)
|
||||
const compareHour = compareDate.hour()
|
||||
if (hour !== compareHour) {
|
||||
return defaultDisable
|
||||
}
|
||||
const compareMinute = compareDate.minute()
|
||||
const nextDisable = isStart
|
||||
? makeSelectRange(compareMinute + 1, 59)
|
||||
: makeSelectRange(0, compareMinute - 1)
|
||||
return union(defaultDisable, nextDisable)
|
||||
}
|
||||
const disabledSeconds_ = (
|
||||
hour: number,
|
||||
minute: number,
|
||||
role: string,
|
||||
compare?: Dayjs
|
||||
) => {
|
||||
const defaultDisable = disabledSeconds
|
||||
? disabledSeconds(hour, minute, role)
|
||||
: []
|
||||
const isStart = role === 'start'
|
||||
const compareDate = compare || (isStart ? endTime.value : startTime.value)
|
||||
const compareHour = compareDate.hour()
|
||||
const compareMinute = compareDate.minute()
|
||||
if (hour !== compareHour || minute !== compareMinute) {
|
||||
return defaultDisable
|
||||
}
|
||||
const compareSecond = compareDate.second()
|
||||
const nextDisable = isStart
|
||||
? makeSelectRange(compareSecond + 1, 59)
|
||||
: makeSelectRange(0, compareSecond - 1)
|
||||
return union(defaultDisable, nextDisable)
|
||||
}
|
||||
|
||||
const getRangeAvailableTime = ([start, end]: Array<Dayjs>) => {
|
||||
return [
|
||||
getAvailableTime(start, 'start', true, end),
|
||||
getAvailableTime(end, 'end', false, start),
|
||||
]
|
||||
}
|
||||
|
||||
const { getAvailableHours, getAvailableMinutes, getAvailableSeconds } =
|
||||
getAvailableArrs(disabledHours_, disabledMinutes_, disabledSeconds_)
|
||||
|
||||
const {
|
||||
timePickerOptions,
|
||||
|
||||
getAvailableTime,
|
||||
onSetOption,
|
||||
} = useTimePanel({
|
||||
getAvailableHours,
|
||||
getAvailableMinutes,
|
||||
getAvailableSeconds,
|
||||
})
|
||||
|
||||
const parseUserInput = (days: Dayjs[] | Dayjs) => {
|
||||
if (!days) return null
|
||||
if (isArray(days)) {
|
||||
return days.map((d) => dayjs(d, props.format).locale(lang.value))
|
||||
}
|
||||
return dayjs(days, props.format).locale(lang.value)
|
||||
}
|
||||
|
||||
const formatToString = (days: Dayjs[] | Dayjs) => {
|
||||
if (!days) return null
|
||||
if (isArray(days)) {
|
||||
return days.map((d) => d.format(props.format))
|
||||
}
|
||||
return days.format(props.format)
|
||||
}
|
||||
|
||||
const getDefaultValue = () => {
|
||||
if (isArray(defaultValue)) {
|
||||
return defaultValue.map((d: Date) => dayjs(d).locale(lang.value))
|
||||
}
|
||||
const defaultDay = dayjs(defaultValue).locale(lang.value)
|
||||
return [defaultDay, defaultDay.add(60, 'm')]
|
||||
}
|
||||
|
||||
emit('set-picker-option', ['formatToString', formatToString])
|
||||
emit('set-picker-option', ['parseUserInput', parseUserInput])
|
||||
emit('set-picker-option', ['isValidValue', isValidValue])
|
||||
emit('set-picker-option', ['handleKeydownInput', handleKeydown])
|
||||
emit('set-picker-option', ['getDefaultValue', getDefaultValue])
|
||||
emit('set-picker-option', ['getRangeAvailableTime', getRangeAvailableTime])
|
||||
</script>
|
||||
|
Loading…
Reference in New Issue
Block a user