Add batch course arrangement to academic planning
This commit is contained in:
1 parent
14bd01d2c3
commit
5dc2d45328
1 file changed
+82
-2
@@ -18,6 +18,8 @@ const simulation = ref<any>(null)
|
||||
const terms = ref<PlanningTerm[]>([])
|
||||
const keyword = ref('')
|
||||
const moduleFilter = ref('')
|
||||
const selectedCourseIds = ref<string[]>([])
|
||||
const batchSemester = ref<number>()
|
||||
let simulationTimer: ReturnType<typeof setTimeout> | undefined
|
||||
|
||||
const courses = computed<any[]>(() => 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(() => {
|
||||
/>
|
||||
</el-select>
|
||||
</div>
|
||||
<div class="batch-arrange-bar">
|
||||
<el-checkbox
|
||||
:model-value="remainingCourses.length > 0 && remainingCourses.every((course) => selectedCourseIds.includes(course.courseId))"
|
||||
:indeterminate="selectedCourseIds.some((courseId) => remainingCourses.some((course) => course.courseId === courseId)) && !remainingCourses.every((course) => selectedCourseIds.includes(course.courseId))"
|
||||
@change="(selected) => remainingCourses.forEach((course) => setCourseSelected(course.courseId, selected === true))"
|
||||
>
|
||||
全选当前结果(已选 {{ selectedCourseIds.length }} 门)
|
||||
</el-checkbox>
|
||||
<div>
|
||||
<el-select v-model="batchSemester" placeholder="批量安排到学期">
|
||||
<el-option
|
||||
v-for="term in terms"
|
||||
:key="term.semester"
|
||||
:label="`第 ${term.semester} 学期 · ${term.label}`"
|
||||
:value="term.semester"
|
||||
/>
|
||||
</el-select>
|
||||
<el-button
|
||||
type="primary"
|
||||
:disabled="!batchSemester || !selectedCourseIds.length"
|
||||
@click="arrangeSelectedCourses"
|
||||
>
|
||||
批量安排
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="pool-list">
|
||||
<article
|
||||
v-for="course in remainingCourses"
|
||||
@@ -308,7 +361,13 @@ onBeforeUnmount(() => {
|
||||
}"
|
||||
>
|
||||
<div class="course-manifest-line">
|
||||
<span>{{ course.courseCode }} · {{ course.moduleName }}</span>
|
||||
<el-checkbox
|
||||
:model-value="selectedCourseIds.includes(course.courseId)"
|
||||
:aria-label="`选择课程 ${course.courseName}`"
|
||||
@change="(selected) => setCourseSelected(course.courseId, selected === true)"
|
||||
>
|
||||
{{ course.courseCode }} · {{ course.moduleName }}
|
||||
</el-checkbox>
|
||||
<i>{{ course.credits }} 学分</i>
|
||||
</div>
|
||||
<h4>{{ course.courseName }}</h4>
|
||||
@@ -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; }
|
||||
|
||||
Reference in new issue
Block a user