element ui 季度选择器

<!--
 * @Descripttion: 季度选择器
 * @version: 1.0
 * @Author: https://www.lervor.com/
 * @Date: 2021-12-06
 * @LastEditTime: 2021-12-09
-->
<template>
  <el-popover
    trigger="focus"
    v-model="pickerVisible"
    popper-class="lervor-quarter-popover"
    :disabled="disabled">
    <el-input
      ref="reference"
      slot="reference"
      class="el-date-editor"
      readonly
      :disabled="disabled"
      :size="size"
      :placeholder="placeholder"
      :value="displayValue"
      :validate-event="false"
      :style="{ width }"
      @mouseenter.native="handleMouseEnter"
      @mouseleave.native="showClose = false">
      <i slot="prefix"
        class="el-input__icon"
        :class="triggerClass">
      </i>
      <i slot="suffix"
        class="el-input__icon"
        :class="[showClose ? '' + clearIcon : '']"
        @click="handleClickIcon"
        @mousedown="handleMousedownIcon">
      </i>
    </el-input>
    <div class="lervor-quarter-picker">
      <div class="el-date-picker__header el-date-picker__header--bordered">
        <button
          type="button"
          aria-label="前一年"
          class="el-picker-panel__icon-btn el-date-picker__prev-btn el-icon-d-arrow-left"
          @click="prevYear">
        </button>
        <span
          role="button"
          class="el-date-picker__header-label">{{ yearLabel }}</span>
        <button
          type="button"
          aria-label="后一年"
          class="el-picker-panel__icon-btn el-date-picker__next-btn el-icon-d-arrow-right"
          @click="nextYear">
        </button>
      </div>
      <div class="el-picker-panel__content" style="width: 200px; margin: 10px 15px;">
        <table class="lervor-quarter-table" @click="handleTableClick">
          <tbody>
            <tr>
              <td class="available" :class="getCellStyle(0)">
                <a class="cell">第一季度</a>
              </td>
              <td class="available" :class="getCellStyle(1)">
                <a class="cell">第二季度</a>
              </td>
            </tr>
            <tr>
              <td class="available" :class="getCellStyle(2)">
                <a class="cell">第三季度</a>
              </td>
              <td class="available" :class="getCellStyle(3)">
                <a class="cell">第四季度</a>
              </td>
            </tr>
          </tbody>
        </table>
      </div>
    </div>
  </el-popover>
</template>

<script>
  import { formatDate, prevYear, nextYear, range, nextDate, isDateObject, parseDate } from 'element-ui/src/utils/date-util'
  import { hasClass } from 'element-ui/src/utils/dom'

  // 获取指定年份和季度的所有日期
  const datesInYearAndQuarter = (year, quarter) => {
    const numOfDays = getDayCountOfQuarter(year, quarter)
    const firstDay = new Date(year, quarter * 3, 1)
    return range(numOfDays).map(n => nextDate(firstDay, n))
  }

  // 获取指定年份和季度总天数
  const getDayCountOfQuarter = (year, quarter) => {
    switch(quarter) {
      case 0: // 第一季度包含二月,需要对是否闰年进行判断处理
        if (year % 4 === 0 && year % 100 !== 0 || year % 400 === 0) {
          return 91
        } else {
          return 90
        }
      case 1:
        return 91
      default:
        return 92
    }
  }

  export default {
    name: 'QuarterPicker',
    props: {
      size: String,
      format: String, // 显示在输入框中的格式,引入季度:q(阿拉伯数字)、Q(中文数字)
      valueFormat: String,
      placeholder: String,
      prefixIcon: String,
      clearIcon: {
        type: String,
        default: 'el-icon-circle-close'
      },
      disabled: Boolean,
      clearable: {
        type: Boolean,
        default: true
      },
      width: { // 组件宽度
        type: String,
        default: ''
      },
      disabledDate: {}, // 不可用的日期
      value: null
    },
    data() {
      return {
        showClose: false,
        pickerVisible: false,
        date: new Date(),
        quarterText: [ '一', '二', '三', '四' ]
      }
    },
    computed: {
      triggerClass() {
        return this.prefixIcon || 'el-icon-date'
      },
      displayValue() {
        if (!this.value) return null
        // 季度,从0开始
        const quarter = parseInt(this.parsedValue.getMonth() / 3)
        let fDate = formatDate(this.parsedValue, this.format)
        fDate = fDate.replace(/q/, quarter + 1).replace(/Q/, this.quarterText[quarter])
        return fDate
      },
      year() {
        return this.date.getFullYear()
      },
      yearLabel() {
        return this.year + ' 年'
      },
      parsedValue() {
        if (!this.value) {
          return this.value
        }
        if (isDateObject(this.value)) {
          return this.value
        }
        // 非时间格式且设置了valueFormat,进行时间转换
        if (this.valueFormat) {
          return parseDate(this.value, this.valueFormat)
        }
        // 非时间格式且未设置valueFormat,再尝试转换时间
        return new Date(this.value)
      }
    },
    watch: {
      value(value) {
        this.date = value ? this.parsedValue : new Date()
      }
    },
    methods: {
      handleMouseEnter() {
        if (this.disabled) return
        if (this.value && this.clearable) {
          this.showClose = true
        }
      },
      handleClickIcon(event) {
        if (this.disabled) return
        if (this.showClose) {
          this.$emit('input', null)
          this.$emit('change', null)
          this.showClose = false
          this.pickerVisible = false
          this.$refs.reference.blur()
        }
      },
      handleMousedownIcon(event) {
        // 阻止鼠标按下清空按钮,防止清空数据时季度选择面板闪现
        event.preventDefault()
      },
      handleTableClick(event) {
        let target = event.target
        if (target.tagName === 'A') {
          target = target.parentNode
        }
        if (target.tagName !== 'TD') return
        if (hasClass(target, 'disabled')) return
        const column = target.cellIndex
        const row = target.parentNode.rowIndex
        // 季度,从0开始
        const quarter = row * 2 + column
        // 季度开始月份,从0开始
        const month = quarter * 3
        let newDate = new Date(this.year, month, 1)
        if (this.valueFormat) {
          newDate = formatDate(newDate, this.valueFormat)
        }
        this.pickerVisible = false
        this.$emit('input', newDate)
        this.$emit('change', newDate)
      },
      prevYear() {
        this.date = prevYear(this.date)
      },
      nextYear() {
        this.date = nextYear(this.date)
      },
      getCellStyle(quarter) {
        const style = {}
        const today = new Date()
        const date = this.parsedValue ? this.parsedValue : today
        style.disabled = typeof this.disabledDate === 'function'
          ? datesInYearAndQuarter(this.year, quarter).every(this.disabledDate) : false
        // 当前选中的季度样式
        style.current = date.getFullYear() === this.year && parseInt(date.getMonth() / 3) === quarter
        // 今日所在季度样式
        style.quarter = today.getFullYear() === this.year && parseInt(today.getMonth() / 3) === quarter
        return style
      }
    }
  }
</script>

<style>
  .lervor-quarter-picker {
    line-height: 30px;
  }
  .lervor-quarter-popover {
    padding: 0;
  }
  .lervor-quarter-table {
    font-size: 12px;
    margin: -1px;
    border-collapse: collapse;
    width: 100%;
  }
  .lervor-quarter-table td {
    text-align: center;
    padding: 10px 3px;
    cursor: pointer;
  }
  .lervor-quarter-table td .cell {
    height: 32px;
    display: block;
    line-height: 32px;
    color: #606266;
    margin: 0 auto;
  }
  .lervor-quarter-table td .cell:hover {
    color: #1890ff;
  }

  .lervor-quarter-table td.current:not(.disabled) .cell {
    color: #409eff;
  }

  .lervor-quarter-table td.quarter .cell {
    color: #409eff;
    font-weight: 700;
  }

  .lervor-quarter-table td.disabled .cell {
    background-color: #F5F7FA;
    cursor: not-allowed;
    color: #C0C4CC;
  }
</style>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值