diff --git a/dto/catalogue.py b/dto/catalogue.py index e58da31..a7e6f3e 100644 --- a/dto/catalogue.py +++ b/dto/catalogue.py @@ -20,6 +20,7 @@ class CatalogueView: children: list[Category] | None = None products: list[Product] | None = None page: int = 0 + total: int = 0 parent_id: int | str | None = None has_next: bool = False show_menu: bool = False diff --git a/handlers/client/search.py b/handlers/client/search.py index c539be8..472496f 100644 --- a/handlers/client/search.py +++ b/handlers/client/search.py @@ -51,6 +51,9 @@ async def searching( await redis_client.set_search_query(query_hash, msg.text) next_cb = f"search:{query_hash}:1" + total = await products_repo.count_search(session, msg.text, include_hidden=is_admin) + total_pages = (total + PAGE_SIZE - 1) // PAGE_SIZE if total else None + await orig_msg.edit_text( "🗒 Результаты поиска:", reply_markup=render_products( @@ -59,6 +62,8 @@ async def searching( back_cb="menu:main", next_cb=next_cb, is_admin=is_admin, + page=0, + total_pages=total_pages, ), ) @@ -89,6 +94,9 @@ async def search_pagination( include_hidden=is_admin, ) + total = await products_repo.count_search(session, query, include_hidden=is_admin) + total_pages = (total + PAGE_SIZE - 1) // PAGE_SIZE if total else None + await cb.message.edit_reply_markup( reply_markup=render_products( results[:PAGE_SIZE], @@ -97,5 +105,7 @@ async def search_pagination( next_cb=f"search:{q_hash}:{page + 1}" if len(results) > PAGE_SIZE else None, prev_cb=f"search:{q_hash}:{page - 1}" if page > 0 else None, is_admin=is_admin, + page=page, + total_pages=total_pages, ) ) diff --git a/misc/kb/client.py b/misc/kb/client.py index 29ee0fb..c592377 100644 --- a/misc/kb/client.py +++ b/misc/kb/client.py @@ -141,6 +141,8 @@ def render_products( columns: int = 2, is_admin: bool = False, cat_id: int | None = None, + page: int = 0, + total_pages: int | None = None, ) -> InlineKeyboardMarkup: builder = InlineKeyboardBuilder() @@ -166,7 +168,10 @@ def render_products( nav_buttons = [] if prev_cb: nav_buttons.append(InlineKeyboardButton(text="◀️", callback_data=prev_cb)) - nav_buttons.append(InlineKeyboardButton(text="🔍", callback_data="find")) + page_text = ( + f"{page + 1}/{total_pages}" if total_pages is not None else f"{page + 1}" + ) + nav_buttons.append(InlineKeyboardButton(text=page_text, callback_data="...")) if next_cb: nav_buttons.append(InlineKeyboardButton(text="▶️", callback_data=next_cb)) @@ -187,6 +192,7 @@ def render_catalogue(view: CatalogueView, *, is_admin: bool): cat_id=view.category, ) if view.view_type == CatalogueType.PRODUCTS: + total_pages = (view.total + PAGE_SIZE - 1) // PAGE_SIZE if view.total else None return render_products( products=view.products[:PAGE_SIZE], # type: ignore product_cb_factory=lambda p: f"product:{p.id}", @@ -195,6 +201,8 @@ def render_catalogue(view: CatalogueView, *, is_admin: bool): next_cb=(f"products:{view.category}:{view.page + 1}" if view.has_next else None), is_admin=is_admin, cat_id=view.category, + page=view.page, + total_pages=total_pages, ) return get_back_to_catalogue( diff --git a/repositories/products.py b/repositories/products.py index 662f7cc..8d9dcaf 100644 --- a/repositories/products.py +++ b/repositories/products.py @@ -83,6 +83,40 @@ class ProductRepository: await session.commit() return product + async def count_products_by_category( + self, + session: AsyncSession, + category_id: int, + *, + include_hidden: bool = False, + ) -> int: + stmt = select(func.count()).select_from(Product).where( + Product.category_id == category_id + ) + + if not include_hidden: + stmt = stmt.where(Product.is_hidden.is_(False)) + + return await session.scalar(stmt) + + async def count_search( + self, + session: AsyncSession, + query: str, + *, + include_hidden: bool = False, + ) -> int: + ts_query = func.plainto_tsquery("simple", query) + + stmt = select(func.count()).select_from(Product).where( + Product.search_vector.op("@@")(ts_query) + ) + + if not include_hidden: + stmt = stmt.where(Product.is_hidden.is_(False)) + + return await session.scalar(stmt) + async def search( self, session: AsyncSession, diff --git a/services/catalogue.py b/services/catalogue.py index 90ee4e1..2450cd8 100644 --- a/services/catalogue.py +++ b/services/catalogue.py @@ -47,6 +47,9 @@ class CatalogueService: view.view_type = CatalogueType.PRODUCTS view.products = products[:PAGE_SIZE] view.has_next = len(products) > PAGE_SIZE + view.total = await self.product_repo.count_products_by_category( + session, cat_id, include_hidden=include_hidden + ) return view view.view_type = CatalogueType.EMPTY