基于 Ant Design Vue分装时间选择组件

97 阅读3分钟

image.png SelectRangePicker/index.vue

<template>
  <div class="flex justify-start items-center w-full" :value="props.value">
    <div class="max-w-22">
      <Select
        :options="optionsValue"
        v-model:value="timeSelectValue"
        @change="handleSelectChange"
        dropdown-class-name="time-picker-select"
        :allow-clear="false"
      />
    </div>
    <RangePicker v-model:value="timePickerValue" @change="handlePickerChange" :show-time="true" />
  </div>
</template>

<script setup lang="ts">
  import { ref, watch } from 'vue';
  import { RangePicker, Select } from 'ant-design-vue';
  import { timeRangeSelectOptions, TimeRangeText, TimeRangeValues, SelectOptions } from './data';
  import { getTimeRangeString, RangeValue } from './utils/time';

  const props = defineProps({
    value: Array as unknown as PropType<RangeValue>,
    options: {
      type: Array as unknown as PropType<SelectOptions[]>,
      default: timeRangeSelectOptions,
    },
    rangeOptions: {
      type: Array as unknown as PropType<Recordable>,
      default: TimeRangeValues,
    },
  });

  const emit = defineEmits(['update:value', 'change']);

  const optionsValue = ref(props.options);

  const timeSelectValue = ref(TimeRangeText.CUSTOM);
  const timePickerValue = ref<RangeValue | undefined>(props.rangeOptions[TimeRangeText.TODAY]);
  watch(
    () => props.value,
    () => {
      if (props.value) {
        timePickerValue.value = props.value;
        timeSelectValue.value = TimeRangeText.CUSTOM;
        for (const key of Object.keys(props.rangeOptions)) {
          if (
            key !== TimeRangeText.CUSTOM &&
            getTimeRangeString(props.rangeOptions[key]) ===
              getTimeRangeString(timePickerValue.value)
          ) {
            timeSelectValue.value = key as TimeRangeText;
            break;
          }
        }
      }
    },
  );

  function handleSelectChange(val: TimeRangeText) {
    timePickerValue.value = props.rangeOptions[val];
    emit('update:value', timePickerValue.value);
    emit('change', timePickerValue.value);
  }

  function handlePickerChange() {
    timeSelectValue.value = TimeRangeText.CUSTOM;
    emit('update:value', timePickerValue.value);
    emit('change', timePickerValue.value);
  }
</script>
<style lang="less" scoped>
  //时间选择 禁用样式
  :deep(.ant-picker-disabled) {
    .ant-picker-input > input[disabled] {
      color: unset;
    }
  }
</style>

SelectRangePicker/data.ts 用于定义需要用到的时间选择类型

import { DefaultTimeRange } from '/@/utils/dataProcessing/time';

export type SelectOptions = { label: string; value: string };

export enum TimeRangeText {
  BEFORE_YESTERDAY = '前天',
  YESTERDAY = '昨天',
  TODAY = '今天',
  THREE_DAY = '近三天',
  ONE_WEEK = '近一周',
  TWO_WEEK = '近两周',
  ONE_MONTH = '近一月',
  THREE_MONTH = '近三月',
  HALF_YEAR = '近半年',
  ONE_YEAR = '近一年',
  CUSTOM = '自定义',
  ONE_HOUR = '1小时',
  TWELVE_HOUR = '12小时',
  TWENTY_FOUR_HOUR = '24小时',
  SEVEN_DAY = '7天',
  THIRTY_DAY = '30天',
}

export const TimeRangeValues = {
  [TimeRangeText.TODAY]: DefaultTimeRange.TODAY,
  [TimeRangeText.THREE_DAY]: DefaultTimeRange.THREE_DAY,
  [TimeRangeText.ONE_WEEK]: DefaultTimeRange.ONE_WEEK,
  [TimeRangeText.TWO_WEEK]: DefaultTimeRange.TWO_WEEK,
  [TimeRangeText.ONE_MONTH]: DefaultTimeRange.ONE_MONTH,
  [TimeRangeText.THREE_MONTH]: DefaultTimeRange.THREE_MONTH,
  [TimeRangeText.HALF_YEAR]: DefaultTimeRange.HALF_YEAR,
  [TimeRangeText.ONE_YEAR]: DefaultTimeRange.ONE_YEAR,
  [TimeRangeText.CUSTOM]: undefined,
};

export const timeRangeSelectOptions: SelectOptions[] = [
  { label: TimeRangeText.TODAY, value: TimeRangeText.TODAY },
  { label: TimeRangeText.THREE_DAY, value: TimeRangeText.THREE_DAY },
  { label: TimeRangeText.ONE_WEEK, value: TimeRangeText.ONE_WEEK },
  { label: TimeRangeText.TWO_WEEK, value: TimeRangeText.TWO_WEEK },
  { label: TimeRangeText.ONE_MONTH, value: TimeRangeText.ONE_MONTH },
  { label: TimeRangeText.THREE_MONTH, value: TimeRangeText.THREE_MONTH },
  { label: TimeRangeText.HALF_YEAR, value: TimeRangeText.HALF_YEAR },
  { label: TimeRangeText.ONE_YEAR, value: TimeRangeText.ONE_YEAR },
  { label: TimeRangeText.CUSTOM, value: TimeRangeText.CUSTOM },
];

export const TimeRangeValuesWithBefore = {
  [TimeRangeText.TODAY]: DefaultTimeRange.TODAY,
  [TimeRangeText.YESTERDAY]: DefaultTimeRange.YESTERDAY,
  [TimeRangeText.BEFORE_YESTERDAY]: DefaultTimeRange.BEFORE_YESTERDAY,
  [TimeRangeText.THREE_DAY]: DefaultTimeRange.THREE_DAY,
  [TimeRangeText.ONE_WEEK]: DefaultTimeRange.ONE_WEEK,
  [TimeRangeText.TWO_WEEK]: DefaultTimeRange.TWO_WEEK,
  [TimeRangeText.ONE_MONTH]: DefaultTimeRange.ONE_MONTH,
  [TimeRangeText.THREE_MONTH]: DefaultTimeRange.THREE_MONTH,
  [TimeRangeText.HALF_YEAR]: DefaultTimeRange.HALF_YEAR,
  [TimeRangeText.ONE_YEAR]: DefaultTimeRange.ONE_YEAR,
  [TimeRangeText.CUSTOM]: undefined,
};

export const timeRangeSelectOptionsWithBefore: SelectOptions[] = [
  { label: TimeRangeText.TODAY, value: TimeRangeText.TODAY },
  { label: TimeRangeText.YESTERDAY, value: TimeRangeText.YESTERDAY },
  { label: TimeRangeText.BEFORE_YESTERDAY, value: TimeRangeText.BEFORE_YESTERDAY },
  { label: TimeRangeText.THREE_DAY, value: TimeRangeText.THREE_DAY },
  { label: TimeRangeText.ONE_WEEK, value: TimeRangeText.ONE_WEEK },
  { label: TimeRangeText.TWO_WEEK, value: TimeRangeText.TWO_WEEK },
  { label: TimeRangeText.ONE_MONTH, value: TimeRangeText.ONE_MONTH },
  { label: TimeRangeText.THREE_MONTH, value: TimeRangeText.THREE_MONTH },
  { label: TimeRangeText.HALF_YEAR, value: TimeRangeText.HALF_YEAR },
  { label: TimeRangeText.ONE_YEAR, value: TimeRangeText.ONE_YEAR },
  { label: TimeRangeText.CUSTOM, value: TimeRangeText.CUSTOM },
];

export const TimeRangeValuesWithHour = {
  [TimeRangeText.ONE_HOUR]: DefaultTimeRange.ONE_HOUR,
  [TimeRangeText.TWELVE_HOUR]: DefaultTimeRange.TWELVE_HOUR,
  [TimeRangeText.TWENTY_FOUR_HOUR]: DefaultTimeRange.TWENTY_FOUR_HOUR,
  [TimeRangeText.SEVEN_DAY]: DefaultTimeRange.SEVEN_DAY,
  [TimeRangeText.THIRTY_DAY]: DefaultTimeRange.THIRTY_DAY,
  [TimeRangeText.CUSTOM]: undefined,
};

export const timeRangeSelectOptionsWithHour: SelectOptions[] = [
  { label: TimeRangeText.ONE_HOUR, value: TimeRangeText.ONE_HOUR },
  { label: TimeRangeText.TWELVE_HOUR, value: TimeRangeText.TWELVE_HOUR },
  { label: TimeRangeText.TWENTY_FOUR_HOUR, value: TimeRangeText.TWENTY_FOUR_HOUR },
  { label: TimeRangeText.SEVEN_DAY, value: TimeRangeText.SEVEN_DAY },
  { label: TimeRangeText.THIRTY_DAY, value: TimeRangeText.THIRTY_DAY },
  { label: TimeRangeText.CUSTOM, value: TimeRangeText.CUSTOM },
];

SelectRangePicker/utils/time 用于处理时间格式

/**
 * 时间处理的相关方法
 */
import type { Dayjs } from 'dayjs';
import dayjs from 'dayjs';
import { useNow, useDateFormat } from '@vueuse/core';

export type RangeValue = [Dayjs, Dayjs];

//常用的时间区间
export const DefaultTimeRange = {
  BEFORE_YESTERDAY: getTimeRange(2, 2), //前天
  YESTERDAY: getTimeRange(1, 1), //昨天
  TODAY: getTimeRange(0), //今天
  THREE_DAY: getTimeRange(2), //近三天
  ONE_WEEK: getTimeRange(6), //近一周
  TWO_WEEK: getTimeRange(13), //近两周
  ONE_MONTH: getTimeRange(29), //近一个月
  THREE_MONTH: getTimeRange(89), //近三个月
  HALF_YEAR: getTimeRange(182), //近半年
  ONE_YEAR: getTimeRange(364), //近一年
  ONE_HOUR: getTimeRangeInHours(1), //1小时
  TWELVE_HOUR: getTimeRangeInHours(12), //12小时
  TWENTY_FOUR_HOUR: getTimeRangeInHours(24), //24小时
  SEVEN_DAY: getTimeRange(6), //7天
  THIRTY_DAY: getTimeRange(29), //30天
};

//获取时间区间 往前推n天
export function getTimeRange(day1: number, day2 = 0): RangeValue {
  return [
    dayjs(`${useDateFormat(useNow(), 'YYYY-MM-DD 00:00:00').value}`).subtract(day1, 'day'),
    dayjs(useDateFormat(useNow(), 'YYYY-MM-DD 23:59:59').value).subtract(day2, 'day'),
  ];
}
// 获取时间区间 往回推n小时
export function getTimeRangeInHours(hours1: number, hours2 = 0): RangeValue {
  return [
    dayjs(`${useDateFormat(useNow(), 'YYYY-MM-DD HH:mm:ss').value}`).subtract(hours1, 'hour'),
    dayjs(useDateFormat(useNow(), 'YYYY-MM-DD HH:mm:ss').value).subtract(hours2, 'hour'),
  ];
}
//将时间区间 处理为 形如 time1 - time2 的字符串
export function getTimeRangeString(range: RangeValue, formatStr = 'YYYY-MM-DD HH:mm:ss'): string {
  return `${dayjs(range[0]).format(formatStr)} - ${dayjs(range[1]).format(formatStr)}`;
}

//将时间区间 处理为 两个字段 的字符串数组
export function transTimeRange2FiledMap(range: RangeValue, formatStr = 'YYYY-MM-DD HH:mm:ss') {
  return [dayjs(range[0]).format(formatStr), dayjs(range[1]).format(formatStr)];
}

const now = new Date();
const daysArr = [6, 0, 1, 2, 3, 4, 5];
const day = daysArr[now.getDay()]; //计算本周区间 需要往前推的天数
const today: RangeValue = [
  dayjs(`${useDateFormat(useNow(), 'YYYY-MM-DD').value} 00:00:00`),
  dayjs(useDateFormat(useNow(), 'YYYY-MM-DD HH:mm:ss').value),
];
const week: RangeValue = [
  dayjs(`${useDateFormat(useNow(), 'YYYY-MM-DD').value}`).subtract(day, 'day'),
  dayjs(useDateFormat(useNow(), 'YYYY-MM-DD HH:mm:ss').value),
];
const month: RangeValue = [
  dayjs(`${useDateFormat(useNow(), 'YYYY-MM').value}-01 00:00:00`),
  dayjs(useDateFormat(useNow(), 'YYYY-MM-DD HH:mm:ss').value),
];
const year: RangeValue = [
  dayjs(`${useDateFormat(useNow(), 'YYYY').value}-01-01 00:00:00`),
  dayjs(useDateFormat(useNow(), 'YYYY-MM-DD HH:mm:ss').value),
];
const quarter: RangeValue = [
  getQuarter(),
  dayjs(useDateFormat(useNow(), 'YYYY-MM-DD HH:mm:ss').value),
];

//计算当前季度
function getQuarter(): Dayjs {
  const currentMonth: number = new Date().getMonth();
  let quarterMonth = '';
  if (currentMonth < 3) {
    quarterMonth = '01';
  } else if (currentMonth >= 3 && currentMonth < 6) {
    quarterMonth = '04';
  } else if (currentMonth >= 6 && currentMonth < 9) {
    quarterMonth = '07';
  } else {
    quarterMonth = '10';
  }
  const dateStr = useDateFormat(useNow(), 'YYYY').value + '-' + quarterMonth + '-01 00:00:00';
  return dayjs(dateStr);
}

export const CurrentTimeRange = {
  TODAY: today, //今日
  THIS_WEEK: week, //本周
  THIS_MONTH: month, //本月
  THIS_QUARTER: quarter, //本季度
  THIS_YEAR: year, //本年
};

使用方法

 <SelectRangePicker
  v-model:value="model[field]"
  :options="timeRangeSelectOptionsWithBefore"
  :range-options="TimeRangeValuesWithBefore"
/>