let currentWeekStart = null; const weekdays = ['Понедельник', 'Вторник', 'Среда', 'Четверг', 'Пятница', 'Суббота', 'Воскресенье']; const weekdaysShort = ['Пн', 'Вт', 'Ср', 'Чт', 'Пт', 'Сб', 'Вс']; function getTodayInLondon() { // Получаем текущую дату в таймзоне London const now = new Date(); const formatter = new Intl.DateTimeFormat('en-CA', { timeZone: 'Europe/London', year: 'numeric', month: '2-digit', day: '2-digit' }); return formatter.format(now); } function getWeekStart(dateStr = null) { if (!dateStr) { dateStr = getTodayInLondon(); } const date = new Date(dateStr + 'T00:00:00'); const day = date.getDay(); const diff = date.getDate() - day + (day === 0 ? -6 : 1); // Понедельник = 1 const monday = new Date(date.setDate(diff)); return monday.toISOString().split('T')[0]; } function formatDate(dateStr) { const date = new Date(dateStr + 'T00:00:00'); return `${weekdaysShort[date.getDay()]}, ${date.getDate()}`; } function formatDateFull(dateStr) { const date = new Date(dateStr + 'T00:00:00'); const months = ['января', 'февраля', 'марта', 'апреля', 'мая', 'июня', 'июля', 'августа', 'сентября', 'октября', 'ноября', 'декабря']; return `${weekdays[date.getDay()]}, ${date.getDate()} ${months[date.getMonth()]}`; } function getWeekDates(startDate) { const dates = []; const start = new Date(startDate + 'T00:00:00'); for (let i = 0; i < 7; i++) { const date = new Date(start); date.setDate(start.getDate() + i); dates.push(date.toISOString().split('T')[0]); } return dates; } async function loadSchedule() { const weekDates = getWeekDates(currentWeekStart); const fromDate = weekDates[0]; const toDate = weekDates[6]; console.log('Loading schedule from', fromDate, 'to', toDate); try { const response = await fetch(`/api/schedule?from_date=${fromDate}&to_date=${toDate}`); const data = await response.json(); console.log('Received items:', data.items); renderSchedule(weekDates, data.items); // Обновляем заголовок недели const startDate = new Date(weekDates[0] + 'T00:00:00'); const endDate = new Date(weekDates[6] + 'T00:00:00'); document.getElementById('week-range').textContent = `${formatDateFull(weekDates[0])} - ${formatDateFull(weekDates[6])}`; } catch (error) { console.error('Error loading schedule:', error); } } function renderSchedule(weekDates, items) { const grid = document.getElementById('schedule-grid'); grid.innerHTML = ''; console.log('Rendering schedule for dates:', weekDates); console.log('All items:', items); weekDates.forEach(dateStr => { const dayItems = items.filter(item => { const match = item.date === dateStr; if (!match && items.length > 0) { console.log(`Item date ${item.date} !== ${dateStr}`); } return match; }); console.log(`Date ${dateStr}: ${dayItems.length} items`); const date = new Date(dateStr + 'T00:00:00'); const column = document.createElement('div'); column.className = 'day-column'; column.innerHTML = `
${formatDateFull(dateStr)}
${renderDayItems(dayItems)}
`; grid.appendChild(column); }); } function renderDayItems(items) { console.log('Rendering items for day:', items); if (items.length === 0) { return '
Нет записей
'; } const tasks = items.filter(item => item.kind === 'task'); const events = items.filter(item => item.kind === 'event'); console.log('Tasks:', tasks, 'Events:', events); let html = ''; // Tasks tasks.forEach(task => { html += `
${task.title}
${task.repeat_weekly ? '
Повторяется
' : ''}
`; }); // Events events.sort((a, b) => a.start_time.localeCompare(b.start_time)).forEach(event => { const endTime = calculateEndTime(event.start_time, event.duration_min); html += `
${event.start_time}-${endTime}
${event.title}
`; }); return html; } function calculateEndTime(startTime, durationMin) { const [hour, minute] = startTime.split(':').map(Number); const totalMinutes = hour * 60 + minute + durationMin; const endHour = Math.floor(totalMinutes / 60); const endMinute = totalMinutes % 60; return `${String(endHour).padStart(2, '0')}:${String(endMinute).padStart(2, '0')}`; } function showModal(content) { document.getElementById('modal-body').innerHTML = content; document.getElementById('modal').style.display = 'block'; } function closeModal() { document.getElementById('modal').style.display = 'none'; } function showAddTaskModal(selectedDate = null) { const weekDates = getWeekDates(currentWeekStart); const today = getTodayInLondon(); const todayDate = new Date(today + 'T00:00:00'); const selectedDateObj = selectedDate ? new Date(selectedDate + 'T00:00:00') : todayDate; // getDay() возвращает 0=воскресенье, 1=понедельник, ..., 6=суббота // Конвертируем в формат 0=понедельник, 6=воскресенье const jsWeekday = selectedDateObj.getDay(); const selectedWeekday = jsWeekday === 0 ? 6 : jsWeekday - 1; // 0=пн, 6=вс const remainingWeekdays = []; // Оставшиеся дни недели после выбранного (среда=2, четверг=3, пятница=4, суббота=5, воскресенье=6) for (let i = selectedWeekday + 1; i <= 6; i++) { remainingWeekdays.push(i); } const content = `

Добавить задачу

`; showModal(content); document.getElementById('task-repeat-weekly').addEventListener('change', function() { document.getElementById('copy-weekdays-group').style.display = this.checked ? 'none' : 'block'; }); document.getElementById('add-task-form').addEventListener('submit', async (e) => { e.preventDefault(); const date = document.getElementById('task-date').value; const title = document.getElementById('task-title').value; const repeatWeekly = document.getElementById('task-repeat-weekly').checked; const copyWeekdays = Array.from(document.querySelectorAll('input[name="copy-weekday"]:checked')) .map(cb => parseInt(cb.value)); try { const response = await fetch('/api/events?kind=task', { method: 'POST', headers: {'Content-Type': 'application/json'}, body: JSON.stringify({ date, title, repeat_weekly: repeatWeekly, copy_to_weekdays: copyWeekdays.length > 0 ? copyWeekdays : null }) }); if (response.ok) { const result = await response.json(); console.log('Task created:', result); closeModal(); await loadSchedule(); } else { const error = await response.json(); console.error('Error creating task:', error); alert('Ошибка: ' + (error.detail || 'Неизвестная ошибка')); } } catch (error) { console.error('Exception creating task:', error); alert('Ошибка при добавлении задачи: ' + error.message); } }); } function showAddEventModal(selectedDate = null) { const today = getTodayInLondon(); const content = `

Добавить занятие

`; showModal(content); document.getElementById('add-event-form').addEventListener('submit', async (e) => { e.preventDefault(); const date = document.getElementById('event-date').value; const hour = document.getElementById('event-hour').value; const minute = document.getElementById('event-minute').value; const durHour = parseInt(document.getElementById('event-duration-hour').value); const durMin = parseInt(document.getElementById('event-duration-minute').value); const title = document.getElementById('event-title').value; const durationMin = durHour * 60 + durMin; if (durationMin === 0) { alert('Длительность должна быть минимум 15 минут'); return; } try { const response = await fetch('/api/events?kind=event', { method: 'POST', headers: {'Content-Type': 'application/json'}, body: JSON.stringify({ date, start_time: `${hour}:${minute}`, duration_min: durationMin, title }) }); if (response.ok) { const result = await response.json(); console.log('Event created:', result); closeModal(); await loadSchedule(); } else { const error = await response.json(); console.error('Error creating event:', error); alert('Ошибка: ' + (error.detail || 'Неизвестная ошибка')); } } catch (error) { console.error('Exception creating event:', error); alert('Ошибка при добавлении занятия: ' + error.message); } }); } async function editItem(id, kind) { // TODO: Реализовать редактирование alert('Редактирование будет реализовано позже'); } async function deleteItem(id, kind) { if (!confirm('Удалить эту запись?')) return; try { const response = await fetch(`/api/events/${id}`, { method: 'DELETE' }); if (response.ok) { loadSchedule(); } else { alert('Ошибка при удалении'); } } catch (error) { alert('Ошибка при удалении'); console.error(error); } } // Инициализация document.addEventListener('DOMContentLoaded', () => { currentWeekStart = getWeekStart(); loadSchedule(); document.getElementById('prev-week').addEventListener('click', () => { const date = new Date(currentWeekStart + 'T00:00:00'); date.setDate(date.getDate() - 7); currentWeekStart = date.toISOString().split('T')[0]; loadSchedule(); }); document.getElementById('next-week').addEventListener('click', () => { const date = new Date(currentWeekStart + 'T00:00:00'); date.setDate(date.getDate() + 7); currentWeekStart = date.toISOString().split('T')[0]; loadSchedule(); }); document.getElementById('add-task-btn').addEventListener('click', () => showAddTaskModal()); document.getElementById('add-event-btn').addEventListener('click', () => showAddEventModal()); document.querySelector('.close').addEventListener('click', closeModal); window.addEventListener('click', (e) => { const modal = document.getElementById('modal'); if (e.target === modal) { closeModal(); } }); // Клик по дню для добавления document.addEventListener('click', (e) => { if (e.target.closest('.day-items')) { const date = e.target.closest('.day-items').dataset.date; if (e.ctrlKey || e.metaKey) { showAddEventModal(date); } else if (e.shiftKey) { showAddTaskModal(date); } } }); });