feat(date-picker): type prop supports 'quarterrange' and 'yearrange'

This commit is contained in:
07akioni 2022-06-27 02:21:39 +08:00
parent 53f86e7c39
commit 3ed7118ca0
14 changed files with 187 additions and 32 deletions

View File

@ -10,6 +10,12 @@
- Fix `n-select` will remove select value in multiple mode in `form` if Enter key is pressed in input element. Closes [#3169](https://github.com/TuSimple/naive-ui/issues/3169).
- Fix `n-select`'s filter prop not working, closes [#3175](https://github.com/TuSimple/naive-ui/issues/3175).
### Feats
### Feats
- `n-date-picker`'s `type` prop supports `'quarterrange'` and `'yearrange'`.
## 2.30.6
### Fixes

View File

@ -10,6 +10,10 @@
- 修复 `n-select``form` 中,多选的情况下,在 input 元素中按下 Enter 键会导致选项被清除,关闭 [#3169](https://github.com/TuSimple/naive-ui/issues/3169)
- 修复 `n-select``filter` 属性不生效,关闭 [#3175](https://github.com/TuSimple/naive-ui/issues/3175)
### Feats
- `n-date-picker` `type` 属性支持 `'quarterrange'``'yearrange'`
## 2.30.6
### Fixes

View File

@ -13,7 +13,9 @@ datetimerange.vue
month.vue
monthrange.vue
year.vue
yearrange.vue
quarter.vue
quarterrange.vue
size.vue
default-time.vue
disabled.vue
@ -134,7 +136,7 @@ panel.vue
| on-update:formatted-value | `(value: string \| null, timestampValue: number \| null) => void` | `undefined` | Formatted value changed callback. | 2.24.0 |
| on-update:value | `(value: number \| null, formattedValue: string \| null) => void` | `undefined` | Value changed callback. | `formattedValue` 2.24.0 |
### MonthRange Type Props
### MonthRange, QuarterRange, YearRange Type Props
| Name | Type | Default | Description | Version |
| --- | --- | --- | --- | --- |

View File

@ -0,0 +1,20 @@
<markdown>
# 季度范围
</markdown>
<template>
<n-date-picker v-model:value="timestamp" type="quarterrange" clearable />
<pre>{{ JSON.stringify(timestamp) }}</pre>
</template>
<script lang="ts">
import { defineComponent, ref } from 'vue'
export default defineComponent({
setup () {
return {
timestamp: ref<[number, number]>([1183135260000, Date.now()])
}
}
})
</script>

View File

@ -0,0 +1,20 @@
<markdown>
# 年份范围
</markdown>
<template>
<n-date-picker v-model:value="timestamp" type="yearrange" clearable />
<pre>{{ JSON.stringify(timestamp) }}</pre>
</template>
<script lang="ts">
import { defineComponent, ref } from 'vue'
export default defineComponent({
setup () {
return {
timestamp: ref<[number, number]>([1183135260000, Date.now()])
}
}
})
</script>

View File

@ -13,7 +13,9 @@ datetimerange.vue
month.vue
monthrange.vue
year.vue
yearrange.vue
quarter.vue
quarterrange.vue
size.vue
default-time.vue
disabled.vue
@ -133,7 +135,7 @@ panel-debug.vue
| on-update:formatted-value | `(value: string \| null, timestampValue: number \| null) => void` | `undefined` | 可控数据更新时触发的回调函数 | 2.24.0 |
| on-update:value | `(value: number \| null, formattedValue: string \| null) => void` | `undefined` | 可控数据更新时触发的回调函数 | `formattedValue` 2.24.0 |
### MonthRange 类型的 Props
### MonthRange、QuarterRange、YearRange 类型的 Props
| 名称 | 类型 | 默认值 | 说明 | 版本 |
| --- | --- | --- | --- | --- |

View File

@ -0,0 +1,20 @@
<markdown>
# 季度范围
</markdown>
<template>
<n-date-picker v-model:value="timestamp" type="quarterrange" clearable />
<pre>{{ JSON.stringify(timestamp) }}</pre>
</template>
<script lang="ts">
import { defineComponent, ref } from 'vue'
export default defineComponent({
setup () {
return {
timestamp: ref<[number, number]>([1183135260000, Date.now()])
}
}
})
</script>

View File

@ -0,0 +1,20 @@
<markdown>
# 年份范围
</markdown>
<template>
<n-date-picker v-model:value="timestamp" type="yearrange" clearable />
<pre>{{ JSON.stringify(timestamp) }}</pre>
</template>
<script lang="ts">
import { defineComponent, ref } from 'vue'
export default defineComponent({
setup () {
return {
timestamp: ref<[number, number]>([1183135260000, Date.now()])
}
}
})
</script>

View File

@ -206,11 +206,13 @@ export default defineComponent({
case 'datetimerange':
return localeRef.value.dateTimeFormat
case 'year':
case 'yearrange':
return localeRef.value.yearTypeFormat
case 'month':
case 'monthrange':
return localeRef.value.monthTypeFormat
case 'quarter':
case 'quarterrange':
return localeRef.value.quarterFormat
}
})
@ -287,7 +289,13 @@ export default defineComponent({
)
})
const isRangeRef = computed(() => {
return ['daterange', 'datetimerange', 'monthrange'].includes(props.type)
return [
'daterange',
'datetimerange',
'monthrange',
'quarterrange',
'yearrange'
].includes(props.type)
})
const localizedPlacehoderRef = computed(() => {
const { placeholder } = props
@ -978,11 +986,13 @@ export default defineComponent({
/>
) : type === 'month' || type === 'year' || type === 'quarter' ? (
<MonthPanel {...commonPanelProps} type={type} key={type} />
) : type === 'monthrange' ? (
) : type === 'monthrange' ||
type === 'yearrange' ||
type === 'quarterrange' ? (
<MonthRangePanel {...commonPanelProps} type={type} />
) : (
) : (
<DatePanel {...commonPanelProps} />
)
)
}
if (this.panel) {
return renderPanel()

View File

@ -11,3 +11,5 @@ export type DatePickerType =
| 'year'
| 'quarter'
| 'monthrange'
| 'quarterrange'
| 'yearrange'

View File

@ -11,7 +11,7 @@ import { VirtualList } from 'vueuc'
import { NxButton } from '../../../button'
import { NBaseFocusDetector, NScrollbar } from '../../../_internal'
import { warnOnce } from '../../../_utils'
import type { MonthItem, YearItem } from '../utils'
import type { MonthItem, QuarterItem, YearItem } from '../utils'
import { MONTH_ITEM_HEIGHT } from '../config'
import { useDualCalendar, useDualCalendarProps } from './use-dual-calendar'
@ -20,7 +20,7 @@ export default defineComponent({
props: {
...useDualCalendarProps,
type: {
type: String as PropType<'monthrange'>,
type: String as PropType<'monthrange' | 'yearrange' | 'quarterrange'>,
required: true
}
},
@ -39,7 +39,7 @@ export default defineComponent({
}
const useCalendarRef = useDualCalendar(props, props.type)
const renderItem = (
item: YearItem | MonthItem,
item: YearItem | MonthItem | QuarterItem,
i: number,
mergedClsPrefix: string,
type: 'start' | 'end'
@ -72,7 +72,9 @@ export default defineComponent({
>
{item.type === 'month'
? item.dateObject.month + 1
: item.dateObject.year}
: item.type === 'quarter'
? item.dateObject.quarter
: item.dateObject.year}
</div>
)
}
@ -137,7 +139,7 @@ export default defineComponent({
)
}}
</NScrollbar>
{type === 'monthrange' ? (
{type === 'monthrange' || type === 'quarterrange' ? (
<div
class={`${mergedClsPrefix}-date-panel-month-calendar__picker-col`}
>
@ -148,12 +150,17 @@ export default defineComponent({
>
{{
default: () => [
this.startMonthArray.map((monthItem, i) =>
renderItem(monthItem, i, mergedClsPrefix, 'start')
(type === 'monthrange'
? this.startMonthArray
: this.startQuarterArray
).map((item, i) =>
renderItem(item, i, mergedClsPrefix, 'start')
),
<div
class={`${mergedClsPrefix}-date-panel-month-calendar__padding`}
/>
type === 'monthrange' && (
<div
class={`${mergedClsPrefix}-date-panel-month-calendar__padding`}
/>
)
]
}}
</NScrollbar>
@ -203,7 +210,7 @@ export default defineComponent({
)
}}
</NScrollbar>
{type === 'monthrange' ? (
{type === 'monthrange' || type === 'quarterrange' ? (
<div
class={`${mergedClsPrefix}-date-panel-month-calendar__picker-col`}
>
@ -214,12 +221,17 @@ export default defineComponent({
>
{{
default: () => [
this.endMonthArray.map((monthItem, i) =>
renderItem(monthItem, i, mergedClsPrefix, 'end')
(type === 'monthrange'
? this.endMonthArray
: this.endQuarterArray
).map((item, i) =>
renderItem(item, i, mergedClsPrefix, 'end')
),
<div
class={`${mergedClsPrefix}-date-panel-month-calendar__padding`}
/>
type === 'monthrange' && (
<div
class={`${mergedClsPrefix}-date-panel-month-calendar__padding`}
/>
)
]
}}
</NScrollbar>

View File

@ -10,7 +10,8 @@ import {
startOfDay,
set,
getDate,
getTime
getTime,
startOfQuarter
} from 'date-fns/esm'
import { VirtualListInst } from 'vueuc'
import {
@ -22,7 +23,9 @@ import {
yearArray,
monthArray,
getDefaultTime,
pluckValueFromRange
pluckValueFromRange,
QuarterItem,
quarterArray
} from '../utils'
import { usePanelCommon, usePanelCommonProps } from './use-panel-common'
import {
@ -47,7 +50,12 @@ const useDualCalendarProps = {
// eslint-disable-next-line @typescript-eslint/explicit-function-return-type
function useDualCalendar (
props: ExtractPropTypes<typeof useDualCalendarProps>,
type: 'daterange' | 'datetimerange' | 'monthrange'
type:
| 'daterange'
| 'datetimerange'
| 'monthrange'
| 'quarterrange'
| 'yearrange'
) {
const {
isDateDisabledRef,
@ -217,6 +225,14 @@ function useDualCalendar (
const endYearArrayRef = computed(() => {
return yearArray(pluckValueFromRange(props.value, 'end'), nowRef.value)
})
const startQuarterArrayRef = computed(() => {
const startValue = pluckValueFromRange(props.value, 'start')
return quarterArray(startValue ?? Date.now(), startValue, nowRef.value)
})
const endQuarterArrayRef = computed(() => {
const endValue = pluckValueFromRange(props.value, 'end')
return quarterArray(endValue ?? Date.now(), endValue, nowRef.value)
})
const startMonthArrayRef = computed(() => {
const startValue = pluckValueFromRange(props.value, 'start')
return monthArray(startValue ?? Date.now(), startValue, nowRef.value)
@ -711,17 +727,27 @@ function useDualCalendar (
}
// only for monthrange
function handleColItemClick (
dateItem: MonthItem | YearItem,
dateItem: MonthItem | QuarterItem | YearItem,
clickType: 'start' | 'end'
): void {
const { value } = props
const noCurrentValue = !Array.isArray(value)
const itemTs =
dateItem.type === 'year'
dateItem.type === 'year' && type !== 'yearrange'
? noCurrentValue
? set(dateItem.ts, { month: getMonth(new Date()) }).valueOf()
? set(dateItem.ts, {
month: getMonth(
type === 'quarterrange'
? startOfQuarter(new Date())
: new Date()
)
}).valueOf()
: set(dateItem.ts, {
month: getMonth(value[clickType === 'start' ? 0 : 1])
month: getMonth(
type === 'quarterrange'
? startOfQuarter(value[clickType === 'start' ? 0 : 1])
: value[clickType === 'start' ? 0 : 1]
)
}).valueOf()
: dateItem.ts
if (noCurrentValue) {
@ -750,6 +776,7 @@ function useDualCalendar (
panelCommon.doUpdateValue(nextValue, props.panel)
switch (type) {
case 'monthrange':
case 'quarterrange':
panelCommon.disableTransitionOneTick()
if (otherPartsChanged) {
justifyColumnsScrollState(nextValue, 'start')
@ -758,6 +785,10 @@ function useDualCalendar (
justifyColumnsScrollState(nextValue, clickType)
}
break
case 'yearrange':
panelCommon.disableTransitionOneTick()
justifyColumnsScrollState(nextValue, 'start')
justifyColumnsScrollState(nextValue, 'end')
}
}
function handleStartYearVlScroll (): void {
@ -816,8 +847,10 @@ function useDualCalendar (
endDateArray: endDateArrayRef,
startYearArray: startYearArrayRef,
startMonthArray: startMonthArrayRef,
startQuarterArray: startQuarterArrayRef,
endYearArray: endYearArrayRef,
endMonthArray: endMonthArrayRef,
endQuarterArray: endQuarterArrayRef,
isSelecting: isSelectingRef,
handleRangeShortcutMouseenter,
handleRangeShortcutClick,

View File

@ -267,12 +267,12 @@ function monthArray (
}
function quarterArray (
quarterTs: number,
yearAnchorTs: number,
valueTs: number | null,
currentTs: number
): QuarterItem[] {
const calendarQuarters: QuarterItem[] = []
const yearStart = startOfYear(quarterTs)
const yearStart = startOfYear(yearAnchorTs)
for (let i = 0; i < 4; i++) {
calendarQuarters.push(
quarterItem(getTime(addQuarters(yearStart, i)), valueTs, currentTs)

View File

@ -21,6 +21,8 @@ export default {
calendarLeftPaddingYear: '0',
calendarLeftPaddingQuarter: '0',
calendarLeftPaddingMonthrange: '0',
calendarLeftPaddingQuarterrange: '0',
calendarLeftPaddingYearrange: '0',
calendarRightPaddingDate: '6px 12px 4px 12px',
calendarRightPaddingDatetime: '4px 12px',
calendarRightPaddingDaterange: '6px 12px 4px 12px',
@ -28,5 +30,7 @@ export default {
calendarRightPaddingMonth: '0',
calendarRightPaddingYear: '0',
calendarRightPaddingQuarter: '0',
calendarRightPaddingMonthrange: '0'
calendarRightPaddingMonthrange: '0',
calendarRightPaddingQuarterrange: '0',
calendarRightPaddingYearrange: '0'
}