Много разных изменений

This commit is contained in:
Zuev
2026-08-20 00:55:27 +03:00
parent 3599d850f6
commit a1c4ee4298
78 changed files with 4698 additions and 428 deletions

View File

@@ -1,5 +1,11 @@
import { api } from '../api.js';
import {
academicYearsFromSemesters,
resolveAcademicPeriod,
semestersForAcademicYear
} from '../academic-period.js';
import { escapeHtml } from '../utils.js';
import { trackUxEvent } from '../../../telemetry.js';
let versionState = null;
@@ -9,6 +15,7 @@ export async function initScheduleVersions() {
versionState = {
root,
semesters: [],
academicYearId: '',
versions: [],
history: [],
modal: null,
@@ -20,6 +27,7 @@ export async function initScheduleVersions() {
function bindEvents() {
const root = versionState.root;
root.querySelector('#version-year')?.addEventListener('change', handleYearChange);
root.querySelector('#version-semester')?.addEventListener('change', loadWorkspace);
root.querySelector('#version-create')?.addEventListener('click', () => openCreateModal());
root.querySelector('#version-drafts')?.addEventListener('click', handleVersionAction);
@@ -37,34 +45,62 @@ function bindEvents() {
}
async function loadSemesters() {
const select = versionState.root.querySelector('#version-semester');
try {
versionState.semesters = await api.get('/api/schedule/semesters');
select.innerHTML = versionState.semesters.map(semester => `
<option value="${escapeHtml(String(semester.id))}">${escapeHtml(semesterLabel(semester))}</option>
`).join('');
if (!versionState.semesters.length) {
select.innerHTML = '<option value="">Семестры не настроены</option>';
renderPeriodSelects('', '');
setStatus('Сначала создайте учебный год и семестр.', 'error');
return;
}
const savedSemester = localStorage.getItem('magistr.schedule.semesterId');
const today = localIsoDate(new Date());
const current = versionState.semesters.find(item => item.startDate <= today && item.endDate >= today);
const selected = versionState.semesters.find(item => String(item.id) === savedSemester)
|| current
|| versionState.semesters[0];
select.value = String(selected.id);
const selected = resolveAcademicPeriod(versionState.semesters, {
academicYearId: localStorage.getItem('magistr.schedule.yearId'),
semesterId: localStorage.getItem('magistr.schedule.semesterId'),
date: localIsoDate(new Date())
});
renderPeriodSelects(selected.academicYearId, selected.semesterId);
await loadWorkspace();
} catch (error) {
setStatus(error.message || 'Не удалось загрузить семестры.', 'error');
}
}
async function handleYearChange() {
const yearId = versionState.root.querySelector('#version-year')?.value || '';
const selected = resolveAcademicPeriod(versionState.semesters, {
academicYearId: yearId,
date: localIsoDate(new Date())
});
renderPeriodSelects(yearId, selected.semesterId);
await loadWorkspace();
}
function renderPeriodSelects(academicYearId, semesterId) {
const yearSelect = versionState.root.querySelector('#version-year');
const semesterSelect = versionState.root.querySelector('#version-semester');
const years = academicYearsFromSemesters(versionState.semesters);
versionState.academicYearId = String(academicYearId || years[0]?.id || '');
yearSelect.innerHTML = years.length
? years.map(year => `<option value="${escapeHtml(year.id)}">${escapeHtml(year.title)}</option>`).join('')
: '<option value="">Учебные годы не настроены</option>';
yearSelect.value = versionState.academicYearId;
const yearSemesters = semestersForAcademicYear(versionState.semesters, versionState.academicYearId);
semesterSelect.innerHTML = yearSemesters.length
? yearSemesters.map(semester => `
<option value="${escapeHtml(String(semester.id))}">${escapeHtml(semesterLabel(semester))}</option>
`).join('')
: '<option value="">Семестры не настроены</option>';
const selectedSemester = yearSemesters.find(semester => String(semester.id) === String(semesterId))
|| yearSemesters[0];
semesterSelect.value = String(selectedSemester?.id || '');
localStorage.setItem('magistr.schedule.yearId', versionState.academicYearId);
}
async function loadWorkspace() {
const semesterId = selectedSemesterId();
if (!semesterId || versionState.loading) return;
versionState.loading = true;
localStorage.setItem('magistr.schedule.yearId', versionState.academicYearId);
localStorage.setItem('magistr.schedule.semesterId', semesterId);
setStatus('Собираем версии, правила и журнал публикаций…', 'loading');
try {
@@ -73,6 +109,7 @@ async function loadWorkspace() {
api.get(`/api/edu-office/schedule/versions/history?semesterId=${encodeURIComponent(semesterId)}`)
]);
renderWorkspace();
trackUxEvent('версии_расписания_загружены', { semesterId, total: versionState.versions.length });
setStatus('Контур версий синхронизирован.', 'success');
} catch (error) {
setStatus(error.message || 'Не удалось загрузить версии расписания.', 'error');
@@ -197,6 +234,7 @@ async function handleVersionAction(event) {
if (!version) return;
const action = button.dataset.action;
if (action === 'edit') {
localStorage.setItem('magistr.schedule.semesterId', String(version.semesterId));
localStorage.setItem('magistr.schedule.openVersionId', String(version.id));
navigateTo('schedule');
return;