mirror of https://github.com/ElemeFE/element
191 lines
5.1 KiB
Vue
191 lines
5.1 KiB
Vue
<script>
|
|
import fecha from 'element-ui/src/utils/date';
|
|
import { range as rangeArr, getFirstDayOfMonth, getPrevMonthLastDays, getMonthDays, getI18nSettings, validateRangeInOneMonth } from 'element-ui/src/utils/date-util';
|
|
export default {
|
|
|
|
props: {
|
|
selectedDay: String, // formated date yyyy-MM-dd
|
|
range: {
|
|
type: Array,
|
|
validator(val) {
|
|
if (!(val && val.length)) return true;
|
|
const [start, end] = val;
|
|
return validateRangeInOneMonth(start, end);
|
|
}
|
|
},
|
|
date: Date,
|
|
hideHeader: Boolean
|
|
},
|
|
|
|
inject: ['elCalendar'],
|
|
|
|
methods: {
|
|
toNestedArr(days) {
|
|
return rangeArr(days.length / 7).map((_, index) => {
|
|
const start = index * 7;
|
|
return days.slice(start, start + 7);
|
|
});
|
|
},
|
|
|
|
getFormateDate(day, type) {
|
|
if (!day || ['prev', 'current', 'next'].indexOf(type) === -1) {
|
|
throw new Error('invalid day or type');
|
|
}
|
|
let prefix = this.curMonthDatePrefix;
|
|
if (type === 'prev') {
|
|
prefix = this.prevMonthDatePrefix;
|
|
} else if (type === 'next') {
|
|
prefix = this.nextMonthDatePrefix;
|
|
}
|
|
day = `00${day}`.slice(-2);
|
|
return `${prefix}-${day}`;
|
|
},
|
|
|
|
getCellClass({ text, type}) {
|
|
const classes = [type];
|
|
if (type === 'current') {
|
|
const date = this.getFormateDate(text, type);
|
|
if (date === this.selectedDay) {
|
|
classes.push('is-selected');
|
|
}
|
|
if (date === this.formatedToday) {
|
|
classes.push('is-today');
|
|
}
|
|
}
|
|
return classes;
|
|
},
|
|
|
|
pickDay({ text, type }) {
|
|
const date = this.getFormateDate(text, type);
|
|
this.$emit('pick', date);
|
|
},
|
|
|
|
cellRenderProxy({ text, type }) {
|
|
let render = this.elCalendar.$scopedSlots.dateCell;
|
|
if (!render) return <span>{ text }</span>;
|
|
|
|
const day = this.getFormateDate(text, type);
|
|
const date = new Date(day);
|
|
const data = {
|
|
isSelected: this.selectedDay === day,
|
|
type: `${type}-month`,
|
|
day
|
|
};
|
|
return render({ date, data });
|
|
}
|
|
},
|
|
|
|
computed: {
|
|
prevMonthDatePrefix() {
|
|
const temp = new Date(this.date.getTime());
|
|
temp.setDate(0);
|
|
return fecha.format(temp, 'yyyy-MM');
|
|
},
|
|
|
|
curMonthDatePrefix() {
|
|
return fecha.format(this.date, 'yyyy-MM');
|
|
},
|
|
|
|
nextMonthDatePrefix() {
|
|
const temp = new Date(this.date.getFullYear(), this.date.getMonth() + 1, 1);
|
|
return fecha.format(temp, 'yyyy-MM');
|
|
},
|
|
|
|
formatedToday() {
|
|
return this.elCalendar.formatedToday;
|
|
},
|
|
|
|
isInRange() {
|
|
return this.range && this.range.length;
|
|
},
|
|
|
|
rows() {
|
|
let days = [];
|
|
// if range exists, should render days in range.
|
|
if (this.isInRange) {
|
|
const [start, end] = this.range;
|
|
const currentMonthRange = rangeArr(end.getDate() - start.getDate() + 1).map((_, index) => ({
|
|
text: start.getDate() + index,
|
|
type: 'current'
|
|
}));
|
|
let remaining = currentMonthRange.length % 7;
|
|
remaining = remaining === 0 ? 0 : 7 - remaining;
|
|
const nextMonthRange = rangeArr(remaining).map((_, index) => ({
|
|
text: index + 1,
|
|
type: 'next'
|
|
}));
|
|
days = currentMonthRange.concat(nextMonthRange);
|
|
} else {
|
|
const date = this.date;
|
|
let firstDay = getFirstDayOfMonth(date);
|
|
firstDay = firstDay === 0 ? 7 : firstDay;
|
|
const prevMonthDays = getPrevMonthLastDays(date, firstDay - 1).map(day => ({
|
|
text: day,
|
|
type: 'prev'
|
|
}));
|
|
const currentMonthDays = getMonthDays(date).map(day => ({
|
|
text: day,
|
|
type: 'current'
|
|
}));
|
|
days = [...prevMonthDays, ...currentMonthDays];
|
|
const nextMonthDays = rangeArr(42 - days.length).map((_, index) => ({
|
|
text: index + 1,
|
|
type: 'next'
|
|
}));
|
|
days = days.concat(nextMonthDays);
|
|
}
|
|
return this.toNestedArr(days);
|
|
}
|
|
},
|
|
|
|
data() {
|
|
const dayNames = getI18nSettings().dayNames;
|
|
return {
|
|
DAYS: dayNames.slice(1).concat(dayNames[0])
|
|
};
|
|
},
|
|
|
|
render() {
|
|
const thead = this.hideHeader ? null : (<thead>
|
|
{
|
|
this.DAYS.map(day => <th key={day}>{ day }</th>)
|
|
}
|
|
</thead>);
|
|
return (
|
|
<table
|
|
class={{
|
|
'el-calendar-table': true,
|
|
'is-range': this.isInRange
|
|
}}
|
|
cellspacing="0"
|
|
cellpadding="0">
|
|
{
|
|
thead
|
|
}
|
|
<tbody>
|
|
{
|
|
this.rows.map((row, index) => <tr
|
|
class={{
|
|
'el-calendar-table__row': true,
|
|
'el-calendar-table__row--hide-border': index === 0 && this.hideHeader
|
|
}}
|
|
key={index}>
|
|
{
|
|
row.map((cell, key) => <td key={key}
|
|
class={ this.getCellClass(cell) }
|
|
onClick={this.pickDay.bind(this, cell)}>
|
|
<div class="el-calendar-day">
|
|
{
|
|
this.cellRenderProxy(cell)
|
|
}
|
|
</div>
|
|
</td>)
|
|
}
|
|
</tr>)
|
|
}
|
|
</tbody>
|
|
</table>);
|
|
}
|
|
};
|
|
</script>
|