diff --git a/docs/BANNERS_WITH_FILTERS_SPECIFICATION.md b/docs/BANNERS_WITH_FILTERS_SPECIFICATION.md new file mode 100644 index 0000000..e6829d6 --- /dev/null +++ b/docs/BANNERS_WITH_FILTERS_SPECIFICATION.md @@ -0,0 +1,819 @@ +# Техническое задание: Система баннеров с динамическими фильтрами товаров + +## 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/TELEGRAM_ANNOUNCEMENTS.md b/docs/TELEGRAM_ANNOUNCEMENTS.md similarity index 66% rename from TELEGRAM_ANNOUNCEMENTS.md rename to docs/TELEGRAM_ANNOUNCEMENTS.md index 7618754..5ef0035 100644 --- a/TELEGRAM_ANNOUNCEMENTS.md +++ b/docs/TELEGRAM_ANNOUNCEMENTS.md @@ -2,8 +2,8 @@ 🎁 **ГЛАВНЫЕ НОВОСТИ:** -💰 **Поддержка купонов и ваучеров** -Telecart теперь поддерживает встроенную систему купонов OpenCart! Используйте нативные купоны и ваучеры для скидок и акций. +💰 **Поддержка купонов и подарочных сертификатов** +Telecart теперь поддерживает встроенную систему купонов OpenCart! Используйте нативные купоны и подарочных сертификаты для скидок и акций. 📊 **Улучшенная Яндекс.Метрика** Теперь с поддержкой ecommerce, хитов и целей! Полная воронка продаж: @@ -14,8 +14,8 @@ Telecart теперь поддерживает встроенную систем Уникальный ID покупателя позволяет анализировать поведение одного пользователя на всех устройствах. 📖 Документация: https://telecart-labs.github.io/docs/analitycs/start/ -🖼️ **Баннеры на главной странице** -Используйте встроенные баннеры OpenCart для акций и промо. Привлекайте внимание покупателей к важным предложениям! +🖼️ **Баннеры с умной фильтрацией — продавайте то, что нужно именно сейчас** +Новинка для вашего Telegram-магазина! Теперь каждый баннер ведет клиента именно на те товары, которые вы хотите продвигать. Запустили акцию на скидки? Создайте баннер "Скидки до 50%" — и он автоматически покажет только товары со скидками. Нужно продать премиум-сегмент? Баннер "Товары от 1000₽" направит клиентов на нужный диапазон. Увеличивайте конверсию и контролируйте, какие товары видит покупатель после клика по баннеру. Встроенная фильтрация по цене, категориям, производителям делает ваши маркетинговые кампании максимально эффективными и результативными! ✏️ **Кастомизация текстов приложения** Теперь можно настраивать ключевые тексты: