<!-- 时间范围选择器 -->
<!--
默认
<TimeRange v-model="searchParams.timeRange" />
记录
<TimeRange ref="timeRange" v-model="searchParams.timeRange" today sticky max-range="3month" />
统计
<TimeRange ref="timeRange" v-model="searchParams.timeRange" max-range="2year" />
统计（维度控制）
<TimeRange v-model="searchParams.timeRange" dim-control :dim.sync="searchParams.statisticalType" />
-->
<template>
  <div class="">
    <el-select v-if="dimControl" :value="type" placeholder="请选择" filterable style="width: 70px;" @change="handleDimChange">
      <el-option label="日" value="daterange" />
      <el-option label="月" value="monthrange" />
      <el-option label="年" value="yearrange" />
    </el-select>
    <span v-if="type == 'yearrange'">
      <el-date-picker
        v-bind="$attrs"
        type="year"
        :value="value[0]"
        placeholder="开始时间"
        style="width: 150px;"
        @input="handleYearRangeChange([$event, value[1]])"
      />
      ~
      <el-date-picker
        v-bind="$attrs"
        type="year"
        :value="value[1]"
        placeholder="结束时间"
        style="width: 150px;"
        @input="handleYearRangeChange([value[0], $event])"
      />
    </span>
    <el-date-picker
      v-else
      v-bind="$attrs"
      :type="type"
      :value="value"
      :default-time="defaultTime"
      :value-format="dateFormat"
      :format="dateFormat"
      :picker-options="datePickerOptions"
      :clearable="clearable && !sticky"
      align="right"
      range-separator="至"
      start-placeholder="开始时间"
      end-placeholder="结束时间"
      v-on="$listeners"
      @input="emitInput"
    />
  </div>
</template>

<script>
import dayjs from 'dayjs'
import { invert } from 'lodash'

const dimTypeMap = { 1: 'daterange', 2: 'monthrange', 3: 'yearrange', 4: 'datetimerange' } // dim转type（后端接口统一时间维度标记，参考减免统计）
const dimTypeMapReverse = invert(dimTypeMap)// type转dim

const dateFormatMap = { 1: 'yyyy-MM-dd', 2: 'yyyy-MM', 3: 'yyyy', 4: 'yyyy-MM-dd HH:mm:ss' } // 日期格式化（element）
const dayjsFormatMap = { 1: 'YYYY-MM-DD', 2: 'YYYY-MM', 3: 'YYYY', 4: 'YYYY-MM-DD HH:mm:ss' } // 日期格式化（dayjs）

export default {
  name: 'TimeRange',
  props: {
    value: {
      type: Array,
      default: () => ([])
    },
    dimControl: { // 开启后使用dim
      type: Boolean,
      default: false
    },
    type: { // 时间范围类型 (daterange/monthrange/yearrange/datetimerange)
      type: String,
      default: 'datetimerange'
    },
    dim: { // 时间范围类型CODE (1/2/3/4)
      type: Number,
      default: 4
    },
    maxRange: { // 最大跨度 (eg. 7day, 3month, 2year)
      type: String,
      default: ''
    },
    default: { // 默认时间 (参考element)
      type: Array,
      default: () => ([])
    },
    pickerOptions: { // 参考element
      type: Object,
      default: () => {}
    },
    clearable: { // 参考element
      type: Boolean,
      default: true
    },
    /* 快捷设置 */
    today: { // 今天为默认时间
      type: Boolean,
      default: false
    },
    pastWeek: { // 近一周为默认时间
      type: Boolean,
      default: false
    },
    sticky: { // 在value清空时，仍然让value=default
      type: Boolean,
      default: false
    }
  },
  data() {
    return {
      selectStartDate: ''
    }
  },
  computed: {
    defaultTime() { // element
      return this.type == 'datetimerange' ? ['00:00:00', '23:59:59'] : []
    },
    dateFormat() { // element
      return dateFormatMap[this.dim]
    },
    dayjsFormat() { // 日期格式（计算用）
      return dayjsFormatMap[this.dim]
    },
    maxRangeNum() { // 跨度（计算用）
      return parseInt(this.maxRange) || Infinity
    },
    maxRangeUnit() { // 跨度单位（计算用）
      return this.maxRange.replaceAll(/\d/g, '')
    },
    datePickerOptions() { // element
      const that = this
      const maxRangeControl = { // maxRange处理逻辑
        onPick({ maxDate, minDate }) {
          if (minDate && !maxDate) that.selectStartDate = minDate.getTime()
          if (maxDate) that.selectStartDate = ''
        },
        disabledDate(time) {
          if (!that.selectStartDate) return false
          return Math.abs(dayjs(that.selectStartDate).diff(dayjs(time), that.maxRangeUnit)) >= that.maxRangeNum
        }
      }
      return Object.assign(
        {},
        that.maxRange ? maxRangeControl : null,
        that.pickerOptions
      )
    }
  },
  watch: {
    type: {
      handler(type) {
        if (!this.dimControl) { // type同步到dim
          this.dim = dimTypeMapReverse[type]
        }
      },
      immediate: true
    },
    dim: {
      handler(dim) {
        if (this.dimControl && dim) { // dim同步到type
          this.type = dimTypeMap[dim]
        }
      },
      immediate: true
    },
    value: {
      handler(value) {
        if (!value?.length && this.sticky && this.default?.length) { // sticky处理逻辑
          this.value = this.default
          this.emitInput(this.value)
        }
      }
    }
  },
  created() {
    if (this.today) {
      this.default = [dayjs().startOf('day'), dayjs().endOf('day')].map(i => i.format(this.dayjsFormat))
    }
    if (this.pastWeek) {
      this.default = [dayjs().subtract(7, 'day').startOf('day'), dayjs().endOf('day')].map(i => i.format(this.dayjsFormat))
    }
    if (this.default?.length) {
      this.value = [...this.default]
      this.emitInput(this.value)
    }
  },
  methods: {
    emitInput(e) {
      if (this.maxRange) {
        // 起始范围不在maxRange内则还原编辑前数据（兼容手动编辑的情况#32608）
        const start = e[0]
        const end = e[1]
        if (Math.abs(dayjs(start).diff(dayjs(end), this.maxRangeUnit)) >= this.maxRangeNum) {
          if (end !== this.value[1]) {
            e[1] = this.value[1]
          } else if (start !== this.value[0]) {
            e[0] = this.value[0]
          }
        }
      }
      this.$emit('input', e)
      this.$emit('change', e) // 顺便兼容一些用change更新数据的页面
    },
    handleDimChange(e) {
      this.type = e
      this.value = []
      this.$emit('input', this.value)
      this.$emit('update:type', e)
      this.$emit('update:dim', dimTypeMapReverse[e])
    },
    handleYearRangeChange(e) { // 年维度处理
      if (this.type == 'yearrange') {
        this.emitInput(e.map(i => dayjs(i).format('YYYY')))
      }
    }
  }
}
</script>
