Redesign #13

Merged
Zuev merged 15 commits from Redesign into main 2026-06-25 16:43:55 +00:00
Showing only changes of commit a966648a7e - Show all commits

View File

@@ -6,6 +6,7 @@ import com.magistr.app.dto.ScheduleRuleSlotDto;
import com.magistr.app.model.*;
import com.magistr.app.repository.*;
import com.magistr.app.service.ScheduleGeneratorService;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;
@@ -81,6 +82,13 @@ public class ScheduleRuleAdminController {
try {
ScheduleRule rule = new ScheduleRule();
applyRule(rule, request);
ScheduleRule conflictRule = findConflictingRule(request, rule.getSlots(), null);
if (conflictRule != null) {
return ResponseEntity.status(HttpStatus.CONFLICT).body(Map.of(
"message", "Невозможно сохранить правило: слот занят",
"conflictRule", toDto(conflictRule)
));
}
ScheduleRule saved = scheduleRuleRepository.save(rule);
scheduleGeneratorService.clearCache();
return ResponseEntity.ok(toDto(saved));
@@ -104,6 +112,13 @@ public class ScheduleRuleAdminController {
try {
applyRule(rule, request);
ScheduleRule conflictRule = findConflictingRule(request, rule.getSlots(), rule.getId());
if (conflictRule != null) {
return ResponseEntity.status(HttpStatus.CONFLICT).body(Map.of(
"message", "Невозможно сохранить правило: слот занят",
"conflictRule", toDto(conflictRule)
));
}
ScheduleRule saved = scheduleRuleRepository.save(rule);
scheduleGeneratorService.clearCache();
return ResponseEntity.ok(toDto(saved));
@@ -181,6 +196,37 @@ public class ScheduleRuleAdminController {
rule.getSlots().addAll(slots);
}
private ScheduleRule findConflictingRule(ScheduleRuleDto request, Collection<ScheduleRuleSlot> newSlots, Long excludeRuleId) {
return scheduleRuleRepository.findAllWithDetails().stream()
.filter(rule -> !Objects.equals(rule.getId(), excludeRuleId))
.filter(rule -> rule.getSemester() != null && Objects.equals(rule.getSemester().getId(), request.semesterId()))
.filter(rule -> hasSlotConflict(newSlots, rule.getSlots()))
.min(Comparator.comparing(ScheduleRule::getId))
.orElse(null);
}
private boolean hasSlotConflict(Collection<ScheduleRuleSlot> newSlots, Collection<ScheduleRuleSlot> existingSlots) {
for (ScheduleRuleSlot newSlot : newSlots) {
for (ScheduleRuleSlot existingSlot : existingSlots) {
if (sameTimeSlot(newSlot, existingSlot) && sameTeacherOrClassroom(newSlot, existingSlot)) {
return true;
}
}
}
return false;
}
private boolean sameTimeSlot(ScheduleRuleSlot first, ScheduleRuleSlot second) {
return Objects.equals(first.getDayOfWeek(), second.getDayOfWeek())
&& Objects.equals(first.getParity(), second.getParity())
&& Objects.equals(first.getTimeSlot().getId(), second.getTimeSlot().getId());
}
private boolean sameTeacherOrClassroom(ScheduleRuleSlot first, ScheduleRuleSlot second) {
return Objects.equals(first.getTeacher().getId(), second.getTeacher().getId())
|| Objects.equals(first.getClassroom().getId(), second.getClassroom().getId());
}
private ScheduleRuleSlot buildSlot(ScheduleRule rule, ScheduleRuleSlotDto slotDto) {
if (slotDto.dayOfWeek() == null || slotDto.dayOfWeek() < 1 || slotDto.dayOfWeek() > 7) {
throw new IllegalArgumentException("День недели должен быть от 1 до 7");