""" Сервис для работы с пагинацией """ from typing import Any, List, Optional, Tuple from aiogram.types import InlineKeyboardMarkup from config.constants import DEFAULT_PAGE_SIZE, MIN_PAGE_NUMBER from services.infrastructure.logger import get_logger logger = get_logger(__name__) class PaginationService: """Сервис для работы с пагинацией""" def __init__(self): pass async def calculate_pagination_from_db( self, total_count: int, page: int, per_page: int = DEFAULT_PAGE_SIZE ) -> Tuple[int, int, int, int]: """ Расчет пагинации на основе общего количества записей в БД Args: total_count: Общее количество записей в БД page: Номер страницы (начиная с 0) per_page: Количество элементов на странице Returns: Кортеж (общее_количество, текущая_страница, общее_количество_страниц, offset) """ try: total_pages = (total_count + per_page - 1) // per_page # Округление вверх # Проверяем корректность номера страницы if page < MIN_PAGE_NUMBER: page = MIN_PAGE_NUMBER elif page >= total_pages and total_pages > 0: page = total_pages - 1 # Вычисляем offset для БД offset = page * per_page return total_count, page, total_pages, offset except Exception as e: logger.error(f"Ошибка при расчете пагинации из БД: {e}") return MIN_PAGE_NUMBER, MIN_PAGE_NUMBER, MIN_PAGE_NUMBER, MIN_PAGE_NUMBER def calculate_pagination( self, items: List[Any], page: int, per_page: int = DEFAULT_PAGE_SIZE ) -> Tuple[List[Any], int, int, int]: """ Расчет пагинации для списка элементов Args: items: Список элементов page: Номер страницы (начиная с 0) per_page: Количество элементов на странице Returns: Кортеж (элементы_страницы, общее_количество, текущая_страница, общее_количество_страниц) """ try: total_items = len(items) total_pages = (total_items + per_page - 1) // per_page # Округление вверх # Проверяем корректность номера страницы if page < MIN_PAGE_NUMBER: page = MIN_PAGE_NUMBER elif page >= total_pages and total_pages > 0: page = total_pages - 1 # Вычисляем диапазон элементов для текущей страницы start_idx = page * per_page end_idx = min(start_idx + per_page, total_items) page_items = items[start_idx:end_idx] return page_items, total_items, page, total_pages except Exception as e: logger.error(f"Ошибка при расчете пагинации: {e}") return [], MIN_PAGE_NUMBER, MIN_PAGE_NUMBER, MIN_PAGE_NUMBER def format_pagination_info( self, current_page: int, total_pages: int, start_idx: int, end_idx: int, total_items: int ) -> str: """ Форматирование информации о пагинации Args: current_page: Текущая страница total_pages: Общее количество страниц start_idx: Начальный индекс end_idx: Конечный индекс total_items: Общее количество элементов Returns: Отформатированная строка с информацией о пагинации """ try: info = f"📊 Показано {start_idx + 1}-{end_idx} из {total_items}\n" info += f"📄 Страница {current_page + 1} из {total_pages}\n\n" return info except Exception as e: logger.error(f"Ошибка при форматировании информации о пагинации: {e}") return "" def get_pagination_buttons( self, current_page: int, total_pages: int, callback_prefix: str, additional_buttons: Optional[List[Tuple[str, str]]] = None ) -> List[Tuple[str, str]]: """ Получение кнопок пагинации Args: current_page: Текущая страница total_pages: Общее количество страниц callback_prefix: Префикс для callback_data additional_buttons: Дополнительные кнопки Returns: Список кортежей (текст_кнопки, callback_data) """ try: buttons = [] # Кнопка "Предыдущая" if current_page > MIN_PAGE_NUMBER: buttons.append(("⬅️", f"{callback_prefix}_page_{current_page - 1}")) # Кнопка "Следующая" if current_page < total_pages - 1: buttons.append(("➡️", f"{callback_prefix}_page_{current_page + 1}")) # Дополнительные кнопки if additional_buttons: buttons.extend(additional_buttons) return buttons except Exception as e: logger.error(f"Ошибка при создании кнопок пагинации: {e}") return [] def validate_page_number(self, page: int, total_pages: int) -> int: """ Валидация номера страницы Args: page: Номер страницы total_pages: Общее количество страниц Returns: Валидный номер страницы """ try: if page < 0: return 0 elif page >= total_pages and total_pages > 0: return total_pages - 1 else: return page except Exception as e: logger.error(f"Ошибка при валидации номера страницы: {e}") return MIN_PAGE_NUMBER