培养方案“学期视图”。
This commit is contained in:
@@ -18,6 +18,7 @@ const planDialog = ref(false)
|
||||
const moduleDialog = ref(false)
|
||||
const courseDialog = ref(false)
|
||||
const cloneDialog = ref(false)
|
||||
const detailView = ref<'structure' | 'semester'>('structure')
|
||||
const editingPlanId = ref('')
|
||||
const editingPlanStatus = ref('')
|
||||
const editingModuleId = ref('')
|
||||
@@ -74,6 +75,34 @@ const configuredCredits = computed(() =>
|
||||
0,
|
||||
) ?? 0,
|
||||
)
|
||||
const semesterGroups = computed(() => {
|
||||
if (!selected.value) return []
|
||||
|
||||
const courses = selected.value.modules.flatMap((module: any) =>
|
||||
module.courses.map((course: any) => ({
|
||||
...course,
|
||||
moduleCode: module.code,
|
||||
moduleName: module.name,
|
||||
})),
|
||||
)
|
||||
const semesterCount = Number(selected.value.schoolingYears) * 2
|
||||
|
||||
return Array.from({ length: semesterCount }, (_, index) => {
|
||||
const semester = index + 1
|
||||
const items = courses
|
||||
.filter((course: any) => Number(course.recommendedSemester) === semester)
|
||||
.sort((first: any, second: any) =>
|
||||
first.moduleCode.localeCompare(second.moduleCode) ||
|
||||
first.courseCode.localeCompare(second.courseCode),
|
||||
)
|
||||
return {
|
||||
semester,
|
||||
courses: items,
|
||||
credits: items.reduce((sum: number, course: any) => sum + Number(course.credits), 0),
|
||||
totalHours: items.reduce((sum: number, course: any) => sum + Number(course.totalHours), 0),
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
async function loadPlans(keepSelection = true) {
|
||||
loading.value = true
|
||||
@@ -450,12 +479,21 @@ onMounted(async () => {
|
||||
|
||||
<div class="module-toolbar">
|
||||
<div>
|
||||
<b>课程结构</b>
|
||||
<span>指定必修须逐门通过;英语、体育等多选课程用“组内选修”,修满模块最低学分即可</span>
|
||||
<b>{{ detailView === 'structure' ? '课程结构' : '学期视图' }}</b>
|
||||
<span>{{ detailView === 'structure'
|
||||
? '指定必修须逐门通过;英语、体育等多选课程用“组内选修”,修满模块最低学分即可'
|
||||
: '按建议修读学期展示课程安排,包含每学期的课程数量、学分和学时。' }}</span>
|
||||
</div>
|
||||
<div class="curriculum-view-actions">
|
||||
<el-radio-group v-model="detailView" size="small" aria-label="培养方案展示方式">
|
||||
<el-radio-button value="structure">课程结构</el-radio-button>
|
||||
<el-radio-button value="semester">学期视图</el-radio-button>
|
||||
</el-radio-group>
|
||||
<el-button v-if="canEdit && detailView === 'structure'" :icon="Plus" @click="openModule()">新增模块</el-button>
|
||||
</div>
|
||||
<el-button v-if="canEdit" :icon="Plus" @click="openModule()">新增模块</el-button>
|
||||
</div>
|
||||
|
||||
<template v-if="detailView === 'structure'">
|
||||
<section v-for="module in selected.modules" :key="module.id" class="curriculum-module">
|
||||
<header>
|
||||
<div>
|
||||
@@ -500,6 +538,34 @@ onMounted(async () => {
|
||||
</el-table>
|
||||
</section>
|
||||
<el-empty v-if="selected.modules.length === 0" description="先建立课程模块,再添加课程" />
|
||||
</template>
|
||||
|
||||
<section v-else class="semester-view" aria-label="课程学期安排">
|
||||
<article v-for="group in semesterGroups" :key="group.semester" class="semester-card">
|
||||
<header>
|
||||
<div>
|
||||
<span>SEMESTER {{ String(group.semester).padStart(2, '0') }}</span>
|
||||
<h4>第 {{ group.semester }} 学期</h4>
|
||||
</div>
|
||||
<b>{{ group.courses.length }} 门</b>
|
||||
</header>
|
||||
<div class="semester-summary">
|
||||
<span>{{ group.credits }} 学分</span>
|
||||
<span>{{ group.totalHours }} 学时</span>
|
||||
</div>
|
||||
<ul v-if="group.courses.length" class="semester-courses">
|
||||
<li v-for="course in group.courses" :key="course.id">
|
||||
<div>
|
||||
<span>{{ course.moduleName }}</span>
|
||||
<b>{{ course.courseName }}</b>
|
||||
<small>{{ course.courseCode }} · {{ courseTypeLabels[course.type] }}</small>
|
||||
</div>
|
||||
<strong>{{ course.credits }}<small>学分</small></strong>
|
||||
</li>
|
||||
</ul>
|
||||
<p v-else class="semester-empty">本学期暂未安排课程</p>
|
||||
</article>
|
||||
</section>
|
||||
</template>
|
||||
</main>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user