From 09f1e514a975fea5c4fcd3b8cc587f906ab30bd3 Mon Sep 17 00:00:00 2001 From: Nikita Kiselev Date: Sun, 16 Nov 2025 20:34:03 +0300 Subject: [PATCH] feat: UI/UX, add reset cache to admin --- docs/BANNERS_WITH_FILTERS_SPECIFICATION.md | 819 ------------------ docs/TELEGRAM_ANNOUNCEMENTS.md | 34 +- docs/create_telegram_bot.md | 0 .../src/components/Form/ResetCacheBtn.vue | 40 + frontend/admin/src/components/TopLead.vue | 5 +- frontend/spa/src/App.vue | 4 +- .../MainPage/Blocks/ProductsCarouselBlock.vue | 34 +- frontend/spa/src/components/Navbar.vue | 2 +- .../spa/src/components/ProductItem/Price.vue | 2 +- frontend/spa/src/components/ProductsList.vue | 3 +- frontend/spa/src/components/Slider.vue | 17 +- .../spa/src/composables/useHapticScroll.js | 2 +- frontend/spa/src/helpers.js | 59 ++ frontend/spa/src/main.js | 43 +- frontend/spa/src/style.css | 18 +- frontend/spa/src/views/BaseViewWrapper.vue | 2 +- frontend/spa/src/views/Home.vue | 8 +- .../bastion/Handlers/SettingsHandler.php | 13 +- .../oc_telegram_shop/bastion/routes.php | 1 + .../framework/Cache/CacheInterface.php | 2 + .../framework/Cache/SymfonyMySqlCache.php | 5 + 21 files changed, 227 insertions(+), 886 deletions(-) delete mode 100644 docs/BANNERS_WITH_FILTERS_SPECIFICATION.md delete mode 100644 docs/create_telegram_bot.md create mode 100644 frontend/admin/src/components/Form/ResetCacheBtn.vue diff --git a/docs/BANNERS_WITH_FILTERS_SPECIFICATION.md b/docs/BANNERS_WITH_FILTERS_SPECIFICATION.md deleted file mode 100644 index e6829d6..0000000 --- a/docs/BANNERS_WITH_FILTERS_SPECIFICATION.md +++ /dev/null @@ -1,819 +0,0 @@ -# Техническое задание: Система баннеров с динамическими фильтрами товаров - -## 1. Описание задачи - -### 1.1. Проблема - -Текущий слайдер на главной странице отображает только изображения, которые не являются кликабельными. Это делает его -бесполезным с точки зрения конверсии. - -### 1.2. Бизнес-цель - -Реализовать интерактивные баннеры, которые при клике будут: - -- Открывать товары из определенной категории -- Показывать конкретный товар -- Отображать товары по заданному фильтру -- Позволять администраторам создавать и сохранять фильтры для повторного использования - -### 1.3. Техническое решение - -- Использовать существующую систему фильтрации на основе JSON-объектов -- Использовать стандартный функционал баннеров OpenCart -- Создать административный интерфейс для управления фильтрами -- Связать фильтры с баннерами через специальный формат URL в поле "ссылка" баннера -- Добавить отслеживание целей Яндекс.Метрики - -**Важно:** Формат ссылки `#filter:{filter_name}` с префиксом якоря `#` обеспечивает обратную совместимость: -- На обычном сайте OpenCart ссылка не будет ломать навигацию (просто не ведет никуда) -- В SPA JavaScript перехватывает и обрабатывает такие ссылки специальным образом - -## 2. Архитектура решения - -### 2.1. Компоненты системы - -``` -┌─────────────────────────────────────────────────────────────┐ -│ ADMIN PANEL │ -├─────────────────────────────────────────────────────────────┤ -│ 1. Конструктор фильтров (Filter Builder) │ -│ - Создание JSON фильтров │ -│ - Сохранение фильтров с именами │ -│ - Редактирование и удаление фильтров │ -│ │ -│ 2. Управление баннерами (расширение OpenCart) │ -│ - Привязка фильтра к слайду через ссылку │ -│ - Формат ссылки: #filter:{filter_name} │ -└─────────────────────────────────────────────────────────────┘ - │ - ▼ -┌─────────────────────────────────────────────────────────────┐ -│ BACKEND API │ -├─────────────────────────────────────────────────────────────┤ -│ 1. FilterService │ -│ - Сохранение/редактирование фильтров │ -│ - Список сохраненных фильтров │ -│ - Получение фильтра по имени │ -│ │ -│ 2. BannerHandler (расширение) │ -│ - Добавление поля filter_name в ответ │ -│ - Определение типа ссылки │ -└─────────────────────────────────────────────────────────────┘ - │ - ▼ -┌─────────────────────────────────────────────────────────────┐ -│ FRONTEND SPA │ -├─────────────────────────────────────────────────────────────┤ -│ 1. Banner.vue (обновление) │ -│ - Обработка клика по слайду │ -│ - Определение типа ссылки │ -│ - Переход на соответствующую страницу │ -│ │ -│ 2. Router (обновление) │ -│ - Новый роут: /products-filter │ -│ - Параметры: filter_name или filter JSON │ -│ │ -│ 3. ProductsFilter.vue (новый компонент) │ -│ - Загрузка товаров по фильтру │ -│ - Интеграция с YaMetrika │ -│ │ -│ 4. YaMetrika Integration │ -│ - Новая цель: BANNER_CLICK │ -│ - Трекинг кликов по баннерам │ -└─────────────────────────────────────────────────────────────┘ -``` - -## 3. Детальная спецификация - -### 3.1. Backend: Система управления фильтрами - -#### 3.1.1. Таблица базы данных - -**Создать таблицу:** `oc_telecart_filter` - -```sql -CREATE TABLE oc_telecart_filter -( - filter_id INT(11) NOT NULL AUTO_INCREMENT, - name VARCHAR(255) NOT NULL, - filter_json TEXT NOT NULL, - created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, - updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, - PRIMARY KEY (filter_id), - UNIQUE KEY unique_name (name) -) ENGINE = InnoDB - DEFAULT CHARSET = utf8mb4; -``` - -#### 3.1.2. Model: FilterModel - -**Путь:** `module/oc_telegram_shop/upload/oc_telegram_shop/src/Models/FilterModel.php` - -```php -settings->get('home_banner_id'); - - if ($bannerId) { - $banner = $this->registry->model_design_banner->getBanner($bannerId); - foreach ($banner as $index => $result) { - if (is_file(DIR_IMAGE . $result['image'])) { - $link = $result['link']; - - // Определяем тип ссылки - $linkType = 'external'; - $filterName = null; - - if (preg_match('/^#filter:(.+)$/', $link, $matches)) { - $linkType = 'filter'; - $filterName = $matches[1]; - } - - $data[] = [ - 'id' => $index, - 'title' => $result['title'], - 'link' => $link, - 'link_type' => $linkType, - 'filter_name' => $filterName, - 'image' => $this->imageTool->resize($result['image'], null, 200), - ]; - } - } - } - - return new JsonResponse([ - 'data' => $data, - ]); -} -``` - -### 3.2. Frontend: Компоненты SPA - -#### 3.2.1. Обновление: Banner.vue - -**Путь:** `spa/src/components/Banner.vue` - -Добавить обработку клика и определение типа ссылки: - -```vue - - - - -``` - -#### 3.2.2. Новый компонент: ProductsFilter.vue - -**Путь:** `spa/src/views/ProductsFilter.vue` - -```vue - - - - -``` - -#### 3.2.3. Обновление: Router - -**Путь:** `spa/src/router.js` - -Добавить новый роут: - -```javascript -{ - path: '/products-filter/:filter_name', - name -: - 'products-filter', - component -: - () => import('@/views/ProductsFilter.vue') -} -``` - -#### 3.2.4. Обновление: ftch.js - -**Путь:** `spa/src/utils/ftch.js` - -Добавить новые методы: - -```javascript -export async function fetchFilterByName(name) { - return await ftch('filterShow', {name}); -} - -export async function fetchFilterList() { - return await ftch('filterList'); -} - -export async function saveFilter(data) { - return await apiFetch(`${BASE_URL}index.php?route=extension/tgshop/handle&api_action=filterStore`, { - method: 'POST', - body: data, - }); -} -``` - -#### 3.2.5. Обновление: yaMetrikaGoals.js - -**Путь:** `spa/src/constants/yaMetrikaGoals.js` - -Добавить новую цель: - -```javascript -export const YA_METRIKA_GOAL = { - // ... существующие цели - BANNER_CLICK: 'banner_click', -}; -``` - -### 3.3. Admin Panel: Управление фильтрами - -#### 3.3.1. Новый контроллер: FilterController - -**Путь:** `module/oc_telegram_shop/upload/admin/controller/extension/tgshop/filter.php` - -```php -db->query("INSERT INTO " . DB_PREFIX . "telecart_filter - SET name = '" . $this->db->escape($data['name']) . "', - filter_json = '" . $this->db->escape(json_encode($data['filter_json'])) . "'"); - - return $this->db->getLastId(); - } - - public function getFilter(int $filterId): ?array - { - $query = $this->db->query("SELECT * FROM " . DB_PREFIX . "telecart_filter - WHERE filter_id = '" . (int)$filterId . "'"); - - return $query->row; - } - - public function getFilters(): array - { - $query = $this->db->query("SELECT * FROM " . DB_PREFIX . "telecart_filter - ORDER BY name ASC"); - - return $query->rows; - } - - public function editFilter(int $filterId, array $data): void - { - $this->db->query("UPDATE " . DB_PREFIX . "telecart_filter - SET name = '" . $this->db->escape($data['name']) . "', - filter_json = '" . $this->db->escape(json_encode($data['filter_json'])) . "' - WHERE filter_id = '" . (int)$filterId . "'"); - } - - public function deleteFilter(int $filterId): void - { - $this->db->query("DELETE FROM " . DB_PREFIX . "telecart_filter - WHERE filter_id = '" . (int)$filterId . "'"); - } -} -``` - -#### 3.3.3. Новый view: Filter Builder - -**Путь:** `module/oc_telegram_shop/upload/admin/view/template/extension/tgshop/filter.twig` - -Создать интерфейс конструктора фильтров на основе существующего функционала из `Filters.vue`: - -- Визуальный редактор для создания JSON фильтров -- Поддержка всех существующих типов фильтров: - - ProductPrice - - ProductCategory - - ProductManufacturer - - ProductModel - - ProductStatus - - ProductQuantity - - И другие -- Поле для ввода имени фильтра -- Кнопки: Сохранить, Удалить, Отменить - -## 4. Схема работы - -### 4.1. Создание баннера с фильтром (Администратор) - -1. Администратор открывает конструктор фильтров в админ-панели -2. Создает фильтр (например: "Товары со скидкой в категории Электроника") -3. Сохраняет фильтр с именем `discount_electronics` -4. Переходит в настройки баннеров OpenCart -5. Создает новый слайд -6. Загружает изображение баннера -7. В поле "Ссылка" вводит: `#filter:discount_electronics` -8. Сохраняет баннер - -### 4.2. Пользователь кликает на баннер (Frontend) - -1. Пользователь видит баннер на главной странице -2. Кликает на баннер -3. YaMetrika фиксирует цель `BANNER_CLICK` -4. Frontend определяет тип ссылки: `filter` -5. Переход на страницу `/products-filter/discount_electronics` -6. Загрузка фильтра по имени `discount_electronics` -7. Применение фильтра к списку товаров -8. Отображение отфильтрованных товаров - -### 4.3. Пример JSON фильтра - -```json -{ - "operand": "AND", - "rules": { - "RULE_PRODUCT_PRICE": { - "criteria": { - "product_price": { - "type": "number", - "params": { - "operator": "between", - "value": { - "from": 1000, - "to": 5000 - } - } - } - } - }, - "RULE_PRODUCT_CATEGORY": { - "criteria": { - "product_category_id": { - "type": "product_category", - "params": { - "operator": "contains", - "value": 15 - } - } - } - } - } -} -``` - -## 5. Технические детали - -### 5.1. Маршруты API - -**Backend (PHP):** - -- `GET /index.php?route=extension/tgshop/handle&api_action=filterList` - список фильтров -- `GET /index.php?route=extension/tgshop/handle&api_action=filterShow&name={name}` - получить фильтр -- `POST /index.php?route=extension/tgshop/handle&api_action=filterStore` - создать фильтр -- `POST /index.php?route=extension/tgshop/handle&api_action=filterUpdate` - обновить фильтр -- `POST /index.php?route=extension/tgshop/handle&api_action=filterDelete&id={id}` - удалить фильтр - -**Admin Panel:** - -- `GET /admin/index.php?route=extension/tgshop/filter` - список фильтров (страница) -- `GET /admin/index.php?route=extension/tgshop/filter/create` - форма создания -- `GET /admin/index.php?route=extension/tgshop/filter/edit&id={id}` - форма редактирования -- `POST /admin/index.php?route=extension/tgshop/filter/save` - сохранить фильтр -- `POST /admin/index.php?route=extension/tgshop/filter/delete&id={id}` - удалить фильтр - -### 5.2. Валидация - -- Имя фильтра: обязательно, уникальное, максимально 255 символов -- JSON фильтра: обязательно, валидный JSON, соответствует существующей схеме фильтров -- Проверка существования всех критериев в системе - -### 5.3. Безопасность - -- Проверка прав доступа для админ-панели -- SQL Injection защита через prepared statements -- XSS защита при выводе данных -- CSRF защита для форм администратора - -### 5.4. Обратная совместимость - -Использование формата ссылки `#filter:{filter_name}` с префиксом `#` гарантирует: - -- **Совместимость с OpenCart**: При установке баннеров на обычный сайт OpenCart, якорная ссылка не приведет к ошибке 404, так как браузер просто оставит пользователя на текущей странице -- **Работа в SPA**: В Telegram веб-приложении JavaScript перехватывает клики и обрабатывает их специальным образом -- **Отказоустойчивость**: Если JavaScript не загрузился, пользователь не увидит ошибку, просто ничего не произойдет при клике - -## 6. Интеграция с Яндекс.Метрикой - -### 6.1. Цели метрики - -Добавить в `spa/src/constants/yaMetrikaGoals.js`: - -```javascript -BANNER_CLICK: 'banner_click', -``` - -### 6.2. События - -- `banner_click` - клик по баннеру - - Параметры: `banner_title`, `link_type`, `filter_name` - -### 6.3. Ecommerce события - -При загрузке отфильтрованных товаров отправлять событие `view_item_list`: - -```javascript -yaMetrika.dataLayerPush({ - ecommerce: { - items: products.map((product, index) => ({ - item_id: product.id, - item_name: product.name, - price: product.final_price_numeric, - item_category: product.category_name, - quantity: 1, - discount: product.price_numeric - product.final_price_numeric, - })), - item_list_id: 'banner_filter', - item_list_name: 'Отфильтрованные товары', - }, -}); -``` - -## 7. План реализации - -### Этап 1: Backend (API для управления фильтрами) - -- [ ] Создать таблицу `oc_telecart_filter` -- [ ] Создать модель `FilterModel` -- [ ] Создать хэндлер `FilterHandler` с методами CRUD -- [ ] Добавить маршруты в `routes.php` -- [ ] Обновить `BannerHandler` для поддержки фильтров - -### Этап 2: Frontend (SPA компоненты) - -- [ ] Создать компонент `ProductsFilter.vue` -- [ ] Обновить `Banner.vue` для обработки клика -- [ ] Добавить маршрут в `router.js` -- [ ] Добавить методы в `ftch.js` -- [ ] Добавить цель `BANNER_CLICK` в YaMetrika - -### Этап 3: Admin Panel (Конструктор фильтров) - -- [ ] Создать контроллер `FilterController` в админке -- [ ] Создать модель `ModelExtensionTgshopFilter` -- [ ] Создать шаблоны для списка и форм -- [ ] Реализовать визуальный конструктор фильтров - -### Этап 4: Тестирование - -- [ ] Unit тесты для модели фильтров -- [ ] Интеграционные тесты для API -- [ ] Функциональные тесты в SPA -- [ ] Тестирование интеграции с Яндекс.Метрикой - -### Этап 5: Документация - -- [ ] Документация для администраторов -- [ ] API документация -- [ ] Описание схемы JSON фильтров - -## 8. Возможные расширения (будущее) - -1. **Предпросмотр фильтров** - возможность увидеть количество товаров, соответствующих фильтру -2. **Предустановленные фильтры** - шаблоны популярных фильтров -3. **A/B тестирование баннеров** - ротация баннеров с отслеживанием конверсии -4. **Аналитика кликов** - статистика по каждому баннеру -5. **Многовариантные фильтры** - баннер может открывать несколько результатов - -## 9. Примеры использования - -### Пример 1: Баннер "Скидки до 50%" - -**Фильтр:** - -```json -{ - "operand": "AND", - "rules": { - "RULE_PRODUCT_SPECIAL": { - "criteria": { - "has_special": { - "type": "boolean", - "params": { - "operator": "equals", - "value": true - } - } - } - } - } -} -``` - -**Ссылка в баннере:** `#filter:specials_50_discount` - -### Пример 2: Баннер "Новинки в категории" - -**Фильтр:** - -```json -{ - "operand": "AND", - "rules": { - "RULE_PRODUCT_CATEGORY": { - "criteria": { - "product_category_id": { - "type": "product_category", - "params": { - "operator": "contains", - "value": 42 - } - } - } - }, - "RULE_PRODUCT_STATUS": { - "criteria": { - "product_status": { - "type": "boolean", - "params": { - "operator": "equals", - "value": 1 - } - } - } - } - } -} -``` - -**Ссылка в баннере:** `#filter:new_in_electronics` - -### Пример 3: Баннер "Товары до 1000₽" - -**Фильтр:** - -```json -{ - "operand": "AND", - "rules": { - "RULE_PRODUCT_PRICE": { - "criteria": { - "product_price": { - "type": "number", - "params": { - "operator": "between", - "value": { - "from": 0, - "to": 1000 - } - } - } - } - } - } -} -``` - -**Ссылка в баннере:** `#filter:budget_under_1000` - -## 10. Выводы - -Данное техническое задание описывает полную систему для реализации интерактивных баннеров с динамической фильтрацией -товаров. Реализация не нарушает существующую архитектуру проекта и полностью использует уже имеющийся функционал -фильтрации. - -Основные преимущества: - -- Гибкость настроек для администраторов -- Масштабируемость (можно добавить новые типы фильтров) -- Интеграция с Яндекс.Метрикой для аналитики -- Простота использования для администраторов магазина -- Обратная совместимость с существующими баннерами -- **Гарантированная совместимость с OpenCart**: использование якорных ссылок `#filter:{filter_name}` позволяет устанавливать баннеры как на SPA, так и на обычный сайт без ошибок - diff --git a/docs/TELEGRAM_ANNOUNCEMENTS.md b/docs/TELEGRAM_ANNOUNCEMENTS.md index 7d07023..9e4e6af 100644 --- a/docs/TELEGRAM_ANNOUNCEMENTS.md +++ b/docs/TELEGRAM_ANNOUNCEMENTS.md @@ -1,9 +1,18 @@ -🚀 Вышла новая версия Telecart v1.3.2! +🚀 Вышла новая версия Telecart v2.0.0! 🎁 **ГЛАВНЫЕ НОВОСТИ:** +**Переработанная страница настроек модуля внутри OpenCart** + +* Вывод базовой статистики по магазину. +* Ещё больше настроек +* Повышение производительности. +* Изменение формата хранения настроек на более расширяемый. Большинство настроек будут перенесены с предыдущей версии, + но всё равно я рекомендую открыть страницу настроек, заново просмотреть и сохранить их. + 💰 **Поддержка купонов и подарочных сертификатов** -Telecart теперь поддерживает встроенную систему купонов OpenCart! Используйте нативные купоны и подарочных сертификаты для скидок и акций. +Telecart теперь поддерживает встроенную систему купонов OpenCart! Используйте нативные купоны и подарочных сертификаты +для скидок и акций. 📊 **Улучшенная Яндекс.Метрика** Теперь с поддержкой ecommerce, хитов и целей! Полная воронка продаж: @@ -15,8 +24,8 @@ Telecart теперь поддерживает встроенную систем 📖 Документация: https://telecart-labs.github.io/docs/analitycs/start/ 🖼️ **Кликабельные Баннеры** -Новинка для вашего Telegram-магазина! -Теперь каждый баннер ведет клиента именно на те товары, которые вы хотите продвигать. +Новинка для вашего Telegram-магазина! +Теперь каждый баннер ведет клиента именно на те товары, которые вы хотите продвигать. Привяжите баннер к категории, товару или укажите внешнюю ссылку. При клике по баннеру покупатель перейдёт туда. Как бонус - клик по баннеру это тоже отдельная цель в Яндекс.Метрике. @@ -28,15 +37,18 @@ Telecart теперь поддерживает встроенную систем Список настраиваемых текстов будет пополняться по запросам покупателей. ✨ **Обновления UI/UX** -• Шапка магазина с вашим логотипом и названием (настраивается в админке). -• Плавающая панель навигации в современном стиле, напоминающая эффект liquid glass от Apple. Полупрозрачный фон с размытием создает эффект глубины и современный эстетичный вид интерфейса. -• Доработки интерфейса корзины, оформления заказа и ускорение поиска товаров. + +* Шапка магазина с вашим логотипом и названием (настраивается в админке). +* Нижняя панель навигации для более удобного доступа к основным страницам магазина. +* Доработана интеграция цветовых тем с Telegram. Теперь цвета темы распространяется на Telegram, плюс решена проблема, + когда цвет часов и иконок статусов сливались с фоном на iPhone. +* Множество мелких изменений, улучшающих внешний вид магазина. 🔧 **Технические улучшения:** -• Добавлены автоматические тесты, запускаемые при каждом билде, что значительно снижает количество багов в новых версиях. -• Исправлены проблемы с поиском и оформлением заказов, обнаруженные на некоторых магазинах. -• Повышена стабильность работы. -• Уменьшен размер архива с модулем примерно в 2 раза. + +* Исправлены проблемы с поиском и оформлением заказов, обнаруженные на некоторых магазинах. +* Повышена стабильность работы. +* Уменьшен размер архива с модулем примерно в 2 раза. Купить модуль: https://liveopencart.ru/opencart-moduli-shablony/moduli/telecart Документация: https://telecart-labs.github.io/docs/ diff --git a/docs/create_telegram_bot.md b/docs/create_telegram_bot.md deleted file mode 100644 index e69de29..0000000 diff --git a/frontend/admin/src/components/Form/ResetCacheBtn.vue b/frontend/admin/src/components/Form/ResetCacheBtn.vue new file mode 100644 index 0000000..1739aa7 --- /dev/null +++ b/frontend/admin/src/components/Form/ResetCacheBtn.vue @@ -0,0 +1,40 @@ + + + diff --git a/frontend/admin/src/components/TopLead.vue b/frontend/admin/src/components/TopLead.vue index fbc3772..4b81c17 100644 --- a/frontend/admin/src/components/TopLead.vue +++ b/frontend/admin/src/components/TopLead.vue @@ -65,6 +65,9 @@
+ + +