123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180 |
- <script setup lang="ts">
- import { computed, onMounted, ref } from 'vue';
- import dayjs from 'dayjs';
- import { t } from '@/i18n';
- import type { PickerMode } from 'ant-design-vue/es/vc-picker/interface';
- import type { Dayjs, OpUnitType } from 'dayjs';
- import type { OptionItem, RangeValue } from '@/types';
- type DateType = 'year' | 'month' | 'date' | 'custom';
- type LastType = '1d' | '7d' | '30d' | 'custom';
- interface Props {
- isLast?: boolean;
- }
- const props = withDefaults(defineProps<Props>(), {
- isLast: false,
- });
- const emit = defineEmits<{
- change: [range: RangeValue];
- }>();
- const selectedType = ref<DateType | LastType>(props.isLast ? '1d' : 'month');
- const singleDate = ref<Dayjs>();
- const rangeDate = ref<RangeValue>();
- const isCustomType = computed(() => {
- return selectedType.value === 'custom';
- });
- const typeOptions = computed<OptionItem<DateType | LastType>[]>(() => {
- if (props.isLast) {
- return [
- { value: '1d', label: t('common.recent1Day') },
- { value: '7d', label: t('common.recent7Day') },
- { value: '30d', label: t('common.recent30Day') },
- { value: 'custom', label: t('common.custom') },
- ];
- }
- return [
- { value: 'year', label: t('common.year') },
- { value: 'month', label: t('common.month') },
- { value: 'date', label: t('common.date') },
- { value: 'custom', label: t('common.custom') },
- ];
- });
- onMounted(() => {
- handleTypeChange();
- });
- const disabledDate = (current: Dayjs) => {
- return current > dayjs().endOf('day');
- };
- const handleTypeChange = () => {
- if (props.isLast) {
- handleLastTypeChange();
- } else {
- handleNormalTypeChange();
- }
- };
- const handleNormalTypeChange = () => {
- const now = dayjs();
- if (isCustomType.value) {
- if (!rangeDate.value) {
- rangeDate.value = [now.startOf('month'), now.endOf('day')];
- }
- handleRangeChange();
- } else {
- if (!singleDate.value) {
- singleDate.value = now;
- }
- handleDateChange();
- }
- };
- const handleLastTypeChange = () => {
- if (!isCustomType.value) {
- const days = parseInt(selectedType.value);
- const end = dayjs();
- const start = end.subtract(days, 'day');
- rangeDate.value = [start, end];
- emitChange(start, end);
- }
- };
- const handleDateChange = () => {
- if (!singleDate.value) {
- return;
- }
- const type = selectedType.value as OpUnitType;
- emitChange(singleDate.value.startOf(type), singleDate.value.endOf(type));
- };
- const handleRangeChange = () => {
- if (!rangeDate.value) {
- return;
- }
- selectedType.value = 'custom';
- emitChange(rangeDate.value[0].startOf('day'), rangeDate.value[1].endOf('day'));
- };
- const emitChange = (start: Dayjs, end: Dayjs) => {
- emit('change', [start, end]);
- };
- </script>
- <template>
- <div class="time-select-container">
- <span class="time-select-label">{{ $t('common.selectTime') }}</span>
- <ASelect class="time-select-type" v-model:value="selectedType" @change="handleTypeChange">
- <ASelectOption v-for="item in typeOptions" :key="item.value" :value="item.value">
- {{ item.label }}
- </ASelectOption>
- </ASelect>
- <ADatePicker
- v-show="!isLast && !isCustomType"
- v-model:value="singleDate"
- :picker="<PickerMode>selectedType"
- :allow-clear="false"
- :disabled-date="disabledDate"
- @change="handleDateChange"
- >
- <template #suffixIcon>
- <SvgIcon name="calendar" color="#333" />
- </template>
- </ADatePicker>
- <ARangePicker
- class="time-select-range-picker"
- v-show="isLast || isCustomType"
- v-model:value="rangeDate"
- :allow-clear="false"
- :separator="$t('common.to')"
- :disabled-date="disabledDate"
- @change="handleRangeChange"
- >
- <template #suffixIcon>
- <SvgIcon name="calendar" color="#333" />
- </template>
- </ARangePicker>
- </div>
- </template>
- <style lang="scss" scoped>
- .time-select-container {
- display: inline-flex;
- align-items: center;
- }
- .time-select-label {
- margin-right: 16px;
- font-size: 14px;
- line-height: 22px;
- color: #000;
- }
- .time-select-type {
- width: 110px;
- margin-right: 12px;
- }
- .time-select-range-picker {
- width: 256px;
- :deep(.ant-picker-range-separator) {
- padding-right: 16px;
- }
- }
- </style>
|