123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309 |
- <template>
- <div
- :class="[n('')]"
- @mouseup.stop
- >
- <div :class="[n('body')]">
- <div :class="[n('body-header')]">
- <div :class="[n('body-header-prev')]">
- <div
- v-if="canYearLess"
- :class="[n('icon')]"
- @click="change('year', -1)"
- >
- <Icon
- :file="dLeftArrowIcon"
- :width="'12px'"
- :height="'12px'"
- />
- </div>
- <div
- v-if="canMonthLess"
- :class="[n('icon')]"
- @click="change('month', -1)"
- >
- <Icon
- :file="leftArrowIcon"
- :width="'10px'"
- :height="'10px'"
- />
- </div>
- </div>
- <div :class="[n('body-header-label')]">
- <div :class="[n('body-header-label-item')]">
- {{ year }}
- </div>
- <div :class="[n('body-header-label-item')]">
- {{ TUITranslateService.t(`time.${month}`) }}
- </div>
- </div>
- <div :class="[n('body-header-next')]">
- <div
- v-if="canMonthMore"
- :class="[n('icon')]"
- @click="change('month', 1)"
- >
- <Icon
- :file="rightArrowIcon"
- :width="'10px'"
- :height="'10px'"
- />
- </div>
- <div
- v-if="canYearMore"
- :class="[n('icon')]"
- @click="change('year', 1)"
- >
- <Icon
- :file="dRightArrowIcon"
- :width="'12px'"
- :height="'12px'"
- />
- </div>
- </div>
- </div>
- <div :class="[n('body-content')]">
- <DateTable
- :type="props.type"
- :date="props.date"
- :startDate="props.startDate"
- :endDate="props.endDate"
- :currentPanelDate="currentPanelDate"
- @pick="handlePick"
- />
- </div>
- </div>
- </div>
- </template>
- <script lang="ts" setup>
- import { computed, ref, onBeforeMount } from '../../../adapter-vue';
- import dayjs, { Dayjs, ManipulateType } from 'dayjs';
- import { TUITranslateService } from '@tencentcloud/chat-uikit-engine';
- import { DateCell } from './date-picker';
- import DateTable from './date-table.vue';
- import Icon from '../Icon.vue';
- import leftArrowIcon from '../../../assets/icon/left-arrow.svg';
- import rightArrowIcon from '../../../assets/icon/right-arrow.svg';
- import dLeftArrowIcon from '../../../assets/icon/d-left-arrow.svg';
- import dRightArrowIcon from '../../../assets/icon/d-right-arrow.svg';
- import { isPC } from '../../../utils/env';
- const props = defineProps({
- type: {
- type: String,
- default: 'range', // "single"/"range"
- },
- // Unique attribute when type is single
- date: {
- type: Dayjs,
- default: () => dayjs(),
- },
- // Unique attribute when type is range
- startDate: {
- type: Dayjs,
- default: null,
- },
- endDate: {
- type: Dayjs,
- default: null,
- },
- rangeType: {
- type: String,
- default: '', // "left"/"right"
- },
- currentOtherPanelValue: {
- type: Dayjs,
- default: null,
- },
- });
- const emit = defineEmits(['pick', 'change']);
- const n = (className: string) => {
- return className
- ? [
- 'tui-date-picker-panel-' + className,
- !isPC && 'tui-date-picker-panel-h5-' + className,
- ]
- : ['tui-date-picker-panel', !isPC && 'tui-date-picker-panel-h5'];
- };
- const currentPanelDate = ref<typeof Dayjs>();
- const year = computed(() => currentPanelDate.value?.get('year'));
- const month = computed(() => currentPanelDate.value?.format('MMMM'));
- const canYearMore = computed(() => {
- const prevYearNumber = props.currentOtherPanelValue?.year() - 1;
- const prevYear = props.currentOtherPanelValue?.year(prevYearNumber);
- return (
- props.rangeType === 'right'
- || currentPanelDate.value?.isBefore(prevYear, 'year')
- );
- });
- const canMonthMore = computed(() => {
- const prevMonthNumber = props.currentOtherPanelValue?.month() - 1;
- const prevMonth = props.currentOtherPanelValue?.month(prevMonthNumber);
- return (
- props.rangeType === 'right'
- || currentPanelDate.value?.isBefore(prevMonth, 'month')
- );
- });
- const canYearLess = computed(() => {
- const nextYearNumber = props.currentOtherPanelValue?.year() + 1;
- const nextYear = props.currentOtherPanelValue?.year(nextYearNumber);
- return (
- props.rangeType === 'left'
- || currentPanelDate.value?.isAfter(nextYear, 'year')
- );
- });
- const canMonthLess = computed(() => {
- const nextMonthNumber = props.currentOtherPanelValue?.month() + 1;
- const nextMonth = props.currentOtherPanelValue?.month(nextMonthNumber);
- return (
- props.rangeType === 'left'
- || currentPanelDate.value?.isAfter(nextMonth, 'month')
- );
- });
- // Range judgment:
- // Premise: If there is only one, it must be the start.
- // If there is a startDate:
- // When the left side of the interface first displays the month/year of the startDate.
- // If there is both a startDate and an endDate:
- // If they are in the same month:
- // Both are displayed on the left, and the next month is displayed on the right.
- // If they are not in the same month:
- // The start is displayed on the left, and the end is displayed on the right.
- // That is, to determine whether the start and end are in the same month.
- // If neither is present, the left displays the current month, and the right displays the next month.
- const handleSingleDate = (): { date: typeof Dayjs } => {
- if (props.date && dayjs(props.date)?.isValid()) {
- // props.date year and month
- return {
- date: props?.date,
- };
- }
- // nowadays year and month
- return {
- date: dayjs(),
- };
- };
- const handleRangeDate = (): { date: typeof Dayjs } => {
- switch (props.rangeType) {
- case 'left':
- if (props.startDate && dayjs.isDayjs(props.startDate)) {
- return {
- date: props?.startDate,
- };
- } else {
- return {
- date: dayjs(),
- };
- }
- case 'right':
- if (
- props.endDate
- && dayjs.isDayjs(props.endDate)
- && props?.endDate?.isAfter(props.startDate, 'month')
- ) {
- return {
- date: props?.endDate,
- };
- } else {
- const _month = (props.startDate || dayjs()).month();
- return {
- date: (props.startDate || dayjs()).month(_month + 1),
- };
- }
- default:
- return {
- date: dayjs(),
- };
- }
- };
- function handlePick(cell: DateCell) {
- emit('pick', cell);
- }
- function change(type: typeof ManipulateType, num: number) {
- currentPanelDate.value = dayjs(currentPanelDate.value.toDate()).add(
- num,
- type,
- );
- emit('change', currentPanelDate.value);
- }
- onBeforeMount(() => {
- switch (props.type) {
- case 'single':
- currentPanelDate.value = handleSingleDate().date;
- emit('change', currentPanelDate.value);
- break;
- case 'range':
- currentPanelDate.value = handleRangeDate().date;
- emit('change', currentPanelDate.value);
- break;
- }
- });
- </script>
- <style scoped lang="scss">
- .tui-date-picker-panel {
- width: 200px;
- margin: 5px;
- &-body {
- width: 200px;
- display: flex;
- flex-direction: column;
- &-header {
- width: 100%;
- display: flex;
- flex-direction: row;
- height: 30px;
- padding: 0 5px;
- box-sizing: border-box;
- &-prev {
- display: flex;
- flex-direction: row;
- cursor: pointer;
- width: 24px;
- }
- &-label {
- flex: 1;
- display: flex;
- flex-direction: row;
- text-align: center;
- align-items: center;
- justify-content: center;
- user-select: none;
- color: #666;
- &-item {
- padding: 0 5px;
- color: #666;
- }
- }
- &-next {
- display: flex;
- flex-direction: row;
- cursor: pointer;
- width: 24px;
- }
- }
- }
- &-icon {
- display: flex;
- justify-content: center;
- align-items: center;
- width: 12px;
- }
- }
- </style>
|