已修复:

实验课场地区块改为独立卡片布局,校区、教学楼和场地选择不再被嵌套表单挤压。
批量设置新增独立的“批量指定实验课场地”入口,包含场地性质、实验校区、教学楼和具体场地,并会联动筛选。
后端会保存并校验批量实验场地范围,避免跨校区/教学楼的无效设置。
This commit is contained in:
2026-08-09 16:26:41 +08:00 Unverified
parent 400761beaa
commit 26a39322fd
4 changed files with 120 additions and 40 deletions
@@ -342,6 +342,7 @@ public sealed class ScheduleSettingsController(AppDbContext db, IAppCache cache)
Building? building = null;
List<Classroom> allowedRooms = [];
var experimentRoomIds = request.AllowedExperimentClassroomIds?.Distinct().ToArray() ?? [];
Building? experimentBuilding = null;
List<Classroom> allowedExperimentRooms = [];
if (request.UpdateClassroomScope)
{
@@ -381,12 +382,34 @@ public sealed class ScheduleSettingsController(AppDbContext db, IAppCache cache)
}
if (request.UpdateExperimentClassroomScope)
{
if (request.ExperimentRequiredBuildingId.HasValue)
{
experimentBuilding = await db.Buildings.AsNoTracking()
.FirstOrDefaultAsync(x => x.Id == request.ExperimentRequiredBuildingId && x.IsEnabled,
cancellationToken);
if (experimentBuilding is null)
return ValidationProblem("指定实验教学楼不存在或已停用。");
if (request.ExperimentRequiredCampusId.HasValue &&
experimentBuilding.CampusId != request.ExperimentRequiredCampusId)
return ValidationProblem("指定实验教学楼不属于所选实验校区。");
}
if (request.ExperimentRequiredCampusId.HasValue &&
!await db.Campuses.AnyAsync(x => x.Id == request.ExperimentRequiredCampusId && x.IsEnabled,
cancellationToken))
return ValidationProblem("指定实验校区不存在或已停用。");
allowedExperimentRooms = await db.Classrooms.AsNoTracking()
.Where(x => x.IsEnabled)
.WhereIn(experimentRoomIds, x => x.Id)
.Include(x => x.Building)
.ToListAsync(cancellationToken);
if (allowedExperimentRooms.Count != experimentRoomIds.Length)
return ValidationProblem("部分指定实验场地不存在或已停用。");
if (experimentBuilding is not null &&
allowedExperimentRooms.Any(x => x.BuildingId != experimentBuilding.Id))
return ValidationProblem("指定实验场地必须位于所选实验教学楼。");
if (request.ExperimentRequiredCampusId.HasValue &&
allowedExperimentRooms.Any(x => x.Building!.CampusId != request.ExperimentRequiredCampusId))
return ValidationProblem("指定实验场地必须位于所选实验校区。");
}
var constraints = await db.TeachingTaskScheduleConstraints
@@ -457,6 +480,8 @@ public sealed class ScheduleSettingsController(AppDbContext db, IAppCache cache)
constraint.AllowedExperimentVenueNatures = request.AllowedExperimentVenueNatures.Value;
if (task.Course?.PracticeHours > 0 && request.UpdateExperimentClassroomScope)
{
constraint.ExperimentRequiredCampusId = request.ExperimentRequiredCampusId;
constraint.ExperimentRequiredBuildingId = request.ExperimentRequiredBuildingId;
db.TeachingTaskAllowedExperimentClassrooms.RemoveRange(
constraint.AllowedExperimentClassrooms);
constraint.AllowedExperimentClassrooms = allowedExperimentRooms.Select(room =>
@@ -548,4 +573,6 @@ public sealed record TeachingTaskScheduleConstraintBatchRequest(
[Range(1, 30)] int? LatestPeriod,
bool UpdateExperimentClassroomScope = false,
TeachingVenueNature? AllowedExperimentVenueNatures = null,
IReadOnlyList<Guid>? AllowedExperimentClassroomIds = null);
IReadOnlyList<Guid>? AllowedExperimentClassroomIds = null,
Guid? ExperimentRequiredCampusId = null,
Guid? ExperimentRequiredBuildingId = null);