Улучшен календарный фильтр дат: динамическое количество дней, отображение месяца и сохранение позиции при выборе
This commit is contained in:
@@ -1,5 +1,5 @@
|
|||||||
/**
|
/**
|
||||||
* Стили для календарного фильтра с лентой из 19 дней
|
* Стили для календарного фильтра с динамическим количеством дней
|
||||||
* Используется в компоненте date_range_filter.html
|
* Используется в компоненте date_range_filter.html
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@@ -118,6 +118,13 @@
|
|||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.date-btn-month {
|
||||||
|
font-size: 0.65rem;
|
||||||
|
font-weight: 500;
|
||||||
|
color: #6c757d;
|
||||||
|
text-transform: lowercase;
|
||||||
|
}
|
||||||
|
|
||||||
/* Сегодняшний день (более светлый оттенок) */
|
/* Сегодняшний день (более светлый оттенок) */
|
||||||
.date-btn.today {
|
.date-btn.today {
|
||||||
background: #cfe2ff;
|
background: #cfe2ff;
|
||||||
@@ -127,7 +134,8 @@
|
|||||||
|
|
||||||
.date-btn.today .date-btn-label,
|
.date-btn.today .date-btn-label,
|
||||||
.date-btn.today .date-btn-day,
|
.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;
|
color: #084298;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -154,7 +162,8 @@
|
|||||||
color: #dc3545;
|
color: #dc3545;
|
||||||
}
|
}
|
||||||
|
|
||||||
.date-btn.selected .date-btn-weekday {
|
.date-btn.selected .date-btn-weekday,
|
||||||
|
.date-btn.selected .date-btn-month {
|
||||||
color: #6c757d;
|
color: #6c757d;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -189,6 +198,10 @@
|
|||||||
.date-btn-weekday {
|
.date-btn-weekday {
|
||||||
font-size: 0.7rem;
|
font-size: 0.7rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.date-btn-month {
|
||||||
|
font-size: 0.6rem;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (max-width: 576px) {
|
@media (max-width: 576px) {
|
||||||
@@ -208,6 +221,10 @@
|
|||||||
.date-btn-weekday {
|
.date-btn-weekday {
|
||||||
font-size: 0.65rem;
|
font-size: 0.65rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.date-btn-month {
|
||||||
|
font-size: 0.55rem;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Анимация при клике */
|
/* Анимация при клике */
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/**
|
/**
|
||||||
* Календарная лента с 19 днями для фильтрации заказов
|
* Календарная лента с динамическим количеством дней для фильтрации заказов
|
||||||
* Сегодня в центре, навигация стрелками
|
* Сегодня всегда в центре при загрузке, количество дней зависит от ширины экрана
|
||||||
*/
|
*/
|
||||||
|
|
||||||
document.addEventListener('DOMContentLoaded', function() {
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
@@ -16,6 +16,13 @@ document.addEventListener('DOMContentLoaded', function() {
|
|||||||
// Инициализация с сегодняшней датой в центре
|
// Инициализация с сегодняшней датой в центре
|
||||||
const carousel = new DateCarousel(container, minInputId, maxInputId);
|
const carousel = new DateCarousel(container, minInputId, maxInputId);
|
||||||
carousel.init();
|
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.centerDate = new Date(); // Центральная дата (по умолчанию сегодня)
|
||||||
this.today = new Date();
|
this.today = new Date();
|
||||||
this.today.setHours(0, 0, 0, 0);
|
this.today.setHours(0, 0, 0, 0);
|
||||||
|
this.daysCount = 0; // Будет рассчитано динамически
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Инициализация календарной ленты
|
* Инициализация календарной ленты
|
||||||
*/
|
*/
|
||||||
init() {
|
init() {
|
||||||
|
this.calculateDaysCount();
|
||||||
|
this.loadSelectedDate(); // Загрузить выбранную дату из фильтра
|
||||||
this.render();
|
this.render();
|
||||||
this.attachNavHandlers();
|
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() {
|
render() {
|
||||||
this.container.innerHTML = '';
|
this.container.innerHTML = '';
|
||||||
@@ -56,19 +121,20 @@ class DateCarousel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Генерация массива из 19 дней (±9 от центральной даты)
|
* Генерация массива дней (динамическое количество от центральной даты)
|
||||||
*/
|
*/
|
||||||
generateDays() {
|
generateDays() {
|
||||||
const days = [];
|
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);
|
const date = new Date(this.centerDate);
|
||||||
date.setDate(date.getDate() + i);
|
date.setDate(date.getDate() + i);
|
||||||
date.setHours(0, 0, 0, 0);
|
date.setHours(0, 0, 0, 0);
|
||||||
|
|
||||||
days.push({
|
days.push({
|
||||||
date: date,
|
date: date,
|
||||||
label: this.getDateLabel(date, i),
|
label: this.getDateLabel(date),
|
||||||
isToday: date.getTime() === this.today.getTime(),
|
isToday: date.getTime() === this.today.getTime(),
|
||||||
isCenter: i === 0
|
isCenter: i === 0
|
||||||
});
|
});
|
||||||
@@ -80,7 +146,7 @@ class DateCarousel {
|
|||||||
/**
|
/**
|
||||||
* Определение текстовой метки для даты
|
* Определение текстовой метки для даты
|
||||||
*/
|
*/
|
||||||
getDateLabel(date, offset) {
|
getDateLabel(date) {
|
||||||
const yesterday = new Date(this.today);
|
const yesterday = new Date(this.today);
|
||||||
yesterday.setDate(yesterday.getDate() - 1);
|
yesterday.setDate(yesterday.getDate() - 1);
|
||||||
yesterday.setHours(0, 0, 0, 0);
|
yesterday.setHours(0, 0, 0, 0);
|
||||||
@@ -125,9 +191,14 @@ class DateCarousel {
|
|||||||
weekday.className = 'date-btn-weekday';
|
weekday.className = 'date-btn-weekday';
|
||||||
weekday.textContent = this.getWeekdayShort(dayData.date);
|
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(label);
|
||||||
btn.appendChild(day);
|
btn.appendChild(day);
|
||||||
btn.appendChild(weekday);
|
btn.appendChild(weekday);
|
||||||
|
btn.appendChild(month);
|
||||||
|
|
||||||
// Обработчик клика
|
// Обработчик клика
|
||||||
btn.addEventListener('click', () => this.selectDate(dayData.date, btn));
|
btn.addEventListener('click', () => this.selectDate(dayData.date, btn));
|
||||||
@@ -139,8 +210,18 @@ class DateCarousel {
|
|||||||
* Получить короткое название дня недели (ПН, ВТ, СР, ЧТ, ПТ, СБ, ВС)
|
* Получить короткое название дня недели (ПН, ВТ, СР, ЧТ, ПТ, СБ, ВС)
|
||||||
*/
|
*/
|
||||||
getWeekdayShort(date) {
|
getWeekdayShort(date) {
|
||||||
const weekdays = ['ВС', 'ПН', 'ВТ', 'СР', 'ЧТ', 'ПТ', 'СБ'];
|
const weekdays = ['ПН', 'ВТ', 'СР', 'ЧТ', 'ПТ', 'СБ', 'ВС'];
|
||||||
return weekdays[date.getDay()];
|
const dayIndex = date.getDay();
|
||||||
|
// Сдвигаем индекс, чтобы понедельник был первым (0), а воскресенье - последним (6)
|
||||||
|
return weekdays[(dayIndex + 6) % 7];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Получить короткое название месяца (янв, фев, мар и т.д.)
|
||||||
|
*/
|
||||||
|
getMonthShort(date) {
|
||||||
|
const months = ['янв', 'фев', 'мар', 'апр', 'май', 'июн', 'июл', 'авг', 'сен', 'окт', 'ноя', 'дек'];
|
||||||
|
return months[date.getMonth()];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -25,7 +25,7 @@
|
|||||||
{{ field_before }}
|
{{ field_before }}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Календарная лента с 19 днями -->
|
<!-- Календарная лента с динамическим количеством дней -->
|
||||||
<div class="date-carousel">
|
<div class="date-carousel">
|
||||||
<button type="button" class="carousel-nav-btn carousel-prev"
|
<button type="button" class="carousel-nav-btn carousel-prev"
|
||||||
data-min-input="{{ field_after.id_for_label }}"
|
data-min-input="{{ field_after.id_for_label }}"
|
||||||
|
|||||||
Reference in New Issue
Block a user