# ПРАВИЛА UI/UX КАБИНЕТА СЕЛЛЕРА (SELLER) > ⚠️ **ВАЖНО**: Это файл с UI/UX деталями кабинета селлера. > Общие бизнес-правила находятся в **[rules-complete.md](./rules-complete.md)** ## Когда использовать этот файл: - Работа с компонентами `/supplies`, `/my-supplies` - UI/UX специфика кабинета селлера - Интерфейсы создания поставок - Визуальные правила компонентов селлера ## 1. 🛍️ СТРУКТУРА КАБИНЕТА СЕЛЛЕРА ### 1.1 Основные разделы **СЕЛЛЕР (`SELLER`)** имеет доступ к следующим разделам: - **Мои поставки** (`/my-supplies`) - управление поставками - **Маркет** (`/market`) - просмотр глобального каталога - **Партнеры** (`/partners`) - управление контрагентами - **Мессенджер** (`/messenger`) - связь с партнерами - **Настройки** (`/settings`) - профиль и настройки - **Экономика** (`/economics`) - финансовая аналитика ### 1.2 Навигация и роутинг #### При входе в систему: ```typescript switch (user?.organization?.type) { case 'SELLER': router.push('/my-supplies') // Направляем на страницу поставок break } ``` #### Специальная логика роутинга: > 📖 **Бизнес-логика роутинга**: См. [rules-complete.md#4-система-ролей-и-доступов](./rules-complete.md#4--система-ролей-и-доступов) ## 2. 🎨 UI/UX КОМПОНЕНТЫ ### 2.1 Dashboard компоненты #### Основные компоненты кабинета: - `SellerHomePage` - главный компонент селлера - `SellerEconomicsPage` - экономическая аналитика - `MySuppliesDashboard` - управление поставками #### Wrapper-компоненты: - `HomePageWrapper` - маршрутизация по типам организаций - `EconomicsPageWrapper` - адаптивная экономика по кабинетам ### 2.2 Детальные правила горизонтального скролла поставщиков **СТРУКТУРА И ОТОБРАЖЕНИЕ:** - **Источник данных**: Партнеры типа `WHOLESALE` из раздела "Партнеры" - **Контейнер**: Фиксированная высота 176px (h-44) с горизонтальным скроллом - **Блок поставщиков**: Общая высота 180px, включает заголовок + контейнер скролла - **Направление**: Слева направо (LTR) - **Поведение**: Плавный скролл с автоскрытием полосы прокрутки **РАЗМЕРЫ И АДАПТИВНОСТЬ:** - **Десктоп**: Карточка 216×92px, отступы 12px между карточками, 16px от краев - **Планшет**: Карточка 200×92px, отступы 12px между карточками - **Мобильный**: Карточка 184×92px, отступы 12px между карточками - **Высота блока**: 180px фиксированная для всего блока поставщиков **ВЗАИМОДЕЙСТВИЕ:** - **Навигация**: Колесо мыши (Shift+скролл), стрелки клавиатуры, свайп на тач - **Выбор**: Клик по карточке → активная рамка + загрузка товаров в блок 2 - **Состояния**: Default, Hover (box-shadow), Active (цветная рамка), Loading (скелетон) **ГРАНИЧНЫЕ СЛУЧАИ:** - **1-4 карточки**: Выравнивание по левому краю, скролл неактивен - **5+ карточек**: Полный горизонтальный скролл - **Нет партнеров**: Заглушка с ссылкой на раздел "Партнеры" **ТЕХНИЧЕСКАЯ РЕАЛИЗАЦИЯ:** **Критическая Flex-архитектура:** ```css .parent-container { display: flex; gap: 16px; min-height: 0; } .left-block { flex: 1; min-width: 0; /* КРИТИЧЕСКИ ВАЖНО для overflow */ display: flex; flex-direction: column; } .suppliers-container { height: 180px; /* Общая высота блока */ flex-shrink: 0; min-width: 0; /* Предотвращает растяжение */ } .right-block { width: 384px; /* w-96 */ flex-shrink: 0; /* Защита от сжатия */ } ``` **Контейнер скролла:** ```css .suppliers-block { display: flex; overflow-x: auto; scroll-behavior: smooth; gap: 12px; padding: 0 16px 8px 16px; /* px-4 pb-2 */ height: 176px; /* h-44 */ scrollbar-width: thin; scrollbar-color: #64748b33 transparent; } .suppliers-block:hover { scrollbar-color: #cbd5e0 #64748b22; } .supplier-card { flex-shrink: 0; width: 216px; /* Десктоп */ height: 92px; /* Фиксированная высота */ padding: 8px; /* p-2 */ transition: all 0.2s ease; } ``` **СОДЕРЖАНИЕ КАРТОЧКИ ПОСТАВЩИКА:** **Структура (3 строки в 92px высоты):** - **Строка 1**: Название + рейтинг (справа, если есть) - **Строка 2**: ИНН (формат "ИНН: 1234567890") - **Строка 3**: Бейдж рынка (отдельная строка) **Элементы:** - **Аватар**: Размер xs, слева с gap-2 - **Текст**: text-xs для компактности - **Отступы**: mb-1 между строками 1-2, mb-0.5 между строками 2-3 - **Padding карточки**: 8px (p-2) **ЦВЕТОВАЯ СХЕМА РЫНКОВ:** - **"Садовод"** (sadovod): Зеленый `bg-green-500/20 text-green-300 border-green-500/30` - **"ТЯК Москва"** (tyak-moscow): Синий `bg-blue-500/20 text-blue-300 border-blue-500/30` - **Другие/не указан**: Серый `bg-gray-500/20 text-gray-300 border-gray-500/30` **ДОСТУПНОСТЬ:** - `role="tablist"` для контейнера - `role="tab"` для карточек - `aria-selected="true/false"` для выбранной карточки - `tabindex="0"` для активной, `-1` для неактивных ### 2.3 Правила блока "Карточки товаров" (Блок 2) **НАЗНАЧЕНИЕ И ЛОГИКА:** - **Источник данных**: Товары выбранного поставщика из Блока 1 - **Триггер отображения**: Клик на карточку поставщика → загрузка карточек товаров - **Взаимодействие**: Клик на карточку товара → добавление в Блок 3 "Товары поставщика" - **Поведение**: Горизонтальный скролл при множестве товаров **АРХИТЕКТУРА И РАЗМЕРЫ:** - **Внешний контейнер**: bg-white/10 backdrop-blur-xl border border-white/20 rounded-2xl flex-shrink-0 - **Внутренний контейнер скролла**: flex gap-3 overflow-x-auto p-4 - **Стилизация скролла**: scrollbarWidth: 'thin' для тонкой полосы прокрутки - **Отступы**: padding: 16px (p-4) внутри, gap: 12px (gap-3) между карточками - **Адаптивная высота**: по содержимому карточек (БЕЗ фиксированной высоты) - **Визуальное единство**: стеклянный эффект как у других блоков системы - **БЕЗ заголовков/иконок**: только чистые карточки товаров в контейнере **РАЗМЕРЫ КАРТОЧЕК ТОВАРОВ:** - **Компактная карточка**: 80×112px (w-20 h-28), соотношение 5:7 - **Адаптивность**: фиксированный размер для всех устройств **СОДЕРЖАНИЕ КАРТОЧКИ ТОВАРА:** - **ТОЛЬКО изображение товара**: 80×112px, object-cover - **Минималистичный дизайн**: БЕЗ текста, названий, цен, иконок - **Состояния**: Default, Selected, Active (БЕЗ Hover-эффектов) - **Рамка**: border-white/10, при выборе border-white/30 - **Фон**: bg-white/5 полупрозрачный **ДЕЙСТВИЕ:** Клик на карточку → добавление товара в Блок 3 (детальный каталог) ### 2.4 ПРАВИЛА КОРЗИНЫ - ЕДИНЫЙ СТАНДАРТ **КРИТИЧЕСКИ ВАЖНО**: Все корзины в системе должны следовать единому стандарту дизайна и функциональности. #### **2.4.1 Размеры и позиционирование** ```tsx
``` **ОБЯЗАТЕЛЬНЫЕ ПАРАМЕТРЫ**: - **Ширина**: `w-72` (288px) - фиксированная ширина для всех корзин - **Флекс**: `flex-shrink-0` - корзина не сжимается - **Позиция**: `sticky top-0` - прилипает к верху при прокрутке - **Стиль**: Glass morphism эффект с `backdrop-blur` и `bg-white/10` #### **2.4.2 Автодобавление товаров** **ПРАВИЛО AUTO-ADD**: При вводе количества товар автоматически добавляется в корзину. ```tsx // ОБЯЗАТЕЛЬНАЯ РЕАЛИЗАЦИЯ: const handleQuantityChange = (e: React.ChangeEvent) => { const inputValue = e.target.value const newQuantity = inputValue === '' ? 0 : Math.max(0, parseInt(inputValue) || 0) if (newQuantity > 0) { // Автоматически добавляем товар в корзину updateProductQuantity(product.id, newQuantity) } else { // Удаляем товар из корзины при количестве 0 removeFromCart(product.id) } } ``` **ДЕФОЛТНОЕ ЗНАЧЕНИЕ**: Пустой инпут (`value={''}`) вместо `value={0}` #### **2.4.3 Структура корзины** **ОБЯЗАТЕЛЬНЫЕ ЭЛЕМЕНТЫ**: 1. **Заголовок**: "Корзина (X шт)" с иконкой корзины 2. **Список товаров**: - Название товара (БЕЗ суффикса "(с рецептурой)") - Цена за единицу × количество - Кнопка удаления (X справа) 3. **Мета-информация**: Дата поставки, фулфилмент-центр, логистика 4. **Итого**: Общая сумма с выделением зелёным цветом 5. **Кнопка действия**: "Создать поставку" с градиентом **ЗАПРЕЩЕНО**: Отображать текст "(с рецептурой)" в названиях товаров в корзине #### **2.4.4 Единая функция расчета стоимости** **КРИТИЧЕСКИ ВАЖНО**: Использовать единую функцию расчета для избежания расхождений: ```tsx const getProductTotalWithRecipe = (productId: string, quantity: number) => { const product = products.find((p) => p.id === productId) if (!product) return 0 // Базовая цена товара let total = (product.pricePerUnit || 0) * quantity // Добавляем услуги if (product.services && product.services.length > 0) { const servicesTotal = product.services.reduce((sum, service) => { return sum + (service.pricePerUnit || 0) * quantity }, 0) total += servicesTotal } // Добавляем FF расходники (используем .price, НЕ .pricePerUnit!) if (product.ffConsumables && product.ffConsumables.length > 0) { const ffConsumablesTotal = product.ffConsumables.reduce((sum, consumable) => { return sum + (consumable.price || 0) * quantity // ВАЖНО: .price! }, 0) total += ffConsumablesTotal } // Добавляем расходники продавца if (product.sellerConsumables && product.sellerConsumables.length > 0) { const sellerConsumablesTotal = product.sellerConsumables.reduce((sum, consumable) => { return sum + (consumable.pricePerUnit || 0) * quantity }, 0) total += sellerConsumablesTotal } return total } ``` #### **2.4.5 Синхронизация данных между блоками** **ПРАВИЛО СИНХРОНИЗАЦИИ**: Данные в корзине должны отражать выборы из всех блоков формы: 1. **Дата поставки**: Из Блока 3 (дата пикер) 2. **Фулфилмент-центр**: Название выбранного FF (реальные данные!) 3. **Логистическая компания**: Только партнеры типа `'LOGIST'` **ПОРЯДОК ОТОБРАЖЕНИЯ В КОРЗИНЕ**: ``` Дата поставки: 08.08.2025 Фулфилмент-центр: ФУЛФИЛМЕНТ РУ Логистическая компания: [Выпадающий список] ``` #### **2.4.6 Критические требования** 🚨 **БЕЗОПАСНОСТЬ ТИПОВ**: - Всегда проверять на `null/undefined`: `selectedSupplier?.id || ''` - Использовать optional chaining для всех вложенных объектов 🚨 **ПРОИЗВОДИТЕЛЬНОСТЬ**: - Мемоизация расчетов: `useMemo` для дорогих вычислений - Debounce для инпутов количества 🚨 **UX КОНСИСТЕНТНОСТЬ**: - Единые стили для всех корзин в системе - Одинаковое поведение auto-add во всех формах - Синхронная валидация данных ### 2.5 Трёхблочная архитектура страницы "Мои поставки" **ПРИНЦИП**: Страница состоит из трёх визуально разделённых блоков ``` ┌─────────────────────────────────────────┐ │ 1. БЛОК ТАБОВ (навигация) │ │ - Фиксированная высота │ │ - Glass-эффект │ │ - Иерархическая структура │ ├─────────────────────────────────────────┤ │ 2. БЛОК СТАТИСТИКИ (метрики) │ │ - Контекстные данные │ │ - 4 карточки в ряд (desktop) │ │ - Динамическое обновление │ ├─────────────────────────────────────────┤ │ 3. ОСНОВНОЙ БЛОК (контент) │ │ - Сохраняет весь функционал │ │ - Таблицы, фильтры, действия │ │ - Высота до низа sidebar │ └─────────────────────────────────────────┘ ``` **ПРАВИЛО**: Статистика меняется в зависимости от выбранных табов **Для путей "Фулфилмент → Товар → Карточки/Поставщики":** - Всего поставок - Активных поставок - Сумма активных поставок - В пути **ФОРМУЛА РАСЧЕТА ВЫСОТЫ**: ```css height: calc(100vh - headerHeight - tabsHeight - statsHeight - margins); ``` **ПРАВИЛО ВЫРАВНИВАНИЯ**: - Нижняя граница основного блока должна быть на одном уровне с нижней границей sidebar - При изменении размера окна высота пересчитывается - Внутренний скролл: `overflow-y-auto` ### 2.6 Четырёхблочная архитектура создания поставки расходников #### **Структура страницы**: **БЛОК 1: ПОСТАВЩИКИ** _(обязательный, 180px)_: - Карточки поставщиков из раздела "Партнеры" - Горизонтальный скролл при превышении ширины - Выбор только одного поставщика одновременно **БЛОК 2: КАРТОЧКИ ТОВАРОВ** _(адаптивная высота - НОВЫЙ БЛОК)_: - ТОЛЬКО минималистичные карточки товаров 80×112px - ТОЛЬКО изображение товара, БЕЗ текста/названий/цен - Горизонтальный скролл при множестве товаров - Клик добавляет товар в блок 3 **БЛОК 3: ТОВАРЫ ПОСТАВЩИКА** _(flex-1, детальный каталог)_: - Детальные карточки выбранных товаров - Управление количеством и параметрами поставки **БЛОК 4: КОРЗИНА И НАСТРОЙКИ** _(правая панель, 384px)_: - Корзина поставки с выбранными товарами - Настройки поставки (фулфилмент-центр, дата, логистика) - Сортировка: цена, название, категория - Фильтры: категория, ценовой диапазон - Карточка с полем ввода количества и кнопками +/- **БЛОК 3: КОРЗИНА** _(правая часть)_: - **РАСПОЛОЖЕНИЕ**: Правая часть экрана - **СОДЕРЖАНИЕ**: - Счетчик видов расходников - Детализация по каждому расходнику (название, количество, цена, сумма) - Общая сумма всех расходников - **УПРАВЛЕНИЕ**: - Изменение количества (с валидацией остатков) - Удаление позиций - **ОБЯЗАТЕЛЬНЫЕ ПОЛЯ**: - Выбор фулфилмент-центра (из партнеров) - Дата поставки (не прошедшая, по умолчанию - текущая) ### 2.7 Многоуровневая таблица поставок #### **ПЕРВЫЙ УРОВЕНЬ** _(основной список)_: - **СОРТИРОВКА**: Номер поставки от большего к меньшему - **ОБЯЗАТЕЛЬНЫЕ КОЛОНКИ**: - Порядковый номер поставки - Количество видов расходников - Стоимость всей поставки - Количество категорий - Статус поставки #### **ВТОРОЙ УРОВЕНЬ** _(детализация по клику)_: - **АКТИВАЦИЯ**: По клику на строку первого уровня - **СОДЕРЖАНИЕ**: - Название расходника - Количество - Цена - Категория - Поставщик - **ОГРАНИЧЕНИЯ**: Только просмотр, редактирование запрещено ## 3. 🛠️ ГРАФИЧЕСКИЙ ИНТЕРФЕЙС И КОМПОНЕНТЫ ### 3.1 React компоненты селлера **Основные компоненты:** - `SellerHomePage` - главная страница селлера (4 типо-зависимых компонента) - `SellerEconomicsPage` - экономическая аналитика селлера ### 3.2 Роутинг для селлера ```typescript switch (user?.organization?.type) { case 'SELLER': router.push('/supplies') break } ``` ### 3.3 Структура разделов кабинета **🛍️ СЕЛЛЕР (`SELLER`):** - Мои поставки (`/supplies`) - управление заказами товаров - WB Интеграция (`/wb-integration`) - связь с Wildberries ## 4. 🛠️ GRAPHQL API ### 4.1 Основные запросы (Queries) #### Получение карточек селлера: ```graphql query GetSellerCards { myMarketplaceCards { id title marketplace article linkedProductId # null если свободна linkedProduct { # для отображения занятости id name } } } ``` --- **Последнее обновление**: Август 2025 **Связанные файлы**: - [rules-complete.md](./rules-complete.md) - Общие бизнес-правила - [visual-design-rules.md](./visual-design-rules.md) - Визуальные правила