绩效考核手机版
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

425 lines
12 KiB

3 years ago
<template>
<s-picker
ref="picker"
:custom-class="c_class"
:custom-style="custom_style"
multiple
:title="title"
:visible="visible"
:columns="columns"
:value="values"
:show-cancel="showCancel"
:mask="mask"
:mask-close="maskClose"
@change="onChange"
@update:visible="updateVisible"
@cancel="onCancel"
@confirm="onConfirm"
@open="$emit('open')"
@opend="$emit('opend')"
@close="$emit('close')"
@closed="$emit('closed')"
/>
</template>
<script>
import componentMixin from '../../mixins/componentMixin';
import formatDate from '../../utils/formatDate';
import getDaysInMonth from '../../utils/getDaysInMonth';
import parseDate from '../../utils/parseDate';
const yearReg = /^\d{4}$/;
const timeReg = /^\d{2}(:\d{2})+$/;
/**
* s-date-time-picker 日期时间选择器
* @description 选择日期和时间
* @property {String} title 标题
* @property {String} type = [date | time | datetime | year | month] 选择类型
* @property {Boolean} visible 显示隐藏双向绑定
* @property {String|Number} value 选择结果双向绑定
* @property {String|Number} start 开始时间
* @property {String|Number} end 结束时间
* @property {Boolean} showTag 是否显示中文单位
* @property {Function} filter ({name,list,valueList}) 过滤每列数据
* @property {Boolean} showCancel 是否显示取消按钮
* @property {Boolean} mask 是否显示遮罩
* @property {Boolean} maskClose 点击遮罩是否关闭
* @event {Function} cancel 点击取消按钮或遮罩关闭取消时触发
* @event {Function} confirm ({type,value,valueList,dataList,timestamp}) 选中事件
* @event {Function} open 打开弹出层时触发
* @event {Function} opened 打开弹出层且动画结束后触发
* @event {Function} close 关闭弹出层时触发
* @event {Function} closed 关闭弹出层且动画结束后触发
* @example <s-date-time-picker v-model="date" :visible.sync="dateVisible" />
*/
export default {
name: 'SDateTimePicker',
mixins: [componentMixin],
props: {
title: String,
type: {
type: String,
default: 'date',
},
visible: Boolean,
value: [String, Number],
start: {
type: [String, Number],
default: '1970/01/01 00:00',
},
end: {
type: [String, Number],
default: formatDate(new Date(new Date().getFullYear() + 10, 11, 31), 'YYYY/MM/DD 23:59'),
},
showTag: {
type: Boolean,
default: true,
},
filter: Function,
showCancel: {
type: Boolean,
default: true,
},
mask: {
type: Boolean,
default: true,
},
maskClose: Boolean,
},
data: () => ({
columns: [],
values: [],
valueList: [],
strDate: formatDate(new Date(), 'YYYY/MM/DD'),
}),
computed: {
c_class() {
return this.$mergeClass('s-date-time-picker', this.custom_class);
},
startTime() {
const { start, endTime, strDate } = this;
let date = start;
if (yearReg.test(date)) {
date = `${date}/01/01`;
} else if (timeReg.test(date)) {
date = `${strDate} ${date}`;
}
date = parseDate(date).getTime();
return date > endTime ? endTime : date;
},
endTime() {
const { end, strDate } = this;
let date = end;
if (yearReg.test(date)) {
date = `${date}/01/01`;
} else if (timeReg.test(date)) {
date = `${strDate} ${date}`;
}
return parseDate(date).getTime();
},
startYear() {
return parseInt(formatDate(this.startTime, 'YYYY'));
},
startMonth() {
return parseInt(formatDate(this.startTime, 'MM'));
},
startDay() {
return parseInt(formatDate(this.startTime, 'DD'));
},
startHour() {
return parseInt(formatDate(this.startTime, 'HH'));
},
startMinute() {
return parseInt(formatDate(this.startTime, 'mm'));
},
endYear() {
return parseInt(formatDate(this.endTime, 'YYYY'));
},
endMonth() {
return parseInt(formatDate(this.endTime, 'MM'));
},
endDay() {
return parseInt(formatDate(this.endTime, 'DD'));
},
endHour() {
return parseInt(formatDate(this.endTime, 'HH'));
},
endMinute() {
return parseInt(formatDate(this.endTime, 'mm'));
},
yearList() {
const list = [];
const { startYear, endYear, showTag } = this;
const tag = showTag ? '年' : '';
for (let i = startYear; i <= endYear; i++) {
const value = String(i).padStart(4, '0');
list.push({ label: value + tag, value });
}
return this.filterList('year', list);
},
monthList() {
const list = [];
const { showTag } = this;
const tag = showTag ? '月' : '';
const [start, end] = this.getListRange(1, 'YYYY', 1, 12);
for (let i = start; i <= end; i++) {
const value = String(i).padStart(2, '0');
list.push({ label: value + tag, value });
}
return this.filterList('month', list);
},
dayList() {
const list = [];
const [year, month] = this.valueList;
if (year && month) {
const { showTag } = this;
const tag = showTag ? '日' : '';
const [start, end] = this.getListRange(2, 'YYYYMM', 1, getDaysInMonth(year, month));
for (let i = start; i <= end; i++) {
const value = String(i).padStart(2, '0');
list.push({ label: value + tag, value });
}
}
return this.filterList('day', list);
},
hourList() {
const list = [];
const { type, startHour, endHour, showTag } = this;
const tag = showTag ? '时' : '';
let range = [0, 0];
if (type === 'time') {
range = [startHour, endHour];
} else {
range = this.getListRange(3, 'YYYYMMDD', 0, 23);
}
const [start, end] = range;
for (let i = start; i <= end; i++) {
const value = String(i).padStart(2, '0');
list.push({ label: value + tag, value });
}
return this.filterList('hour', list);
},
minuteList() {
const list = [];
const { type, startHour, endHour, startMinute, endMinute, showTag } = this;
const tag = showTag ? '分' : '';
let range = [0, 0];
const min = 0;
const max = 59;
if (type !== 'time') {
range = this.getListRange(4, 'YYYYMMDDHH', min, max);
} else {
let [hour] = this.valueList;
if (hour) {
hour = parseInt(hour);
range = [
hour <= startHour ? startMinute : min,
hour >= endHour ? endMinute : max,
];
}
}
const [start, end] = range;
for (let i = start; i <= end; i++) {
const value = String(i).padStart(2, '0');
list.push({ label: value + tag, value });
}
return this.filterList('minute', list);
},
initState() {
return [
this.type,
this.startTime,
this.endTime,
];
},
},
watch: {
initState() {
this.init();
},
value() {
this.setValue(this.value);
},
},
created() {
this.init();
},
methods: {
init() {
switch (this.type) {
case 'datetime':
this.columns = [this.yearList, this.monthList, this.dayList, this.hourList, this.minuteList];
break;
case 'year':
this.columns = [this.yearList];
break;
case 'month':
this.columns = [this.yearList, this.monthList];
break;
case 'time':
this.columns = [this.hourList, this.minuteList];
break;
default:
this.columns = [this.yearList, this.monthList, this.dayList];
break;
}
this.setValue(this.value);
},
getListRange(n, fmt, min, max) {
const { startTime, endTime, valueList } = this;
const values = valueList.slice(0, n);
let range = [0, 0];
if (values.every(value => value)) {
const current = values.join('');
range = [
current <= formatDate(startTime, fmt) ? this[[
'startYear',
'startMonth',
'startDay',
'startHour',
'startMinute',
][n]] : min,
current >= formatDate(endTime, fmt) ? this[[
'endYear',
'endMonth',
'endDay',
'endHour',
'endMinute',
][n]] : max,
];
}
return range;
},
filterList(name, list) {
const filter = this.$getPropsFn('filter');
return filter ? filter({
name,
list,
valueList: this.valueList,
}) : list;
},
updateVisible(visible) {
this.$emit('update:visible', visible);
},
setValue(value) {
const { type, strDate } = this;
let date = value;
if (!date) {
date = new Date();
} else if (yearReg.test(date)) {
date = `${date}/01/01`;
} else if (timeReg.test(date)) {
date = `${strDate} ${date}`;
}
date = parseDate(Math.min(Math.max(parseDate(date).getTime(), this.startTime), this.endTime));
const values = [
formatDate(date, 'YYYY'),
formatDate(date, 'MM'),
formatDate(date, 'DD'),
formatDate(date, 'HH'),
formatDate(date, 'mm'),
];
switch (type) {
case 'year':
this.values = values.slice(0, 1);
break;
case 'month':
this.values = values.slice(0, 2);
break;
case 'datetime':
this.values = values.slice(0);
break;
case 'time':
this.values = values.slice(3);
break;
default:
this.values = values.slice(0, 3);
break;
}
},
onChange({ i, setData, valueList }) {
this.valueList = valueList;
switch (this.type) {
case 'datetime':
if (i < 1) {
setData(1, this.monthList);
}
if (i < 2) {
setData(2, this.dayList);
}
if (i < 3) {
setData(3, this.hourList);
}
if (i < 4) {
setData(4, this.minuteList);
}
break;
case 'year':
break;
case 'month':
if (i < 1) {
setData(1, this.monthList);
}
break;
case 'time':
if (i < 1) {
setData(1, this.minuteList);
}
break;
default:
if (i < 1) {
setData(1, this.monthList);
}
if (i < 2) {
setData(2, this.dayList);
}
break;
}
},
onCancel() {
this.$emit('cancel');
},
onConfirm({ valueList, dataList }) {
let value = '';
let date = '';
const { type, strDate } = this;
switch (type) {
case 'datetime':
date = parseDate(valueList.slice(0, 3).join('/') + ' ' + valueList.slice(3, 5).join(':'));
value = formatDate(date, 'YYYY-MM-DD HH:mm');
break;
case 'year':
date = parseDate(valueList[0] + '/01/01');
value = formatDate(date, 'YYYY');
break;
case 'month':
date = parseDate(valueList.join('/') + '/01');
value = formatDate(date, 'YYYY-MM');
break;
case 'time':
date = parseDate(strDate + ' ' + valueList.join(':'));
value = formatDate(date, 'HH:mm');
break;
default:
date = parseDate(valueList.join('/'));
value = formatDate(date, 'YYYY-MM-DD');
break;
}
let timestamp = date.getTime();
if (type === 'time') {
timestamp -= parseDate(strDate).getTime();
}
this.$emit('input', value);
this.$emit('confirm', {
type,
value,
valueList,
dataList,
timestamp,
});
},
},
};
</script>