This commit is contained in:
2026-07-28 15:41:28 +08:00 Unverified
parent a61dacff1a
commit 2dae303cf1
17 changed files with 6796 additions and 90 deletions
+64 -5
View File
@@ -167,11 +167,21 @@ const weekEntries = computed(() =>
const dayEntries = computed(() =>
weekEntries.value.filter((entry: any) => entry.dayOfWeek === selectedDay.value),
)
const sortedExamEntries = computed(() =>
examEntries.value.slice().sort((a: any, b: any) =>
String(a.examDate).localeCompare(String(b.examDate)) ||
a.startPeriod - b.startPeriod ||
String(a.courseCode).localeCompare(String(b.courseCode)),
),
)
const visibleGridEntries = computed(() =>
viewMode.value === 'overview'
? timedEntries.value
? (timetable.value?.entries ?? [])
: weekEntries.value,
)
const hasOverviewCourseEntries = computed(() =>
(timetable.value?.entries ?? []).length > 0,
)
const selectedWeekLabel = computed(() => weekLabel(selectedWeek.value))
const selectedDayDate = computed(() => {
if (!termMonday.value) return ''
@@ -910,7 +920,7 @@ onMounted(async () => {
</section>
<div
v-if="(viewMode === 'overview' || viewMode === 'week') && hasTimedEntries"
v-if="(viewMode === 'week' && hasTimedEntries) || (viewMode === 'overview' && hasOverviewCourseEntries)"
class="timetable-view-section"
>
<div class="view-context">
@@ -918,11 +928,11 @@ onMounted(async () => {
<strong>{{ viewMode === 'overview' ? '全学期总览' : selectedWeekLabel }}</strong>
<span>
{{ viewMode === 'overview'
? '固定课程与已发布考试按节次合并显示'
? '固定课程按节次展示,考试安排按日期列于下方'
: `本周共 ${weekEntries.length} 项课程、考试安排` }}
</span>
</div>
<small v-if="viewMode === 'overview'">考试卡片显示具体日期课程卡片保留周次信息</small>
<small v-if="viewMode === 'overview'">课程卡片保留起止周与单双周信息</small>
<small v-else-if="!weekEntries.length">本周没有课程或考试安排</small>
</div>
<div class="timetable-scroll">
@@ -1012,9 +1022,38 @@ onMounted(async () => {
</div>
</div>
<el-empty
v-else-if="timetable && !loading && !timetable.flexibleCourses?.length"
v-else-if="timetable && !loading && !hasTimedEntries && !timetable.flexibleCourses?.length"
:description="timetable.plan ? '该课表暂时没有课程或考试安排' : '所选学期尚未发布课表或考试安排'"
/>
<section v-if="viewMode === 'overview' && sortedExamEntries.length" class="exam-overview">
<header>
<div>
<span>EXAM AGENDA</span>
<strong>已发布考试安排</strong>
</div>
<small> {{ sortedExamEntries.length }} · 按考试日期排序</small>
</header>
<div class="exam-overview-list">
<article v-for="entry in sortedExamEntries" :key="entryKey(entry)">
<div class="exam-date">
<strong>{{ formatExamDate(entry.examDate) }}</strong>
<span>{{ weekdays[entry.dayOfWeek] }}</span>
<small> {{ entry.startWeek }} </small>
</div>
<div class="exam-summary">
<span>{{ entry.courseCode }} · {{ entry.examPlanName || '已发布考试' }}</span>
<strong>{{ entry.courseName }}</strong>
<p>{{ location(entry) }}</p>
<small>
{{ entry.startWeek }} ·
{{ entry.startPeriod }}{{ entry.startPeriod + entry.periodCount - 1 }}
</small>
<small>{{ entry.teacherNames.join('、') || '监考教师待定' }}</small>
</div>
</article>
</div>
</section>
</div>
</section>
@@ -1189,6 +1228,23 @@ onMounted(async () => {
.course-block.exam-block strong, .day-course-block.exam-block strong { color: #78391e; }
.course-block.exam-block small, .day-course-block.exam-block small { color: #8b5b43; }
.entry-kind { display: inline-block; margin-right: 5px; padding: 1px 5px; border-radius: 2px; background: #b65b32; color: #fff; font-size: 10px !important; line-height: 1.5; vertical-align: 1px; }
.exam-overview { margin-top: 20px; border: 1px solid #e2d6cf; background: #fffaf7; }
.exam-overview > header { padding: 14px 16px; display: flex; align-items: center; justify-content: space-between; gap: 16px; border-bottom: 1px solid #eaded7; background: #fff5ef; }
.exam-overview > header > div { display: flex; align-items: baseline; gap: 10px; }
.exam-overview > header span { color: #a34f2b; font: 700 10px/1.4 Consolas, monospace; letter-spacing: .08em; }
.exam-overview > header strong { color: #633824; font-size: 15px; }
.exam-overview > header small { color: #8e6f60; }
.exam-overview-list { padding: 14px; display: grid; grid-template-columns: repeat(auto-fit, minmax(320px, 1fr)); gap: 12px; }
.exam-overview-list article { min-width: 0; display: grid; grid-template-columns: 88px minmax(0, 1fr); border: 1px solid #eadbd2; border-left: 4px solid #b65b32; background: #fff; }
.exam-date { padding: 13px 10px; display: grid; align-content: start; gap: 4px; border-right: 1px solid #efe3dc; background: #fff7f2; text-align: center; }
.exam-date strong { color: #8c4022; font-size: 14px; }
.exam-date span { color: #76594b; font-size: 12px; }
.exam-date small { color: #9a7a6b; font-size: 11px; }
.exam-summary { min-width: 0; padding: 12px 14px; display: grid; gap: 5px; }
.exam-summary > span { overflow: hidden; color: #a0502d; font: 700 10px/1.4 Consolas, monospace; text-overflow: ellipsis; white-space: nowrap; }
.exam-summary > strong { color: #533225; font-size: 15px; }
.exam-summary p { margin: 0; color: #6e584e; font-size: 12px; }
.exam-summary small { color: #8a7469; font-size: 11px; line-height: 1.5; }
.day-view { border: 1px solid #dce4eb; }
.day-view > header { padding: 14px 16px; display: flex; align-items: baseline; justify-content: space-between; background: #173e72; color: #fff; }
.day-view > header > div { display: grid; gap: 3px; }
@@ -1225,6 +1281,9 @@ onMounted(async () => {
.calendar-actions .el-button, .calendar-security-actions .el-button { width: 100%; margin-left: 0; }
.timetable-sheet { padding: 12px; }
.view-context, .day-view > header { align-items: flex-start; flex-direction: column; gap: 5px; }
.exam-overview > header { align-items: flex-start; flex-direction: column; }
.exam-overview-list { grid-template-columns: 1fr; }
.exam-overview-list article { grid-template-columns: 78px minmax(0, 1fr); }
.day-grid { grid-template-columns: 90px minmax(0, 1fr); }
}
</style>