修复实验排课

This commit is contained in:
2026-08-09 15:21:58 +08:00 Unverified
parent bb2b43b0d9
commit 1e60e46c7b
12 changed files with 6968 additions and 42 deletions
+90 -15
View File
@@ -55,8 +55,10 @@ const weekdays = [
{ value: 7, label: '星期日' },
]
const experimentVenueNatures = [
{ value: 2, label: '实验室' }, { value: 4, label: '实室' },
{ value: 8, label: '计算机机房' }, { value: 16, label: '语音室' },
{ value: 1, label: '普通教室' }, { value: 2, label: '实室' },
{ value: 4, label: '实训室' }, { value: 8, label: '计算机机房' },
{ value: 16, label: '语音室' }, { value: 32, label: '体育场地' },
{ value: 64, label: '艺术场地' },
]
const periods = computed(() => {
const configured = timeSlots.value
@@ -129,8 +131,6 @@ const publishStatusText = computed(() => {
const selectedTaskConstraint = computed(() =>
constraints.value.find((item) => item.id === entryForm.teachingTaskId),
)
const isExperimentRoom = (room: any) =>
(Number(room.teachingVenueNature) & (2 | 4 | 8 | 16)) !== 0
const entryClassrooms = computed(() =>
classrooms.value.filter((room) =>
(!selectedTaskConstraint.value?.requiredCampusId
@@ -139,7 +139,9 @@ const entryClassrooms = computed(() =>
|| room.buildingId === selectedTaskConstraint.value.requiredBuildingId) &&
(!selectedTaskConstraint.value?.allowedClassroomIds?.length
|| selectedTaskConstraint.value.allowedClassroomIds.includes(room.id)) &&
(entryForm.kind !== 'Experiment' || isExperimentRoom(room)),
(entryForm.kind !== 'Experiment' ||
!selectedTaskConstraint.value?.allowedExperimentClassroomIds?.length ||
selectedTaskConstraint.value.allowedExperimentClassroomIds.includes(room.id)),
),
)
const entryWeekdays = computed(() => {
@@ -192,6 +194,13 @@ const filteredClassrooms = computed(() =>
(!constraintForm.requiredBuildingId || item.buildingId === constraintForm.requiredBuildingId),
),
)
const filteredExperimentClassrooms = computed(() =>
filteredClassrooms.value.filter((item) =>
(!(constraintForm.allowedExperimentVenueNatures ?? []).length ||
(Number(item.teachingVenueNature) & (constraintForm.allowedExperimentVenueNatures ?? [])
.reduce((value: number, nature: number) => value | nature, 0)) !== 0),
),
)
const batchFilteredBuildings = computed(() =>
constraintBatchForm.requiredCampusId
? buildings.value.filter((item) => item.campusId === constraintBatchForm.requiredCampusId)
@@ -205,6 +214,14 @@ const batchFilteredClassrooms = computed(() =>
item.buildingId === constraintBatchForm.requiredBuildingId),
),
)
const batchFilteredExperimentClassrooms = computed(() =>
batchFilteredClassrooms.value.filter((item) =>
(!(constraintBatchForm.allowedExperimentVenueNatures ?? []).length ||
(Number(item.teachingVenueNature) &
(constraintBatchForm.allowedExperimentVenueNatures ?? [])
.reduce((value: number, nature: number) => value | nature, 0)) !== 0),
),
)
const filteredEntries = computed(() => {
const text = keyword.value.trim().toLowerCase()
if (!text) return selected.value?.entries ?? []
@@ -293,11 +310,13 @@ function openConstraint(item: any) {
Object.assign(constraintForm, {
teachingTaskId: item.id,
title: `${item.taskNumber} · ${item.name}`,
coursePracticeHours: item.coursePracticeHours,
schedulingMode: item.schedulingMode,
requiresClassroom: item.requiresClassroom,
requiredCampusId: item.requiredCampusId,
requiredBuildingId: item.requiredBuildingId,
allowedClassroomIds: [...item.allowedClassroomIds],
allowedExperimentClassroomIds: [...item.allowedExperimentClassroomIds],
allowedExperimentVenueNatures: experimentVenueNatures
.filter((nature) => (Number(item.allowedExperimentVenueNatures) & nature.value) !== 0)
.map((nature) => nature.value),
@@ -318,6 +337,7 @@ async function saveConstraint() {
requiredCampusId: constraintForm.requiredCampusId || null,
requiredBuildingId: constraintForm.requiredBuildingId || null,
allowedClassroomIds: constraintForm.allowedClassroomIds ?? [],
allowedExperimentClassroomIds: constraintForm.allowedExperimentClassroomIds ?? [],
allowedExperimentVenueNatures: (constraintForm.allowedExperimentVenueNatures ?? [])
.reduce((value: number, nature: number) => value | nature, 0),
allowedDayOfWeeks: constraintForm.allowedDayOfWeeks ?? [],
@@ -358,6 +378,9 @@ function openConstraintBatch() {
requiredCampusId: undefined,
requiredBuildingId: undefined,
allowedClassroomIds: [],
updateExperimentClassroomScope: false,
allowedExperimentVenueNatures: [],
allowedExperimentClassroomIds: [],
updateDays: false,
allowedDayOfWeeks: [1, 2, 3, 4, 5],
updatePeriodRange: false,
@@ -369,8 +392,9 @@ function openConstraintBatch() {
async function saveConstraintBatch() {
if (!constraintBatchForm.updateSchedulingMode &&
!constraintBatchForm.updateRequiresClassroom &&
!constraintBatchForm.updateClassroomScope &&
!constraintBatchForm.updateRequiresClassroom &&
!constraintBatchForm.updateClassroomScope &&
!constraintBatchForm.updateExperimentClassroomScope &&
!constraintBatchForm.updateDays &&
!constraintBatchForm.updatePeriodRange) {
ElMessage.warning('请至少勾选一项需要批量修改的设置。')
@@ -390,6 +414,9 @@ async function saveConstraintBatch() {
!(constraintBatchForm.updateRequiresClassroom &&
!constraintBatchForm.requiresClassroom) &&
constraintBatchForm.updateClassroomScope
const updateExperimentClassroomScope = !flexible &&
!(constraintBatchForm.updateRequiresClassroom && !constraintBatchForm.requiresClassroom) &&
constraintBatchForm.updateExperimentClassroomScope
const { data } = await http.put('/schedules/constraints/batch', {
academicTermId: termId.value,
teachingTaskIds: targets.map((item) => item.id),
@@ -409,6 +436,14 @@ async function saveConstraintBatch() {
allowedClassroomIds: updateClassroomScope
? constraintBatchForm.allowedClassroomIds
: null,
updateExperimentClassroomScope,
allowedExperimentVenueNatures: updateExperimentClassroomScope
? (constraintBatchForm.allowedExperimentVenueNatures ?? [])
.reduce((value: number, nature: number) => value | nature, 0)
: null,
allowedExperimentClassroomIds: updateExperimentClassroomScope
? constraintBatchForm.allowedExperimentClassroomIds
: null,
allowedDayOfWeeks: !flexible && constraintBatchForm.updateDays
? constraintBatchForm.allowedDayOfWeeks
: null,
@@ -711,7 +746,8 @@ function changeEntryTask() {
(task.requiredCampusId && room.campusId !== task.requiredCampusId) ||
(task.requiredBuildingId && room.buildingId !== task.requiredBuildingId) ||
(task.allowedClassroomIds?.length && !task.allowedClassroomIds.includes(room.id)) ||
(entryForm.kind === 'Experiment' && !isExperimentRoom(room))
(entryForm.kind === 'Experiment' && task.allowedExperimentClassroomIds?.length &&
!task.allowedExperimentClassroomIds.includes(room.id))
)) {
entryForm.classroomId = null
}
@@ -719,7 +755,9 @@ function changeEntryTask() {
function changeEntryKind() {
const room = classrooms.value.find((item) => item.id === entryForm.classroomId)
if (entryForm.kind === 'Experiment' && room && !isExperimentRoom(room)) {
const task = selectedTaskConstraint.value
if (entryForm.kind === 'Experiment' && room && task?.allowedExperimentClassroomIds?.length &&
!task.allowedExperimentClassroomIds.includes(room.id)) {
entryForm.classroomId = null
}
}
@@ -1047,7 +1085,7 @@ onBeforeUnmount(() => {
/>
<el-form-item
v-else
:label="entryForm.kind === 'Experiment' ? '实验室 / 实训室 / 机房' : '教室'"
:label="entryForm.kind === 'Experiment' ? '教学场地' : '教室'"
required
:hint="selectedTaskConstraint?.requiredBuildingId ? '仅显示约束范围内教室' : ''"
>
@@ -1227,12 +1265,23 @@ onBeforeUnmount(() => {
/>
</el-select>
</el-form-item>
<el-form-item label="实验课允许的场地性质">
<el-form-item label="实验课允许的场地性质">
<el-checkbox-group v-model="constraintForm.allowedExperimentVenueNatures">
<el-checkbox v-for="nature in experimentVenueNatures" :key="nature.value" :value="nature.value">{{ nature.label }}</el-checkbox>
</el-checkbox-group>
<small class="field-hint">仅约束实验课不勾选时可使用全部实验教学场地</small>
</el-form-item>
<small class="field-hint">仅约束实验课不勾选时可使用全部实验教学场地</small>
</el-form-item>
<el-form-item v-if="constraintForm.coursePracticeHours" label="实验课指定可用场地">
<el-select v-model="constraintForm.allowedExperimentClassroomIds" multiple filterable collapse-tags>
<el-option
v-for="item in filteredExperimentClassrooms"
:key="item.id"
:label="`${item.buildingName} / ${item.name}${item.roomType}${item.capacity}人)`"
:value="item.id"
/>
</el-select>
<small class="field-hint">可在上方场地性质范围内指定实验室不选择时按场地性质自动筛选</small>
</el-form-item>
</template>
<el-form-item label="允许上课日">
<el-checkbox-group v-model="constraintForm.allowedDayOfWeeks">
@@ -1291,7 +1340,7 @@ onBeforeUnmount(() => {
<el-checkbox v-model="constraintBatchForm.updateClassroomScope">
批量指定教室范围
</el-checkbox>
<div v-if="constraintBatchForm.updateClassroomScope" class="batch-classroom-scope">
<div v-if="constraintBatchForm.updateClassroomScope" class="batch-classroom-scope">
<el-alert
title="将统一设置为需要教室;校区、教学楼和教室均不选择时,表示清除原有限定并允许系统自动分配。"
type="warning"
@@ -1317,7 +1366,33 @@ onBeforeUnmount(() => {
<el-option v-for="item in batchFilteredBuildings" :key="item.id" :label="item.name" :value="item.id" />
</el-select>
</el-form-item>
</div>
</div>
<el-checkbox v-model="constraintBatchForm.updateExperimentClassroomScope">
批量指定实验课场地
</el-checkbox>
<div v-if="constraintBatchForm.updateExperimentClassroomScope" class="batch-classroom-scope">
<el-alert
title="仅作用于含实验学时的教学任务;不选择具体场地时,按场地性质自动分配。"
type="warning"
:closable="false"
show-icon
/>
<el-form-item label="统一实验课允许的场地性质">
<el-checkbox-group v-model="constraintBatchForm.allowedExperimentVenueNatures">
<el-checkbox v-for="nature in experimentVenueNatures" :key="nature.value" :value="nature.value">{{ nature.label }}</el-checkbox>
</el-checkbox-group>
</el-form-item>
<el-form-item label="统一实验课指定可用场地">
<el-select v-model="constraintBatchForm.allowedExperimentClassroomIds" multiple filterable collapse-tags placeholder="不选择则允许符合性质的任意实验场地">
<el-option
v-for="item in batchFilteredExperimentClassrooms"
:key="item.id"
:label="`${item.buildingName} / ${item.name}${item.roomType}${item.capacity}人)`"
:value="item.id"
/>
</el-select>
</el-form-item>
</div>
<el-form-item label="统一指定可用教室">
<el-select
v-model="constraintBatchForm.allowedClassroomIds"