实现步骤:
1、季度选择器组件
<template> <div style="display: inline-block;"> <mark style="position: fixed;top: 0;bottom: 0;left: 0;right: 0;background: rgba(0,0,0,0);z-index: 999;" v-show="showSeason" @click.stop="showSeason=false" ></mark> <el-input :placeholder="placeholder" v-model="showValue" v-bind="$attrs" @focus="clickInput" ref="inputText"> <i slot="prefix" class="el-input__icon el-icon-date"></i> </el-input> <el-card class="box-card" style="width: 322px;padding: 0 30px 20px;margin-top: 10px;position: fixed;z-index: 9999" :style="{top:divTop + 'px'}" v-show="showSeason" ref="card" > <div class="clearfix" style="text-align: center;padding: 0;" slot="header"> <button class="el-picker-panel__icon-btn el-date-picker__prev-btn el-icon-d-arrow-left" type="button" aria-label="前一年" @click="prev" ></button> <span class="el-date-picker__header-label">{{ year }}年</span> <button class="el-picker-panel__icon-btn el-date-picker__next-btn el-icon-d-arrow-right" type="button" aria-label="后一年" @click="next" ></button> </div> <div class="text item" style="text-align: center;"> <el-button style="width: 40%;color: #606266;float: left;" type="text" size="medium" @click="selectSeason(0)" >第一季度 </el-button> <el-button style="width: 40%;color: #606266;float: right;" type="text" size="medium" @click="selectSeason(1)" >第二季度 </el-button> </div> <div class="text item" style="text-align: center;"> <el-button style="width: 40%;color: #606266;float: left;" type="text" size="medium" @click="selectSeason(2)" >第三季度 </el-button> <el-button style="width: 40%;color: #606266;float: right;" type="text" size="medium" @click="selectSeason(3)" >第四季度 </el-button> </div> </el-card> </div> </template> <script> export default { name: "quarter-picker", model: { prop: 'inputValue', event: 'inputValue' }, props: { valueArr: { type: Array, default: () => { return ['01-01,03-31', '04-01,06-30', '07-01,09-30', '10-01,12-31']; } }, placeholder: { type: String, default: '请选择季度' }, inputValue: { type: Array, default: function() { return []; } }, changeValue: { type: Function, default: () => {} }, otherData: { type: Object, default: () => { return {}; } } }, mounted() { if (this.inputValue != null && this.inputValue.length > 0) { this.showText(this.inputValue); } window.addEventListener('scroll', this.handleScroll, true); }, watch: { inputValue(newValue) { if (newValue.length > 0) { this.showText(newValue); } else { this.showValue = ""; } } }, data() { return { showSeason: false, showValue: '', year: new Date().getFullYear(), season: '', divTop: 0 }; }, methods: { handleScroll() { let inputText = this.$refs.inputText.$el; if (inputText.getBoundingClientRect().top + 220 > document.body.offsetHeight) { this.divTop = inputText.getBoundingClientRect().top - 215; } else { this.divTop = inputText.getBoundingClientRect().top + 30; } }, clickInput() { this.handleScroll(); this.showSeason = true; }, prev() { this.year = this.year * 1 - 1; }, next() { this.year = this.year * 1 + 1; }, selectSeason(i) { let that = this; that.season = i + 1; // 得到当前季度 let arr = that.valueArr[i].split(','); let value = []; let start = that.year + '-' + arr[0]; // 得到当前季度的开始日期 let end = that.year + '-' + arr[1]; // 得到当前季度的结束日期 value.push(start); // 将季度开始日期和季度结束日期存入数组中 value.push(end); if (this.inputValue != null && this.inputValue[0] != value[0]) { this.changeValue(value, this.otherData); } this.$emit('inputValue', value); that.showSeason = false; this.showText(value); }, showText(value) { // value为数组,数组索引为0的值为季度开始时间 let arr = value[0].split('-'); // 将季度开始时间用-进行分割 this.year = arr[0]; let month = arr[1]; this.season = Math.ceil(month / 3); // 向上取整 this.showValue = `${this.year}年${this.season}季度`; // 设置显示格式 } } } </script> <style scoped> ._mark { position: fixed; top: 0; bottom: 0; left: 0; right: 0; background: rgba(0, 0, 0, 0); z-index: 999; } .yearBtn { text-align: center; padding: 0 } .box-card { width: 322px; padding: 0 3px 20px; margin-top: 10px; position: fixed; z-index: 9999 } .text.item { text-align: center; } .text.item >>> .el-button { width: 40%; color: #606266; } .text.item ._left { float: left; } .text.item ._right { float: right; } </style>
2、引入季度选择器组件
import QuarterPicker from "../../../components/quarter-picker/index";
3、注册季度选择器组件
components: { QuarterPicker },
4、使用季度选择器组件
<el-table-column label="季度" align="center" width="150px"> <template slot-scope="scope"> <quarter-picker v-model="scope.row.quarter" readonly="readonly" :other-data="scope.row" :change-value="saveQuarter" /> </template> </el-table-column>
通过other-data属性将scope.row传递到子组件,通过change-value将saveQuarter方法传递到子组件,然后在子组件中调用saveQuarter方法。
其中saveQuarter方法如下:
saveQuarter(value, row) { const data = { id: row.id, start: value[0], // 季度开始日期 end: value[1] // 季度结束日期 }; inAPI.saveOrUpdateQuarter(data).then(response => { if (response.success) { this.$message.success(response.msg); } }); },
后台可以使用NVARCHAR2存储季度,长度为6,格式为:年度-季度,如2022-1,2022-2,2022-3,2022-4
将季度开始时间转化为季度的方法:
private String toQuarter(String start) { String[] arr = start.split("-"); String year = arr[0]; String month = arr[1]; int q = Integer.parseInt(month) / 3 + 1; return year + "-" + q; }
将季度转成季度开始日期和季度结束日期的方法:
private List<String> toRange(String quarter) { List<String> result = new ArrayList<>(); String[] arr = quarter.split("-"); String year = arr[0]; String q = arr[1]; switch (q) { case "1": result.add(year + "-01-01"); result.add(year + "-03-31"); break; case "2": result.add(year + "-04-01"); result.add(year + "-06-30"); break; case "3": result.add(year + "-07-01"); result.add(year + "-09-30"); break; case "4": result.add(year + "-10-01"); result.add(year + "-12-31"); break; } return result; }