diff --git a/web/src/views/AcademicPlanningView.vue b/web/src/views/AcademicPlanningView.vue index 928fd15..c9be769 100644 --- a/web/src/views/AcademicPlanningView.vue +++ b/web/src/views/AcademicPlanningView.vue @@ -18,6 +18,8 @@ const simulation = ref(null) const terms = ref([]) const keyword = ref('') const moduleFilter = ref('') +const selectedCourseIds = ref([]) +const batchSemester = ref() let simulationTimer: ReturnType | undefined const courses = computed(() => payload.value?.courses ?? []) @@ -95,6 +97,29 @@ function removeCourse(courseId: string) { setCourseSemester(courseId) } +function setCourseSelected(courseId: string, selected: boolean) { + if (selected) { + if (!selectedCourseIds.value.includes(courseId)) { + selectedCourseIds.value.push(courseId) + } + return + } + selectedCourseIds.value = selectedCourseIds.value.filter((id) => id !== courseId) +} + +function arrangeSelectedCourses() { + if (!batchSemester.value || !selectedCourseIds.value.length) return + const courseIds = selectedCourseIds.value.filter((courseId) => + courses.value.some((course) => course.courseId === courseId), + ) + for (const courseId of courseIds) { + setCourseSemester(courseId, batchSemester.value) + } + selectedCourseIds.value = [] + const target = terms.value.find((term) => term.semester === batchSemester.value) + ElMessage.success(`已将 ${courseIds.length} 门课程安排到${target?.label ?? `第 ${batchSemester.value} 学期`}`) +} + function applySuggestion() { const target = terms.value.find( (term) => term.semester === payload.value?.plan?.nextSemester, @@ -142,6 +167,8 @@ async function load() { ...term, courseIds: [], })) + selectedCourseIds.value = [] + batchSemester.value = undefined initialized.value = true await simulate() } catch (error) { @@ -298,6 +325,32 @@ onBeforeUnmount(() => { /> +
+ + 全选当前结果(已选 {{ selectedCourseIds.length }} 门) + +
+ + + + + 批量安排 + +
+
{ }" >
- {{ course.courseCode }} · {{ course.moduleName }} + + {{ course.courseCode }} · {{ course.moduleName }} + {{ course.credits }} 学分

{{ course.courseName }}

@@ -627,6 +686,20 @@ onBeforeUnmount(() => { gap: 8px; border-bottom: 1px solid var(--line); } +.batch-arrange-bar { + padding: 10px 11px; + display: grid; + gap: 8px; + border-bottom: 1px solid var(--line); + background: #f7f9fc; +} +.batch-arrange-bar > div { + display: grid; + grid-template-columns: minmax(0, 1fr) auto; + gap: 8px; +} +.batch-arrange-bar .el-select { width: 100%; } +.batch-arrange-bar .el-checkbox { height: auto; color: #536176; font-size: 10px; } .pool-list { max-height: 680px; overflow: auto; @@ -644,7 +717,14 @@ onBeforeUnmount(() => { justify-content: space-between; gap: 8px; } -.course-manifest-line span { color: var(--teal); font: 700 9px/1.2 Consolas, monospace; } +.course-manifest-line .el-checkbox { min-width: 0; height: auto; } +.course-manifest-line :deep(.el-checkbox__label) { + overflow: hidden; + color: var(--teal); + font: 700 9px/1.2 Consolas, monospace; + text-overflow: ellipsis; + white-space: nowrap; +} .course-manifest-line i { color: var(--muted); font-size: 9px; font-style: normal; } .pool-list h4 { margin: 7px 0; font-size: 13px; } .course-flags { display: flex; flex-wrap: wrap; gap: 5px; }