поправил добавление дисциплин и расписание занятий
This commit is contained in:
@@ -289,6 +289,25 @@
|
|||||||
grid-template-columns: repeat(8, minmax(125px, 1fr)) auto;
|
grid-template-columns: repeat(8, minmax(125px, 1fr)) auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.subject-import-rows-list {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 0.75rem;
|
||||||
|
margin-top: 0.75rem;
|
||||||
|
overflow: visible;
|
||||||
|
}
|
||||||
|
|
||||||
|
.subject-import-row {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: minmax(120px, 1fr) minmax(200px, 3fr) auto;
|
||||||
|
gap: 0.75rem;
|
||||||
|
align-items: end;
|
||||||
|
padding: 0.75rem;
|
||||||
|
background: var(--bg-input);
|
||||||
|
border: 1px solid var(--bg-card-border);
|
||||||
|
border-radius: var(--radius-sm);
|
||||||
|
}
|
||||||
|
|
||||||
.schedule-rule-actions {
|
.schedule-rule-actions {
|
||||||
margin-top: 0.25rem;
|
margin-top: 0.25rem;
|
||||||
clear: both;
|
clear: both;
|
||||||
@@ -1259,6 +1278,10 @@
|
|||||||
grid-template-columns: 1fr;
|
grid-template-columns: 1fr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.subject-import-row {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
}
|
||||||
|
|
||||||
.calendar-fill-panel {
|
.calendar-fill-panel {
|
||||||
grid-template-columns: 1fr;
|
grid-template-columns: 1fr;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,6 +12,8 @@ export async function initDepartmentWorkspace() {
|
|||||||
const endInput = document.getElementById('department-workspace-end');
|
const endInput = document.getElementById('department-workspace-end');
|
||||||
const refreshButton = document.getElementById('department-workspace-refresh');
|
const refreshButton = document.getElementById('department-workspace-refresh');
|
||||||
const importForm = document.getElementById('department-subject-import-form');
|
const importForm = document.getElementById('department-subject-import-form');
|
||||||
|
const importRowsContainer = document.getElementById('subject-import-rows');
|
||||||
|
const importAddButton = document.getElementById('subject-import-add');
|
||||||
const subjectsTbody = document.getElementById('department-subjects-tbody');
|
const subjectsTbody = document.getElementById('department-subjects-tbody');
|
||||||
const subjectCount = document.getElementById('department-subject-count');
|
const subjectCount = document.getElementById('department-subject-count');
|
||||||
const commentsCard = document.getElementById('department-comments-card');
|
const commentsCard = document.getElementById('department-comments-card');
|
||||||
@@ -32,6 +34,15 @@ export async function initDepartmentWorkspace() {
|
|||||||
startInput?.addEventListener('change', handleStartDateChange);
|
startInput?.addEventListener('change', handleStartDateChange);
|
||||||
endInput?.addEventListener('change', loadWorkload);
|
endInput?.addEventListener('change', loadWorkload);
|
||||||
importForm?.addEventListener('submit', importSubjects);
|
importForm?.addEventListener('submit', importSubjects);
|
||||||
|
importAddButton?.addEventListener('click', () => renderImportRows([...readImportRows(), { code: '', name: '' }]));
|
||||||
|
importRowsContainer?.addEventListener('click', (event) => {
|
||||||
|
const removeBtn = event.target.closest('.subject-import-remove');
|
||||||
|
if (removeBtn) {
|
||||||
|
const rows = readImportRows();
|
||||||
|
rows.splice(Number(removeBtn.dataset.index), 1);
|
||||||
|
renderImportRows(rows.length ? rows : [{ code: '', name: '' }]);
|
||||||
|
}
|
||||||
|
});
|
||||||
commentsForm?.addEventListener('submit', saveComment);
|
commentsForm?.addEventListener('submit', saveComment);
|
||||||
commentsCloseButton?.addEventListener('click', () => {
|
commentsCloseButton?.addEventListener('click', () => {
|
||||||
commentsCard.hidden = true;
|
commentsCard.hidden = true;
|
||||||
@@ -50,6 +61,7 @@ export async function initDepartmentWorkspace() {
|
|||||||
departmentField.hidden = true;
|
departmentField.hidden = true;
|
||||||
departmentSelect.value = userDepartmentId || '';
|
departmentSelect.value = userDepartmentId || '';
|
||||||
}
|
}
|
||||||
|
renderImportRows([{ code: '', name: '' }]);
|
||||||
await loadWorkspace();
|
await loadWorkspace();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
showAlert('department-workspace-alert', error.message || 'Ошибка загрузки кабинета кафедры', 'error');
|
showAlert('department-workspace-alert', error.message || 'Ошибка загрузки кабинета кафедры', 'error');
|
||||||
@@ -96,38 +108,57 @@ export async function initDepartmentWorkspace() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function renderImportRows(rows) {
|
||||||
|
if (!importRowsContainer) return;
|
||||||
|
importRowsContainer.innerHTML = (rows || [{ code: '', name: '' }]).map((row, index) => `
|
||||||
|
<div class="subject-import-row" data-index="${index}">
|
||||||
|
<div class="form-group">
|
||||||
|
<label>Код</label>
|
||||||
|
<input type="text" class="subject-import-code" value="${escapeHtml(row.code || '')}" placeholder="DB201">
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label>Название</label>
|
||||||
|
<input type="text" class="subject-import-name" value="${escapeHtml(row.name || '')}" placeholder="Базы данных">
|
||||||
|
</div>
|
||||||
|
<button type="button" class="btn-delete subject-import-remove" data-index="${index}">Удалить</button>
|
||||||
|
</div>
|
||||||
|
`).join('');
|
||||||
|
}
|
||||||
|
|
||||||
|
function readImportRows() {
|
||||||
|
if (!importRowsContainer) return [];
|
||||||
|
return Array.from(importRowsContainer.querySelectorAll('.subject-import-row')).map(row => ({
|
||||||
|
code: (row.querySelector('.subject-import-code')?.value || '').trim(),
|
||||||
|
name: (row.querySelector('.subject-import-name')?.value || '').trim()
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
async function importSubjects(event) {
|
async function importSubjects(event) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
const alertId = 'department-subject-import-alert';
|
const alertId = 'department-subject-import-alert';
|
||||||
hideAlert(alertId);
|
hideAlert(alertId);
|
||||||
const departmentId = selectedDepartmentId();
|
const departmentId = selectedDepartmentId();
|
||||||
const rows = document.getElementById('department-subject-import-text').value
|
const rows = readImportRows()
|
||||||
.split('\n')
|
.filter(item => item.name)
|
||||||
.map(row => row.trim())
|
.map(item => ({
|
||||||
.filter(Boolean)
|
code: item.code,
|
||||||
.map(row => {
|
name: item.name,
|
||||||
const [code, ...nameParts] = row.split(';');
|
departmentId: Number(departmentId)
|
||||||
return {
|
}));
|
||||||
code: (code || '').trim(),
|
|
||||||
name: nameParts.join(';').trim(),
|
|
||||||
departmentId: Number(departmentId)
|
|
||||||
};
|
|
||||||
})
|
|
||||||
.filter(item => item.name);
|
|
||||||
|
|
||||||
if (!departmentId) {
|
if (!departmentId) {
|
||||||
showAlert(alertId, 'Выберите кафедру', 'error');
|
showAlert(alertId, 'Выберите кафедру', 'error');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!rows.length) {
|
if (!rows.length) {
|
||||||
showAlert(alertId, 'Добавьте хотя бы одну строку в формате «код; название»', 'error');
|
showAlert(alertId, 'Заполните название хотя бы одной дисциплины', 'error');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const result = await api.post('/api/department/subjects/import', rows);
|
const result = await api.post('/api/department/subjects/import', rows);
|
||||||
showAlert(alertId, result.message || 'Дисциплины загружены', 'success');
|
showAlert(alertId, result.message || 'Дисциплины загружены', 'success');
|
||||||
document.getElementById('department-subject-import-text').value = '';
|
renderImportRows([{ code: '', name: '' }]);
|
||||||
await loadSubjects();
|
await loadSubjects();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
showAlert(alertId, error.message || 'Ошибка загрузки дисциплин', 'error');
|
showAlert(alertId, error.message || 'Ошибка загрузки дисциплин', 'error');
|
||||||
|
|||||||
@@ -416,9 +416,7 @@ export async function initSchedule() {
|
|||||||
if (!lessons.length) return '';
|
if (!lessons.length) return '';
|
||||||
const oddLessons = lessons.filter(lesson => lesson.parity === 'BOTH' || lesson.parity === 'ODD');
|
const oddLessons = lessons.filter(lesson => lesson.parity === 'BOTH' || lesson.parity === 'ODD');
|
||||||
const evenLessons = lessons.filter(lesson => lesson.parity === 'BOTH' || lesson.parity === 'EVEN');
|
const evenLessons = lessons.filter(lesson => lesson.parity === 'BOTH' || lesson.parity === 'EVEN');
|
||||||
const shouldSplit = oddLessons.length > 0
|
const shouldSplit = lessons.some(l => l.parity !== 'BOTH');
|
||||||
&& evenLessons.length > 0
|
|
||||||
&& visualLessonSignature(oddLessons) !== visualLessonSignature(evenLessons);
|
|
||||||
|
|
||||||
if (!shouldSplit) {
|
if (!shouldSplit) {
|
||||||
return `<div class="schedule-visual-unified">${uniqueVisualLessons(lessons).map(renderVisualLesson).join('')}</div>`;
|
return `<div class="schedule-visual-unified">${uniqueVisualLessons(lessons).map(renderVisualLesson).join('')}</div>`;
|
||||||
@@ -1111,21 +1109,7 @@ export async function initSchedule() {
|
|||||||
function compactWeekRanges(weeks) {
|
function compactWeekRanges(weeks) {
|
||||||
const uniqueWeeks = [...new Set((weeks || []).map(Number).filter(Boolean))].sort((a, b) => a - b);
|
const uniqueWeeks = [...new Set((weeks || []).map(Number).filter(Boolean))].sort((a, b) => a - b);
|
||||||
if (!uniqueWeeks.length) return '';
|
if (!uniqueWeeks.length) return '';
|
||||||
const ranges = [];
|
return `(${weekRangeText(uniqueWeeks[0], uniqueWeeks[uniqueWeeks.length - 1])})`;
|
||||||
let start = uniqueWeeks[0];
|
|
||||||
let previous = uniqueWeeks[0];
|
|
||||||
for (let index = 1; index < uniqueWeeks.length; index += 1) {
|
|
||||||
const week = uniqueWeeks[index];
|
|
||||||
if (week === previous + 1) {
|
|
||||||
previous = week;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
ranges.push(weekRangeText(start, previous));
|
|
||||||
start = week;
|
|
||||||
previous = week;
|
|
||||||
}
|
|
||||||
ranges.push(weekRangeText(start, previous));
|
|
||||||
return `(${ranges.join(', ')})`;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function weekRangeText(start, end) {
|
function weekRangeText(start, end) {
|
||||||
|
|||||||
@@ -30,9 +30,12 @@
|
|||||||
<h2>Загрузка дисциплин</h2>
|
<h2>Загрузка дисциплин</h2>
|
||||||
</div>
|
</div>
|
||||||
<form id="department-subject-import-form" class="stack-form">
|
<form id="department-subject-import-form" class="stack-form">
|
||||||
<div class="form-group">
|
<div class="subject-import-slots-panel">
|
||||||
<label for="department-subject-import-text">Строки в формате «код; название»</label>
|
<div class="card-header-row">
|
||||||
<textarea id="department-subject-import-text" rows="8" placeholder="DB201; Базы данных AI101; Искусственный интеллект"></textarea>
|
<label class="schedule-section-label" style="margin:0">Дисциплины для загрузки</label>
|
||||||
|
<button type="button" class="btn-edit-classroom" id="subject-import-add">Добавить строку</button>
|
||||||
|
</div>
|
||||||
|
<div id="subject-import-rows" class="subject-import-rows-list"></div>
|
||||||
</div>
|
</div>
|
||||||
<button type="submit" class="btn-primary">Загрузить</button>
|
<button type="submit" class="btn-primary">Загрузить</button>
|
||||||
<div class="form-alert" id="department-subject-import-alert" role="alert"></div>
|
<div class="form-alert" id="department-subject-import-alert" role="alert"></div>
|
||||||
|
|||||||
Reference in New Issue
Block a user