Добавил для групп поле численности.
В модалку на UI добавил отображение численности групп и вместимости аудиторий, проверку на доступность и вместимость.
This commit is contained in:
@@ -32,6 +32,7 @@ public class GroupController {
|
|||||||
.map(g -> new GroupResponse(
|
.map(g -> new GroupResponse(
|
||||||
g.getId(),
|
g.getId(),
|
||||||
g.getName(),
|
g.getName(),
|
||||||
|
g.getGroupSize(),
|
||||||
g.getEducationForm().getId(),
|
g.getEducationForm().getId(),
|
||||||
g.getEducationForm().getName()))
|
g.getEducationForm().getName()))
|
||||||
.toList();
|
.toList();
|
||||||
@@ -45,6 +46,9 @@ public class GroupController {
|
|||||||
if (groupRepository.findByName(request.getName().trim()).isPresent()) {
|
if (groupRepository.findByName(request.getName().trim()).isPresent()) {
|
||||||
return ResponseEntity.badRequest().body(Map.of("message", "Группа с таким названием уже существует"));
|
return ResponseEntity.badRequest().body(Map.of("message", "Группа с таким названием уже существует"));
|
||||||
}
|
}
|
||||||
|
if (request.getGroupSize() == null) {
|
||||||
|
return ResponseEntity.badRequest().body(Map.of("message", "Численность группы обязательна"));
|
||||||
|
}
|
||||||
if (request.getEducationFormId() == null) {
|
if (request.getEducationFormId() == null) {
|
||||||
return ResponseEntity.badRequest().body(Map.of("message", "Форма обучения обязательна"));
|
return ResponseEntity.badRequest().body(Map.of("message", "Форма обучения обязательна"));
|
||||||
}
|
}
|
||||||
@@ -56,12 +60,14 @@ public class GroupController {
|
|||||||
|
|
||||||
StudentGroup group = new StudentGroup();
|
StudentGroup group = new StudentGroup();
|
||||||
group.setName(request.getName().trim());
|
group.setName(request.getName().trim());
|
||||||
|
group.setGroupSize(request.getGroupSize());
|
||||||
group.setEducationForm(efOpt.get());
|
group.setEducationForm(efOpt.get());
|
||||||
groupRepository.save(group);
|
groupRepository.save(group);
|
||||||
|
|
||||||
return ResponseEntity.ok(new GroupResponse(
|
return ResponseEntity.ok(new GroupResponse(
|
||||||
group.getId(),
|
group.getId(),
|
||||||
group.getName(),
|
group.getName(),
|
||||||
|
group.getGroupSize(),
|
||||||
group.getEducationForm().getId(),
|
group.getEducationForm().getId(),
|
||||||
group.getEducationForm().getName()));
|
group.getEducationForm().getName()));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package com.magistr.app.dto;
|
|||||||
public class CreateGroupRequest {
|
public class CreateGroupRequest {
|
||||||
|
|
||||||
private String name;
|
private String name;
|
||||||
|
private Long groupSize;
|
||||||
private Long educationFormId;
|
private Long educationFormId;
|
||||||
|
|
||||||
public String getName() {
|
public String getName() {
|
||||||
@@ -13,6 +14,14 @@ public class CreateGroupRequest {
|
|||||||
this.name = name;
|
this.name = name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Long getGroupSize() {
|
||||||
|
return groupSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setGroupSize(Long groupSize) {
|
||||||
|
this.groupSize = groupSize;
|
||||||
|
}
|
||||||
|
|
||||||
public Long getEducationFormId() {
|
public Long getEducationFormId() {
|
||||||
return educationFormId;
|
return educationFormId;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,12 +4,14 @@ public class GroupResponse {
|
|||||||
|
|
||||||
private Long id;
|
private Long id;
|
||||||
private String name;
|
private String name;
|
||||||
|
private Long groupSize;
|
||||||
private Long educationFormId;
|
private Long educationFormId;
|
||||||
private String educationFormName;
|
private String educationFormName;
|
||||||
|
|
||||||
public GroupResponse(Long id, String name, Long educationFormId, String educationFormName) {
|
public GroupResponse(Long id, String name, Long groupSize, Long educationFormId, String educationFormName) {
|
||||||
this.id = id;
|
this.id = id;
|
||||||
this.name = name;
|
this.name = name;
|
||||||
|
this.groupSize = groupSize;
|
||||||
this.educationFormId = educationFormId;
|
this.educationFormId = educationFormId;
|
||||||
this.educationFormName = educationFormName;
|
this.educationFormName = educationFormName;
|
||||||
}
|
}
|
||||||
@@ -22,6 +24,10 @@ public class GroupResponse {
|
|||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Long getGroupSize() {
|
||||||
|
return groupSize;
|
||||||
|
}
|
||||||
|
|
||||||
public Long getEducationFormId() {
|
public Long getEducationFormId() {
|
||||||
return educationFormId;
|
return educationFormId;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,6 +13,9 @@ public class StudentGroup {
|
|||||||
@Column(unique = true, nullable = false, length = 100)
|
@Column(unique = true, nullable = false, length = 100)
|
||||||
private String name;
|
private String name;
|
||||||
|
|
||||||
|
@Column(name = "group_size", nullable = false)
|
||||||
|
private Long groupSize;
|
||||||
|
|
||||||
@ManyToOne(optional = false)
|
@ManyToOne(optional = false)
|
||||||
@JoinColumn(name = "education_form_id", nullable = false)
|
@JoinColumn(name = "education_form_id", nullable = false)
|
||||||
private EducationForm educationForm;
|
private EducationForm educationForm;
|
||||||
@@ -36,6 +39,14 @@ public class StudentGroup {
|
|||||||
this.name = name;
|
this.name = name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Long getGroupSize() {
|
||||||
|
return groupSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setGroupSize(Long groupSize) {
|
||||||
|
this.groupSize = groupSize;
|
||||||
|
}
|
||||||
|
|
||||||
public EducationForm getEducationForm() {
|
public EducationForm getEducationForm() {
|
||||||
return educationForm;
|
return educationForm;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,14 +43,16 @@ ON CONFLICT (name) DO NOTHING;
|
|||||||
CREATE TABLE IF NOT EXISTS student_groups (
|
CREATE TABLE IF NOT EXISTS student_groups (
|
||||||
id BIGSERIAL PRIMARY KEY,
|
id BIGSERIAL PRIMARY KEY,
|
||||||
name VARCHAR(100) UNIQUE NOT NULL,
|
name VARCHAR(100) UNIQUE NOT NULL,
|
||||||
|
group_size BIGINT NOT NULL,
|
||||||
education_form_id BIGINT NOT NULL REFERENCES education_forms(id),
|
education_form_id BIGINT NOT NULL REFERENCES education_forms(id),
|
||||||
course INT CHECK (course BETWEEN 1 AND 6),
|
course INT CHECK (course BETWEEN 1 AND 6),
|
||||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||||
);
|
);
|
||||||
|
|
||||||
-- Тестовая базовая группа для работы
|
-- Тестовая базовая группа для работы
|
||||||
INSERT INTO student_groups (name, education_form_id, course)
|
INSERT INTO student_groups (name, group_size, education_form_id, course)
|
||||||
VALUES ('ИВТ-21-1', 1, 3)
|
VALUES ('ИВТ-21-1', 25, 1, 3),
|
||||||
|
('ИБ-41м', 15, 2, 2)
|
||||||
ON CONFLICT (name) DO NOTHING;
|
ON CONFLICT (name) DO NOTHING;
|
||||||
|
|
||||||
-- ==========================================
|
-- ==========================================
|
||||||
|
|||||||
@@ -68,6 +68,7 @@ export async function initGroups() {
|
|||||||
<tr>
|
<tr>
|
||||||
<td>${g.id}</td>
|
<td>${g.id}</td>
|
||||||
<td>${escapeHtml(g.name)}</td>
|
<td>${escapeHtml(g.name)}</td>
|
||||||
|
<td>${escapeHtml(g.groupSize)}</td>
|
||||||
<td><span class="badge badge-ef">${escapeHtml(g.educationFormName)}</span></td>
|
<td><span class="badge badge-ef">${escapeHtml(g.educationFormName)}</span></td>
|
||||||
<td><button class="btn-delete" data-id="${g.id}">Удалить</button></td>
|
<td><button class="btn-delete" data-id="${g.id}">Удалить</button></td>
|
||||||
</tr>`).join('');
|
</tr>`).join('');
|
||||||
@@ -77,13 +78,15 @@ export async function initGroups() {
|
|||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
hideAlert('create-group-alert');
|
hideAlert('create-group-alert');
|
||||||
const name = document.getElementById('new-group-name').value.trim();
|
const name = document.getElementById('new-group-name').value.trim();
|
||||||
|
const groupSize = document.getElementById('new-group-size').value;
|
||||||
const educationFormId = newGroupEfSelect.value;
|
const educationFormId = newGroupEfSelect.value;
|
||||||
|
|
||||||
if (!name) { showAlert('create-group-alert', 'Введите название группы', 'error'); return; }
|
if (!name) { showAlert('create-group-alert', 'Введите название группы', 'error'); return; }
|
||||||
|
if (!groupSize) { showAlert('create-group-alert', 'Введите размер группы', 'error'); return; }
|
||||||
if (!educationFormId) { showAlert('create-group-alert', 'Выберите форму обучения', 'error'); return; }
|
if (!educationFormId) { showAlert('create-group-alert', 'Выберите форму обучения', 'error'); return; }
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const data = await api.post('/api/groups', { name, educationFormId: Number(educationFormId) });
|
const data = await api.post('/api/groups', { name, groupSize, educationFormId: Number(educationFormId) });
|
||||||
showAlert('create-group-alert', `Группа "${escapeHtml(data.name)}" создана`, 'success');
|
showAlert('create-group-alert', `Группа "${escapeHtml(data.name)}" создана`, 'success');
|
||||||
createGroupForm.reset();
|
createGroupForm.reset();
|
||||||
loadGroups();
|
loadGroups();
|
||||||
|
|||||||
@@ -79,8 +79,19 @@ export async function initUsers() {
|
|||||||
|
|
||||||
// Заполнение select группами
|
// Заполнение select группами
|
||||||
function renderGroupOptions() {
|
function renderGroupOptions() {
|
||||||
|
if (!groups || groups.length === 0) {
|
||||||
|
lessonClassroomSelect.innerHTML = '<option value="">Нет доступных групп</option>';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
lessonGroupSelect.innerHTML = '<option value="">Выберите группу</option>' +
|
lessonGroupSelect.innerHTML = '<option value="">Выберите группу</option>' +
|
||||||
groups.map(g => `<option value="${g.id}">${escapeHtml(g.name)}</option>`).join('');
|
groups.map(g => {
|
||||||
|
let optionText = escapeHtml(g.name);
|
||||||
|
if(g.groupSize) {
|
||||||
|
optionText += ` (численность: ${g.groupSize} чел.)`;
|
||||||
|
}
|
||||||
|
return `<option value="${g.id}">${optionText}</option>`;
|
||||||
|
}).join('');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Заполнение select дисциплинами
|
// Заполнение select дисциплинами
|
||||||
@@ -90,10 +101,40 @@ export async function initUsers() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function renderClassroomsOptions() {
|
function renderClassroomsOptions() {
|
||||||
lessonClassroomSelect.innerHTML = '<option value="">Выберите аудиторию</option>' +
|
if (!classrooms || classrooms.length ===0) {
|
||||||
classrooms.map(c => `<option value="${c.id}">${escapeHtml(c.name)}</option>`).join('');
|
lessonClassroomSelect.innerHTML = '<option value="">Нет доступных аудиторий</option>';
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const selectedGroupId = lessonGroupSelect.value;
|
||||||
|
const selectedGroup = groups?.find(g => g.id == selectedGroupId);
|
||||||
|
const groupSize = selectedGroup?.groupSize || 0;
|
||||||
|
|
||||||
|
lessonClassroomSelect.innerHTML = '<option value="">Выберите аудиторию</option>' +
|
||||||
|
classrooms.map(c => {
|
||||||
|
let optionText = escapeHtml(c.name);
|
||||||
|
// Добавление текста с инфой о вместимости чел.
|
||||||
|
if(c.capacity) {
|
||||||
|
optionText += ` (вместимость: ${c.capacity} чел.)`;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Если аудитория занята, то рисуем крестик допом
|
||||||
|
if (c.isAvailable === false) {
|
||||||
|
optionText += ` ❌ Занята`
|
||||||
|
// Если свободна, но меньше численности группы, отображаем воскл. знак
|
||||||
|
} else if (selectedGroupId && groupSize > 0 && c.capacity && groupSize > c.capacity) {
|
||||||
|
optionText += ` ⚠️ Недостаточно места`;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return `<option value="${c.id}">${optionText}</option>`;
|
||||||
|
}).join('');
|
||||||
|
}
|
||||||
|
|
||||||
|
lessonGroupSelect.addEventListener('change', function() {
|
||||||
|
renderClassroomsOptions();
|
||||||
|
});
|
||||||
|
|
||||||
// NEW: функция обновления списка времени в зависимости от дня
|
// NEW: функция обновления списка времени в зависимости от дня
|
||||||
function updateTimeOptions(dayValue) {
|
function updateTimeOptions(dayValue) {
|
||||||
let times = [];
|
let times = [];
|
||||||
|
|||||||
@@ -7,6 +7,10 @@
|
|||||||
<label for="new-group-name">Название группы</label>
|
<label for="new-group-name">Название группы</label>
|
||||||
<input type="text" id="new-group-name" placeholder="ИВТ-21-1" required>
|
<input type="text" id="new-group-name" placeholder="ИВТ-21-1" required>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="new-group-size">Численность группы</label>
|
||||||
|
<input type="text" id="new-group-size" placeholder="20" required>
|
||||||
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="new-group-ef">Форма обучения</label>
|
<label for="new-group-ef">Форма обучения</label>
|
||||||
<select id="new-group-ef">
|
<select id="new-group-ef">
|
||||||
@@ -35,6 +39,7 @@
|
|||||||
<tr>
|
<tr>
|
||||||
<th>ID</th>
|
<th>ID</th>
|
||||||
<th>Название</th>
|
<th>Название</th>
|
||||||
|
<th>Численность (чел.)</th>
|
||||||
<th>Форма обучения</th>
|
<th>Форма обучения</th>
|
||||||
<th>Действия</th>
|
<th>Действия</th>
|
||||||
</tr>
|
</tr>
|
||||||
|
|||||||
Reference in New Issue
Block a user