319 lines
9.5 KiB
Vue
319 lines
9.5 KiB
Vue
<template>
|
||
<div class='time-control'>
|
||
<el-select
|
||
class='select'
|
||
v-model='timeUnit'
|
||
placeholder='选择时间单位'
|
||
@change='handleChange'
|
||
>
|
||
<!-- 采用 v-for 动态渲染 -->
|
||
<el-option
|
||
v-for='unit in timeUnits'
|
||
:key='unit.value'
|
||
:label='unit.label'
|
||
:value='unit.value'
|
||
></el-option>
|
||
</el-select>
|
||
|
||
<!-- 禁用时间选择器 -->
|
||
<div class='date-display'>
|
||
<el-date-picker
|
||
class='date-picker'
|
||
v-model='startDate'
|
||
type='date'
|
||
placeholder='起始时间'
|
||
@change='emitDateChange'
|
||
:disabled-date='disableStartDate'
|
||
:readonly="timeUnit != '自定义'"
|
||
></el-date-picker>
|
||
<el-text>~</el-text>
|
||
<el-date-picker
|
||
class='date-picker'
|
||
v-model='endDate'
|
||
type='date'
|
||
placeholder='结束时间'
|
||
@change='emitDateChange'
|
||
:disabled-date='disableEndDate'
|
||
:readonly="timeUnit !== '自定义'"
|
||
></el-date-picker>
|
||
</div>
|
||
<div class='date-display' v-if="timeUnit !== '自定义'">
|
||
<el-button
|
||
style='width: 10px;'
|
||
class='triangle-button'
|
||
type='primary'
|
||
@click='prevPeriod'
|
||
@change='emitDateChange'
|
||
>
|
||
<div class='left_triangle'></div>
|
||
</el-button>
|
||
<el-button class='triangle-button' type='primary' @click='goToCurrent'>
|
||
当前
|
||
</el-button>
|
||
<el-button
|
||
style='width: 10px;'
|
||
class='triangle-button'
|
||
type='primary'
|
||
@click='nextPeriod'
|
||
:disabled='isNextDisabled'
|
||
>
|
||
<div class='right_triangle'></div>
|
||
</el-button>
|
||
</div>
|
||
</div>
|
||
</template>
|
||
|
||
|
||
<script setup lang='ts'>
|
||
import { ref, onMounted, defineProps, defineEmits } from 'vue'
|
||
|
||
// 定义时间单位的类型
|
||
interface TimeUnit {
|
||
label: string;
|
||
value: string;
|
||
}
|
||
|
||
// 定义组件的props,包含包括和排除的时间单位
|
||
const props = defineProps({
|
||
include: {
|
||
type: Array as () => string[],
|
||
default: () => ['日', '周', '月', '季度', '年', '自定义'],
|
||
},
|
||
exclude: {
|
||
type: Array as () => string[],
|
||
default: () => [],
|
||
},
|
||
default: {
|
||
type: String,
|
||
default: '月',
|
||
},
|
||
})
|
||
|
||
// 定义事件
|
||
const emit = defineEmits<{
|
||
(e: 'update-dates', startDate: string, endDate: string): void;
|
||
}>()
|
||
const timeUnit = ref<string>(props.default) // 默认选择
|
||
const startDate = ref<Date>(new Date()) // 起始日期
|
||
const endDate = ref<Date>(new Date()) // 结束日期
|
||
const isNextDisabled = ref<boolean>(false) // 控制下一周期按钮的禁用状态
|
||
const today = ref<Date>(new Date()) // 当前日期
|
||
// 过滤出可用的时间单位
|
||
const timeUnits = ref<TimeUnit[]>(
|
||
props.include.filter(unit => !props.exclude.includes(unit)).map(unit => ({
|
||
label: unit,
|
||
value: unit,
|
||
})),
|
||
)
|
||
|
||
// 发出日期变化事件
|
||
const emitDateChange = () => {
|
||
emit('update-dates', formatDate(startDate.value), formatDate(endDate.value))
|
||
|
||
}
|
||
|
||
// 在组件挂载时更新日期范围
|
||
onMounted(() => {
|
||
updateDateRange()
|
||
})
|
||
const handleChange = (unit: string) => {
|
||
// 根据选择的时间单位处理日期变化
|
||
if (unit !== '自定义') {
|
||
updateDateRange()
|
||
} else {
|
||
// 自定义选项逻辑
|
||
startDate.value = new Date(new Date().setDate(new Date().getDate() - 1))
|
||
endDate.value = new Date()
|
||
}
|
||
timeUnit.value = unit
|
||
|
||
// 确保开始时间和结束时间不为空
|
||
if (!startDate.value) {
|
||
startDate.value = new Date()
|
||
}
|
||
if (!endDate.value) {
|
||
endDate.value = new Date()
|
||
}
|
||
|
||
emitDateChange() // 变化时也发出更新事件
|
||
updateNextButtonStatus()
|
||
}
|
||
const updateDateRange = () => {
|
||
|
||
// 根据选择的时间单位计算起始和结束日期
|
||
if (timeUnit.value === '日') {
|
||
startDate.value = today.value
|
||
endDate.value = today.value
|
||
} else if (timeUnit.value === '周') {
|
||
startDate.value = getStartOfWeek(today.value)
|
||
endDate.value = getEndOfWeek(today.value)
|
||
|
||
} else if (timeUnit.value === '月') {
|
||
// 获取本月的开始和结束日期
|
||
startDate.value = new Date(today.value.getFullYear(), today.value.getMonth(), 1);
|
||
endDate.value = new Date(today.value.getFullYear(), today.value.getMonth() + 1, 0);
|
||
|
||
// // 确保结束日期不超过今天
|
||
// if (endDate.value > today.value) {
|
||
// endDate.value = new Date(today.value);
|
||
// endDate.value.setHours(23, 59, 59, 999); // 设置结束时间为今天的23:59:59.999
|
||
// }
|
||
|
||
} else if (timeUnit.value === '季度') {
|
||
const quarter = Math.floor(today.value.getMonth() / 3);
|
||
startDate.value = new Date(today.value.getFullYear(), quarter * 3, 1);
|
||
endDate.value = new Date(today.value.getFullYear(), quarter * 3 + 3, 0);
|
||
|
||
// // 确保结束日期不超过今天
|
||
// if (endDate.value > today.value) {
|
||
// endDate.value = new Date(today.value);
|
||
// endDate.value.setHours(23, 59, 59, 999); // 设置结束时间为今天的23:59:59.999
|
||
// }
|
||
|
||
} else if (timeUnit.value === '年') {
|
||
startDate.value = new Date(today.value.getFullYear(), 0, 1);
|
||
endDate.value = new Date(today.value.getFullYear(), 11, 31);
|
||
|
||
// // 确保结束日期不超过今天
|
||
// if (endDate.value > today.value) {
|
||
|
||
// endDate.value = new Date(today.value);
|
||
// endDate.value.setHours(23, 59, 59, 999); // 设置结束时间为今天的23:59:59.999
|
||
// }
|
||
}
|
||
// 确保开始时间和结束时间不为空
|
||
if (!startDate.value) {
|
||
startDate.value = new Date()
|
||
}
|
||
if (!endDate.value) {
|
||
endDate.value = new Date()
|
||
}
|
||
|
||
updateNextButtonStatus()
|
||
}
|
||
const getStartOfWeek = (date: Date) => {
|
||
const startOfWeek = new Date(date)
|
||
const day = startOfWeek.getDay()
|
||
const diff = day === 0 ? -6 : 1 - day // 星期天的情况
|
||
startOfWeek.setDate(startOfWeek.getDate() + diff)
|
||
return startOfWeek
|
||
}
|
||
const getEndOfWeek = (date: Date) => {
|
||
const endOfWeek = new Date(date)
|
||
const day = endOfWeek.getDay()
|
||
const diff = day === 0 ? 0 : 7 - day // 星期天的情况
|
||
endOfWeek.setDate(endOfWeek.getDate() + diff)
|
||
|
||
// 获取今天的日期
|
||
const today = new Date();
|
||
today.setHours(23, 59, 59, 999); // 设置今天的结束时间(23:59:59.999)
|
||
|
||
// 返回不超过今天的结束时间
|
||
//return endOfWeek > today ? today : endOfWeek;
|
||
return endOfWeek
|
||
}
|
||
const prevPeriod = () => {
|
||
const prevStartDate = new Date(startDate.value)
|
||
const prevEndDate = new Date(endDate.value)
|
||
|
||
if (timeUnit.value === '日') {
|
||
prevStartDate.setDate(prevStartDate.getDate() - 1)
|
||
prevEndDate.setDate(prevEndDate.getDate() - 1)
|
||
} else if (timeUnit.value === '周') {
|
||
prevStartDate.setDate(prevStartDate.getDate() - 7)
|
||
prevEndDate.setDate(prevEndDate.getDate() - 7)
|
||
} else if (timeUnit.value === '月') {
|
||
|
||
|
||
prevStartDate.setMonth(prevStartDate.getMonth() - 1)
|
||
prevEndDate.setMonth(prevEndDate.getMonth() - 1)
|
||
|
||
|
||
|
||
} else if (timeUnit.value === '季度') {
|
||
prevStartDate.setMonth(prevStartDate.getMonth() - 3)
|
||
prevEndDate.setMonth(prevEndDate.getMonth() - 3)
|
||
} else if (timeUnit.value === '年') {
|
||
prevStartDate.setFullYear(prevStartDate.getFullYear() - 1)
|
||
prevEndDate.setFullYear(prevEndDate.getFullYear() - 1)
|
||
}
|
||
|
||
startDate.value = prevStartDate
|
||
endDate.value = prevEndDate
|
||
updateNextButtonStatus()
|
||
}
|
||
const goToCurrent = () => {
|
||
if (timeUnit.value !== '自定义') {
|
||
updateDateRange() // 更新为当前选择时间单位的时间范围
|
||
}
|
||
}
|
||
const nextPeriod = () => {
|
||
const nextStartDate = new Date(startDate.value)
|
||
const nextEndDate = new Date(endDate.value)
|
||
|
||
if (timeUnit.value === '日') {
|
||
nextStartDate.setDate(nextStartDate.getDate() + 1)
|
||
nextEndDate.setDate(nextEndDate.getDate() + 1)
|
||
} else if (timeUnit.value === '周') {
|
||
nextStartDate.setDate(nextStartDate.getDate() + 7)
|
||
nextEndDate.setDate(nextEndDate.getDate() + 7)
|
||
} else if (timeUnit.value === '月') {
|
||
nextStartDate.setMonth(nextStartDate.getMonth() + 1)
|
||
nextEndDate.setMonth(nextEndDate.getMonth() + 1)
|
||
} else if (timeUnit.value === '季度') {
|
||
nextStartDate.setMonth(nextStartDate.getMonth() + 3)
|
||
nextEndDate.setMonth(nextStartDate.getMonth() + 3)
|
||
} else if (timeUnit.value === '年') {
|
||
nextStartDate.setFullYear(nextStartDate.getFullYear() + 1)
|
||
nextEndDate.setFullYear(nextEndDate.getFullYear() + 1)
|
||
}
|
||
|
||
startDate.value = nextStartDate
|
||
endDate.value = nextEndDate
|
||
updateNextButtonStatus()
|
||
}
|
||
const updateNextButtonStatus = () => {
|
||
|
||
// 更新下一个按钮的禁用状态
|
||
const maxDate = new Date() // 假设最新日期为今天
|
||
// 将 maxDate 设置为当天的开始时间
|
||
maxDate.setHours(0, 0, 0, 0)
|
||
// 将 endDate 设置为当天的开始时间并进行比较
|
||
const endDateAdjusted = new Date(endDate.value)
|
||
endDateAdjusted.setHours(0, 0, 0, 0)
|
||
// 仅比较日期部分
|
||
isNextDisabled.value = endDateAdjusted >= maxDate
|
||
emitDateChange() // 变化时也发出更新事件
|
||
}
|
||
|
||
|
||
// 限制开始日期不能选择超过当前日期
|
||
const disableStartDate = (date: Date) => {
|
||
return date > today.value
|
||
}
|
||
// 限制结束日期不能超过当前日期且必须大于开始日期
|
||
const disableEndDate = (date: Date) => {
|
||
if (timeUnit.value !== '自定义') return false // 如果不是自定义时间单位,则不限制
|
||
const start = new Date(startDate.value)
|
||
return date > today.value || (start && date <= start)
|
||
}
|
||
|
||
|
||
// 格式化日期yyyy-mm-dd
|
||
function formatDate(date: Date | null): string {
|
||
if (!date) {
|
||
return '';
|
||
}
|
||
const year = date.getFullYear();
|
||
const month = String(date.getMonth() + 1).padStart(2, '0');
|
||
const day = String(date.getDate()).padStart(2, '0');
|
||
return `${year}-${month}-${day}`;
|
||
}
|
||
|
||
</script>
|
||
|
||
<style scoped lang='scss'>
|
||
@import "./index.scss";
|
||
</style>
|
||
|