Улучшен календарный фильтр дат: динамическое количество дней, отображение месяца и сохранение позиции при выборе

This commit is contained in:
2025-11-07 20:03:06 +03:00
parent a271bfa809
commit 7a725f485a
3 changed files with 111 additions and 13 deletions

View File

@@ -1,5 +1,5 @@
/**
* Стили для календарного фильтра с лентой из 19 дней
* Стили для календарного фильтра с динамическим количеством дней
* Используется в компоненте date_range_filter.html
*/
@@ -118,6 +118,13 @@
text-transform: uppercase;
}
.date-btn-month {
font-size: 0.65rem;
font-weight: 500;
color: #6c757d;
text-transform: lowercase;
}
/* Сегодняшний день (более светлый оттенок) */
.date-btn.today {
background: #cfe2ff;
@@ -127,7 +134,8 @@
.date-btn.today .date-btn-label,
.date-btn.today .date-btn-day,
.date-btn.today .date-btn-weekday {
.date-btn.today .date-btn-weekday,
.date-btn.today .date-btn-month {
color: #084298;
}
@@ -154,7 +162,8 @@
color: #dc3545;
}
.date-btn.selected .date-btn-weekday {
.date-btn.selected .date-btn-weekday,
.date-btn.selected .date-btn-month {
color: #6c757d;
}
@@ -189,6 +198,10 @@
.date-btn-weekday {
font-size: 0.7rem;
}
.date-btn-month {
font-size: 0.6rem;
}
}
@media (max-width: 576px) {
@@ -208,6 +221,10 @@
.date-btn-weekday {
font-size: 0.65rem;
}
.date-btn-month {
font-size: 0.55rem;
}
}
/* Анимация при клике */

View File

@@ -1,6 +1,6 @@
/**
* Календарная лента с 19 днями для фильтрации заказов
* Сегодня в центре, навигация стрелками
* Календарная лента с динамическим количеством дней для фильтрации заказов
* Сегодня всегда в центре при загрузке, количество дней зависит от ширины экрана
*/
document.addEventListener('DOMContentLoaded', function() {
@@ -16,6 +16,13 @@ document.addEventListener('DOMContentLoaded', function() {
// Инициализация с сегодняшней датой в центре
const carousel = new DateCarousel(container, minInputId, maxInputId);
carousel.init();
// Пересчёт количества дней при изменении размера окна
let resizeTimeout;
window.addEventListener('resize', () => {
clearTimeout(resizeTimeout);
resizeTimeout = setTimeout(() => carousel.handleResize(), 250);
});
});
});
@@ -32,18 +39,76 @@ class DateCarousel {
this.centerDate = new Date(); // Центральная дата (по умолчанию сегодня)
this.today = new Date();
this.today.setHours(0, 0, 0, 0);
this.daysCount = 0; // Будет рассчитано динамически
}
/**
* Инициализация календарной ленты
*/
init() {
this.calculateDaysCount();
this.loadSelectedDate(); // Загрузить выбранную дату из фильтра
this.render();
this.attachNavHandlers();
}
/**
* Генерация и отображение 19 дней
* Загрузка выбранной даты из скрытых полей фильтра
*/
loadSelectedDate() {
// Если есть выбранная дата в фильтре, не центрируем на ней - пусть остается в том же положении
if (this.minInput.value && this.maxInput.value &&
this.minInput.value === this.maxInput.value) {
const parts = this.minInput.value.split('-');
if (parts.length === 3) {
const selectedDate = new Date(
parseInt(parts[0]),
parseInt(parts[1]) - 1,
parseInt(parts[2])
);
selectedDate.setHours(0, 0, 0, 0);
// Не изменяем центральную дату, просто оставим как есть
console.log(`Selected date: ${this.formatDate(selectedDate)}, not centering`);
}
} else {
// Если фильтра нет, центрируем на сегодняшнем дне
console.log('No filter active - centering on today');
}
}
/**
* Расчёт количества дней на основе доступной ширины
*/
calculateDaysCount() {
const containerWidth = this.container.offsetWidth;
const dayButtonWidth = 78; // 70px min-width + 8px gap
const maxDays = Math.floor(containerWidth / dayButtonWidth);
// Гарантируем нечётное количество дней для центрирования
this.daysCount = maxDays % 2 === 0 ? maxDays - 1 : maxDays;
// Минимум 5 дней, максимум 31 день
this.daysCount = Math.max(5, Math.min(31, this.daysCount));
console.log(`Calculated days count: ${this.daysCount} (container width: ${containerWidth}px)`);
}
/**
* Обработка изменения размера окна
*/
handleResize() {
const oldDaysCount = this.daysCount;
this.calculateDaysCount();
// Перерисовываем только если количество дней изменилось
if (oldDaysCount !== this.daysCount) {
this.render();
}
}
/**
* Генерация и отображение дней
*/
render() {
this.container.innerHTML = '';
@@ -56,19 +121,20 @@ class DateCarousel {
}
/**
* Генерация массива из 19 дней (±9 от центральной даты)
* Генерация массива дней (динамическое количество от центральной даты)
*/
generateDays() {
const days = [];
const halfDays = Math.floor(this.daysCount / 2);
for (let i = -9; i <= 9; i++) {
for (let i = -halfDays; i <= halfDays; i++) {
const date = new Date(this.centerDate);
date.setDate(date.getDate() + i);
date.setHours(0, 0, 0, 0);
days.push({
date: date,
label: this.getDateLabel(date, i),
label: this.getDateLabel(date),
isToday: date.getTime() === this.today.getTime(),
isCenter: i === 0
});
@@ -80,7 +146,7 @@ class DateCarousel {
/**
* Определение текстовой метки для даты
*/
getDateLabel(date, offset) {
getDateLabel(date) {
const yesterday = new Date(this.today);
yesterday.setDate(yesterday.getDate() - 1);
yesterday.setHours(0, 0, 0, 0);
@@ -125,9 +191,14 @@ class DateCarousel {
weekday.className = 'date-btn-weekday';
weekday.textContent = this.getWeekdayShort(dayData.date);
const month = document.createElement('div');
month.className = 'date-btn-month';
month.textContent = this.getMonthShort(dayData.date);
btn.appendChild(label);
btn.appendChild(day);
btn.appendChild(weekday);
btn.appendChild(month);
// Обработчик клика
btn.addEventListener('click', () => this.selectDate(dayData.date, btn));
@@ -139,8 +210,18 @@ class DateCarousel {
* Получить короткое название дня недели (ПН, ВТ, СР, ЧТ, ПТ, СБ, ВС)
*/
getWeekdayShort(date) {
const weekdays = ['ВС', 'ПН', 'ВТ', 'СР', 'ЧТ', 'ПТ', 'СБ'];
return weekdays[date.getDay()];
const weekdays = ['ПН', 'ВТ', 'СР', 'ЧТ', 'ПТ', 'СБ', 'ВС'];
const dayIndex = date.getDay();
// Сдвигаем индекс, чтобы понедельник был первым (0), а воскресенье - последним (6)
return weekdays[(dayIndex + 6) % 7];
}
/**
* Получить короткое название месяца (янв, фев, мар и т.д.)
*/
getMonthShort(date) {
const months = ['янв', 'фев', 'мар', 'апр', 'май', 'июн', 'июл', 'авг', 'сен', 'окт', 'ноя', 'дек'];
return months[date.getMonth()];
}
/**

View File

@@ -25,7 +25,7 @@
{{ field_before }}
</div>
<!-- Календарная лента с 19 днями -->
<!-- Календарная лента с динамическим количеством дней -->
<div class="date-carousel">
<button type="button" class="carousel-nav-btn carousel-prev"
data-min-input="{{ field_after.id_for_label }}"