<!--
|
* @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"
|
:validateEvent="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 v-if="year<new Date().getFullYear()"
|
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开始
|
let 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>
|