校历优化
This commit is contained in:
1 parent
0ef0d4d399
commit
4ef4164b00
6 files changed
+196
-39
No files matched your search
@@ -121,6 +121,13 @@ function label(kind: number | string) {
|
||||
function spans(item: CalendarEvent, day: string) {
|
||||
return item.startsOn <= day && (item.endsOn ?? item.startsOn) >= day;
|
||||
}
|
||||
interface WeekEventSegment {
|
||||
item: CalendarEvent;
|
||||
id: string;
|
||||
startColumn: number;
|
||||
length: number;
|
||||
lane: number;
|
||||
}
|
||||
const today = key(new Date()),
|
||||
monthTitle = computed(
|
||||
() => `${cursor.value.getFullYear()} 年 ${cursor.value.getMonth() + 1} 月`,
|
||||
@@ -145,13 +152,40 @@ const days = computed(() => {
|
||||
};
|
||||
});
|
||||
});
|
||||
const weeks = computed(() =>
|
||||
Array.from({ length: 6 }, (_, weekIndex) => {
|
||||
const weekDays = days.value.slice(weekIndex * 7, weekIndex * 7 + 7);
|
||||
const firstDay = weekDays[0].day;
|
||||
const lastDay = weekDays[6].day;
|
||||
const laneEnds: string[] = [];
|
||||
const eventSegments: WeekEventSegment[] = events.value
|
||||
.filter((item) => spans(item, firstDay) || spans(item, lastDay) || (item.startsOn < firstDay && (item.endsOn ?? item.startsOn) > lastDay))
|
||||
.map((item) => {
|
||||
const startsOn = item.startsOn > firstDay ? item.startsOn : firstDay;
|
||||
const endsOn = (item.endsOn ?? item.startsOn) < lastDay ? (item.endsOn ?? item.startsOn) : lastDay;
|
||||
return {
|
||||
item,
|
||||
startsOn,
|
||||
endsOn,
|
||||
startColumn: weekDays.findIndex((day) => day.day === startsOn) + 1,
|
||||
length: Math.round((parse(endsOn).getTime() - parse(startsOn).getTime()) / 86400000) + 1,
|
||||
};
|
||||
})
|
||||
.sort((left, right) => left.startsOn.localeCompare(right.startsOn) || right.length - left.length || left.item.title.localeCompare(right.item.title))
|
||||
.map((segment) => {
|
||||
const lane = laneEnds.findIndex((endsOn) => endsOn < segment.startsOn);
|
||||
const assignedLane = lane === -1 ? laneEnds.length : lane;
|
||||
laneEnds[assignedLane] = segment.endsOn;
|
||||
return { ...segment, id: `${segment.item.id}-${weekIndex}`, lane: assignedLane };
|
||||
});
|
||||
return { days: weekDays, eventSegments };
|
||||
}),
|
||||
);
|
||||
const monthEvents = computed(() =>
|
||||
events.value.filter((item) => {
|
||||
const date = parse(item.startsOn);
|
||||
return (
|
||||
date.getFullYear() === cursor.value.getFullYear() &&
|
||||
date.getMonth() === cursor.value.getMonth()
|
||||
);
|
||||
const monthStart = key(new Date(cursor.value.getFullYear(), cursor.value.getMonth(), 1));
|
||||
const monthEnd = key(new Date(cursor.value.getFullYear(), cursor.value.getMonth() + 1, 0));
|
||||
return item.startsOn <= monthEnd && (item.endsOn ?? item.startsOn) >= monthStart;
|
||||
}),
|
||||
);
|
||||
function shift(amount: number) {
|
||||
@@ -238,7 +272,7 @@ async function syncHolidays() {
|
||||
academicTermId: selectedTermId.value,
|
||||
year: holidayYear.value,
|
||||
});
|
||||
ElMessage.success(`已同步 ${data.syncedCount} 条节假日与调休数据。`);
|
||||
ElMessage.success(`已同步 ${data.syncedCount} 个节假日/调休日程,覆盖 ${data.sourceDayCount} 天。`);
|
||||
holidayDialogVisible.value = false;
|
||||
await load();
|
||||
} finally {
|
||||
@@ -352,8 +386,10 @@ onMounted(async () => {
|
||||
>
|
||||
</div>
|
||||
<div class="calendar-grid">
|
||||
<section v-for="(week, weekIndex) in weeks" :key="weekIndex" class="calendar-week">
|
||||
<div class="week-days">
|
||||
<article
|
||||
v-for="day in days"
|
||||
v-for="day in week.days"
|
||||
:key="day.day"
|
||||
:class="[
|
||||
'calendar-day',
|
||||
@@ -365,25 +401,20 @@ onMounted(async () => {
|
||||
]"
|
||||
>
|
||||
<div class="day-number">{{ day.date.getDate() }}</div>
|
||||
<button
|
||||
v-for="item in day.events.slice(0, 3)"
|
||||
:key="item.id"
|
||||
type="button"
|
||||
:class="[
|
||||
'calendar-event',
|
||||
kindKey(item.kind),
|
||||
{ due: due(item) },
|
||||
]"
|
||||
:title="item.title"
|
||||
@click="canManage && open(item)"
|
||||
>
|
||||
<span>{{
|
||||
item.title.replace("(法定节假日)", "")
|
||||
}}</span></button
|
||||
><span v-if="day.events.length > 3" class="more-events"
|
||||
>+{{ day.events.length - 3 }} 项</span
|
||||
>
|
||||
</article>
|
||||
</div>
|
||||
<div v-if="week.eventSegments.length" class="week-events">
|
||||
<button
|
||||
v-for="segment in week.eventSegments"
|
||||
:key="segment.id"
|
||||
type="button"
|
||||
:style="{ gridColumn: `${segment.startColumn} / span ${segment.length}`, gridRow: segment.lane + 1 }"
|
||||
:class="['calendar-event', kindKey(segment.item.kind), { due: due(segment.item) }]"
|
||||
:title="segment.item.title"
|
||||
@click="canManage && open(segment.item)"
|
||||
><span>{{ segment.item.title.replace("(法定节假日)", "") }}</span></button>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
<aside class="month-agenda">
|
||||
@@ -627,7 +658,8 @@ onMounted(async () => {
|
||||
background: #fff;
|
||||
}
|
||||
.weekdays,
|
||||
.calendar-grid {
|
||||
.week-days,
|
||||
.week-events {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(7, minmax(0, 1fr));
|
||||
}
|
||||
@@ -645,11 +677,20 @@ onMounted(async () => {
|
||||
.weekdays span:nth-last-child(-n + 2) {
|
||||
color: #a45a55;
|
||||
}
|
||||
.calendar-week {
|
||||
border-bottom: 1px solid #e4ecee;
|
||||
}
|
||||
.calendar-week:last-child {
|
||||
border-bottom: 0;
|
||||
}
|
||||
.week-events {
|
||||
gap: 3px 0;
|
||||
padding: 0 8px 8px;
|
||||
}
|
||||
.calendar-day {
|
||||
min-height: 120px;
|
||||
padding: 8px;
|
||||
border-right: 1px solid #e4ecee;
|
||||
border-bottom: 1px solid #e4ecee;
|
||||
background: #fff;
|
||||
}
|
||||
.calendar-day:nth-child(7n) {
|
||||
@@ -684,7 +725,8 @@ onMounted(async () => {
|
||||
display: block;
|
||||
overflow: hidden;
|
||||
width: 100%;
|
||||
margin: 3px 0;
|
||||
min-width: 0;
|
||||
margin: 0;
|
||||
padding: 3px 5px;
|
||||
color: #315966;
|
||||
text-overflow: ellipsis;
|
||||
@@ -847,9 +889,12 @@ onMounted(async () => {
|
||||
margin-left: 0;
|
||||
}
|
||||
.calendar-day {
|
||||
min-height: 88px;
|
||||
min-height: 70px;
|
||||
padding: 5px;
|
||||
}
|
||||
.week-events {
|
||||
padding: 0 5px 5px;
|
||||
}
|
||||
.calendar-event {
|
||||
padding: 2px 3px;
|
||||
font-size: 10px;
|
||||
|
||||
Reference in new issue
Block a user