Skip to content

Commit

Permalink
feat(time-picker): props.presets预设快捷时间选择 (#3665)
Browse files Browse the repository at this point in the history
* feat(time-picker): props.presets实现

* fix: 类型错误

* fix: presets ts类型

* fix: ts类型报错

* docs: 预设快捷时间选择示例

* feat: 代码调整

* feat: 代码调整

* feat: 代码调整

* feat: 代码调整

* feat: 代码调整
  • Loading branch information
liweijie0812 authored Dec 4, 2023
1 parent 0055e2b commit 9d1c104
Show file tree
Hide file tree
Showing 11 changed files with 278 additions and 52 deletions.
26 changes: 26 additions & 0 deletions src/time-picker/_example/presets.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<template>
<t-space direction="vertical">
<t-time-picker v-model="time1" class="demos" :presets="{ 上午十一点: '11:00:00' }" />
<t-time-range-picker
v-model="time2"
class="demos"
clearable
format="HH:mm:ss"
allow-input
:presets="{ 下午: ['13:00:00', '18:00:00'] }"
/>
</t-space>
</template>

<script setup>
import { ref } from 'vue';
const time1 = ref('20:22');
const time2 = ref(['00:00:00', '23:59:59']);
</script>

<style scoped>
.demos {
margin-top: 20px;
}
</style>
7 changes: 7 additions & 0 deletions src/time-picker/panel/props.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import dayjs from 'dayjs';

import * as Props from '../props';
import { EPickerCols } from '../../_common/js/time-picker/const';
import { TdTimePickerProps, TdTimeRangePickerProps } from '../type';

// 布尔类型
const BooleanType = {
Expand Down Expand Up @@ -47,6 +48,12 @@ export const panelProps = () => ({
default: true,
},
},
activeIndex: {
type: Number,
},
presets: {
type: Object as PropType<TdTimePickerProps['presets'] | TdTimeRangePickerProps['presets']>,
},
hideDisabledTime: {
...Props.default.hideDisabledTime,
},
Expand Down
30 changes: 14 additions & 16 deletions src/time-picker/panel/single-panel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import {
MERIDIEM_LIST,
} from '../../_common/js/time-picker/const';
import { closestLookup } from '../../_common/js/time-picker/utils';
import { useConfig } from '../../hooks/useConfig';
import { useCommonClassName, useConfig, usePrefixClass } from '../../hooks/useConfig';

dayjs.extend(customParseFormat);

Expand All @@ -38,11 +38,11 @@ export default defineComponent({
},

setup(props) {
const { steps, value, format, position, triggerScroll } = toRefs(props);

const { globalConfig } = useConfig('timePicker');
const COMPONENT_NAME = usePrefixClass('time-picker__panel');
const { STATUS } = useCommonClassName();

const { classPrefix } = useConfig();
const { steps, value, format, position, triggerScroll } = toRefs(props);

const cols = ref<Array<EPickerCols>>([]);
const bodyRef = ref();
Expand All @@ -51,7 +51,7 @@ export default defineComponent({
const colsRef = reactive({ 0: null, 1: null, 2: null, 3: null, 4: null, 5: null });

const dayjsValue = computed(() => {
const isStepsSet = !!steps.value.filter((v) => v > 1).length;
const isStepsSet = !!steps.value.filter((step) => Number(step) > 1).length;

if (value.value) return dayjs(value.value, format.value);

Expand All @@ -60,8 +60,6 @@ export default defineComponent({
return dayjs();
});

const panelClassName = computed(() => `${classPrefix.value}-time-picker__panel`);

// 面板打开时 触发滚动 初始化面板
watch(
() => dayjsValue.value,
Expand Down Expand Up @@ -271,17 +269,17 @@ export default defineComponent({
} else {
const currentHour = dayjsValue.value.hour();
if (el === AM && currentHour >= 12) {
props.onChange(dayjsValue.value.hour(currentHour - 12).format(format.value), e);
props.onChange?.(dayjsValue.value.hour(currentHour - 12).format(format.value), e);
} else if (el === PM && currentHour < 12) {
props.onChange(dayjsValue.value.hour(currentHour + 12).format(format.value), e);
props.onChange?.(dayjsValue.value.hour(currentHour + 12).format(format.value), e);
}
}
};

// update each columns scroll distance
const updateTimeScrollPos = (isAutoScroll = false) => {
const behavior = value.value && !isAutoScroll ? 'smooth' : 'auto';
const isStepsSet = !!steps.value.filter((v) => v > 1).length;
const isStepsSet = !!steps.value.filter((step) => Number(step) > 1).length;
nextTick(() => {
cols.value.forEach((col: EPickerCols, idx: number) => {
if (!isStepsSet || (isStepsSet && value.value)) {
Expand Down Expand Up @@ -316,8 +314,8 @@ export default defineComponent({
};

return () => (
<div class={`${panelClassName.value}-body`} ref={bodyRef}>
<div class={`${panelClassName.value}-body-active-mask`} ref={maskRef}>
<div class={`${COMPONENT_NAME.value}-body`} ref={bodyRef}>
<div class={`${COMPONENT_NAME.value}-body-active-mask`} ref={maskRef}>
{/* 渲染遮罩层 */}
{cols.value.map?.((col, idx) => (
<div key={`${col}_${idx}`} />
Expand All @@ -328,17 +326,17 @@ export default defineComponent({
<ul
key={`${col}_${idx}`}
ref={(el) => (colsRef[idx] = el)}
class={`${panelClassName.value}-body-scroll`}
class={`${COMPONENT_NAME.value}-body-scroll`}
onScroll={debounce((e) => handleScroll(col, idx, e), 50)}
>
{getColList(col).map((el) => (
<li
key={el}
class={[
`${panelClassName.value}-body-scroll-item`,
`${COMPONENT_NAME.value}-body-scroll-item`,
{
[`${classPrefix.value}-is-disabled`]: !timeItemCanUsed(col, el),
[`${classPrefix.value}-is-current`]: isCurrent(col, el),
[STATUS.value.disabled]: !timeItemCanUsed(col, el),
[STATUS.value.current]: isCurrent(col, el),
},
]}
onClick={(e) => handleTimeItemClick(col, el, idx, e)}
Expand Down
44 changes: 36 additions & 8 deletions src/time-picker/panel/time-picker-panel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import { panelProps } from './props';
import SinglePanel from './single-panel';
import TButton from '../../button/button';
import { useConfig, usePrefixClass } from '../../hooks/useConfig';
import { TimePickerValue, TimeRangeValue } from '../type';
import log from '../../_common/js/log';

dayjs.extend(customParseFormat);

Expand All @@ -21,12 +23,12 @@ export default defineComponent({
},

setup(props) {
const panelClassName = usePrefixClass('time-picker__panel');
const { globalConfig } = useConfig('timePicker');
const COMPONENT_NAME = usePrefixClass('time-picker__panel');
const { steps, isFooterDisplay, isShowPanel } = toRefs(props);
const triggerScroll = ref(false);
const panelRef = ref();
const { globalConfig } = useConfig('timePicker');
const showNowTimeBtn = computed(() => !!steps.value.filter((v) => v > 1).length);
const showNowTimeBtn = computed(() => !!steps.value.filter((step) => Number(step) > 1).length);

const defaultValue = computed(() => {
const isStepsSet = showNowTimeBtn.value;
Expand All @@ -50,6 +52,20 @@ export default defineComponent({
const resetTriggerScroll = () => {
triggerScroll.value = false;
};
const handlePresetClick = (
presetValue: TimePickerValue | (() => TimePickerValue) | TimeRangeValue | (() => TimeRangeValue),
) => {
const presetVal = typeof presetValue === 'function' ? presetValue() : presetValue;
if (typeof props.activeIndex === 'number') {
if (Array.isArray(presetVal)) {
props.onChange?.(presetVal[props.activeIndex]);
} else {
log.error('TimePicker', `preset: ${props.presets} 预设值必须是数组!`);
}
} else {
props.onChange?.(presetVal);
}
};

// 渲染后执行update 使面板滚动至当前时间位置
onMounted(() => {
Expand All @@ -64,8 +80,8 @@ export default defineComponent({
);

return () => (
<div class={panelClassName.value}>
<div class={`${panelClassName.value}-section-body`}>
<div class={COMPONENT_NAME.value}>
<div class={`${COMPONENT_NAME.value}-section-body`}>
<SinglePanel
{...props}
ref={panelRef}
Expand All @@ -79,12 +95,12 @@ export default defineComponent({
/>
</div>
{isFooterDisplay.value ? (
<div class={`${panelClassName.value}-section-footer`}>
<div class={`${COMPONENT_NAME.value}-section-footer`}>
<TButton
theme="primary"
variant="base"
disabled={!props.value}
onClick={() => props.handleConfirmClick(defaultValue.value)}
onClick={() => props.handleConfirmClick?.(defaultValue.value)}
size="small"
>
{globalConfig.value.confirm}
Expand All @@ -94,11 +110,23 @@ export default defineComponent({
theme="primary"
variant="text"
size="small"
onClick={() => props.onChange(dayjs().format(props.format))}
onClick={() => props.onChange?.(dayjs().format(props.format))}
>
{globalConfig.value.now}
</TButton>
) : null}
{props.presets &&
Object.keys(props.presets).map((key: string) => (
<TButton
key={key}
theme="primary"
size="small"
variant="text"
onClick={() => handlePresetClick(props.presets[key])}
>
{key}
</TButton>
))}
</div>
) : null}
</div>
Expand Down
8 changes: 4 additions & 4 deletions src/time-picker/time-picker.en-US.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ name | type | default | description | required
allowInput | Boolean | false | \- | N
clearable | Boolean | false | \- | N
disableTime | Function | - | disable time config function。Typescript:`(h: number, m: number, s: number, ms: number) => Partial<{ hour: Array<number>, minute: Array<number>, second: Array<number>, millisecond: Array<number> }>` | N
disabled | Boolean | false | \- | N
disabled | Boolean | - | \- | N
format | String | HH:mm:ss | \- | N
hideDisabledTime | Boolean | true | \- | N
inputProps | Object | - | Typescript:`InputProps`[Input API Documents](./input?tab=api)[see more ts definition](https://github.com/Tencent/tdesign-vue-next/tree/develop/src/time-picker/type.ts) | N
Expand All @@ -21,7 +21,7 @@ steps | Array | [1, 1, 1] | Typescript:`Array<string \| number>` | N
tips | String / Slot / Function | - | Typescript:`string \| TNode`[see more ts definition](https://github.com/Tencent/tdesign-vue-next/blob/develop/src/common.ts) | N
value | String | - | `v-model` and `v-model:value` is supported。Typescript:`TimePickerValue` `type TimePickerValue = string`[see more ts definition](https://github.com/Tencent/tdesign-vue-next/tree/develop/src/time-picker/type.ts) | N
defaultValue | String | - | uncontrolled property。Typescript:`TimePickerValue` `type TimePickerValue = string`[see more ts definition](https://github.com/Tencent/tdesign-vue-next/tree/develop/src/time-picker/type.ts) | N
onBlur | Function | | Typescript:`(context: { value: TimePickerValue; e: FocusEvent }) => void`<br/> | N
onBlur | Function | | Typescript:`(context: { value: TimePickerValue } & SelectInputBlurContext) => void`<br/>[see more ts definition](https://github.com/Tencent/tdesign-vue-next/tree/develop/src/time-picker/type.ts)。<br/>`import { SelectInputBlurContext } from '@SelectInput'`<br/> | N
onChange | Function | | Typescript:`(value: TimePickerValue) => void`<br/> | N
onClose | Function | | Typescript:`(context: { e: MouseEvent }) => void`<br/> | N
onFocus | Function | | Typescript:`(context: { value: TimePickerValue; e: FocusEvent }) => void`<br/> | N
Expand All @@ -33,7 +33,7 @@ onPick | Function | | Typescript:`(value: TimePickerValue, context: { e: Mous

name | params | description
-- | -- | --
blur | `(context: { value: TimePickerValue; e: FocusEvent })` | \-
blur | `(context: { value: TimePickerValue } & SelectInputBlurContext)` | [see more ts definition](https://github.com/Tencent/tdesign-vue-next/tree/develop/src/time-picker/type.ts)。<br/>`import { SelectInputBlurContext } from '@SelectInput'`<br/>
change | `(value: TimePickerValue)` | \-
close | `(context: { e: MouseEvent })` | \-
focus | `(context: { value: TimePickerValue; e: FocusEvent })` | \-
Expand All @@ -48,7 +48,7 @@ name | type | default | description | required
allowInput | Boolean | false | \- | N
clearable | Boolean | false | \- | N
disableTime | Function | - | Typescript:`(h: number, m: number, s: number, context: { partial: TimeRangePickerPartial }) =>Partial<{ hour: Array<number>, minute: Array<number>, second: Array<number> }>` `type TimeRangePickerPartial = 'start' \| 'end'`[see more ts definition](https://github.com/Tencent/tdesign-vue-next/tree/develop/src/time-picker/type.ts) | N
disabled | Boolean / Array | false | Typescript:`boolean \| Array<boolean>` | N
disabled | Boolean / Array | - | Typescript:`boolean \| Array<boolean>` | N
format | String | HH:mm:ss | \- | N
hideDisabledTime | Boolean | true | \- | N
placeholder | String / Array | undefined | Typescript:`string \| Array<string>` | N
Expand Down
8 changes: 4 additions & 4 deletions src/time-picker/time-picker.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
allowInput | Boolean | false | 是否允许直接输入时间 | N
clearable | Boolean | false | 是否允许清除选中值 | N
disableTime | Function | - | 禁用时间项的配置函数。TS 类型:`(h: number, m: number, s: number, ms: number) => Partial<{ hour: Array<number>, minute: Array<number>, second: Array<number>, millisecond: Array<number> }>` | N
disabled | Boolean | false | 是否禁用组件 | N
disabled | Boolean | - | 是否禁用组件 | N
format | String | HH:mm:ss | 用于格式化时间,[详细文档](https://day.js.org/docs/en/display/format) | N
hideDisabledTime | Boolean | true | 是否隐藏禁用状态的时间项 | N
inputProps | Object | - | 透传给输入框(Input)组件的参数。TS 类型:`InputProps`[Input API Documents](./input?tab=api)[详细类型定义](https://github.com/Tencent/tdesign-vue-next/tree/develop/src/time-picker/type.ts) | N
Expand All @@ -21,7 +21,7 @@ steps | Array | [1, 1, 1] | 时间间隔步数,数组排列 [小时, 分钟,
tips | String / Slot / Function | - | 输入框下方提示文本,会根据不同的 `status` 呈现不同的样式。TS 类型:`string \| TNode`[通用类型定义](https://github.com/Tencent/tdesign-vue-next/blob/develop/src/common.ts) | N
value | String | - | 选中值。支持语法糖 `v-model``v-model:value`。TS 类型:`TimePickerValue` `type TimePickerValue = string`[详细类型定义](https://github.com/Tencent/tdesign-vue-next/tree/develop/src/time-picker/type.ts) | N
defaultValue | String | - | 选中值。非受控属性。TS 类型:`TimePickerValue` `type TimePickerValue = string`[详细类型定义](https://github.com/Tencent/tdesign-vue-next/tree/develop/src/time-picker/type.ts) | N
onBlur | Function | | TS 类型:`(context: { value: TimePickerValue; e: FocusEvent }) => void`<br/>当输入框失去焦点时触发,value 表示组件当前有效值 | N
onBlur | Function | | TS 类型:`(context: { value: TimePickerValue } & SelectInputBlurContext) => void`<br/>当输入框失去焦点时触发,value 表示组件当前有效值[详细类型定义](https://github.com/Tencent/tdesign-vue-next/tree/develop/src/time-picker/type.ts)。<br/>`import { SelectInputBlurContext } from '@SelectInput'`<br/> | N
onChange | Function | | TS 类型:`(value: TimePickerValue) => void`<br/>选中值发生变化时触发 | N
onClose | Function | | TS 类型:`(context: { e: MouseEvent }) => void`<br/>面板关闭时触发 | N
onFocus | Function | | TS 类型:`(context: { value: TimePickerValue; e: FocusEvent }) => void`<br/>输入框获得焦点时触发,value 表示组件当前有效值 | N
Expand All @@ -33,7 +33,7 @@ onPick | Function | | TS 类型:`(value: TimePickerValue, context: { e: Mouse

名称 | 参数 | 描述
-- | -- | --
blur | `(context: { value: TimePickerValue; e: FocusEvent })` | 当输入框失去焦点时触发,value 表示组件当前有效值
blur | `(context: { value: TimePickerValue } & SelectInputBlurContext)` | 当输入框失去焦点时触发,value 表示组件当前有效值[详细类型定义](https://github.com/Tencent/tdesign-vue-next/tree/develop/src/time-picker/type.ts)。<br/>`import { SelectInputBlurContext } from '@SelectInput'`<br/>
change | `(value: TimePickerValue)` | 选中值发生变化时触发
close | `(context: { e: MouseEvent })` | 面板关闭时触发
focus | `(context: { value: TimePickerValue; e: FocusEvent })` | 输入框获得焦点时触发,value 表示组件当前有效值
Expand All @@ -48,7 +48,7 @@ pick | `(value: TimePickerValue, context: { e: MouseEvent })` | 面板选中值
allowInput | Boolean | false | 是否允许直接输入时间 | N
clearable | Boolean | false | 是否允许清除选中值 | N
disableTime | Function | - | 禁用时间项。TS 类型:`(h: number, m: number, s: number, context: { partial: TimeRangePickerPartial }) =>Partial<{ hour: Array<number>, minute: Array<number>, second: Array<number> }>` `type TimeRangePickerPartial = 'start' \| 'end'`[详细类型定义](https://github.com/Tencent/tdesign-vue-next/tree/develop/src/time-picker/type.ts) | N
disabled | Boolean / Array | false | 是否禁用组件,值为数组表示可分别控制开始日期和结束日期是否禁用。TS 类型:`boolean \| Array<boolean>` | N
disabled | Boolean / Array | - | 是否禁用组件,值为数组表示可分别控制开始日期和结束日期是否禁用。TS 类型:`boolean \| Array<boolean>` | N
format | String | HH:mm:ss | 用于格式化时间,[详细文档](https://day.js.org/docs/en/display/format) | N
hideDisabledTime | Boolean | true | 是否隐藏禁用状态的时间项 | N
placeholder | String / Array | undefined | 占位符,值为数组表示可分别为开始日期和结束日期设置占位符。TS 类型:`string \| Array<string>` | N
Expand Down
Loading

0 comments on commit 9d1c104

Please sign in to comment.