效果图:
<script setup lang="ts">
import { ref } from "vue";
import dayjs, { Dayjs } from "dayjs";
import { Calendar } from "ant-design-vue";
import { useScheduleStore } from "../../schedule";
const scheduleStore = useScheduleStore();
const value = ref<Dayjs>();
const data: { content: string; start: string; end: string; sort?: number }[] = [
{ content: "123", start: "2024-11-20", end: "2024-11-20" },
{ content: "456", start: "2024-11-21", end: "2024-11-21" },
{ content: "789", start: "2024-11-23", end: "2024-11-30" },
{ content: "111", start: "2024-11-22", end: "2024-11-22" },
{ content: "222", start: "2024-11-20", end: "2024-11-26" },
{ content: "333", start: "2024-11-27", end: "2024-12-02" },
];
const dataSort = dataP => {
dataP.sort((a, b) => {
const dateA = dayjs(dayjs(a.start).format("YYYY-MM-DD")).valueOf();
const dateB = dayjs(dayjs(b.start).format("YYYY-MM-DD")).valueOf();
if (dateA - dateB === 0) {
const endA = dayjs(dayjs(a.end).format("YYYY-MM-DD")).valueOf();
const endB = dayjs(dayjs(b.end).format("YYYY-MM-DD")).valueOf();
return endB - endA;
}
return dateA - dateB;
});
};
dataSort(data);
// 判断是否显示杠
const isShowBar = (item, current) => {
if (item === undefined) return { isShow: false, isFirst: false, isLast: false };
const currentValue = dayjs(dayjs(current).format("YYYY-MM-DD")).valueOf();
const startValue = dayjs(dayjs(item.start).format("YYYY-MM-DD")).valueOf();
const endValue = dayjs(dayjs(item.end).format("YYYY-MM-DD")).valueOf();
return {
isShow: startValue <= currentValue && endValue >= currentValue,
isFirst: startValue === currentValue,
isLast: endValue === currentValue,
};
};
// 判断是否有更多
const isMore = current => {
const currentValue = dayjs(dayjs(current).format("YYYY-MM-DD")).valueOf();
return data.filter(item => {
const startValue = dayjs(dayjs(item.start).format("YYYY-MM-DD")).valueOf();
if (startValue === currentValue) return true;
});
};
// 选择数据
const selectData = current => {
const currentValue = dayjs(dayjs(current).format("YYYY-MM-DD")).valueOf();
const selectNewData = data.filter(item => {
const startValue = dayjs(dayjs(item.start).format("YYYY-MM-DD")).valueOf();
const endValue = dayjs(dayjs(item.end).format("YYYY-MM-DD")).valueOf();
return startValue <= currentValue && endValue >= currentValue;
});
const sortItem = selectNewData.find(item => item.sort);
if (sortItem) {
const noSortItem = selectNewData.find(item => !item.sort);
if (noSortItem) {
if (sortItem.sort === 1) noSortItem.sort = 2;
else if (sortItem.sort === 2) noSortItem.sort = 1;
}
} else selectNewData.forEach((item, index) => (item.sort = index + 1));
selectNewData.sort((a, b) => a.sort - b.sort);
return selectNewData;
};
// 获取内容
const getContent = (current, index) => {
return isShowBar(selectData(current)[index - 1], current).isFirst ? selectData(current)[index - 1].content : "";
};
</script>
<template>
<Calendar v-model:value="value">
<template #headerRender></template>
<template #dateFullCellRender="{ current }">
<div class="day-item">
<div
:class="{ current: scheduleStore.currentDay === dayjs(current).format('YYYY-MM-DD') }"
class="flex items-center justify-start"
>
<span class="num">{{ dayjs(current).format("DD") }}</span>
</div>
<template v-if="selectData(current).length === 1 && selectData(current)[0].sort === 2">
<div class="bar flex items-center justify-start" style="background-color: #fff">
<span class="q-ml-xs"></span>
</div>
<div
class="bar flex items-center justify-start"
v-if="isShowBar(selectData(current)[0], current).isShow"
:class="{
'first-left-bar': isShowBar(selectData(current)[0], current).isFirst,
'last-right-radius': isShowBar(selectData(current)[0], current).isLast,
}"
>
<span class="q-ml-xs">{{ getContent(current, 1) }}</span>
</div>
</template>
<template v-else>
<template v-for="index in 2">
<div
class="bar flex items-center justify-start"
v-if="isShowBar(selectData(current)[index - 1], current).isShow"
:class="{
'first-left-bar': isShowBar(selectData(current)[index - 1], current).isFirst,
'last-right-radius': isShowBar(selectData(current)[index - 1], current).isLast,
}"
>
<span class="q-ml-xs">{{ getContent(current, index) }}</span>
</div>
</template>
</template>
<div style="position: relative" v-if="isMore(current).length > 0">
<img
src="../../images/more.svg"
alt=""
width="35px"
height="35px"
style="position: absolute; top: -11px; left: 50%; transform: translateX(-50%)"
/>
</div>
</div>
</template>
</Calendar>
</template>
<style scoped lang="scss">
.events {
margin: 0;
padding: 0;
list-style: none;
.ant-badge-status {
width: 100%;
}
}
:deep(.ant-picker-content) {
border: 2px solid rgba(5, 5, 5, 0.06);
}
:deep(.ant-picker-calendar-date) {
height: 112px !important;
}
.day-item {
height: 107.7px;
background: rgba(255, 255, 255, 0.05);
border: 1px solid #dee2ec;
.num {
color: #3a454c;
font-size: 16px;
font-family: Microsoft YaHei, serif;
margin: 0 0 0 6px;
}
}
.bar {
height: 28px;
font-size: 12px;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
background: rgba(206, 239, 255, 0.6);
margin-bottom: 5px;
line-height: 28px;
color: rgba(58, 69, 76, 0.8);
font-family: Microsoft YaHei, serif;
&:last-child {
margin-bottom: 0;
}
}
.first-left-bar {
border-style: solid;
border-width: 0 0 0 3px;
border-color: #1ba1eb;
border-radius: 5px;
margin-left: 8px;
}
.last-right-radius {
border-radius: 5px;
margin-right: 7px;
}
:deep(.ant-picker-content) {
th {
height: 50px !important;
border: 1px solid #dee2ec;
background: rgba(41, 110, 213, 0.05);
color: #3a454c;
font-size: 14px;
font-weight: 700;
text-align: left;
line-height: 50px;
padding-left: 16px !important;
padding-bottom: 0 !important;
font-family: Microsoft YaHei, serif;
}
}
</style>