Compare commits
5 Commits
9d06c69e2b
...
47039ee878
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
47039ee878 | ||
|
|
88f1abfe25 | ||
|
|
2004766855 | ||
|
|
0e03dcb2d6 | ||
|
|
438a16c383 |
@@ -0,0 +1,240 @@
|
||||
package com.magistr.app.controller;
|
||||
|
||||
import com.magistr.app.dto.CreateLessonRequest;
|
||||
import com.magistr.app.dto.LessonResponse;
|
||||
import com.magistr.app.model.*;
|
||||
import com.magistr.app.repository.*;
|
||||
import com.magistr.app.utils.DayAndWeekValidator;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.springframework.http.HttpStatus;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/users/lessons")
|
||||
public class LessonsController {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(LessonsController.class);
|
||||
|
||||
private final LessonRepository lessonRepository;
|
||||
private final UserRepository teacherRepository;
|
||||
private final GroupRepository groupRepository;
|
||||
private final SubjectRepository subjectRepository;
|
||||
private final EducationFormRepository educationFormRepository;
|
||||
|
||||
public LessonsController(LessonRepository lessonRepository, UserRepository teacherRepository, GroupRepository groupRepository, SubjectRepository subjectRepository, EducationFormRepository educationForm) {
|
||||
this.lessonRepository = lessonRepository;
|
||||
this.teacherRepository = teacherRepository;
|
||||
this.groupRepository = groupRepository;
|
||||
this.subjectRepository = subjectRepository;
|
||||
this.educationFormRepository = educationForm;
|
||||
}
|
||||
|
||||
@PostMapping("/create")
|
||||
public ResponseEntity<?> createLesson(@RequestBody CreateLessonRequest request) {
|
||||
//Полное логирование входящего запроса
|
||||
logger.info("Получен запрос на создание занятия: teacherId={}, groupId={}, lessonTypeId={}, day={}, week={}, time={}",
|
||||
request.getTeacherId(), request.getGroupId(), request.getSubjectId(), request.getDay(), request.getWeek(), request.getTime());
|
||||
|
||||
//Проверка teacherId
|
||||
if (request.getTeacherId() == null || request.getTeacherId() == 0) {
|
||||
String errorMessage = "ID преподавателя обязателен";
|
||||
logger.info("Ошибка валидации: {}", errorMessage);
|
||||
return ResponseEntity.badRequest().body(Map.of("message", errorMessage));
|
||||
}
|
||||
|
||||
//Проверка groupId
|
||||
if (request.getGroupId() == null || request.getGroupId() == 0) {
|
||||
String errorMessage = "ID группы обязателен";
|
||||
logger.info("Ошибка валидации: {}", errorMessage);
|
||||
return ResponseEntity.badRequest().body(Map.of("message", errorMessage));
|
||||
}
|
||||
|
||||
//Проверка lessonTypeId
|
||||
if (request.getSubjectId() == null || request.getSubjectId() == 0) {
|
||||
String errorMessage = "ID предмета обязателен";
|
||||
logger.info("Ошибка валидации: {}", errorMessage);
|
||||
return ResponseEntity.badRequest().body(Map.of("message", errorMessage));
|
||||
}
|
||||
|
||||
//Проверка day
|
||||
if (request.getDay() == null || request.getDay().isBlank()) {
|
||||
String errorMessage = "Выбор дня обязателен";
|
||||
logger.info("Ошибка валидации: {}", errorMessage);
|
||||
return ResponseEntity.badRequest().body(Map.of("message", errorMessage));
|
||||
} else if(!DayAndWeekValidator.isValidDay(request.getDay())){
|
||||
String errorMessage = "Некорректный день недели. " + DayAndWeekValidator.getValidDaysMessage();
|
||||
logger.info("Ошибка валидации дня: '{}' - {}", request.getDay(), errorMessage);
|
||||
return ResponseEntity.badRequest().body(Map.of("message", errorMessage));
|
||||
}
|
||||
|
||||
//Проверка week
|
||||
if (request.getWeek() == null || request.getWeek().isBlank()) {
|
||||
String errorMessage = "Выбор недели обязателен";
|
||||
logger.info("Ошибка валидации: {}", errorMessage);
|
||||
return ResponseEntity.badRequest().body(Map.of("message", errorMessage));
|
||||
} else if(!DayAndWeekValidator.isValidWeek(request.getWeek())){
|
||||
String errorMessage = "Некорректная неделя. " + DayAndWeekValidator.getValidWeekMessage();
|
||||
logger.info("Ошибка валидации недели: '{}' - {}", request.getWeek(), errorMessage);
|
||||
return ResponseEntity.badRequest().body(Map.of("message", errorMessage));
|
||||
}
|
||||
|
||||
//Проверка time
|
||||
if (request.getTime() == null || request.getTime().isBlank()) {
|
||||
String errorMessage = "Время обязательно";
|
||||
logger.info("Ошибка валидации: {}", errorMessage);
|
||||
return ResponseEntity.badRequest().body(Map.of("message", errorMessage));
|
||||
}
|
||||
|
||||
//Сохранение полученных данных и формирование ответа клиенту
|
||||
try {
|
||||
Lesson lesson = new Lesson();
|
||||
lesson.setTeacherId(request.getTeacherId());
|
||||
lesson.setSubjectId(request.getSubjectId());
|
||||
lesson.setGroupId(request.getGroupId());
|
||||
lesson.setDay(request.getDay());
|
||||
lesson.setWeek(request.getWeek());
|
||||
lesson.setTime(request.getTime());
|
||||
|
||||
Lesson savedLesson = lessonRepository.save(lesson);
|
||||
|
||||
Map<String, Object> response = new LinkedHashMap<>();
|
||||
response.put("id", savedLesson.getId());
|
||||
response.put("teacherId", savedLesson.getTeacherId());
|
||||
response.put("groupId", savedLesson.getGroupId());
|
||||
response.put("subjectId", savedLesson.getSubjectId());
|
||||
response.put("day", savedLesson.getDay());
|
||||
response.put("week", savedLesson.getWeek());
|
||||
response.put("time", savedLesson.getTime());
|
||||
|
||||
logger.info("Занятие успешно создано с ID: {}", savedLesson.getId());
|
||||
|
||||
return ResponseEntity.ok(response);
|
||||
} catch (Exception e) {
|
||||
logger.error("Ошибка при сохранении занятия: {}", e.getMessage(),e);
|
||||
|
||||
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
|
||||
.body(Map.of("message", "Произошла ошибка при создании занятия: " + e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
@GetMapping
|
||||
public List<LessonResponse> getAllLessons() {
|
||||
logger.info("Запрос на получение всех занятий");
|
||||
|
||||
try {
|
||||
List<Lesson> lessons = lessonRepository.findAll();
|
||||
|
||||
List<LessonResponse> response = lessons.stream()
|
||||
.map(lesson -> {
|
||||
String teacherName = teacherRepository.findById(lesson.getTeacherId())
|
||||
.map(User::getUsername)
|
||||
.orElse("Неизвестно");
|
||||
|
||||
StudentGroup group = groupRepository.findById(lesson.getGroupId()).orElse(null);
|
||||
String groupName = groupRepository.findById(lesson.getGroupId())
|
||||
.map(StudentGroup::getName)
|
||||
.orElse("Неизвестно");
|
||||
|
||||
String educationFormName = "Неизвестно";
|
||||
if(group != null && group.getEducationForm() != null) {
|
||||
Long educationFormId = group.getEducationForm().getId();
|
||||
educationFormName = educationFormRepository.findById(educationFormId)
|
||||
.map(EducationForm::getName)
|
||||
.orElse("Неизвестно");
|
||||
}
|
||||
|
||||
String subjectName = subjectRepository.findById(lesson.getSubjectId())
|
||||
.map(Subject::getName)
|
||||
.orElse("Неизвестно");
|
||||
|
||||
return new LessonResponse(
|
||||
lesson.getId(),
|
||||
teacherName,
|
||||
groupName,
|
||||
educationFormName,
|
||||
subjectName,
|
||||
lesson.getDay(),
|
||||
lesson.getWeek(),
|
||||
lesson.getTime()
|
||||
);
|
||||
})
|
||||
.toList();
|
||||
|
||||
logger.info("Получено {} занятий", lessons.size());
|
||||
return response;
|
||||
} catch (Exception e) {
|
||||
logger.error("Ошибка при получении списка всех занятий: {}", e.getMessage(), e);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
@GetMapping("/{teacherId}")
|
||||
public ResponseEntity<?> getLessonsById(@PathVariable Long teacherId) {
|
||||
logger.info("Запрос на получение занятий для преподавателя с ID: {}", teacherId);
|
||||
try {
|
||||
List<Lesson> lessons = lessonRepository.findByTeacherId(teacherId);
|
||||
|
||||
if(lessons.isEmpty()) {
|
||||
logger.info("У преподавателя с ID {} нет занятий", teacherId);
|
||||
return ResponseEntity.ok(Map.of(
|
||||
"message", "У преподавателя с ID " + teacherId +" нет занятий.",
|
||||
"lessons", Collections.emptyList()
|
||||
));
|
||||
}
|
||||
|
||||
List<LessonResponse> lessonResponses = lessons.stream()
|
||||
.map(l -> new LessonResponse(
|
||||
l.getId(),
|
||||
l.getTeacherId(),
|
||||
l.getSubjectId(),
|
||||
l.getGroupId(),
|
||||
l.getDay(),
|
||||
l.getWeek(),
|
||||
l.getTime()
|
||||
))
|
||||
.toList();
|
||||
logger.info("Найдено {} занянтий для преподавателя с ID: {}", lessonResponses.size(), teacherId);
|
||||
return ResponseEntity.ok(lessonResponses);
|
||||
} catch (Exception e ){
|
||||
logger.error("Ошибка при получении занятий для преподавателя с ID {}: {}", teacherId, e.getMessage(), e);
|
||||
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
|
||||
.body(Map.of("message", "Ошибка при поиске занятий: " + e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
@GetMapping("/debug/subjects")
|
||||
public ResponseEntity<?> debugSubjects() {
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
|
||||
// Через JPA репозиторий
|
||||
List<Subject> allSubjects = subjectRepository.findAll();
|
||||
result.put("jpa_count", allSubjects.size());
|
||||
result.put("jpa_subjects", allSubjects.stream()
|
||||
.map(s -> Map.of("id", s.getId(), "name", s.getName()))
|
||||
.toList());
|
||||
|
||||
// Проверка конкретных ID
|
||||
Map<Long, Boolean> existenceCheck = new HashMap<>();
|
||||
for (long id = 1; id <= 6; id++) {
|
||||
boolean exists = subjectRepository.existsById(id);
|
||||
existenceCheck.put(id, exists);
|
||||
}
|
||||
result.put("existence_check", existenceCheck);
|
||||
|
||||
return ResponseEntity.ok(result);
|
||||
}
|
||||
|
||||
//Тестовый запрос на проверку доступности контроллера
|
||||
@GetMapping("/ping")
|
||||
public String ping() {
|
||||
logger.debug("Получен ping запрос");
|
||||
String response = "pong";
|
||||
logger.debug("Ответ на ping: {}", response);
|
||||
return response;
|
||||
}
|
||||
}
|
||||
@@ -1,67 +0,0 @@
|
||||
package com.magistr.app.controller;
|
||||
|
||||
import com.magistr.app.dto.CreateLessonRequest;
|
||||
import com.magistr.app.dto.LessonResponse;
|
||||
import com.magistr.app.model.Lesson;
|
||||
import com.magistr.app.repository.LessonRepository;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/users/test")
|
||||
public class TestController {
|
||||
|
||||
private final LessonRepository lessonRepository;
|
||||
|
||||
public TestController(LessonRepository lessonRepository) {
|
||||
this.lessonRepository = lessonRepository;
|
||||
}
|
||||
|
||||
@PostMapping("/create")
|
||||
public ResponseEntity<?> createLesson(@RequestBody CreateLessonRequest request) {
|
||||
if (request.getTeacherId() == null || request.getTeacherId() == 0) {
|
||||
return ResponseEntity.badRequest().body(Map.of("message", "ID преподавателя обязателен"));
|
||||
}
|
||||
if (request.getGroupId() == null || request.getGroupId() == 0) {
|
||||
return ResponseEntity.badRequest().body(Map.of("message", "ID группы обязателен"));
|
||||
}
|
||||
if (request.getLessonTypeId() == null || request.getLessonTypeId() == 0) {
|
||||
return ResponseEntity.badRequest().body(Map.of("message", "ID предмета обязателен"));
|
||||
}
|
||||
if (request.getDay() == null || request.getDay().isBlank()) {
|
||||
return ResponseEntity.badRequest().body(Map.of("message", "Выбор дня обязателен"));
|
||||
}
|
||||
if (request.getWeek() == null || request.getWeek().isBlank()) {
|
||||
return ResponseEntity.badRequest().body(Map.of("message", "Выбор недели обязателен"));
|
||||
}
|
||||
if (request.getTime() == null || request.getTime().isBlank()) {
|
||||
return ResponseEntity.badRequest().body(Map.of("message", "Время обязательно"));
|
||||
}
|
||||
|
||||
Lesson lesson = new Lesson();
|
||||
lesson.setTeacherId(request.getTeacherId());
|
||||
lesson.setLessonTypeId(request.getLessonTypeId());
|
||||
lesson.setGroupId(request.getGroupId());
|
||||
lesson.setDay(request.getDay());
|
||||
lesson.setWeek(request.getWeek());
|
||||
lesson.setTime(request.getTime());
|
||||
lessonRepository.save(lesson);
|
||||
|
||||
return ResponseEntity.ok(new LessonResponse(lesson.getId(), lesson.getDay(), lesson.getWeek(), lesson.getTime()));
|
||||
}
|
||||
|
||||
@GetMapping
|
||||
public List<LessonResponse> getAllLessons() {
|
||||
return lessonRepository.findAll().stream()
|
||||
.map(l -> new LessonResponse(l.getId(), l.getTeacherId(), l.getLessonTypeId(), l.getDay(), l.getWeek(), l.getTime()))
|
||||
.toList();
|
||||
}
|
||||
|
||||
@GetMapping("/ping")
|
||||
public String ping() {
|
||||
return "pong";
|
||||
}
|
||||
}
|
||||
@@ -4,7 +4,7 @@ public class CreateLessonRequest {
|
||||
|
||||
private Long teacherId;
|
||||
private Long groupId;
|
||||
private Long lessonTypeId;
|
||||
private Long subjectId;
|
||||
private String day;
|
||||
private String week;
|
||||
private String time;
|
||||
@@ -28,12 +28,12 @@ public class CreateLessonRequest {
|
||||
this.groupId = groupId;
|
||||
}
|
||||
|
||||
public Long getLessonTypeId() {
|
||||
return lessonTypeId;
|
||||
public Long getSubjectId() {
|
||||
return subjectId;
|
||||
}
|
||||
|
||||
public void setLessonTypeId(Long lessonTypeId) {
|
||||
this.lessonTypeId= lessonTypeId;
|
||||
public void setSubjectId(Long subjectId) {
|
||||
this.subjectId = subjectId;
|
||||
}
|
||||
|
||||
public String getDay() {
|
||||
|
||||
@@ -1,11 +1,19 @@
|
||||
package com.magistr.app.dto;
|
||||
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
public class LessonResponse {
|
||||
|
||||
private Long id;
|
||||
private Long teacherId;
|
||||
private String teacherName;
|
||||
private Long groupId;
|
||||
private Long lessonTypeId;
|
||||
private String groupName;
|
||||
private String educationFormName;
|
||||
private Long subjectId;
|
||||
private String subjectName;
|
||||
private String day;
|
||||
private String week;
|
||||
private String time;
|
||||
@@ -13,17 +21,22 @@ public class LessonResponse {
|
||||
public LessonResponse() {
|
||||
}
|
||||
|
||||
public LessonResponse(Long lessonTypeId, String day, String week, String time) {
|
||||
this.lessonTypeId = lessonTypeId;
|
||||
public LessonResponse(Long id, Long teacherId, Long groupId, Long subjectId, String day, String week, String time) {
|
||||
this.id = id;
|
||||
this.teacherId = teacherId;
|
||||
this.groupId = groupId;
|
||||
this.subjectId = subjectId;
|
||||
this.day = day;
|
||||
this.week = week;
|
||||
this.time = time;
|
||||
}
|
||||
|
||||
public LessonResponse(Long id, Long teacherId, Long lessonTypeId, String day, String week, String time) {
|
||||
public LessonResponse(Long id, String teacherName, String groupName, String educationFormName, String subjectName, String day, String week, String time) {
|
||||
this.id = id;
|
||||
this.teacherId = teacherId;
|
||||
this.lessonTypeId = lessonTypeId;
|
||||
this.teacherName = teacherName;
|
||||
this.groupName = groupName;
|
||||
this.educationFormName = educationFormName;
|
||||
this.subjectName = subjectName;
|
||||
this.day = day;
|
||||
this.week = week;
|
||||
this.time = time;
|
||||
@@ -45,6 +58,14 @@ public class LessonResponse {
|
||||
this.teacherId = teacherId;
|
||||
}
|
||||
|
||||
public String getTeacherName() {
|
||||
return teacherName;
|
||||
}
|
||||
|
||||
public void setTeacherName(String teacherName) {
|
||||
this.teacherName = teacherName;
|
||||
}
|
||||
|
||||
public Long getGroupId() {
|
||||
return groupId;
|
||||
}
|
||||
@@ -53,12 +74,36 @@ public class LessonResponse {
|
||||
this.groupId = groupId;
|
||||
}
|
||||
|
||||
public Long getLessonTypeId() {
|
||||
return lessonTypeId;
|
||||
public String getGroupName() {
|
||||
return groupName;
|
||||
}
|
||||
|
||||
public void setLessonTypeId(Long lessonTypeId) {
|
||||
this.lessonTypeId = lessonTypeId;
|
||||
public void setGroupName(String groupName) {
|
||||
this.groupName = groupName;
|
||||
}
|
||||
|
||||
public String getEducationFormName() {
|
||||
return educationFormName;
|
||||
}
|
||||
|
||||
public void setEducationFormName(String educationFormName) {
|
||||
this.educationFormName = educationFormName;
|
||||
}
|
||||
|
||||
public Long getSubjectId() {
|
||||
return subjectId;
|
||||
}
|
||||
|
||||
public void setSubjectId(Long subjectId) {
|
||||
this.subjectId = subjectId;
|
||||
}
|
||||
|
||||
public String getSubjectName() {
|
||||
return subjectName;
|
||||
}
|
||||
|
||||
public void setSubjectName(String subjectName) {
|
||||
this.subjectName = subjectName;
|
||||
}
|
||||
|
||||
public String getDay() {
|
||||
|
||||
@@ -16,8 +16,8 @@ public class Lesson {
|
||||
@Column(name = "group_id", nullable = false)
|
||||
private Long groupId;
|
||||
|
||||
@Column(name = "lesson_type_id", nullable = false)
|
||||
private Long lessonTypeId;
|
||||
@Column(name = "subject_id", nullable = false)
|
||||
private Long subjectId;
|
||||
|
||||
@Column(name = "day", nullable = false, length = 255)
|
||||
private String day;
|
||||
@@ -55,12 +55,12 @@ public class Lesson {
|
||||
this.groupId = groupId;
|
||||
}
|
||||
|
||||
public Long getLessonTypeId() {
|
||||
return lessonTypeId;
|
||||
public Long getSubjectId() {
|
||||
return subjectId;
|
||||
}
|
||||
|
||||
public void setLessonTypeId(Long lessonTypeId) {
|
||||
this.lessonTypeId = lessonTypeId;
|
||||
public void setSubjectId(Long subjectId) {
|
||||
this.subjectId = subjectId;
|
||||
}
|
||||
|
||||
public String getDay() {
|
||||
|
||||
@@ -3,9 +3,12 @@ package com.magistr.app.repository;
|
||||
import com.magistr.app.model.Lesson;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
public interface LessonRepository extends JpaRepository<Lesson, Long> {
|
||||
|
||||
Optional<Lesson> findByLessonTypeId(Long lessonTypeId);
|
||||
Optional<Lesson> findBySubjectId(Long subjectId);
|
||||
|
||||
List<Lesson> findByTeacherId(Long teacherId);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
package com.magistr.app.utils;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
public class DayAndWeekValidator {
|
||||
|
||||
private static final Set<String> VALID_DAYS = Set.of(
|
||||
"Понедельник", "Вторник", "Среда", "Четверг", "Пятница", "Суббота"
|
||||
);
|
||||
|
||||
private static final Set<String> VALID_WEEKS = Set.of(
|
||||
"Верхняя", "Нижняя", "Обе"
|
||||
);
|
||||
|
||||
public static boolean isValidDay(String day) {
|
||||
return day != null && VALID_DAYS.contains(day);
|
||||
}
|
||||
|
||||
public static boolean isValidWeek(String week) {
|
||||
return week != null && VALID_WEEKS.contains(week);
|
||||
}
|
||||
|
||||
public static String getValidDaysMessage() {
|
||||
return "Допустимые дни: " + String.join(", ", VALID_DAYS);
|
||||
}
|
||||
|
||||
public static String getValidWeekMessage() {
|
||||
return "Допустимы для выбора: " + String.join(", ", VALID_WEEKS);
|
||||
}
|
||||
}
|
||||
@@ -10,3 +10,6 @@ spring.datasource.driver-class-name=org.postgresql.Driver
|
||||
spring.jpa.hibernate.ddl-auto=validate
|
||||
spring.jpa.show-sql=false
|
||||
spring.jpa.open-in-view=false
|
||||
|
||||
#Eta nastroyka otvechayet za vklyucheniye vidimosti logov urovnya DEBUG v logakh BE, poka vyklyuchil chtoby ne zasoryat'. Zapisi INFO otobrazhat'sya budut
|
||||
#logging.level.root=DEBUG
|
||||
|
||||
@@ -185,7 +185,7 @@ CREATE TABLE IF NOT EXISTS lessons (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
teacher_id BIGINT NOT NULL REFERENCES users(id),
|
||||
group_id BIGINT NOT NULL REFERENCES student_groups(id),
|
||||
lesson_type_id BIGINT NOT NULL REFERENCES lesson_types(id),
|
||||
subject_id BIGINT NOT NULL REFERENCES subjects(id),
|
||||
day VARCHAR(255) NOT NULL,
|
||||
week VARCHAR(255) NOT NULL,
|
||||
time VARCHAR(255) NOT NULL
|
||||
|
||||
@@ -585,3 +585,49 @@ tbody tr:hover {
|
||||
.modal-close:hover {
|
||||
color: var(--error);
|
||||
}
|
||||
|
||||
.btn-add-lesson {
|
||||
padding: 0.35rem 0.7rem;
|
||||
background: rgba(16, 185, 129, 0.1);
|
||||
border: 1px solid rgba(16, 185, 129, 0.2);
|
||||
border-radius: var(--radius-sm);
|
||||
color: var(--success);
|
||||
font-family: inherit;
|
||||
font-size: 0.8rem;
|
||||
cursor: pointer;
|
||||
transition: background var(--transition), transform var(--transition);
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.btn-add-lesson:hover {
|
||||
background: rgba(16, 185, 129, 0.2);
|
||||
transform: scale(1.05);
|
||||
}
|
||||
|
||||
/* Кнопки-переключатели для недели */
|
||||
.btn-checkbox {
|
||||
display: inline-block;
|
||||
cursor: pointer;
|
||||
}
|
||||
.btn-checkbox input {
|
||||
position: absolute;
|
||||
opacity: 0;
|
||||
width: 0;
|
||||
height: 0;
|
||||
}
|
||||
.checkbox-btn {
|
||||
display: inline-block;
|
||||
padding: 0.5rem 1rem;
|
||||
background: var(--bg-secondary);
|
||||
border: 1px solid var(--bg-card-border);
|
||||
border-radius: var(--radius-sm);
|
||||
color: var(--text-primary);
|
||||
transition: all var(--transition);
|
||||
user-select: none;
|
||||
}
|
||||
.btn-checkbox input:checked + .checkbox-btn {
|
||||
background: var(--success, #10b981); /* используем success или зелёный */
|
||||
border-color: var(--success, #10b981);
|
||||
color: white;
|
||||
}
|
||||
@@ -86,6 +86,15 @@
|
||||
</svg>
|
||||
Дисциплины
|
||||
</a>
|
||||
<a href="#" class="nav-item" data-tab="schedule">
|
||||
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<rect x="3" y="4" width="18" height="18" rx="2" ry="2"></rect>
|
||||
<line x1="16" y1="2" x2="16" y2="6"></line>
|
||||
<line x1="8" y1="2" x2="8" y2="6"></line>
|
||||
<line x1="3" y1="10" x2="21" y2="10"></line>
|
||||
</svg>
|
||||
Расписание занятий
|
||||
</a>
|
||||
</nav>
|
||||
<div class="sidebar-footer">
|
||||
<button class="btn-logout" id="btn-logout">
|
||||
|
||||
@@ -7,6 +7,7 @@ import { initEduForms } from './views/edu-forms.js';
|
||||
import { initEquipments } from './views/equipments.js';
|
||||
import { initClassrooms } from './views/classrooms.js';
|
||||
import { initSubjects } from './views/subjects.js';
|
||||
import {initSchedule} from "./views/schedule.js";
|
||||
|
||||
// Configuration
|
||||
const ROUTES = {
|
||||
@@ -16,6 +17,8 @@ const ROUTES = {
|
||||
equipments: { title: 'Оборудование', file: 'views/equipments.html', init: initEquipments },
|
||||
classrooms: { title: 'Аудитории', file: 'views/classrooms.html', init: initClassrooms },
|
||||
subjects: { title: 'Дисциплины и преподаватели', file: 'views/subjects.html', init: initSubjects },
|
||||
// Новая вкладка
|
||||
schedule: { title: 'Расписание занятий', file: 'views/schedule.html', init: initSchedule },
|
||||
};
|
||||
|
||||
let currentTab = null;
|
||||
|
||||
50
frontend/admin/js/views/schedule.js
Normal file
50
frontend/admin/js/views/schedule.js
Normal file
@@ -0,0 +1,50 @@
|
||||
import { api } from '../api.js';
|
||||
import { escapeHtml } from '../utils.js';
|
||||
|
||||
export async function initSchedule() {
|
||||
const tbody = document.getElementById('schedule-tbody');
|
||||
|
||||
async function loadSchedule() {
|
||||
try {
|
||||
// Предполагается, что на сервере есть endpoint GET /api/lessons,
|
||||
// возвращающий массив объектов с полями:
|
||||
// id, teacher (объект с username), group (объект с name),
|
||||
// subject (объект с name), day, week, time.
|
||||
const lessons = await api.get('/api/users/lessons');
|
||||
renderSchedule(lessons);
|
||||
} catch (e) {
|
||||
tbody.innerHTML = `<tr><td colspan="7" class="loading-row">Ошибка загрузки: ${escapeHtml(e.message)}</td></tr>`;
|
||||
}
|
||||
}
|
||||
|
||||
function renderSchedule(lessons) {
|
||||
if (!lessons || !lessons.length) {
|
||||
tbody.innerHTML = '<tr><td colspan="7" class="loading-row">Нет занятий</td></tr>';
|
||||
return;
|
||||
}
|
||||
|
||||
tbody.innerHTML = lessons.map(lesson => {
|
||||
// Извлекаем имена из вложенных объектов или используем запасные поля
|
||||
const teacherName = lesson.teacher?.username || lesson.teacherName || '—';
|
||||
const groupName = lesson.group?.name || lesson.groupName || '—';
|
||||
const educationForm = lesson.educationForm?.name || lesson.educationFormName || '-';
|
||||
const subjectName = lesson.subject?.name || lesson.subjectName || '—';
|
||||
const day = lesson.day || '—';
|
||||
const week = lesson.week || '—';
|
||||
const time = lesson.time || '—';
|
||||
|
||||
return `<tr>
|
||||
<td>${escapeHtml(lesson.id)}</td>
|
||||
<td>${escapeHtml(teacherName)}</td>
|
||||
<td>${escapeHtml(groupName)}</td>
|
||||
<td>${escapeHtml(educationForm)}</td>
|
||||
<td>${escapeHtml(subjectName)}</td>
|
||||
<td>${escapeHtml(day)}</td>
|
||||
<td>${escapeHtml(week)}</td>
|
||||
<td>${escapeHtml(time)}</td>
|
||||
</tr>`;
|
||||
}).join('');
|
||||
}
|
||||
|
||||
await loadSchedule();
|
||||
}
|
||||
@@ -7,7 +7,91 @@ const ROLE_BADGE = { ADMIN: 'badge-admin', TEACHER: 'badge-teacher', STUDENT: 'b
|
||||
export async function initUsers() {
|
||||
const usersTbody = document.getElementById('users-tbody');
|
||||
const createForm = document.getElementById('create-form');
|
||||
const createAlert = document.getElementById('create-alert');
|
||||
|
||||
// Элементы модального окна добавления занятия
|
||||
const modalAddLesson = document.getElementById('modal-add-lesson');
|
||||
const modalAddLessonClose = document.getElementById('modal-add-lesson-close');
|
||||
const addLessonForm = document.getElementById('add-lesson-form');
|
||||
const lessonGroupSelect = document.getElementById('lesson-group');
|
||||
const lessonDisciplineSelect = document.getElementById('lesson-discipline');
|
||||
const lessonUserId = document.getElementById('lesson-user-id');
|
||||
const lessonDaySelect = document.getElementById('lesson-day');
|
||||
const weekUpper = document.getElementById('week-upper');
|
||||
const weekLower = document.getElementById('week-lower');
|
||||
// NEW: получаем элемент выбора времени
|
||||
const lessonTimeSelect = document.getElementById('lesson-time');
|
||||
|
||||
// Переменные для хранения загруженных данных
|
||||
let groups = [];
|
||||
let subjects = [];
|
||||
|
||||
// NEW: массивы с временными слотами
|
||||
const weekdaysTimes = [
|
||||
"8:00-9:30",
|
||||
"9:40-11:10",
|
||||
"11:40-13:10",
|
||||
"13:20-14:50",
|
||||
"15:00-16:30",
|
||||
"16:50-18:20",
|
||||
"18:30-19:00"
|
||||
];
|
||||
|
||||
const saturdayTimes = [
|
||||
"8:20-9:50",
|
||||
"10:00-11:30",
|
||||
"11:40-13:10",
|
||||
"13:20-14:50"
|
||||
];
|
||||
|
||||
// Загрузка групп с сервера
|
||||
async function loadGroups() {
|
||||
try {
|
||||
groups = await api.get('/api/groups');
|
||||
renderGroupOptions();
|
||||
} catch (e) {
|
||||
console.error('Ошибка загрузки групп:', e);
|
||||
}
|
||||
}
|
||||
|
||||
// Загрузка дисциплин
|
||||
async function loadSubjects() {
|
||||
try {
|
||||
subjects = await api.get('/api/subjects');
|
||||
renderSubjectOptions();
|
||||
} catch (e) {
|
||||
console.error('Ошибка загрузки дисциплин:', e);
|
||||
}
|
||||
}
|
||||
|
||||
// Заполнение select группами
|
||||
function renderGroupOptions() {
|
||||
lessonGroupSelect.innerHTML = '<option value="">Выберите группу</option>' +
|
||||
groups.map(g => `<option value="${g.id}">${escapeHtml(g.name)}</option>`).join('');
|
||||
}
|
||||
|
||||
// Заполнение select дисциплинами
|
||||
function renderSubjectOptions() {
|
||||
lessonDisciplineSelect.innerHTML = '<option value="">Выберите дисциплину</option>' +
|
||||
subjects.map(s => `<option value="${s.id}">${escapeHtml(s.name)}</option>`).join('');
|
||||
}
|
||||
|
||||
// NEW: функция обновления списка времени в зависимости от дня
|
||||
function updateTimeOptions(dayValue) {
|
||||
let times = [];
|
||||
if (dayValue === "Суббота") {
|
||||
times = saturdayTimes;
|
||||
} else if (dayValue && dayValue !== '') {
|
||||
times = weekdaysTimes;
|
||||
} else {
|
||||
lessonTimeSelect.innerHTML = '<option value="">Сначала выберите день</option>';
|
||||
lessonTimeSelect.disabled = true;
|
||||
return;
|
||||
}
|
||||
|
||||
lessonTimeSelect.innerHTML = '<option value="">Выберите время</option>' +
|
||||
times.map(t => `<option value="${t}">${t}</option>`).join('');
|
||||
lessonTimeSelect.disabled = false;
|
||||
}
|
||||
|
||||
async function loadUsers() {
|
||||
try {
|
||||
@@ -29,9 +113,93 @@ export async function initUsers() {
|
||||
<td>${escapeHtml(u.username)}</td>
|
||||
<td><span class="badge ${ROLE_BADGE[u.role] || ''}">${ROLE_LABELS[u.role] || escapeHtml(u.role)}</span></td>
|
||||
<td><button class="btn-delete" data-id="${u.id}">Удалить</button></td>
|
||||
<td><button class="btn-add-lesson" data-id="${u.id}">Добавить занятие</button></td>
|
||||
</tr>`).join('');
|
||||
}
|
||||
|
||||
// Сброс формы модального окна
|
||||
function resetLessonForm() {
|
||||
addLessonForm.reset();
|
||||
lessonUserId.value = '';
|
||||
if (weekUpper) weekUpper.checked = false;
|
||||
if (weekLower) weekLower.checked = false;
|
||||
// NEW: сбрасываем селект времени
|
||||
lessonTimeSelect.innerHTML = '<option value="">Сначала выберите день</option>';
|
||||
lessonTimeSelect.disabled = true;
|
||||
hideAlert('add-lesson-alert');
|
||||
}
|
||||
|
||||
// Открытие модалки с установкой userId
|
||||
function openAddLessonModal(userId) {
|
||||
lessonUserId.value = userId;
|
||||
// NEW: сбрасываем выбранный день и время
|
||||
lessonDaySelect.value = '';
|
||||
updateTimeOptions('');
|
||||
modalAddLesson.classList.add('open');
|
||||
}
|
||||
|
||||
// Обработчик отправки формы добавления занятия
|
||||
addLessonForm.addEventListener('submit', async (e) => {
|
||||
e.preventDefault();
|
||||
hideAlert('add-lesson-alert');
|
||||
|
||||
const userId = lessonUserId.value;
|
||||
const groupId = lessonGroupSelect.value;
|
||||
const subjectId = lessonDisciplineSelect.value;
|
||||
const dayOfWeek = lessonDaySelect.value;
|
||||
const timeSlot = lessonTimeSelect.value; // NEW: получаем выбранное время
|
||||
|
||||
// Проверка обязательных полей
|
||||
if (!groupId) {
|
||||
showAlert('add-lesson-alert', 'Выберите группу', 'error');
|
||||
return;
|
||||
}
|
||||
if (!subjectId) {
|
||||
showAlert('add-lesson-alert', 'Выберите дисциплину', 'error');
|
||||
return;
|
||||
}
|
||||
if (!dayOfWeek) {
|
||||
showAlert('add-lesson-alert', 'Выберите день недели', 'error');
|
||||
return;
|
||||
}
|
||||
// NEW: проверка времени
|
||||
if (!timeSlot) {
|
||||
showAlert('add-lesson-alert', 'Выберите время', 'error');
|
||||
return;
|
||||
}
|
||||
|
||||
// Определяем выбранный тип недели
|
||||
const weekUpperChecked = weekUpper?.checked || false;
|
||||
const weekLowerChecked = weekLower?.checked || false;
|
||||
let weekType = null;
|
||||
if (weekUpperChecked && weekLowerChecked) {
|
||||
weekType = 'Обе';
|
||||
} else if (weekUpperChecked) {
|
||||
weekType = 'Верхняя';
|
||||
} else if (weekLowerChecked) {
|
||||
weekType = 'Нижняя';
|
||||
}
|
||||
|
||||
try {
|
||||
// Отправляем данные на сервер
|
||||
const response = await api.post('/api/users/lessons/create', {
|
||||
teacherId: parseInt(userId),
|
||||
groupId: parseInt(groupId),
|
||||
subjectId: parseInt(subjectId),
|
||||
day: dayOfWeek,
|
||||
week: weekType,
|
||||
time: timeSlot // передаём время
|
||||
});
|
||||
showAlert('add-lesson-alert', 'Занятие добавлено', 'success');
|
||||
setTimeout(() => {
|
||||
modalAddLesson.classList.remove('open');
|
||||
resetLessonForm();
|
||||
}, 1500);
|
||||
} catch (e) {
|
||||
showAlert('add-lesson-alert', e.message || 'Ошибка добавления занятия', 'error');
|
||||
}
|
||||
});
|
||||
|
||||
createForm.addEventListener('submit', async (e) => {
|
||||
e.preventDefault();
|
||||
hideAlert('create-alert');
|
||||
@@ -50,18 +218,52 @@ export async function initUsers() {
|
||||
}
|
||||
});
|
||||
|
||||
// Обработчик кликов по таблице
|
||||
usersTbody.addEventListener('click', async (e) => {
|
||||
const btn = e.target.closest('.btn-delete');
|
||||
if (!btn) return;
|
||||
if (!confirm('Удалить пользователя?')) return;
|
||||
try {
|
||||
await api.delete('/api/users/' + btn.dataset.id);
|
||||
loadUsers();
|
||||
} catch (e) {
|
||||
alert(e.message || 'Ошибка удаления');
|
||||
const deleteBtn = e.target.closest('.btn-delete');
|
||||
if (deleteBtn) {
|
||||
if (!confirm('Удалить пользователя?')) return;
|
||||
try {
|
||||
await api.delete('/api/users/' + deleteBtn.dataset.id);
|
||||
loadUsers();
|
||||
} catch (e) {
|
||||
alert(e.message || 'Ошибка удаления');
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
const addLessonBtn = e.target.closest('.btn-add-lesson');
|
||||
if (addLessonBtn) {
|
||||
e.preventDefault();
|
||||
if (modalAddLesson) {
|
||||
openAddLessonModal(addLessonBtn.dataset.id);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Initial load
|
||||
loadUsers();
|
||||
// NEW: обработчик изменения дня недели для обновления списка времени
|
||||
lessonDaySelect.addEventListener('change', function() {
|
||||
updateTimeOptions(this.value);
|
||||
});
|
||||
|
||||
// Закрытие модалки по крестику
|
||||
if (modalAddLessonClose) {
|
||||
modalAddLessonClose.addEventListener('click', () => {
|
||||
modalAddLesson.classList.remove('open');
|
||||
resetLessonForm();
|
||||
});
|
||||
}
|
||||
|
||||
// Закрытие по клику на overlay
|
||||
if (modalAddLesson) {
|
||||
modalAddLesson.addEventListener('click', (e) => {
|
||||
if (e.target === modalAddLesson) {
|
||||
modalAddLesson.classList.remove('open');
|
||||
resetLessonForm();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Загружаем все данные при инициализации
|
||||
await Promise.all([loadUsers(), loadGroups(), loadSubjects()]);
|
||||
}
|
||||
24
frontend/admin/views/schedule.html
Normal file
24
frontend/admin/views/schedule.html
Normal file
@@ -0,0 +1,24 @@
|
||||
<div class="card">
|
||||
<h2>Расписание занятий</h2>
|
||||
<div class="table-wrap">
|
||||
<table id="schedule-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>ID</th>
|
||||
<th>Преподаватель</th>
|
||||
<th>Группа</th>
|
||||
<th>Форма обучения</th>
|
||||
<th>Дисциплина</th>
|
||||
<th>День недели</th>
|
||||
<th>Неделя</th>
|
||||
<th>Время</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="schedule-tbody">
|
||||
<tr>
|
||||
<td colspan="7" class="loading-row">Загрузка...</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
@@ -45,3 +45,66 @@
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Add Lesson Modal -->
|
||||
<div class="modal-overlay" id="modal-add-lesson">
|
||||
<div class="modal-content card">
|
||||
<h2>Добавить занятие</h2>
|
||||
<button class="modal-close" id="modal-add-lesson-close">×</button>
|
||||
<form id="add-lesson-form">
|
||||
<input type="hidden" id="lesson-user-id">
|
||||
|
||||
<div class="form-group" style="margin-top: 1rem;">
|
||||
<label for="lesson-group">Группа</label>
|
||||
<select id="lesson-group" required>
|
||||
<option value="">Выберите группу</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="form-group" style="margin-top: 1rem;">
|
||||
<label for="lesson-discipline">Дисциплина</label>
|
||||
<select id="lesson-discipline" required>
|
||||
<option value="">Выберите дисциплину</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="form-row" style="margin-top: 1rem;">
|
||||
<div class="form-group" style="flex: 1;">
|
||||
<label for="lesson-day">День недели</label>
|
||||
<select id="lesson-day" required>
|
||||
<option value="">Выберите день</option>
|
||||
<option value="Понедельник">Понедельник</option>
|
||||
<option value="Вторник">Вторник</option>
|
||||
<option value="Среда">Среда</option>
|
||||
<option value="Четверг">Четверг</option>
|
||||
<option value="Пятница">Пятница</option>
|
||||
<option value="Суббота">Суббота</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-group" style="flex: 1;">
|
||||
<label>Неделя</label>
|
||||
<div style="display: flex; gap: 0.5rem;">
|
||||
<label class="btn-checkbox">
|
||||
<input type="checkbox" name="weekType" value="Верхняя" id="week-upper">
|
||||
<span class="checkbox-btn">Верхняя</span>
|
||||
</label>
|
||||
<label class="btn-checkbox">
|
||||
<input type="checkbox" name="weekType" value="Нижняя" id="week-lower">
|
||||
<span class="checkbox-btn">Нижняя</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group" style="margin-top: 1rem;">
|
||||
<label for="lesson-time">Время занятия</label>
|
||||
<select id="lesson-time" required disabled>
|
||||
<option value="">Сначала выберите день</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<button type="submit" class="btn-primary" style="width: 100%; margin-top: 1rem;">Сохранить</button>
|
||||
<div class="form-alert" id="add-lesson-alert" role="alert"></div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
Reference in New Issue
Block a user