<template>
<div class="custom-date">
<div class="left">
<el-icon
v-if="currentIndex != 3"
@click="preNum"
><ArrowLeft
/></el-icon>
<div v-if="currentIndex == 0">{{ currentDay }}</div>
<div v-if="currentIndex == 1">{{ currentWeek }}</div>
<div v-if="currentIndex == 2">{{ currentMonth }}</div>
<el-date-picker
v-if="currentIndex == 3"
v-model="currentCustom"
:teleported="false"
@change="cusomChange"
@calendar-change="calendarChange"
type="daterange"
:disabled-date="disabledDate"
style="width: 225px; height: 30px"
format="YYYY/MM/DD"
value-format="YYYY-MM-DD"
:clearable="false"
range-separator="~"
start-placeholder="开始日期"
end-placeholder="结束日期" />
<el-icon
v-if="currentIndex != 3"
@click="nextNum"
><ArrowRight
/></el-icon>
</div>
<div class="right">
<template
v-for="(item, index) in dateArr"
:key="index">
<div
@click="callbackDateType(index)"
:class="['right-item', currentIndex == index ? 'active' : '']">
{{ item }}
</div>
</template>
</div>
</div>
</template>
<script lang="ts" setup>
import { ArrowLeft, ArrowRight } from '@element-plus/icons-vue';
import moment from 'moment';
moment.locale('zh-cn'); //dayjs 时间本地化
type Props = {
delay?: number;
};
const props = withDefaults(defineProps<Props>(), {
delay: 400
});
const emits = defineEmits(['changeCurrentTime']);
const currentIndex = ref<number>(0);
const logIndex = ref<number>(0); // 记录index
const dateArr = ref(['日', '周', '月', '自定义']);
const currentDay = ref('');
const currentDayNum = ref(1);
const currentWeek = ref('');
const currentWeekNum = ref(1);
const currentMonth = ref('');
const currentMonthNum = ref(1);
const currentCustom = ref();
const optionalRange = ref();
const timer = ref();
const clearAllNum = () => {
currentDayNum.value = 1;
currentWeekNum.value = 1;
currentMonthNum.value = 1;
currentCustom.value = getCurrentWeek('log');
};
// 点击日、周、月、自定义
const callbackDateType = (index) => {
currentIndex.value = index;
if (logIndex.value == currentIndex.value) return;
clearAllNum(); // 清楚缓存时间
if (currentIndex.value == 0) {
getCurrentDay();
} else if (currentIndex.value == 1) {
getCurrentWeek();
} else if (currentIndex.value == 2) {
getCurrentMonth();
} else if (currentIndex.value == 3) {
if (timer.value) {
clearTimeout(timer.value);
}
timer.value = setTimeout(() => {
emits('changeCurrentTime', currentCustom.value[0], currentCustom.value[1], 'custom');
}, props.delay);
}
logIndex.value = index;
};
/**
* @funciton 获取日
*/
const getCurrentDay = () => {
const arr = ['周一', '周二', '周三', '周四', '周五', '周六', '周日'];
let day = moment().subtract(currentDayNum.value, 'day').format('YYYY/MM/DD');
let week = moment().subtract(currentDayNum.value, 'day').weekday() - 1;
currentDay.value = arr[week == -1 ? 6 : week] + ' ' + day;
if (timer.value) {
clearTimeout(timer.value);
}
timer.value = setTimeout(() => {
emits('changeCurrentTime', day, '', 'day');
}, props.delay);
};
/**
* @funciton 获取周
*/
const getCurrentWeek = (isReturn?) => {
// 获取当前日期
const currentDate = moment();
// clone必须加否则会改变currentDate当前日期
let currentWeekDay = currentDate.clone().weekday();
// day指定周几 subtract指定本周、上周为2 下周-1
let firstThursday = currentDate
.clone()
.day(5)
.subtract(currentWeekDay > 4 ? currentWeekNum.value : currentWeekNum.value + 1, 'week')
.format('YYYY/MM/DD');
let lastThursday = currentDate
.clone()
.day(4)
.subtract(currentWeekDay > 4 ? currentWeekNum.value - 1 : currentWeekNum.value, 'week')
.format('YYYY/MM/DD');
if (isReturn == 'log') {
return [firstThursday, lastThursday];
} else {
currentWeek.value = firstThursday + '~' + lastThursday;
if (timer.value) {
clearTimeout(timer.value);
}
timer.value = setTimeout(() => {
emits('changeCurrentTime', firstThursday, lastThursday, 'week');
}, props.delay);
}
};
/**
* @funciton 获取月
*/
const getCurrentMonth = () => {
// clone必须加否则会改变currentDate当前日期
const day = moment().subtract(currentMonthNum.value, 'month').format('YYYY-MM');
let monthfirst = moment(day).startOf('month').format('YYYY/MM/DD');
let monthend = moment(day).endOf('month').format('YYYY/MM/DD');
currentMonth.value = monthfirst + '~' + monthend;
if (timer.value) {
clearTimeout(timer.value);
}
timer.value = setTimeout(() => {
emits('changeCurrentTime', monthfirst, monthend, 'month');
}, props.delay);
};
/**
* @funciton 获取自定义
*/
const cusomChange = (e) => {
optionalRange.value = '';
emits('changeCurrentTime', e[0], e[1], 'custom');
};
const calendarChange = (e) => {
optionalRange.value = e[0];
};
/**
* @function 禁止时间
*/
const disabledDate = (time: Date) => {
const startDay = new Date(moment(optionalRange.value).subtract(90, 'days').format('YYYY-MM-DD')).getTime();
const endDay = new Date(moment(optionalRange.value).subtract(-90, 'days').format('YYYY-MM-DD')).getTime();
const yesterday = moment().subtract(1, 'days').format('YYYY-MM-DD');
if (!optionalRange.value) {
return time.getTime() > new Date(yesterday).getTime();
} else {
const day = Math.abs(moment(yesterday).diff(moment(optionalRange.value).format('YYYY-MM-DD'), 'days'));
if (day < 90) {
return time.getTime() > new Date(yesterday).getTime() || time.getTime() < startDay;
} else {
return time.getTime() < startDay || time.getTime() > endDay;
}
}
};
/**
* @function 点击<
* currentIndex.value == 0 日 1 周 2月
*/
const preNum = () => {
if (currentIndex.value == 0) {
currentDayNum.value += 1;
getCurrentDay();
} else if (currentIndex.value == 1) {
currentWeekNum.value += 1;
getCurrentWeek();
} else if (currentIndex.value == 2) {
currentMonthNum.value += 1;
getCurrentMonth();
}
};
/**
* @function 点击>
* currentIndex.value == 0 日 1 周 2月
*/
const nextNum = () => {
if (currentIndex.value == 0) {
if (
new Date(currentDay.value.slice(3, currentDay.value.length)).getTime() >=
new Date(moment().subtract(1, 'day').format('YYYY/MM/DD')).getTime()
)
return;
currentDayNum.value -= 1;
getCurrentDay();
} else if (currentIndex.value == 1) {
const currentWeekDay = moment().clone().weekday();
const lastweek = new Date(
moment()
.clone()
.day(4)
.subtract(currentWeekDay > 0 && currentWeekDay < 5 ? 1 : 0, 'week')
.format('YYYY/MM/DD')
).getTime();
// 如果可选择数据周周四 大于本周四则直接返回
if (new Date(currentWeek.value.slice(11, currentWeek.value.length)).getTime() >= lastweek) return;
currentWeekNum.value -= 1;
getCurrentWeek();
} else if (currentIndex.value == 2) {
const lastmonth = new Date(
moment(moment().subtract(1, 'month').format('YYYY-MM')).endOf('month').format('YYYY/MM/DD')
).getTime();
if (new Date(currentMonth.value.slice(11, currentMonth.value.length)).getTime() >= new Date(lastmonth).getTime())
return;
currentMonthNum.value -= 1;
getCurrentMonth();
}
};
const init = () => {
clearAllNum();
getCurrentDay();
};
init();
</script>
<style lang="less" scoped>
.custom-date {
display: flex;
align-items: center;
::v-deep(.today .el-date-table-cell__text) {
font-weight: normal;
color: var(--el-text-color-placeholder);
}
.left {
display: flex;
width: 225px;
height: 32px;
align-items: center;
border-radius: 3px;
border: 1px solid #dcdcdc;
justify-content: space-around;
color: rgba(0, 0, 0, 0.9);
font-family: 'PingFang SC';
font-size: 14px;
font-style: normal;
font-weight: 400;
margin-right: 8px;
::v-deep(.el-range-input),
::v-deep(.el-range-input)::placeholder {
height: 32px;
color: rgba(0, 0, 0, 0.9) !important;
font-size: 14px !important;
}
::v-deep(.el-select),
::v-deep(.el-cascader),
::v-deep(.el-input),
::v-deep(.el-date-editor),
::v-deep(.el-range-editor) {
box-shadow: none !important;
border: none !important;
.el-input__wrapper {
box-shadow: none !important;
border: none !important;
}
}
::v-deep(.el-date-editor .el-range-separator) {
color: rgba(0, 0, 0, 0.9) !important;
}
.el-icon {
cursor: pointer;
}
}
.right {
display: flex;
align-items: center;
.right-item {
display: flex;
align-items: center;
justify-content: center;
width: 74px;
height: 32px;
color: #00000099;
text-align: center;
font-family: 'PingFang SC';
font-size: 14px;
font-style: normal;
font-weight: 400;
border-bottom: 1px solid #dcdcdc;
border-top: 1px solid #dcdcdc;
border-left: 1px solid #dcdcdc;
box-sizing: border-box;
cursor: pointer;
}
.right-item:nth-of-type(1) {
border-top-left-radius: 3px;
border-bottom-left-radius: 3px;
}
.right-item:last-child {
border-right: 1px solid #dcdcdc;
border-top-right-radius: 3px;
border-bottom-right-radius: 3px;
}
.active {
border: 1px solid #4679fa !important;
color: #0052d9;
box-sizing: border-box;
}
}
}
</style>