исправил настройку временных слотов
This commit is contained in:
@@ -67,6 +67,9 @@ export async function initAcademicCalendar() {
|
||||
const calendarDayDialogDay = document.getElementById('calendar-day-dialog-day');
|
||||
const calendarDayDialogActivitySummary = document.getElementById('calendar-day-dialog-activity-summary');
|
||||
const calendarDayDialogActivitySelect = document.getElementById('calendar-day-dialog-activity');
|
||||
const calendarDayDialogTimeScopeSelect = document.getElementById('calendar-day-dialog-time-scope');
|
||||
const calendarDayDialogTimeSaveButton = document.getElementById('calendar-day-dialog-time-save');
|
||||
const calendarDayDialogTimeClearButton = document.getElementById('calendar-day-dialog-time-clear');
|
||||
|
||||
let academicYears = [];
|
||||
let semesters = [];
|
||||
@@ -75,12 +78,21 @@ export async function initAcademicCalendar() {
|
||||
let studyForms = [];
|
||||
let activityTypes = [];
|
||||
let calendars = [];
|
||||
let timeSlotScopes = [];
|
||||
let timeSlotDateAssignments = [];
|
||||
let activeCalendarDay = null;
|
||||
|
||||
bindEvents();
|
||||
|
||||
try {
|
||||
await Promise.all([loadBaseLists(), loadYears(), loadStudyForms(), loadActivityTypes()]);
|
||||
await Promise.all([
|
||||
loadBaseLists(),
|
||||
loadYears(),
|
||||
loadStudyForms(),
|
||||
loadActivityTypes(),
|
||||
loadTimeSlotScopes(),
|
||||
loadTimeSlotDateAssignments()
|
||||
]);
|
||||
await loadCalendars();
|
||||
} catch (error) {
|
||||
showAlert('academic-calendar-alert', error.message || 'Ошибка загрузки календарных графиков', 'error');
|
||||
@@ -126,6 +138,8 @@ export async function initAcademicCalendar() {
|
||||
updateCalendarDayDialogSummary(activeCalendarDay);
|
||||
renderCalendarTotals();
|
||||
});
|
||||
calendarDayDialogTimeSaveButton?.addEventListener('click', saveTimeSlotDateAssignment);
|
||||
calendarDayDialogTimeClearButton?.addEventListener('click', clearTimeSlotDateAssignment);
|
||||
|
||||
academicYearForm?.addEventListener('submit', saveAcademicYear);
|
||||
semesterForm?.addEventListener('submit', saveSemester);
|
||||
@@ -309,6 +323,14 @@ export async function initAcademicCalendar() {
|
||||
populateActivitySelects();
|
||||
}
|
||||
|
||||
async function loadTimeSlotScopes() {
|
||||
timeSlotScopes = await api.get('/api/admin/time-slots/scopes');
|
||||
}
|
||||
|
||||
async function loadTimeSlotDateAssignments() {
|
||||
timeSlotDateAssignments = await api.get('/api/admin/time-slots/date-assignments');
|
||||
}
|
||||
|
||||
async function loadCalendars() {
|
||||
calendarsTbody.innerHTML = '<tr><td colspan="7" class="loading-row">Загрузка...</td></tr>';
|
||||
try {
|
||||
@@ -432,6 +454,7 @@ export async function initAcademicCalendar() {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
await loadTimeSlotDateAssignments();
|
||||
const rows = await api.get(`/api/admin/academic-calendars/${calendar.id}/grid`);
|
||||
const gridRows = rows.length ? rows : buildDefaultGrid(calendar);
|
||||
renderCalendarGrid(gridRows);
|
||||
@@ -573,12 +596,15 @@ export async function initAcademicCalendar() {
|
||||
data-date="${row.date}"
|
||||
data-week="${row.weekNumber}"
|
||||
data-day="${row.dayOfWeek}"
|
||||
data-time-assignment-id="${timeAssignmentForDate(row.date)?.id || ''}"
|
||||
data-time-scope-id="${timeAssignmentForDate(row.date)?.scopeId || ''}"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
aria-label="${escapeHtml(`${formatShortDate(row.date)} ${dayName}, ${row.weekNumber} неделя, код ${code}`)}"
|
||||
title="${escapeHtml(`${formatLongDate(row.date)}, ${dayName}, ${row.weekNumber} неделя, ${code} - ${activity.name || ''}`)}"
|
||||
style="--activity-color:${escapeHtml(color)}">
|
||||
<strong class="calendar-day-code">${escapeHtml(code)}</strong>
|
||||
${timeAssignmentForDate(row.date) ? '<span class="calendar-day-time-marker">вр.</span>' : ''}
|
||||
<select class="calendar-day-activity custom-select-initialized" aria-hidden="true" tabindex="-1">${options(activityTypes.map(toActivityOption), selected)}</select>
|
||||
</td>
|
||||
`;
|
||||
@@ -594,7 +620,9 @@ export async function initAcademicCalendar() {
|
||||
activityTypes.map(toActivityOption),
|
||||
day.querySelector('.calendar-day-activity').value
|
||||
);
|
||||
populateTimeScopeDialogSelect(day.dataset.date);
|
||||
syncSelects(calendarDayDialogActivitySelect);
|
||||
syncSelects(calendarDayDialogTimeScopeSelect);
|
||||
updateCalendarDayDialogSummary(day);
|
||||
calendarDayDialog.classList.add('open');
|
||||
}
|
||||
@@ -619,6 +647,77 @@ export async function initAcademicCalendar() {
|
||||
`;
|
||||
}
|
||||
|
||||
async function saveTimeSlotDateAssignment() {
|
||||
if (!activeCalendarDay) return;
|
||||
hideAlert('calendar-day-dialog-time-alert');
|
||||
const scopeId = calendarDayDialogTimeScopeSelect.value;
|
||||
if (!scopeId) {
|
||||
await clearTimeSlotDateAssignment();
|
||||
return;
|
||||
}
|
||||
try {
|
||||
await api.post('/api/admin/time-slots/date-assignments', {
|
||||
date: activeCalendarDay.dataset.date,
|
||||
scopeId: Number(scopeId)
|
||||
});
|
||||
await loadTimeSlotDateAssignments();
|
||||
updateTimeAssignmentVisuals(activeCalendarDay.dataset.date);
|
||||
populateTimeScopeDialogSelect(activeCalendarDay.dataset.date);
|
||||
syncSelects(calendarDayDialogTimeScopeSelect);
|
||||
showAlert('calendar-day-dialog-time-alert', 'Ручная сетка применена к дате', 'success');
|
||||
} catch (error) {
|
||||
showAlert('calendar-day-dialog-time-alert', error.message || 'Ошибка применения временной сетки', 'error');
|
||||
}
|
||||
}
|
||||
|
||||
async function clearTimeSlotDateAssignment() {
|
||||
if (!activeCalendarDay) return;
|
||||
hideAlert('calendar-day-dialog-time-alert');
|
||||
const assignment = timeAssignmentForDate(activeCalendarDay.dataset.date);
|
||||
if (!assignment) {
|
||||
calendarDayDialogTimeScopeSelect.value = '';
|
||||
syncSelects(calendarDayDialogTimeScopeSelect);
|
||||
showAlert('calendar-day-dialog-time-alert', 'Для даты нет ручной сетки', 'success');
|
||||
return;
|
||||
}
|
||||
try {
|
||||
await api.delete('/api/admin/time-slots/date-assignments/' + assignment.id);
|
||||
await loadTimeSlotDateAssignments();
|
||||
updateTimeAssignmentVisuals(activeCalendarDay.dataset.date);
|
||||
populateTimeScopeDialogSelect(activeCalendarDay.dataset.date);
|
||||
syncSelects(calendarDayDialogTimeScopeSelect);
|
||||
showAlert('calendar-day-dialog-time-alert', 'Ручная сетка убрана', 'success');
|
||||
} catch (error) {
|
||||
showAlert('calendar-day-dialog-time-alert', error.message || 'Ошибка удаления ручной сетки', 'error');
|
||||
}
|
||||
}
|
||||
|
||||
function populateTimeScopeDialogSelect(date) {
|
||||
const assignment = timeAssignmentForDate(date);
|
||||
const manualScopes = timeSlotScopes.filter(scope => scope.applyMode === 'MANUAL');
|
||||
const automaticLabel = automaticTimeScopeLabel(date);
|
||||
calendarDayDialogTimeScopeSelect.innerHTML = `<option value="">${escapeHtml(automaticLabel)}</option>` +
|
||||
manualScopes.map(scope => `<option value="${scope.id}">${escapeHtml(scope.name)}</option>`).join('');
|
||||
calendarDayDialogTimeScopeSelect.value = assignment?.scopeId || '';
|
||||
calendarDayDialogTimeSaveButton.disabled = manualScopes.length === 0 && !assignment;
|
||||
calendarDayDialogTimeClearButton.disabled = !assignment;
|
||||
}
|
||||
|
||||
function updateTimeAssignmentVisuals(date) {
|
||||
const assignment = timeAssignmentForDate(date);
|
||||
calendarGrid.querySelectorAll(`.calendar-day[data-date="${date}"]`).forEach(day => {
|
||||
day.dataset.timeAssignmentId = assignment?.id || '';
|
||||
day.dataset.timeScopeId = assignment?.scopeId || '';
|
||||
const marker = day.querySelector('.calendar-day-time-marker');
|
||||
if (assignment && !marker) {
|
||||
day.insertAdjacentHTML('beforeend', '<span class="calendar-day-time-marker">вр.</span>');
|
||||
}
|
||||
if (!assignment && marker) {
|
||||
marker.remove();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function updateCalendarDayVisual(day) {
|
||||
if (!day) return;
|
||||
const select = day.querySelector('.calendar-day-activity');
|
||||
@@ -784,6 +883,20 @@ export async function initAcademicCalendar() {
|
||||
return activityTypes.find(type => String(type.id) === String(id));
|
||||
}
|
||||
|
||||
function timeAssignmentForDate(date) {
|
||||
return timeSlotDateAssignments.find(item => item.date === date);
|
||||
}
|
||||
|
||||
function automaticTimeScopeLabel(date) {
|
||||
const jsDate = new Date(`${date}T00:00:00`);
|
||||
const jsDay = jsDate.getDay();
|
||||
const isoDay = jsDay === 0 ? 7 : jsDay;
|
||||
const weekdayScope = timeSlotScopes.find(scope => scope.applyMode === 'WEEKDAY' && Number(scope.dayOfWeek) === isoDay);
|
||||
const defaultScope = timeSlotScopes.find(scope => scope.applyMode === 'DEFAULT');
|
||||
const scopeName = weekdayScope?.name || defaultScope?.name || 'базовая сетка';
|
||||
return `По правилу даты (${scopeName})`;
|
||||
}
|
||||
|
||||
function semesterLabel(semester) {
|
||||
const type = normalizeSemesterType(semester.semesterType);
|
||||
return `${semester.academicYearTitle || '-'}, ${SEMESTER_LABELS[type] || type} (${semester.startDate} - ${semester.endDate})`;
|
||||
|
||||
Reference in New Issue
Block a user