Skip to content

Commit

Permalink
feat(Datepicker): support multiple select
Browse files Browse the repository at this point in the history
  • Loading branch information
uyarn committed Dec 25, 2024
1 parent 34cd5bd commit 8f3b093
Show file tree
Hide file tree
Showing 4 changed files with 122 additions and 11 deletions.
66 changes: 58 additions & 8 deletions src/date-picker/DatePicker.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,14 @@ import { usePrefixClass, useConfig } from '../hooks/useConfig';
import { useDisabled } from '../hooks/useDisabled';
import useSingle from './hooks/useSingle';
import { parseToDayjs, getDefaultFormat, formatTime, formatDate } from '../_common/js/date-picker/format';
import { subtractMonth, addMonth, extractTimeObj, covertToDate } from '../_common/js/date-picker/utils';
import { subtractMonth, addMonth, extractTimeObj, covertToDate, isSame } from '../_common/js/date-picker/utils';
import props from './props';
import TSelectInput from '../select-input';
import TSinglePanel from './panel/SinglePanel';
import { useReadonly } from '../hooks/useReadonly';

import type { TdDatePickerProps } from './type';
import type { DateValue } from './type';
import type { TdDatePickerProps, PresetDate, DateMultipleValue, DateValue } from './type';
import type { TagInputRemoveContext } from '../tag-input';
import isDate from 'lodash/isDate';

export default defineComponent({
Expand Down Expand Up @@ -52,7 +52,7 @@ export default defineComponent({
mode: props.mode,
format: props.format,
valueType: props.valueType,
enableTimePicker: props.enableTimePicker,
enableTimePicker: props.multiple ? false : props.enableTimePicker,
}),
);
const valueDisplayParams = computed(() => {
Expand Down Expand Up @@ -104,8 +104,8 @@ export default defineComponent({

// 面板展开重置数据
if (visible) {
year.value = parseToDayjs(value.value, formatRef.value.valueType).year();
month.value = parseToDayjs(value.value, formatRef.value.format).month();
year.value = parseToDayjs(value.value as DateValue, formatRef.value.valueType).year();
month.value = parseToDayjs(value.value as DateValue, formatRef.value.format).month();
time.value = formatTime(value.value, formatRef.value.format, formatRef.value.timeFormat, props.defaultTime);
} else {
isHoverCell.value = false;
Expand All @@ -114,6 +114,8 @@ export default defineComponent({

// 日期 hover
function onCellMouseEnter(date: Date) {
if (props.multiple) return;

isHoverCell.value = true;
inputValue.value = formatDate(date, {
format: formatRef.value.format,
Expand All @@ -122,6 +124,8 @@ export default defineComponent({

// 日期 leave
function onCellMouseLeave() {
if (props.multiple) return;

isHoverCell.value = false;
inputValue.value = formatDate(cacheValue.value, {
format: formatRef.value.format,
Expand All @@ -141,6 +145,15 @@ export default defineComponent({
format: formatRef.value.format,
});
} else {
if (props.multiple) {
const newDate = processDate(date);
onChange(newDate, {
dayjsValue: parseToDayjs(date, format),
trigger: 'pick',
});
return;
}

onChange?.(
formatDate(date, {
format: formatRef.value.format,
Expand All @@ -157,6 +170,38 @@ export default defineComponent({
props.onPick?.(date);
}

function processDate(date: Date) {
const isSameDate = (value.value as DateMultipleValue).some((val) => isSame(dayjs(val).toDate(), date));
let currentDate: DateMultipleValue;

if (!isSameDate) {
currentDate = (value.value as DateMultipleValue).concat(formatDate(date, { format, targetFormat: valueType }));
} else {
currentDate = (value.value as DateMultipleValue).filter(
(val) =>
formatDate(val, { format, targetFormat: valueType }) !==
formatDate(date, { format, targetFormat: valueType }),
);
}

return currentDate.sort((a, b) => dayjs(a).valueOf() - dayjs(b).valueOf());
}

const onTagRemoveClick = (ctx: TagInputRemoveContext) => {
const removeDate = dayjs(ctx.item).toDate();
const newDate = processDate(removeDate);
onChange?.(newDate, {
dayjsValue: parseToDayjs(removeDate, format),
trigger: 'pick',
});
};

const onTagClearClick = ({ e }) => {
e.stopPropagation();
setPopupVisible(false);
onChange([], { dayjsValue: dayjs(), trigger: 'clear' });
};

// 头部快速切换
function onJumperClick({ trigger }: { trigger: string }) {
const monthCountMap = { date: 1, week: 1, month: 12, quarter: 12, year: 120 };
Expand Down Expand Up @@ -264,11 +309,11 @@ export default defineComponent({
format: formatRef.value.format,
mode: props.mode,
presets: props.presets,
time: time.value as string,
time: props.multiple ? false : time.value,
disableDate: props.disableDate,
firstDayOfWeek: props.firstDayOfWeek,
timePickerProps: props.timePickerProps,
enableTimePicker: props.enableTimePicker,
enableTimePicker: props.multiple ? false : props.enableTimePicker,
presetsPlacement: props.presetsPlacement,
popupVisible: popupVisible.value,
needConfirm: props.needConfirm,
Expand All @@ -294,6 +339,7 @@ export default defineComponent({
status={props.status}
tips={props.tips}
clearable={props.clearable}
multiple={props.multiple}
popupProps={popupProps.value}
inputProps={inputProps.value}
placeholder={props.placeholder || globalConfig.value.placeholder[props.mode]}
Expand All @@ -302,6 +348,10 @@ export default defineComponent({
needConfirm={props.needConfirm}
{...(props.selectInputProps as TdDatePickerProps['selectInputProps'])}
panel={() => <TSinglePanel {...panelProps.value} />}
tagInputProps={{
onRemove: onTagRemoveClick,
}}
onClear={onTagClearClick}
/>
</div>
);
Expand Down
31 changes: 31 additions & 0 deletions src/date-picker/_example-ts/multiple.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<template>
<t-space direction="vertical">
<t-date-picker v-model="date2" @change="handleChange" />
<t-date-picker
v-model="date"
placeholder="可清除、可输入的日期选择器"
clearable
allow-input
@change="handleChange"
/>
</t-space>
</template>

<script lang="ts" setup>
import { Dayjs } from 'dayjs';
import { ref } from 'vue';
import { DateValue, DatePickerTriggerSource } from 'tdesign-vue-next';
const date = ref('');
const date2 = ref('');
function handleChange(
value: DateValue,
context: {
dayjsValue?: Dayjs;
trigger?: DatePickerTriggerSource;
},
) {
console.log('onChange:', value, context);
console.log('timestamp:', context.dayjsValue.valueOf());
console.log('YYYYMMDD:', context.dayjsValue.format('YYYYMMDD'));
}
</script>
25 changes: 25 additions & 0 deletions src/date-picker/_example/multiple.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<template>
<t-space direction="vertical">
<t-date-picker v-model="date2" @change="handleChange" />
<t-date-picker
v-model="date"
placeholder="可清除、可输入的日期选择器"
clearable
allow-input
@change="handleChange"
/>
</t-space>
</template>

<script setup>
import { ref } from 'vue';
const date = ref('');
const date2 = ref('');
function handleChange(value, context) {
console.log('onChange:', value, context);
console.log('timestamp:', context.dayjsValue.valueOf());
console.log('YYYYMMDD:', context.dayjsValue.format('YYYYMMDD'));
}
</script>
11 changes: 8 additions & 3 deletions src/date-picker/base/Table.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
import { defineComponent, PropType, computed } from 'vue';
import dayjs from 'dayjs';
import isoWeek from 'dayjs/plugin/isoWeek';
import TDatePickerCell from './Cell';
import { useConfig, usePrefixClass } from '../../hooks/useConfig';
import type { TdDatePickerProps } from '../type';
import { parseToDayjs } from '../../_common/js/date-picker/format';
import isArray from 'lodash/isArray';

dayjs.extend(isoWeek);

export default defineComponent({
name: 'TDatePickerTable',
props: {
Expand Down Expand Up @@ -55,12 +59,13 @@ export default defineComponent({
const endWeek = endObj?.locale?.(dayjsLocale)?.week?.();

const targetObj = parseToDayjs(targetValue, format);
const targetYear = targetObj.year();
const targetWeek = targetObj.week();
const targetYear = targetObj.isoWeekYear();
const targetWeek = targetObj.isoWeek();
const isActive =
(targetYear === startYear && targetWeek === startWeek) || (targetYear === endYear && targetWeek === endWeek);
const isRange =
targetYear >= startYear && targetYear <= endYear && targetWeek > startWeek && targetWeek < endWeek;
(targetYear > startYear || (targetYear === startYear && targetWeek > startWeek)) &&
(targetYear < endYear || (targetYear === endYear && targetWeek < endWeek));
return {
// 同年同周
[`${COMPONENT_NAME.value}-${props.mode}-row--active`]: isActive,
Expand Down

0 comments on commit 8f3b093

Please sign in to comment.