<style lang="less">
.nt-date-fast-panel {
  width: 350px;
  &.el-popper[x-placement^=bottom] .popper__arrow {
    border-bottom-color: #E4E7ED;
    &::after {
      border-bottom-color: #f2f4f8;
    }
  }
  label {
    white-space: nowrap;
    font-size: 90%;
  }
  .pad {
    padding: 10px 15px;
  }
  .el-tabs {
    user-select: none;
  }
  .between {
    display: flex;
    justify-content: space-between;
  }
  .grid {
    display: grid;

    .col {
      text-align: center;
    }

    .el-button {
      margin: 10px 0;
      min-width: 70px;
    }

    // 常用网格
    &.common {
      grid-template-columns: 50% 50%;
      .el-button {
        margin: 10px 0 0;
      }
    }
    
    // 月份网格
    &.months {
      grid-template-columns: 33% 33% 33%;
      grid-template-rows: 50px 50px 50px 50px;
    }

    // 季度网格
    &.quarter {
      grid-template-columns: 100%;
      grid-template-rows: 50px 50px 50px 50px;
    }

    // 年度网格
    &.annual {
    }
  }
}
.nt-date-fast-panel--head {
  background-color: #f2f4f8;
  display: flex;
  align-items: center;
  .el-select {
    flex: 1;
  }
  .el-button {
    margin-left: 5px;
  }
}
.nt-date-fast-panel--body {
  align-items: center;

  .el-input {
    flex: 1;
  }
}
.nt-date-fast-panel--foot {
  background-color: #f2f4f8;
}
</style>


<template>
  <transition name="el-zoom-in-top" @after-leave="$emit('dodestroy')">
    <div
      v-show="visible"
      class="el-picker-panel nt-date-fast-panel el-popper"
      :class="[{
      }, popperClass]">
      <div class="nt-date-fast-panel--head pad">
        <label>年份：</label>
        <el-select
          v-model="valYear"
          size="medium"
          ref="yearPicker"
          :filterable="false"
          @change="setYear(valYear)"
          @visible-change="onYearPicking"
        >
          <template v-for="(y, i) in yearsRange">
            <el-option :key="i" :label="y" :value="y">
              <span style="float: left">{{ y }}</span>
              <span style="float: right; color: #8492a6; font-size: 13px">
                <template v-if="isYear - y === 0">今年</template>
                <template v-else-if="isYear - y > 0">{{ `${isYear - y}年前` }}</template>
                <template v-else-if="isYear - y < 0">{{ `${isYear - y}年后` }}</template>
              </span>
            </el-option>
          </template>
        </el-select>
        <el-button size="medium" type="default" @click="setYear(isYear)" :disabled="valYear === isYear">今年</el-button>
      </div>
      <!-- 快速选择 -->
      <div class="nt-date-fast-panel--body">
        <el-tabs v-model="isTab" tab-position="left">
          <el-tab-pane label="常用" name="common">
            <div class="grid common">
              <template v-for="(c, i) in commonGrid">
                <div class="col" :key="i">
                  <el-button
                    size="small"
                    round
                    @click="handleCommon(c)"
                    :type="isActiveLabel(c, 'common')"
                  >{{ c }}</el-button>
                </div>
              </template>
            </div>
          </el-tab-pane>
          <el-tab-pane label="月份" name="months">
            <div class="grid months">
              <template v-for="(m, i) in monthRange">
                <div :key="i" class="col">
                  <el-button
                    size="small"
                    round
                    @click="handleMonth(m)" 
                    :type="isActiveLabel(`${m}月份`, 'months')"
                  >{{m}}月</el-button>
                </div>
              </template>
            </div>
          </el-tab-pane>
          <el-tab-pane label="季度" name="quarter">
            <div class="grid quarter">
              <template v-for="(a, q, i) in quarterGrid">
                <div class="col" :key="i">
                  <el-button
                    size="small"
                    round
                    @click="handleQuarter(a, q)"
                    :type="isActiveLabel(q, 'quarter')"
                  >{{ q }}</el-button>
                </div>
              </template>
            </div>
          </el-tab-pane>
          <el-tab-pane label="年度" name="annual">
            <div class="grid annual">
              <template v-for="(c, i) in annualGrid">
                <div class="col" :key="i">
                  <el-button
                    size="small"
                    round
                    @click="handleAnnual(c)"
                    :type="isActiveLabel(c, 'annual')"
                  >{{ c }}</el-button>
                </div>
              </template>
            </div>
          </el-tab-pane>
        </el-tabs>
      </div>
      <!-- 自定义 -->
      <div class="nt-date-fast-panel--body pad between">
        <label>自定义：</label>
        <el-date-picker
          v-model="custom"
          size="medium"
          type="daterange"
          range-separator="至"
          start-placeholder="开始日期"
          end-placeholder="结束日期"
          ref="customPicker"
          @change="onDatePickerChange"
          @blur="onDatePickerBlur"
          @focus="onDatePickerFocus"
        ></el-date-picker>
      </div>
      <div class="nt-date-fast-panel--foot pad between">
        <div>
          <slot name="tools"></slot>
        </div>
        <!-- <el-checkbox label="设为默认" v-model="storage"></el-checkbox> -->
        <div>
          <el-button size="small" type="default" @click="handleCancel">取消</el-button>
          <el-button size="small" type="primary" @click="handleConfirm">确定</el-button>
        </div>
      </div>
    </div>
  </transition>
</template>

<script>
import {
  prevDate,
  prevMonth,
  prevYear,
  getDayCountOfMonth,
} from 'element-ui/src/utils/date-util';
const weekDate = (date, n) => {
  let tmp = new Date(date.getFullYear(), date.getMonth(), date.getDate(), date.getHours(), date.getMinutes(), date.getSeconds(), date.getMilliseconds())
  let day = tmp.getDay(); // 返回星期几的某一天
  n = day == 0 ? n + 6 : n + (day - 1)
  tmp.setDate(tmp.getDate() - n);
  return tmp
}
export default {
  data() {
    const today = new Date()
    return {
      popperClass: '',
      isLabel: '', // 当前label
      value: [],
      picking: false,
      visible: false,
      isTab: 'common',
      isYear: new Date().getFullYear(), // 现在哪年
      minYear: 1970, // 年选择限制 最小年
      maxYear: today.getFullYear(), // 年选择限制 最大年
      valYear: today.getFullYear(), // 当前值 年
      current: [], // 当前值
      custom: [], // 自定义
      // 常用
      commonGrid: [
        '昨日', '今日',
        '上周', '本周',
        '上月', '本月',
        '上半年', '下半年',
        '上季度', '本季度'
      ],
      // 季度
      quarterGrid: {
        '第一季度': [1, 3],
        '第二季度': [4, 6],
        '第三季度': [7, 9],
        '第四季度': [10, 12],
      },
      // 年度
      annualGrid: [
        '上半年', '下半年',
        '全年'
      ],
      // 常用 + 年度的处理方法
      handlers: {
        '昨日': () => {
          let t = new Date()
          let d = prevDate(new Date(this.valYear, t.getMonth(), t.getDate()), 1)
          let n = new Date(this.valYear, d.getMonth(), d.getDate(), 23, 59, 59, 0);
          this.current = [d, n]
          this.custom = []
        },
        '今日': () => {
          let t = new Date()
          let d = prevDate(new Date(this.valYear, t.getMonth(), t.getDate()), 0)
          let n = new Date(this.valYear, d.getMonth(), d.getDate(), 23, 59, 59, 0);
          this.current = [d, n]
          this.custom = []
        },
        '上周': () => {
          let t = new Date()
          let ymd = new Date(this.valYear, t.getMonth(), t.getDate())
          // 上周一
          let d1 = weekDate(ymd, 7)
          // 上周日
          let d7 = weekDate(ymd, 1)
          let n = new Date(this.valYear, d1.getMonth(), d1.getDate(), 0, 0, 0, 0);
          let d = new Date(this.valYear, d7.getMonth(), d7.getDate(), 23, 59, 59, 0);
          this.current = [n, d]
          this.custom = []
        },
        '本周': () => {
          let t = new Date()
          let ymd = new Date(this.valYear, t.getMonth(), t.getDate())
          // 本周一
          let d1 = weekDate(ymd, 0)
          // 本周日
          let d7 = weekDate(ymd, -6)
          let d = new Date(this.valYear, d1.getMonth(), d1.getDate(), 0, 0, 0, 0);
          let n = new Date(this.valYear, d7.getMonth(), d7.getDate(), 23, 59, 59, 0);
          this.current = [d, n]
          this.custom = []
        },
        '上月': () => {
          let m = prevMonth(new Date())
          let days = getDayCountOfMonth(this.valYear, m.getMonth())
          let d = new Date(this.valYear, m.getMonth(), 1, 0, 0, 0, 0);
          let n = new Date(this.valYear, m.getMonth(), days, 23, 59, 59, 0);
          this.current = [d, n]
          this.custom = []
        },
        '本月': () => {
          let m = new Date()
          let days = getDayCountOfMonth(this.valYear, m.getMonth())
          let d = new Date(this.valYear, m.getMonth(), 1, 0, 0, 0, 0);
          let n = new Date(this.valYear, m.getMonth(), days, 23, 59, 59, 0);
          this.current = [d, n]
          this.custom = []
        },
        '上半年': () => {
          this.chooseMonthRange(1, 6)
        },
        '下半年': () => {
          this.chooseMonthRange(7, 12)
        },
        '全年': () => {
          this.chooseMonthRange(1, 12)
        },
        '上季度': () => {
          let m = new Date()
          let mm = m.getMonth()
          if (mm < 3) {
            this.valYear = prevYear(m)
            this.chooseMonthRange(9, 12)
          } else if (mm > 3 && mm < 6) {
            this.chooseMonthRange(1, 3)
          } else if (mm > 6 && mm < 9) {
            this.chooseMonthRange(4, 6)
          } else if (mm > 9 && mm < 12) {
            this.chooseMonthRange(7, 9)
          }
        },
        '本季度': () => {
          let m = new Date()
          let mm = m.getMonth()
          if (mm < 3) {
            this.chooseMonthRange(1, 3)
          } else if (mm > 3 && mm < 6) {
            this.chooseMonthRange(4, 6)
          } else if (mm > 6 && mm < 9) {
            this.chooseMonthRange(7, 9)
          } else if (mm > 9 && mm < 12) {
            this.chooseMonthRange(9, 12)
          }
        }
      },
    }
  },
  computed: {
    yearsRange() {
      let t = []
      for (let index = this.minYear; index <= this.maxYear; index++) {
        t.push(index)
      }
      return t.reverse()
    },
    monthRange() {
      return Array.from(new Array(12)).map((_, i) => i + 1)
    }
  },
  methods: {
    // 重置视图
    resetView() {
      // console.log('fast-resetView', this.value)

      // 数据重置
      this.isLabel = '自定义:common'
      this.isTab = 'common'
      this.isYear = new Date().getFullYear()
      this.valYear = this.isYear
      this.custom = []
      this.current = []

      if (!this.value || this.value.length !== 2) {
        return
      }

      let isSameYear = this.value[0].getFullYear() === this.value[1].getFullYear()
      let isSameMonth = this.value[0].getMonth() === this.value[1].getMonth()
      let isSameDate = this.value[0].getDate() === this.value[1].getDate()

      // 年相同
      if (!isSameYear) {
        this.custom = [...this.value]
        return
      }

      // 确认年
      this.valYear = this.value[0].getFullYear()

      // 由大到小判断

      // 全年
      if (
        this.value[0].getMonth() === 0 && this.value[1].getMonth() === 11 &&
        this.value[0].getDate() === 1 && this.value[1].getDate() === 31
      ) {
        this.isLabel = '全年:annual'
        this.current = [...this.value]
        return
      }

      // 上半年
      if (
        this.value[0].getMonth() === 0 && this.value[1].getMonth() === 5 &&
        this.value[0].getDate() === 1 && this.value[1].getDate() === 30
      ) {
        if (this.valYear === this.isYear) {
          this.isLabel = '上半年:common' // 今年上半年
          this.current = [...this.value]
        } else {
          this.isLabel = '上半年:annual' // 年度上半年
          this.current = [...this.value]
        }
        return
      }

      // 下半年
      if (
        this.value[0].getMonth() === 6 && this.value[1].getMonth() === 11 &&
        this.value[0].getDate() === 1 && this.value[1].getDate() === 31
      ) {
        if (this.valYear === this.isYear) {
          this.isLabel = '下半年:common' // 今年下半年
          this.current = [...this.value]
        } else {
          this.isLabel = '下半年:annual' // 年度下半年
          this.current = [...this.value]
        }
        return
      }

      let now = new Date()
      let month = now.getMonth()

      // 识别季度

      // 上季度
      let lastQuarter = false
      if (month < 3) {
        let last = prevYear(now)
        lastQuarter = this.value[0].getFullYear() === last.getFullYear() && this.value[1].getFullYear() === last.getFullYear() &&
          this.value[0].getMonth() === 10 - 1 && this.value[1].getMonth() === 12 - 1 &&
          this.value[0].getDate() === 1 && this.value[1].getDate() === getDayCountOfMonth(last.getFullYear(), 12 - 1)
      } else if (month > 3 && month < 6) {
        lastQuarter = this.value[0].getMonth() === 1 - 1 && this.value[1].getMonth() === 3 - 1 &&
          this.value[0].getDate() === 1 && this.value[1].getDate() === getDayCountOfMonth(now.getFullYear(), 3 - 1)
      } else if (month > 6 && month < 9) {
        lastQuarter = this.value[0].getMonth() === 4 - 1 && this.value[1].getMonth() === 6 - 1 &&
          this.value[0].getDate() === 1 && this.value[1].getDate() === getDayCountOfMonth(now.getFullYear(), 6 - 1)
      } else if (month > 9 && month < 12) {
        lastQuarter = this.value[0].getMonth() === 7 - 1 && this.value[1].getMonth() === 9 - 1 &&
          this.value[0].getDate() === 1 && this.value[1].getDate() === getDayCountOfMonth(now.getFullYear(), 9 - 1)
      }
      if (lastQuarter) {
        this.isLabel = '上季度:common'
        this.current = [...this.value]
        return
      }

      // 本季度
      let currQuarter = false
      if (month < 3) {
        currQuarter = this.value[0].getMonth() === 1 - 1 && this.value[1].getMonth() === 3 - 1 &&
          this.value[0].getDate() === 1 && this.value[1].getDate() === getDayCountOfMonth(this.value[0].getFullYear(), 3 - 1)
      } else if (month > 3 && month < 6) {
        currQuarter = this.value[0].getMonth() === 4 - 1 && this.value[1].getMonth() === 6 - 1 &&
          this.value[0].getDate() === 1 && this.value[1].getDate() === getDayCountOfMonth(this.value[0].getFullYear(), 6 - 1)
      } else if (month > 6 && month < 9) {
        currQuarter = this.value[0].getMonth() === 7 - 1 && this.value[1].getMonth() === 9 - 1 &&
          this.value[0].getDate() === 1 && this.value[1].getDate() === getDayCountOfMonth(this.value[0].getFullYear(), 9 - 1)
      } else if (month > 9 && month < 12) {
        currQuarter = this.value[0].getMonth() === 10 - 1 && this.value[1].getMonth() === 12 - 1 &&
          this.value[0].getDate() === 1 && this.value[1].getDate() === getDayCountOfMonth(this.value[0].getFullYear(), 12 - 1)
      }
      if (this.valYear === this.isYear && currQuarter) {
        this.isLabel = '本季度:common'
        this.current = [...this.value]
        return
      }

      // 批量季度
      for (let label in this.quarterGrid) {
        let quarter = this.quarterGrid[label]

        // 判断日期
        let dayLast = getDayCountOfMonth(this.value[1].getFullYear(), quarter[1] - 1)

        if (
          this.value[0].getMonth() === quarter[0] - 1 && this.value[1].getMonth() === quarter[1] - 1 &&
          this.value[0].getDate() === 1 && this.value[1].getDate() === dayLast
        ) {
          this.isLabel = label + ':quarter'
          this.current = [...this.value]
          return
        }
      }

      // 识别月份

      // 上月
      let lastMonth = prevMonth(now)
      if (
        this.value[0].getMonth() === lastMonth.getMonth() && this.value[1].getMonth() === lastMonth.getMonth() &&
        this.value[0].getDate() === 1 && this.value[1].getDate() === getDayCountOfMonth(this.value[0].getFullYear(), lastMonth.getMonth())
      ) {
        this.isLabel = '上月:common'
        this.current = [...this.value]
        return
      }

      // 本月
      if (
        this.valYear === this.isYear &&
        this.value[0].getMonth() === month && this.value[1].getMonth() === month &&
        this.value[0].getDate() === 1 && this.value[1].getDate() === getDayCountOfMonth(this.value[0].getFullYear(), month)
      ) {
        this.isLabel = '本月:common'
        this.current = [...this.value]
        return
      }

      // 批量月份
      for (let month of this.monthRange) {
        // 判断日期
        let dayLast = getDayCountOfMonth(this.value[0].getFullYear(), month - 1)

        if (
          isSameMonth &&
          this.value[0].getMonth() === month - 1 && this.value[1].getMonth() === month - 1 &&
          this.value[0].getDate() === 1 && this.value[1].getDate() === dayLast
        ) {
          this.isLabel = `${month}月份:months`
          this.current = [...this.value]
          return
        }
      }

      // 上周
      let lastWeek1 = weekDate(now, 7) // 上周一
      let lastWeek7 = weekDate(now, 1) // 上周日
      if (
        this.value[0].getMonth() === lastWeek1.getMonth() && this.value[1].getMonth() === lastWeek7.getMonth() &&
        this.value[0].getDate() === lastWeek1.getDate() && this.value[1].getDate() === lastWeek7.getDate()
      ) {
        this.isLabel = '上周:common'
        this.current = [...this.value]
        return
      }

      // 本周
      let thisWeek1 = weekDate(now, 0) // 本周一
      let thisWeek7 = weekDate(now, -6) // 本周日
      if (
        this.value[0].getMonth() === thisWeek1.getMonth() && this.value[1].getMonth() === thisWeek7.getMonth() &&
        this.value[0].getDate() === thisWeek1.getDate() && this.value[1].getDate() === thisWeek7.getDate()
      ) {
        this.isLabel = '本周:common'
        this.current = [...this.value]
        return
      }

      // 今日
      if (
        isSameDate &&
        this.value[0].getMonth() === now.getMonth() && this.value[1].getMonth() === now.getMonth() &&
        this.value[0].getDate() === now.getDate() && this.value[1].getDate() === now.getDate()
      ) {
        this.isLabel = '今日:common'
        this.current = [...this.value]
        return
      }

      // 昨日
      let yesterday = prevDate(now, 1)
      if (
        this.value[0].getMonth() === yesterday.getMonth() && this.value[1].getMonth() === yesterday.getMonth() &&
        this.value[0].getDate() === yesterday.getDate() && this.value[1].getDate() === yesterday.getDate()
      ) {
        this.isLabel = '昨日:common'
        this.current = [...this.value]
        return
      }

      // 没有识别出来的
      this.custom = [...this.value]
    },
    // 选年ing
    onYearPicking(on) {
      this.picking = on
    },
    onDatePickerChange() {
      this.isLabel = '自定义'
    },
    onDatePickerBlur() {
      this.picking = false
    },
    onDatePickerFocus() {
      this.picking = true
    },
    // 选择常用
    handleCommon(label) {
      this.handlers[label].call(this)
      this.setLabel(label + ':common')
      this.valYear = this.isYear
    },
    // 选择月份
    handleMonth(month) {
      this.chooseMonth(month)
      this.setLabel(`${month}月份` + ':months')
    },
    // 选择季度
    handleQuarter(quarter, label) {
      this.chooseMonthRange(quarter[0], quarter[1])
      this.setLabel(label + ':quarter')
    },
    // 年度
    handleAnnual(annual) {
      this.handlers[annual].call(this)
      this.setLabel(annual + ':annual')
    },
    setLabel(label) {
      this.isLabel = label
    },
    isActiveLabel(label, tab) {
      if (this.isLabel.indexOf(tab) > -1) this.isTab = tab
      return this.isLabel.indexOf(label) === 0 && (tab ? this.isLabel.indexOf(tab) > -1 : true) ? 'primary' : ''
    },
    setYear(year) {
      year = year || this.isYear
      this.valYear = year
      if (this.current.length === 2) {
        this.current = [...this.current.map(i => {
          i.setYear(year)
          return i
        })]
      }
      if (this.custom.length === 2) {
        this.custom = [...this.custom.map(i => {
          i.setYear(year)
          return i
        })]
      }
    },
    chooseMonth(month) {
      let days = getDayCountOfMonth(this.valYear, month - 1)
      let d = new Date(this.valYear, month - 1, 1, 0, 0, 0, 0)
      let n = new Date(this.valYear, month - 1, days, 23, 59, 59, 0)
      this.current = [d, n]
      this.custom = []
    },
    chooseMonthRange(first, end) {
      let eDays = getDayCountOfMonth(this.valYear, end - 1)
      let d = new Date(this.valYear, first - 1, 1, 0, 0, 0, 0)
      let n = new Date(this.valYear, end - 1, eDays, 23, 59, 59, 0)
      this.current = [d, n]
      this.custom = []
    },
    handleCancel() {
      this.$emit('pick', this.value, false)
    },
    handleConfirm() {
      this.$emit('pick', [].concat(this.custom.length ? this.custom : this.current), false)
    }
  }
}
</script>
