目录

功能点

组件图示

常用

自定义

源码

TDatePicker

TRangePicker

调用方式

参数列表

常用快捷日期文本对应

自定义日期


功能点

  • 支持快速选择常用的日期或日期范围
  • 可自定义选择的日期范围
  • 手动选择想要的日期范围

组件图示

常用

常用

自定义

自定义

源码

TDatePicker

<!--TDatePicker-->
<template>
  <div class="date_body">
    <div class="tangent-date-picker" ref="tangentDatePicker" style="width: 100%">
      <a-popover
        trigger="click"
        placement="bottomLeft"
        v-model:visible="visible"
        overlayClassName="popover-range-picker-dropdown"
        :getPopupContainer="(node) => node.parentNode || document.body"
      >
        <template #content>
          <TRangePicker
            :prop-dynamic="dynamic"
            :prop-range-date="rangeDate"
            :prop-dynamic-type="dynamicType"
            :prop-cus-date-active="customizeActive"
            @changeDate="changeDate"
          />
        </template>
        <a-input
          readOnly
          @click="showDatePicker"
          v-model:value="value"
          :bordered="false"
          size="small"
          class="inputClass"
          :placeholder="placeholder"
          :style="{ fontSize: inputSpanFontSize }"
        />
      </a-popover>
    </div>
  </div>
</template>

<script lang="ts">
  import { defineComponent, ref, watch } from 'vue';
  import dayjs from 'dayjs';
  import TRangePicker from './TRangePicker.vue';
  export default defineComponent({
    name: 'TDatePicker',
    components: { TRangePicker },
    props: {
      // 左侧常用快捷数据
      propDynamic: {
        type: String,
        default: '',
      },

      // 快捷日期类型:常用|自定义
      propDynamicType: {
        type: String,
        default: 'common',
      },

      // 自定义快捷日期高亮
      propCusDateActive: {
        type: String,
        default: '',
      },

      // 日期
      propRangeDate: {
        type: Array,
        default: () => {
          return [
            dayjs(dayjs().startOf('day').subtract(6, 'days').format('YYYY-MM-DD')),
            dayjs(dayjs().format('YYYY-MM-DD')),
          ];
        },
      },

      placeholder: {
        type: String,
        default: ' - ',
      },
      inputSpanFontSize: {
        type: String,
        default: '12px',
      },
    },
    setup(props, context) {
      // 初始近7日
      const rangeDate = ref();
      let tempDate = JSON.parse(JSON.stringify(props.propRangeDate));
      if (tempDate[0] !== '' && tempDate[1] !== '') {
        rangeDate.value = [
          dayjs(tempDate[0]).format('YYYY-MM-DD'),
          dayjs(tempDate[1]).format('YYYY-MM-DD'),
        ];
      } else {
        rangeDate.value = ['', ''];
      }

      const value = ref<string>('');
      // 日期范围
      if (rangeDate.value[0] && rangeDate.value[1]) {
        value.value = rangeDate.value.join(' - ');
      }

      // 初始快捷日期,包含常用和自定义
      const dynamic = ref('');
      dynamic.value = JSON.parse(JSON.stringify(props.propDynamic));

      // 是常用还是自定义日期
      const dynamicType = ref('common');
      dynamicType.value = JSON.parse(JSON.stringify(props.propDynamicType));

      // 自定义日期高亮文本
      const customizeActive = ref('');
      customizeActive.value = JSON.parse(JSON.stringify(props.propCusDateActive));

      // 点击显示日期选择器
      const visible = ref(false);
      function showDatePicker() {
        visible.value = true;
      }
      function hideDatePicker() {
        visible.value = false;
      }

      // 子组件日期选择反馈
      function changeDate(tempVal, isHideDatePicker) {
        if (isHideDatePicker) {
          hideDatePicker();
        }
        dynamic.value = tempVal.dynamic;
        rangeDate.value = tempVal.rangeDate;
        dynamicType.value = tempVal.dynamicType;
        customizeActive.value = tempVal.customizeActive ? tempVal.customizeActive : '';
        value.value = tempVal.rangeDate.join(' - ');

        // 将选择的日期反馈回父组件
        context.emit('changeDate', tempVal);
      }

      function setDateInfo() {
        let tempDate = JSON.parse(JSON.stringify(props.propRangeDate));
        if (tempDate[0] !== '' && tempDate[1] !== '') {
          rangeDate.value = [
            dayjs(tempDate[0]).format('YYYY-MM-DD'),
            dayjs(tempDate[1]).format('YYYY-MM-DD'),
          ];
        } else {
          rangeDate.value = ['', ''];
        }
        // 日期范围
        if (rangeDate.value[0] && rangeDate.value[1]) {
          value.value = rangeDate.value.join(' - ');
        } else {
          value.value = '';
        }
        dynamic.value = JSON.parse(JSON.stringify(props.propDynamic));
        dynamicType.value = JSON.parse(JSON.stringify(props.propDynamicType));
        customizeActive.value = JSON.parse(JSON.stringify(props.propCusDateActive));
      }

      watch(
        () => props.propRangeDate,
        () => {
          setDateInfo();
        },
      );

      return {
        value,
        rangeDate,
        dynamic,
        dynamicType,
        customizeActive,

        changeDate,

        // 日期选择器的显示与隐藏
        visible,
        showDatePicker,
        hideDatePicker,
      };
    },
  });
</script>

<style scoped>
  .date_body {
    display: inline-block;
    border: 1px solid #d9d9d9;
    background-color: #fff;
    height: 32px;
    border-radius: 4px;
    line-height: 32px;
    margin-left: 5px;
    /*text-align: center;*/
    /*width: 150px;*/
    width: 260px;
    text-align: left;
    &:hover {
      border: 1px solid #85a5ff;
    }
  }
  .tangent-date-picker .ant-input {
    border-top-color: transparent !important;
    border-left-color: transparent !important;
    border-right-color: transparent !important;
    /*border-bottom: 1px solid #d9d9d9 !important;*/
    border-top: 0 !important;
    border-left: 0 !important;
    border-right: 0 !important;
  }

  .tangent-date-picker .ant-input:hover {
    border-top-color: transparent !important;
    border-left-color: transparent !important;
    border-right-color: transparent !important;
    border-bottom-color: rgb(89, 126, 247) !important;
    border-top: 0 !important;
    border-left: 0 !important;
    border-right: 0 !important;
  }

  /*:deep(.tangent-date-picker .ant-popover-inner-content) {*/
  /*  color: rgba(0, 0, 0, 0.85);*/
  /*  padding: 12px 16px 0px 16px !important;*/
  /*}*/

  :deep(.popover-range-picker-dropdown .ant-popover-inner) {
    background-color: #fff;
    background-clip: padding-box;
    border-radius: 2px;
    box-shadow: 0 3px 6px -4px rgba(0, 0, 0, 0.12), 0 6px 16px 0 rgba(0, 0, 0, 0.08),
      0 9px 28px 8px rgba(0, 0, 0, 0.05);
    box-shadow: 0 0 8px rgba(0, 0, 0, 0.15) \9;
  }

  :deep(.popover-range-picker-dropdown .ant-popover-inner-content) {
    color: rgba(0, 0, 0, 0.85);
  }
</style>

 TRangePicker

<!--TRangePicker-->
<template>
  <div class="range-picker" ref="rangePicker">
    <div class="quick-date date-packer-opt">
      <a-tabs :default-active-key='"common"'
              v-model:activeKey="activeKey"
              :centered="true"
              @change="changeActive"
              class='tabsClass'
              size="small">
        <a-tab-pane tab='常用' key='common'>
          <template v-for="(item, index) in commonOptData" :key="index">
            <div v-if="index % 2 === 0">
              <span class='common-opt'
                    style='margin-right: 8%'
                    @click='commonOptSelect(commonOptData[index])'
                    :class='{"common-opt-select": commonOptActive === commonOptData[index]}'>
                {{ commonOptData[index] }}
              </span>
              <span class='common-opt'
                    @click='commonOptSelect(commonOptData[index + 1])'
                    :class='{"common-opt-select": commonOptActive === commonOptData[index + 1]}'>
                {{ commonOptData[index + 1] }}
              </span>
            </div>
          </template>
        </a-tab-pane>
        <a-tab-pane tab='自定义' key='customize'>
          <!--     近n日     -->
          <div
            class='Customize-opt'
            :class='{"Customize-opt-select": customizeActive == "近n日"}'>
            近
            <span>
              <a-input
                size="small"
                type='text'
                placeholder='n'
                v-model:value='customizeDate[0]'
                @input="customizeChange('近n日')"
                style="display: inline-block; width: 45px;"
                class='Customize-opt-input' />
            </span>
            日
          </div>

          <!--     过去n日     -->
          <div
            class='Customize-opt'
            :class='{"Customize-opt-select": customizeActive == "过去n日"}'>
            过去
            <span>
              <a-input
                no-border
                size="small"
                type='text'
                placeholder='n'
                v-model:value='customizeDate[1]'
                @input="customizeChange('过去n日')"
                style="display: inline-block; width: 45px;"
                class='Customize-opt-input' />
            </span>
            日
          </div>

          <!--     过去n-m日     -->
          <div
            class='Customize-opt'
            :class='{"Customize-opt-select": customizeActive == "过去n-m日"}'>
            过去
            <span>
              <a-input
                no-border
                size="small"
                type='text'
                placeholder='n'
                v-model:value='customizeDate[2]'
                @input="customizeChange('过去n-m日')"
                style="display: inline-block; width: 45px;"
                class='Customize-opt-input' />
            </span>
            -
            <span>
              <a-input
                no-border
                size="small"
                type='text'
                placeholder='m'
                v-model:value='customizeDate[3]'
                @input="customizeChange('过去n-m日')"
                style="display: inline-block; width: 45px;"
                class='Customize-opt-input' />
            </span>
            日
          </div>

          <!--     近n月     -->
          <div
            class='Customize-opt'
            :class='{"Customize-opt-select": customizeActive == "近n月"}'>
            近
            <span>
              <a-input
                no-border
                size="small"
                type='text'
                placeholder='n'
                v-model:value='customizeDate[4]'
                @input="customizeChange('近n月')"
                style="display: inline-block; width: 45px;"
                class='Customize-opt-input' />
            </span>
            月
          </div>

          <!--     过去n月     -->
          <div
            class='Customize-opt'
            :class='{"Customize-opt-select": customizeActive == "过去n月"}'>
            过去
            <span>
              <a-input
                no-border
                size="small"
                type='text'
                placeholder='n'
                v-model:value='customizeDate[5]'
                @input="customizeChange('过去n月')"
                style="display: inline-block; width: 45px;"
                class='Customize-opt-input' />
            </span>
            月
          </div>

          <!--     近n年     -->
          <div
            class='Customize-opt'
            :class='{"Customize-opt-select": customizeActive == "近n年"}'>
            近
            <span>
            <a-input
              no-border
              size="small"
              type='text'
              placeholder='n'
              v-model:value='customizeDate[6]'
              @input="customizeChange('近n年')"
              style="display: inline-block; width: 45px;"
              class='Customize-opt-input' />
          </span>
            年
          </div>

          <!--     过去n年     -->
          <div
            class='Customize-opt'
            :class='{"Customize-opt-select": customizeActive == "过去n年"}'>
            过去
            <span>
              <a-input
                no-border
                size="small"
                type='text'
                placeholder='n'
                v-model:value='customizeDate[7]'
                @input="customizeChange('过去n年')"
                style="display: inline-block; width: 45px;"
                class='Customize-opt-input' />
            </span>
            年
          </div>
        </a-tab-pane>
      </a-tabs>
    </div>
    <div style="display: inline-flex; border: 1px; margin-top: 5px; height: 270px">
      <n-config-provider :locale="zhCN" :date-locale="dateZhCN">
        <n-date-picker
          dropdownClassName="range-picker-dropdown"
          panel
          type="daterange"
          :actions="null"
          :is-date-disabled="disabledDate"
          :first-day-of-week="6"
          @update:value="changeDate"
          :getPopupContainer="(node) => node.parentNode || document.body"
          v-model:value="dateValue" />
      </n-config-provider>

    </div>
  </div>
</template>

<script>
import { NDatePicker, NConfigProvider, zhCN, dateZhCN } from 'naive-ui';
import { defineComponent, ref, onMounted } from 'vue';
import dayjs from 'dayjs';
import { message } from "ant-design-vue";
import locale from "ant-design-vue/es/date-picker/locale/zh_CN";

export default defineComponent({
  name: "TRangePicker",
  components: { NDatePicker, NConfigProvider },

  props: {
    // 左侧常用快捷数据
    propDynamic: {
      type: String,
      default: ''
    },

    // 快捷日期类型:常用|自定义
    propDynamicType: {
      type: String,
      default: 'common'
    },

    // 自定义快捷日期高亮
    propCusDateActive: {
      type: String,
      default: ''
    },

    // 日期值
    propRangeDate: {
      type: Array,
      default: () => {
        return [dayjs(dayjs().startOf('day').subtract(6, 'days').format('YYYY-MM-DD')),
          dayjs(dayjs().format('YYYY-MM-DD'))]
      }
    }
  },

  setup(props, context) {
    // 常用按钮文本数据
    const commonOptData = ref()
    commonOptData.value = [
      '今日', '昨日',
      '本周', '上周',
      '本月', '上月',
      '今年', '去年',
      '近30日', '过去30日',
      '近90日', '过去90日',
    ]

    // 不可选择日期
    const disabledDate = (ts) => {
      // 无法选择今天之后的天数
      return ts && ts > dayjs().endOf('day');
    };

    // 日期
    const dateValue = ref()
    let tempDate = JSON.parse(JSON.stringify(props.propRangeDate))
    if (tempDate[0] !== '' && tempDate[1] !== '') {
      dateValue.value = [dayjs(tempDate[0]).valueOf(), dayjs(tempDate[1]).valueOf()]
    } else {
      dateValue.value = null
    }

    //
    const activeKey = ref('common')
    activeKey.value = JSON.parse(JSON.stringify(props.propDynamicType))

    // 常用快捷日期高亮文本
    const commonOptActive = ref('')

    // 自定义日期
    const customizeActive = ref('')
    const customizeDate = ref(['', '', '', '', '', '', '', ''])
    customizeActive.value = JSON.parse(JSON.stringify(props.propCusDateActive))

    // 常用动态日期文本
    const dynamicDate = ref('')
    let tempDynamic = JSON.parse(JSON.stringify(props.propDynamic))
    dynamicDate.value = tempDynamic

    // 根据不同的类型回显
    if (activeKey.value === 'common') {
      // 根据传入的常用快捷日期回显
      switchByDynamicText(dynamicDate.value)
    } else {
      switchByDynamicTextInCus(dynamicDate.value, customizeActive.value)
    }


    // 切换面板的回调
    function changeActive(value) {
      activeKey.value = value
    }

    // 常用快捷日期按钮选择
    function commonOptSelect(value) {
      commonOptActive.value = value
      // 根据选择的快捷常用按钮计算具体的日期值
      calculationDateByCommonOpt(value)
      // 将自定义日期输入框的值置空
      customizeDate.value = ['', '', '', '', '', '', '', '']
      // 将自定义日期高亮文本置空
      customizeActive.value = ''
    }


    // 根据选择的快捷常用按钮计算具体的日期值
    function calculationDateByCommonOpt (value) {
      const startDate = ref()
      const endDate = ref()
      switch (value) {
        case '今日':
          startDate.value = dayjs().format('YYYY-MM-DD')
          endDate.value = dayjs().format('YYYY-MM-DD')
          dynamicDate.value = 'near,day,1'
          break
        case '昨日':
          startDate.value = dayjs().startOf('day').subtract(1, 'days').format('YYYY-MM-DD')
          endDate.value = dayjs().startOf('day').subtract(1, 'days').format('YYYY-MM-DD')
          dynamicDate.value = 'past,day,1'
          break
        case '本周':
          startDate.value = dayjs().startOf('week').format('YYYY-MM-DD')
          endDate.value = dayjs().format('YYYY-MM-DD')
          dynamicDate.value = 'this week'
          break
        case '上周':
          startDate.value = dayjs().startOf('week').subtract(1, 'weeks').format('YYYY-MM-DD')
          endDate.value = dayjs().endOf('week').subtract(1, 'weeks').format('YYYY-MM-DD')
          dynamicDate.value = 'last week'
          break
        case '本月':
          startDate.value = dayjs().startOf('month').format('YYYY-MM-DD')
          endDate.value = dayjs().format('YYYY-MM-DD')
          dynamicDate.value = 'near,month,1'
          break
        case '上月':
          startDate.value = dayjs().startOf('month').subtract(1, 'months').format('YYYY-MM-DD')
          endDate.value = dayjs().subtract(1, 'months').endOf('month').format('YYYY-MM-DD')
          dynamicDate.value = 'past,month,1'
          break
        case '今年':
          startDate.value = dayjs().startOf('year').format('YYYY-MM-DD')
          endDate.value = dayjs().format('YYYY-MM-DD')
          dynamicDate.value = 'near,year,1'
          break
        case '去年':
          startDate.value = dayjs().startOf('year').subtract(1, 'years').format('YYYY-MM-DD')
          endDate.value = dayjs().startOf('year').subtract(1, 'days').format('YYYY-MM-DD')
          dynamicDate.value = 'past,year,1'
          break
        case '近30日':
          startDate.value = dayjs().startOf('day').subtract(29, 'days').format('YYYY-MM-DD')
          endDate.value = dayjs().format('YYYY-MM-DD')
          dynamicDate.value = 'near,day,30'
          break
        case '过去30日':
          startDate.value = dayjs().startOf('day').subtract(30, 'days').format('YYYY-MM-DD')
          endDate.value = dayjs().startOf('day').subtract(1, 'days').format('YYYY-MM-DD')
          dynamicDate.value = 'past,day,30'
          break
        case '近90日':
          startDate.value = dayjs().startOf('day').subtract(89, 'days').format('YYYY-MM-DD')
          endDate.value = dayjs().format('YYYY-MM-DD')
          dynamicDate.value = 'near,day,90'
          break
        case '过去90日':
          startDate.value = dayjs().startOf('day').subtract(90, 'days').format('YYYY-MM-DD')
          endDate.value = dayjs().startOf('day').subtract(1, 'days').format('YYYY-MM-DD')
          dynamicDate.value = 'past,day,90'
          break
        default:
          break
      }

      // 右侧日期选择器的绑定值
      dateValue.value = [dayjs(startDate.value).valueOf(), dayjs(endDate.value).valueOf()]

      // 传回父组件响应
      let param = {
        rangeDate: [startDate.value, endDate.value],
        dynamic: dynamicDate.value,
        dynamicType: activeKey.value
      }
      context.emit('changeDate', param, true)
    }


    // 根据传入的常用快捷日期回显
    function switchByDynamicText (value) {
      switch (value) {
        case 'near,day,1':
          commonOptActive.value = '今日'
          break
        case 'past,day,1':
          commonOptActive.value = '昨日'
          break
        case 'this week':
          commonOptActive.value = '本周'
          break
        case 'last week':
          commonOptActive.value = '上周'
          break
        case 'near,month,1':
          commonOptActive.value = '本月'
          break
        case 'past,month,1':
          commonOptActive.value = '上月'
          break
        case 'near,year,1':
          commonOptActive.value = '今年'
          break
        case 'past,year,1':
          commonOptActive.value = '去年'
          break
        case 'near,day,30':
          commonOptActive.value = '近30日'
          break
        case 'past,day,30':
          commonOptActive.value = '过去30日'
          break
        case 'near,day,90':
          commonOptActive.value = '近90日'
          break
        case 'past,day,90':
          commonOptActive.value = '过去90日'
          break
        default:
          break
      }
    }


    // 根据传入的自定义快捷日期回显
    function customizeChange (inputVal) {
      // 校验规则
      let test = ''
      const startDate = ref()
      const endDate = ref()
      // 输入内容
      let tempDateNum = ''
      switch (inputVal) {
        case '近n日':
          tempDateNum = customizeDate.value[0]
          // 校验是否是正整数
          test = tempDateNum.replace(/[^\d]/g, '')
          if (test !== '' && test === tempDateNum && parseInt(tempDateNum) > 0) {
            startDate.value = dayjs().startOf('day').subtract(parseInt(tempDateNum) - 1, 'days').format('YYYY-MM-DD')
            endDate.value = dayjs().format('YYYY-MM-DD')
            dynamicDate.value = 'near,day,' + tempDateNum
            customizeDate.value = [tempDateNum, '', '', '', '', '', '', '']
          } else {
            if (tempDateNum !== '') {
              customizeDate.value[0] = ''
              message.warning('请输入正整数!')
            }
          }
          break
        case '过去n日':
          tempDateNum = customizeDate.value[1]
          // 校验是否是正整数
          test = tempDateNum.replace(/[^\d]/g, '')
          if (test !== '' && test === tempDateNum && parseInt(tempDateNum) > 0) {
            startDate.value = dayjs().startOf('day').subtract(parseInt(tempDateNum), 'days').format('YYYY-MM-DD')
            endDate.value = dayjs().startOf('day').subtract(1, 'days').format('YYYY-MM-DD')
            dynamicDate.value = 'past,day,' + tempDateNum
            customizeDate.value = ['', tempDateNum, '', '', '', '', '', '']
          } else {
            if (tempDateNum !== '') {
              customizeDate.value[1] = ''
              message.warning('请输入正整数!')
            }
          }
          break
        case '过去n-m日':
          let tempDateNum3 = customizeDate.value[2]
          let tempDateNum4 = customizeDate.value[3]
          // 校验是否是正整数
          let test3 = tempDateNum3.replace(/[^\d]/g, '')
          let test4 = tempDateNum4.replace(/[^\d]/g, '')
          if ((test3 !== '' && test3 === tempDateNum3 && parseInt(tempDateNum3) > 0) || (test4 !== '' && test4 === tempDateNum4 && parseInt(tempDateNum3) > 0)) {
            if (tempDateNum3 !== '' && tempDateNum4 !== '' && parseInt(tempDateNum3) > 0 && parseInt(tempDateNum3) > 0) {
              let min = Math.min(parseInt(tempDateNum3), parseInt(tempDateNum4))
              let max = Math.max(parseInt(tempDateNum3), parseInt(tempDateNum4))
              startDate.value = dayjs().startOf('day').subtract(max, 'days').format('YYYY-MM-DD')
              endDate.value = dayjs().startOf('day').subtract(min, 'days').format('YYYY-MM-DD')
              customizeActive.value = inputVal
              dynamicDate.value = 'past,day,' + min + ',' + max
              customizeDate.value = ['', '', tempDateNum3, tempDateNum4, '', '', '', '']
              // 将常用日期高亮文本置空
              commonOptActive.value = ''

              // 右侧日期选择器的绑定值
              dateValue.value = [dayjs(startDate.value).valueOf(), dayjs(endDate.value).valueOf()]

              // 传回父组件响应
              let param = {
                rangeDate: [startDate.value, endDate.value],
                dynamic: dynamicDate.value,
                dynamicType: activeKey.value
              }
              context.emit('changeDate', param, false)
            }
          } else {
            if (tempDateNum3 !== '' || tempDateNum4 !== '') {
              customizeDate.value[2] = test3 === '' || test3 !== tempDateNum3 || parseInt(tempDateNum3) <= 0 ? '' : customizeDate.value[2]
              customizeDate.value[3] = test4 === '' || test4 !== tempDateNum4 || parseInt(tempDateNum4) <= 0 ? '' : customizeDate.value[3]
              message.warning('请输入正整数!')
            }
          }
          break
        case '近n月':
          tempDateNum = customizeDate.value[4]
          // 校验是否是正整数
          test = tempDateNum.replace(/[^\d]/g, '')
          if (test !== '' && test === tempDateNum && parseInt(tempDateNum) > 0) {
            startDate.value = dayjs().startOf('month').subtract(parseInt(customizeDate.value[4]) - 1, 'months').format('YYYY-MM-DD')
            endDate.value = dayjs().format('YYYY-MM-DD')
            dynamicDate.value = 'near,month,' + tempDateNum
            customizeDate.value = ['', '', '', '', tempDateNum, '', '', '']
          } else {
            if (tempDateNum !== '') {
              customizeDate.value[4] = ''
              message.warning('请输入正整数!')
            }
          }
          break
        case '过去n月':
          tempDateNum = customizeDate.value[5]
          // 校验是否是正整数
          test = tempDateNum.replace(/[^\d]/g, '')
          if (test !== '' && test === tempDateNum && parseInt(tempDateNum) > 0) {
            startDate.value = dayjs().startOf('month').subtract(parseInt(tempDateNum), 'months').format('YYYY-MM-DD')
            endDate.value = dayjs().startOf('month').subtract(0, 'months').subtract(1, 'days').format('YYYY-MM-DD')
            dynamicDate.value = 'past,month,' + tempDateNum
            customizeDate.value = ['', '', '', '', '', tempDateNum, '', '']
          } else {
            if (tempDateNum !== '') {
              customizeDate.value[5] = ''
              message.warning('请输入正整数!')
            }
          }
          break
        case '近n年':
          tempDateNum = customizeDate.value[6]
          // 校验是否是正整数
          test = tempDateNum.replace(/[^\d]/g, '')
          if (test !== '' && test === tempDateNum && parseInt(tempDateNum) > 0) {
            startDate.value = dayjs().startOf('year').subtract(parseInt(tempDateNum) - 1, 'years').format('YYYY-MM-DD')
            endDate.value = dayjs().format('YYYY-MM-DD')
            dynamicDate.value = 'near,year,' + tempDateNum
            customizeDate.value = ['', '', '', '', '', '', tempDateNum, '']
          } else {
            if (tempDateNum !== '') {
              customizeDate.value[6] = ''
              message.warning('请输入正整数!')
            }
          }
          break
        case '过去n年':
          tempDateNum = customizeDate.value[7]
          // 校验是否是正整数
          test = tempDateNum.replace(/[^\d]/g, '')
          if (test !== '' && test === tempDateNum && parseInt(tempDateNum) > 0) {
            startDate.value = dayjs().startOf('year').subtract(parseInt(tempDateNum), 'years').format('YYYY-MM-DD')
            endDate.value = dayjs().startOf('year').subtract(0, 'years').subtract(1, 'days').format('YYYY-MM-DD')
            dynamicDate.value = 'past,year,' + tempDateNum
            customizeDate.value = ['', '', '', '', '', '', '', tempDateNum]
          } else {
            if (tempDateNum !== '') {
              customizeDate.value[7] = ''
              message.warning('请输入正整数!')
            }
          }
          break
        default:
          break
      }

      // 校验通过才能继续
      if (test !== '' && test === tempDateNum && inputVal !== '过去n-m日') {
        // 右侧日期选择器的绑定值
        dateValue.value = [dayjs(startDate.value).valueOf(), dayjs(endDate.value).valueOf()]
        customizeActive.value = inputVal
        // 将常用日期高亮文本置空
        commonOptActive.value = ''

        // 传回父组件响应
        let param = {
          rangeDate: [startDate.value, endDate.value],
          dynamic: dynamicDate.value,
          dynamicType: activeKey.value,
          customizeActive: customizeActive.value
        }
        context.emit('changeDate', param, false)
      }
    }

    // 根据传入的自定义快捷日期回显
    function switchByDynamicTextInCus (tempDate, activeVal) {
      let tempText = tempDate.split(',')
      switch (activeVal) {
        case '近n日':
          dynamicDate.value = 'near,day,' + tempText[2]
          customizeDate.value = [tempText[2], '', '', '', '', '', '', '']
          break
        case '过去n日':
          dynamicDate.value = 'past,day,' + tempText[2]
          customizeDate.value = ['', tempText[2], '', '', '', '', '', '']
          break
        case '过去n-m日':
          dynamicDate.value = 'past,day,' + tempText[2] + ',' + tempText[3]
          customizeDate.value = ['', '', tempText[3], tempText[2], '', '', '', '']
          break
        case '近n月':
          dynamicDate.value = 'near,month,' + tempText[2]
          customizeDate.value = ['', '', '', '', tempText[2], '', '', '']
          break
        case '过去n月':
          dynamicDate.value = 'past,month,' + tempText[2]
          customizeDate.value = ['', '', '', '', '', tempText[2], '', '']
          break
        case '近n年':
          dynamicDate.value = 'near,year,' + tempText[2]
          customizeDate.value = ['', '', '', '', '', '', tempText[2], '']
          break
        case '过去n年':
          dynamicDate.value = 'past,year,' + tempText[2]
          customizeDate.value = ['', '', '', '', '', '', '', tempText[2]]
          break
        default:
          break
      }
    }


    // 右侧的日期选择器日期发生变化的回调
    function changeDate (date, dateString) {
      // 常用快捷日期按钮选择置空
      commonOptActive.value = ''
      dynamicDate.value = ''
      // console.log(date)
      // console.log(dateString)

      // 传回父组件响应
      let param = {
        rangeDate: dateString,
        dynamic: dynamicDate.value
      }
      context.emit('changeDate', param, false)
    }

    function panelChange(value) {
      console.log(value)
    }

    onMounted(() => {

    })

    return {
      zhCN,
      dateZhCN,
      locale,
      dateValue,
      // 不可选择日期
      disabledDate,
      // 日期发生变化的回调
      changeDate,
      panelChange,

      // 标签页绑定值
      activeKey,
      changeActive,

      // 当前选择的常用按钮
      commonOptActive,
      // 常用快捷按钮文本
      commonOptData,
      // 快捷常用按钮日期选择
      commonOptSelect,

      // 自定义日期
      customizeChange,
      customizeActive,
      customizeDate
    }
  }
});
</script>

<style scoped>
/*--------------------------------左侧快捷选择日期模块样式-----------------------------*/
.quick-date {
  width: 200px;
  height: 270px;
  display: inline-flex;
  position: relative;
}

.date-packer-opt {
  background: #ecf3f8;
  border-right: 1px solid #e4eaf1;
  overflow: hidden;
  padding: 5px;
  -webkit-box-sizing: border-box;
  box-sizing: border-box;
  z-index: 0;
  /*box-shadow: 0px 0px 18px 0 rgba(0,0,0,.14);*/
  position: relative;
  top: 0px;
}

/*------------------------标签页 样式 开始------------------------*/
.tabsClass {
  background-color: #ECF3F8;
  padding-left:10px;
  font-size: 13px;
  width: 100%;
  /*margin-top: 5px;*/
}

:deep(.tabsClass .ant-tabs-nav) {
  position: relative;
  display: flex;
  flex: none;
  align-items: center;
  height: 30px !important;
  margin: 0 0 6px 0 !important;
}

/*-----------标签页文本------------*/
:deep(.tabsClass .ant-tabs-tab.ant-tabs-tab-active .ant-tabs-tab-btn) {
  color: #597EF7 !important;
  text-shadow: 0 0 0.25px currentcolor;
  /*padding: 0 17px;*/
}

/*-----------标签页激活的下杠线------------*/
:deep(.tabsClass .ant-tabs-ink-bar) {
  position: absolute;
  background: #597EF7 !important;
  pointer-events: none;
}

/*-----------常用标签页内的按钮样式------------*/
.common-opt {
  display: inline-block;
  width: 43%;
  padding: 3px 0;
  margin: 6px 0;
  cursor: pointer;
  font-size: 12px;
  background-color: #fff;
  text-align: center;
  border-radius: 20px;
}

.common-opt:hover{
  background-color: #688ff4;
  color: #FFFFFF;
}

.common-opt-select {
  display: inline-block;
  width: 43%;
  padding: 3px 0;
  margin: 6px 0;
  cursor: pointer;
  font-size: 12px;
  background-color: #688FF4;
  color: white;
  text-align: center;
  border-radius: 20px;
}
/*------------------------常用标签页的按钮 样式 结束------------------------*/
/*------------------------自定义标签页的按钮 样式 开始------------------------*/
.Customize-opt {
  background-color: #fff;
  height: 25px;
  width: 179px;
  text-align:center;
  border-radius:20px;
  margin-bottom: 8px
}

.Customize-opt-select {
  background-color: #fff;
  height: 25px;
  width: 179px;
  text-align: center;
  border-radius: 20px;
  margin-bottom: 8px;
  border: 1px solid #688FF4;
}

/*-------输入框边框只留下bottom--------*/
.Customize-opt-input {
  display: inline-block;
  width: 45px;
  border-right: none;
  border-top: none;
  border-left: none;
}

/*-------自定义输入框文本居中显示--------*/
.ant-input {
  text-align: center;
}

/*-------自定义输入框提示语n居中显示--------*/
.ant-input:placeholder-shown {
  text-overflow: ellipsis;
  text-align: center;
}


/*-------------------------------右侧日期面板样式-----------------------------------*/
/*----------------当天日期的右上角圆点-------------------*/
:deep(.n-date-panel .n-date-panel-dates .n-date-panel-date.n-date-panel-date--current .n-date-panel-date__sup) {
  position: absolute;
  top: 1px;
  right: 1px;
  content: "";
  height: 5px;
  width: 5px;
  border-radius: 50%;
  background-color: #688ff4;
}

:deep(.n-date-panel .n-date-panel-dates .n-date-panel-date--excluded) {
  /*opacity: 0;*/
}

/*--------------选择择的开始、结束日期样式-----------------*/
:deep(.n-date-panel .n-date-panel-dates .n-date-panel-date.n-date-panel-date--selected:not(.n-date-panel-date--excluded)::after) {
  background-color: #688ff4 !important;
}

:deep(.n-date-panel .n-date-panel-dates .n-date-panel-date.n-date-panel-date--selected.n-date-panel-date--start:not(.n-date-panel-date--excluded)::after) {
  background-color: #688ff4 !important;
  margin-right: -1px;
}

:deep(.n-date-panel .n-date-panel-dates .n-date-panel-date.n-date-panel-date--selected.n-date-panel-date--end:not(.n-date-panel-date--excluded)::after) {
  background-color: #688ff4 !important;
  margin-left: -1px;
}

/*-----------选择的开始日期左半圆----------*/
:deep(.n-date-panel .n-date-panel-dates .n-date-panel-date--start:not(.n-date-panel-date--excluded)) {
  border-bottom-left-radius: 50%;
  border-top-left-radius: 50%;
}

/*-----------选择的结束日期右半圆----------*/
:deep(.n-date-panel .n-date-panel-dates .n-date-panel-date--end:not(.n-date-panel-date--excluded)) {
  border-bottom-right-radius: 50%;
  border-top-right-radius: 50%;
}

/*-----------选择的非开始、结束日期的背景颜色----------*/
:deep(.n-date-panel .n-date-panel-dates .n-date-panel-date.n-date-panel-date--covered:not(.n-date-panel-date--excluded)::before) {
  background-color: #688ff4 !important;
  margin-left: 7px;
  padding: 0 1px;
  width: 26px;
}

:deep(.n-date-panel .n-date-panel-dates .n-date-panel-date.n-date-panel-date--start:not(.n-date-panel-date--excluded)::before) {
  background-color: #688ff4 !important;
  display: none;
}

:deep(.n-date-panel .n-date-panel-dates .n-date-panel-date.n-date-panel-date--end:not(.n-date-panel-date--excluded)::before) {
  background-color: #688ff4 !important;
  display: none;
}

/*-----------选择的非开始、结束日期的文本颜色----------*/
:deep(.n-date-panel .n-date-panel-dates .n-date-panel-date--covered:not(.n-date-panel-date--excluded)) {
  color: #ffffff;
}

/*-----------面板宽度----------*/
:deep(.n-date-panel .n-date-panel-calendar) {
  width: 210px;
}

/*-----------面板首行年月行样式----------*/
:deep(.n-date-panel .n-date-panel-month) {
  width: 195px;
  margin-bottom: 7px;
  font-size: 13px;
  margin-top: -5px;
}

:deep(.n-date-panel .n-date-panel-month .n-date-panel-month__month-year .n-date-panel-month__text) {
  padding: 0;
  font-size: 12px;
  color: #4C6072;
  font-family: sans-serif;
}

/*-----------面板星期行样式----------*/
:deep(.n-date-panel .n-date-panel-weekdays) {
  display: block;
  margin-bottom: 3px;
  border: unset;
}

:deep(.n-date-panel .n-date-panel-weekdays .n-date-panel-weekdays__day) {
  width: 26px;
  display: inline-flex;
  color: #c5ced8;
  font-size: 13px;
}

/*-----------面板具体日期样式----------*/
:deep(.n-date-panel .n-date-panel-dates) {
  margin: auto;
  display: flex;
  align-items: center;
  justify-items: center;
  flex-wrap: wrap;
  width: 200px;
  height: 200px;
}

:deep(.n-date-panel .n-date-panel-dates .n-date-panel-date) {
  width: 26px;
  display: inline-table;
}

/*-----------两个面板之间的竖线隐藏----------*/
:deep(.n-date-panel .n-date-panel__vertical-divider) {
  display: none;
}

/*-----------不可选日期样式----------*/
:deep(.n-date-panel .n-date-panel-dates .n-date-panel-date.n-date-panel-date--disabled) {
  cursor: not-allowed;
  color: #C5CED8;
  background-color: #ECF3F8;
}
</style>

 调用方式

<TDatePicker
      :input-span-font-size="'14px'"
      :prop-dynamic="dynamic"
      :prop-cus-date-active="customizeActive"
      :prop-dynamic-type="dynamicType"
      :prop-range-date="rangeDate"
      @changeDate="changeDate"
 />

<!-- js部分-->

// 初始快捷日期,包含常用和自定义,例如 'near,day,30',表示近30日
const dynamic = ref('');

// 快捷日期类型:常用common|自定义customize
const dynamicType = ref('common');

// 自定义快捷日期高亮文本,例如 '近n日'
const customizeActive = ref('');

// 日期,初始为近7日
const rangeDate = ref([
  dayjs().startOf('day').subtract(6, 'days').format('YYYY-MM-DD'),
  dayjs().format('YYYY-MM-DD'),
]);

// 选择日期后的回显
function changeDate(tempVal) {
  dynamic.value = tempVal.dynamic;
  customizeActive.value = tempVal.customizeActive ? tempVal.customizeActive : '';
  dynamicType.value = tempVal.dynamicType;
  rangeDate.value = tempVal.rangeDate;
}

参数列表

参数名 类型 必传 说明
propRangeDate array ✔️  日期,例如['2023-01-01', '2023-03-01']
propDynamicType String ✔️  快捷日期类型:常用common|自定义customize
propDynamic String ✔️  快捷日期数据,例如 'near,day,30',表示近30日
propCusDateActive String ✔️ 自定义快捷日期高亮,例如 '近n日',用于高亮样式显示

使用到的组件:除了日期面板外,都是使用的ant-design-vue中的组件;日期面板使用的是Naive UI

组件 图示 备注
Popover 气泡卡片 如上示的效果图的悬浮显示效果
Tabs 标签页

n-date-picker 日期选择框 如上效果图右侧的日期选择 Naive UI提供了只使用面板的属性;更改部分样式
Input 输入框 设置为只读输入框,且将样式处理为只有下边框的样式; 自定义日期里的输入框依旧是可输入的,且将样式处理为只有下边框的样式

常用快捷日期文本对应

显示文本 传给后台的值
今日 near,day,1
昨日 past,day,1
本周 this week
上周 last week
本月 near,month,1
上月 past,month,1
今年 near,year,1
去年 past,year,1
近30日 near,day,30
过去30日 past,day,30
近90日 near,day,90
过去90日 past,day,90

自定义日期

  • 过去n-m日:past,day,min,max (min、max分别为输入的两个数值,小的在前,大的在后)
  • 其他的与常用类似,比如 过去n日,也就是 past,day,n      ;   近n月,也就是  near,month,n  (n为输入的数组)
  • 这里的所有输入框均设置了校验,只能输入正整数
Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐