diff --git a/frontend/admin/css/components.css b/frontend/admin/css/components.css
index 594da25..22d67bb 100755
--- a/frontend/admin/css/components.css
+++ b/frontend/admin/css/components.css
@@ -289,6 +289,25 @@
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 {
margin-top: 0.25rem;
clear: both;
@@ -1259,6 +1278,10 @@
grid-template-columns: 1fr;
}
+ .subject-import-row {
+ grid-template-columns: 1fr;
+ }
+
.calendar-fill-panel {
grid-template-columns: 1fr;
}
diff --git a/frontend/admin/js/views/department-workspace.js b/frontend/admin/js/views/department-workspace.js
index ab9208a..f2e55b8 100644
--- a/frontend/admin/js/views/department-workspace.js
+++ b/frontend/admin/js/views/department-workspace.js
@@ -12,6 +12,8 @@ export async function initDepartmentWorkspace() {
const endInput = document.getElementById('department-workspace-end');
const refreshButton = document.getElementById('department-workspace-refresh');
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 subjectCount = document.getElementById('department-subject-count');
const commentsCard = document.getElementById('department-comments-card');
@@ -32,6 +34,15 @@ export async function initDepartmentWorkspace() {
startInput?.addEventListener('change', handleStartDateChange);
endInput?.addEventListener('change', loadWorkload);
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);
commentsCloseButton?.addEventListener('click', () => {
commentsCard.hidden = true;
@@ -50,6 +61,7 @@ export async function initDepartmentWorkspace() {
departmentField.hidden = true;
departmentSelect.value = userDepartmentId || '';
}
+ renderImportRows([{ code: '', name: '' }]);
await loadWorkspace();
} catch (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) => `
+
+
+
+
+
+
+
+
+
+
+
+ `).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) {
event.preventDefault();
const alertId = 'department-subject-import-alert';
hideAlert(alertId);
const departmentId = selectedDepartmentId();
- const rows = document.getElementById('department-subject-import-text').value
- .split('\n')
- .map(row => row.trim())
- .filter(Boolean)
- .map(row => {
- const [code, ...nameParts] = row.split(';');
- return {
- code: (code || '').trim(),
- name: nameParts.join(';').trim(),
- departmentId: Number(departmentId)
- };
- })
- .filter(item => item.name);
+ const rows = readImportRows()
+ .filter(item => item.name)
+ .map(item => ({
+ code: item.code,
+ name: item.name,
+ departmentId: Number(departmentId)
+ }));
if (!departmentId) {
showAlert(alertId, 'Выберите кафедру', 'error');
return;
}
if (!rows.length) {
- showAlert(alertId, 'Добавьте хотя бы одну строку в формате «код; название»', 'error');
+ showAlert(alertId, 'Заполните название хотя бы одной дисциплины', 'error');
return;
}
try {
const result = await api.post('/api/department/subjects/import', rows);
showAlert(alertId, result.message || 'Дисциплины загружены', 'success');
- document.getElementById('department-subject-import-text').value = '';
+ renderImportRows([{ code: '', name: '' }]);
await loadSubjects();
} catch (error) {
showAlert(alertId, error.message || 'Ошибка загрузки дисциплин', 'error');
diff --git a/frontend/admin/js/views/schedule.js b/frontend/admin/js/views/schedule.js
index 02ecc74..7fc5a4b 100644
--- a/frontend/admin/js/views/schedule.js
+++ b/frontend/admin/js/views/schedule.js
@@ -416,9 +416,7 @@ export async function initSchedule() {
if (!lessons.length) return '';
const oddLessons = lessons.filter(lesson => lesson.parity === 'BOTH' || lesson.parity === 'ODD');
const evenLessons = lessons.filter(lesson => lesson.parity === 'BOTH' || lesson.parity === 'EVEN');
- const shouldSplit = oddLessons.length > 0
- && evenLessons.length > 0
- && visualLessonSignature(oddLessons) !== visualLessonSignature(evenLessons);
+ const shouldSplit = lessons.some(l => l.parity !== 'BOTH');
if (!shouldSplit) {
return `${uniqueVisualLessons(lessons).map(renderVisualLesson).join('')}
`;
@@ -1111,21 +1109,7 @@ export async function initSchedule() {
function compactWeekRanges(weeks) {
const uniqueWeeks = [...new Set((weeks || []).map(Number).filter(Boolean))].sort((a, b) => a - b);
if (!uniqueWeeks.length) return '';
- const ranges = [];
- 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(', ')})`;
+ return `(${weekRangeText(uniqueWeeks[0], uniqueWeeks[uniqueWeeks.length - 1])})`;
}
function weekRangeText(start, end) {
diff --git a/frontend/admin/views/department-workspace.html b/frontend/admin/views/department-workspace.html
index 7539b7b..951fb12 100644
--- a/frontend/admin/views/department-workspace.html
+++ b/frontend/admin/views/department-workspace.html
@@ -30,9 +30,12 @@
Загрузка дисциплин