自动排课完成后逐条显示“需人工处理”的任务和原因,并提供“检查排课约束”入口;刷新页面后仍可读取最近一次结果。

批量排课约束新增校区、教学楼、多教室统一指定,也支持清除原有限定。
课表新增“总视图”,同一时段、不同周次课程会并列显示。
周视图按教学周过滤,支持上一周、下一周、周次下拉和回到本周。
日视图按周次过滤;连续两节课程会跨两行完整占格。
This commit is contained in:
2026-07-25 10:55:09 +08:00 Unverified
parent db91988264
commit e4a12931ea
8 changed files with 652 additions and 51 deletions
+102
View File
@@ -141,6 +141,19 @@ const filteredClassrooms = computed(() =>
(!constraintForm.requiredBuildingId || item.buildingId === constraintForm.requiredBuildingId),
),
)
const batchFilteredBuildings = computed(() =>
constraintBatchForm.requiredCampusId
? buildings.value.filter((item) => item.campusId === constraintBatchForm.requiredCampusId)
: buildings.value,
)
const batchFilteredClassrooms = computed(() =>
classrooms.value.filter((item) =>
(!constraintBatchForm.requiredCampusId ||
item.campusId === constraintBatchForm.requiredCampusId) &&
(!constraintBatchForm.requiredBuildingId ||
item.buildingId === constraintBatchForm.requiredBuildingId),
),
)
const filteredEntries = computed(() => {
const text = keyword.value.trim().toLowerCase()
if (!text) return selected.value?.entries ?? []
@@ -285,6 +298,10 @@ function openConstraintBatch() {
schedulingMode: 'Standard',
updateRequiresClassroom: false,
requiresClassroom: true,
updateClassroomScope: false,
requiredCampusId: undefined,
requiredBuildingId: undefined,
allowedClassroomIds: [],
updateDays: false,
allowedDayOfWeeks: [1, 2, 3, 4, 5],
updatePeriodRange: false,
@@ -297,6 +314,7 @@ function openConstraintBatch() {
async function saveConstraintBatch() {
if (!constraintBatchForm.updateSchedulingMode &&
!constraintBatchForm.updateRequiresClassroom &&
!constraintBatchForm.updateClassroomScope &&
!constraintBatchForm.updateDays &&
!constraintBatchForm.updatePeriodRange) {
ElMessage.warning('请至少勾选一项需要批量修改的设置。')
@@ -312,6 +330,10 @@ async function saveConstraintBatch() {
constraintBatchSaving.value = true
const flexible = constraintBatchForm.updateSchedulingMode &&
constraintBatchForm.schedulingMode === 'Flexible'
const updateClassroomScope = !flexible &&
!(constraintBatchForm.updateRequiresClassroom &&
!constraintBatchForm.requiresClassroom) &&
constraintBatchForm.updateClassroomScope
const { data } = await http.put('/schedules/constraints/batch', {
academicTermId: termId.value,
teachingTaskIds: targets.map((item) => item.id),
@@ -321,6 +343,16 @@ async function saveConstraintBatch() {
requiresClassroom: !flexible && constraintBatchForm.updateRequiresClassroom
? constraintBatchForm.requiresClassroom
: null,
updateClassroomScope,
requiredCampusId: updateClassroomScope
? constraintBatchForm.requiredCampusId || null
: null,
requiredBuildingId: updateClassroomScope
? constraintBatchForm.requiredBuildingId || null
: null,
allowedClassroomIds: updateClassroomScope
? constraintBatchForm.allowedClassroomIds
: null,
allowedDayOfWeeks: !flexible && constraintBatchForm.updateDays
? constraintBatchForm.allowedDayOfWeeks
: null,
@@ -342,6 +374,11 @@ async function saveConstraintBatch() {
}
}
function openManualHandling() {
settingsTab.value = 'constraints'
settingsDrawer.value = true
}
async function autoSchedule() {
try {
await ElMessageBox.confirm(
@@ -694,6 +731,20 @@ onBeforeUnmount(clearAutoSchedulePoll)
:indeterminate="autoJob.status === 'Queued'"
:duration="2"
/>
<div
v-if="autoJob.status === 'Succeeded' && autoJob.messages.length"
class="auto-schedule-issues"
>
<div class="auto-schedule-issues-head">
<b>未完成任务与处理建议</b>
<el-button size="small" type="warning" plain @click="openManualHandling">
检查排课约束
</el-button>
</div>
<ol>
<li v-for="message in autoJob.messages" :key="message">{{ message }}</li>
</ol>
</div>
</div>
<div class="schedule-search">
@@ -1024,8 +1075,59 @@ onBeforeUnmount(clearAutoSchedulePoll)
v-model="constraintBatchForm.requiresClassroom"
active-text="需要占用教室"
inactive-text="不占用教室"
@change="!constraintBatchForm.requiresClassroom && (constraintBatchForm.updateClassroomScope = false)"
/>
</el-form-item>
<template v-if="!(constraintBatchForm.updateRequiresClassroom && !constraintBatchForm.requiresClassroom)">
<el-checkbox v-model="constraintBatchForm.updateClassroomScope">
批量指定教室范围
</el-checkbox>
<div v-if="constraintBatchForm.updateClassroomScope" class="batch-classroom-scope">
<el-alert
title="将统一设置为需要教室;校区、教学楼和教室均不选择时,表示清除原有限定并允许系统自动分配。"
type="warning"
:closable="false"
show-icon
/>
<div class="form-grid">
<el-form-item label="统一限定校区">
<el-select
v-model="constraintBatchForm.requiredCampusId"
clearable
@change="constraintBatchForm.requiredBuildingId = undefined; constraintBatchForm.allowedClassroomIds = []"
>
<el-option v-for="item in campuses" :key="item.id" :label="item.name" :value="item.id" />
</el-select>
</el-form-item>
<el-form-item label="统一限定教学楼">
<el-select
v-model="constraintBatchForm.requiredBuildingId"
clearable
@change="constraintBatchForm.allowedClassroomIds = []"
>
<el-option v-for="item in batchFilteredBuildings" :key="item.id" :label="item.name" :value="item.id" />
</el-select>
</el-form-item>
</div>
<el-form-item label="统一指定可用教室">
<el-select
v-model="constraintBatchForm.allowedClassroomIds"
multiple
filterable
collapse-tags
collapse-tags-tooltip
placeholder="不选择则允许范围内任意教室"
>
<el-option
v-for="item in batchFilteredClassrooms"
:key="item.id"
:label="`${item.buildingName} / ${item.name}${item.capacity}人)`"
:value="item.id"
/>
</el-select>
</el-form-item>
</div>
</template>
<el-checkbox v-model="constraintBatchForm.updateDays">修改允许上课日</el-checkbox>
<el-form-item v-if="constraintBatchForm.updateDays" label="统一允许上课日">
<el-checkbox-group v-model="constraintBatchForm.allowedDayOfWeeks">