div(class="admin-products") div(class="admin-products__header") h1(class="admin-products__title") Управление товарами div(class="admin-products__actions") button( @click="showProductModal = true" class="admin-products__btn admin-products__btn--primary" ) Добавить товар button( @click="showImportModal = true" class="admin-products__btn admin-products__btn--secondary" ) Импорт из CSV button( @click="showCategoriesModal = true" class="admin-products__btn admin-products__btn--secondary" ) Управление категориями button( @click="showMassActionsModal = true" class="admin-products__btn admin-products__btn--primary" ) Массовые действия div(class="admin-products__content") div(class="admin-products__filters") div(class="admin-products__filter-group") label(class="admin-products__label") Поиск input( v-model="searchQuery" type="text" class="admin-products__input" placeholder="Название или артикул..." ) div(class="admin-products__filter-group") label(class="admin-products__label") Категория select(v-model="selectedCategory" class="admin-products__select") option(value="") Все категории option( v-for="category in categories" :key="category._id" :value="category._id" ) {{ category.name }} div(class="admin-products__filter-group") label(class="admin-products__label") Статус select(v-model="selectedStatus" class="admin-products__select") option(value="") Все option(value="active") Активные option(value="inactive") Неактивные div(class="admin-products__mass-actions") div(class="admin-products__mass-header") div(class="admin-products__selection-info") span Выбрано товаров: {{ selectedProducts.length }} button( v-if="selectedProducts.length > 0" @click="clearSelection" class="admin-products__btn admin-products__btn--secondary" ) Сбросить div(class="admin-products__mass-buttons") button( @click="activateSelected" :disabled="selectedProducts.length === 0" class="admin-products__btn admin-products__btn--secondary" ) Активировать button( @click="deactivateSelected" :disabled="selectedProducts.length === 0" class="admin-products__btn admin-products__btn--secondary" ) Деактивировать button( @click="deleteSelected" :disabled="selectedProducts.length === 0" class="admin-products__btn admin-products__btn--danger" ) Удалить button( @click="showCategoryAssignModal = true" :disabled="selectedProducts.length === 0" class="admin-products__btn admin-products__btn--primary" ) Назначить категорию div(class="admin-products__list") div(class="admin-products__table-container") table(class="admin-products__table") thead tr th(class="admin-products__th admin-products__th--checkbox") input( type="checkbox" v-model="selectAll" @change="toggleSelectAll" class="admin-products__checkbox" ) th(class="admin-products__th") Изобр. th(class="admin-products__th") Название th(class="admin-products__th") Артикул th(class="admin-products__th") Цена th(class="admin-products__th") Категория th(class="admin-products__th") Статус th(class="admin-products__th") Действия tbody tr( v-for="product in filteredProducts" :key="product._id" class="admin-products__tr" :class="{'admin-products__tr--selected': isProductSelected(product._id)}" ) td(class="admin-products__td admin-products__td--checkbox") input( type="checkbox" :value="product._id" v-model="selectedProducts" class="admin-products__checkbox" ) td(class="admin-products__td") img( v-if="product.image" :src="product.image" :alt="product.name" class="admin-products__image" ) div(v-else class="admin-products__no-image") Нет td(class="admin-products__td") div(class="admin-products__name") {{ product.name }} td(class="admin-products__td") {{ product.sku }} td(class="admin-products__td") div(class="admin-products__price") {{ formatPrice(product.price) }} div( v-if="product.oldPrice" class="admin-products__old-price" ) {{ formatPrice(product.oldPrice) }} td(class="admin-products__td") {{ getCategoryName(product.category) }} td(class="admin-products__td") span( :class="getStatusClass(product.active)" ) {{ product.active ? 'Активен' : 'Неактивен' }} td(class="admin-products__td") div(class="admin-products__action-buttons") button( @click="editProduct(product)" class="admin-products__action-btn admin-products__action-btn--edit" ) Редакт. button( @click="toggleProductStatus(product)" class="admin-products__action-btn admin-products__action-btn--toggle" ) {{ product.active ? 'Выкл.' : 'Вкл.' }} button( @click="deleteProduct(product._id)" class="admin-products__action-btn admin-products__action-btn--delete" ) Удалить // Модальное окно массового назначения категории div(v-if="showCategoryAssignModal" class="admin-products__modal") div(class="admin-products__modal-content") h3(class="admin-products__modal-title") Назначить категорию для {{ selectedProducts.length }} товаров div(class="admin-products__modal-form") div(class="admin-products__form-group") label(class="admin-products__label") Категория select(v-model="massCategory" class="admin-products__select") option(value="") Без категории option( v-for="category in categories" :key="category._id" :value="category._id" ) {{ category.name }} div(class="admin-products__form-group") label(class="admin-products__checkbox-label") input( v-model="removeExistingCategories" type="checkbox" class="admin-products__checkbox" ) span Удалить существующие категории div(class="admin-products__modal-actions") button( @click="assignCategoryToSelected" :disabled="!massCategory" class="admin-products__btn admin-products__btn--primary" ) Назначить button( @click="showCategoryAssignModal = false" class="admin-products__btn admin-products__btn--secondary" ) Отмена // Модальное окно массовых действий div(v-if="showMassActionsModal" class="admin-products__modal") div(class="admin-products__modal-content") h3(class="admin-products__modal-title") Массовые действия с товарами div(class="admin-products__mass-actions-grid") div(class="admin-products__mass-action") h4(class="admin-products__mass-action-title") Изменение статуса div(class="admin-products__mass-action-buttons") button( @click="massChangeStatus(true)" class="admin-products__btn admin-products__btn--secondary" ) Активировать все товары button( @click="massChangeStatus(false)" class="admin-products__btn admin-products__btn--secondary" ) Деактивировать все товары div(class="admin-products__mass-action") h4(class="admin-products__mass-action-title") Управление категориями div(class="admin-products__mass-action-buttons") button( @click="showMassCategoryAssign = true" class="admin-products__btn admin-products__btn--secondary" ) Назначить категорию всем button( @click="massRemoveCategories" class="admin-products__btn admin-products__btn--danger" ) Удалить все категории div(class="admin-products__mass-action") h4(class="admin-products__mass-action-title") Цены div(class="admin-products__mass-action-buttons") button( @click="showMassPriceModal = true" class="admin-products__btn admin-products__btn--secondary" ) Массовое изменение цен div(class="admin-products__mass-action") h4(class="admin-products__mass-action-title") Экспорт div(class="admin-products__mass-action-buttons") button( @click="exportProducts" class="admin-products__btn admin-products__btn--primary" ) Экспорт в CSV button( @click="exportSelectedProducts" :disabled="selectedProducts.length === 0" class="admin-products__btn admin-products__btn--primary" ) Экспорт выбранных div(class="admin-products__modal-actions") button( @click="showMassActionsModal = false" class="admin-products__btn admin-products__btn--secondary" ) Закрыть // Модальное окно массового назначения категории всем товарам div(v-if="showMassCategoryAssign" class="admin-products__modal") div(class="admin-products__modal-content") h3(class="admin-products__modal-title") Назначить категорию всем товарам div(class="admin-products__modal-form") div(class="admin-products__form-group") label(class="admin-products__label") Категория select(v-model="massAllCategory" class="admin-products__select") option(value="") Без категории option( v-for="category in categories" :key="category._id" :value="category._id" ) {{ category.name }} div(class="admin-products__form-group") label(class="admin-products__checkbox-label") input( v-model="massRemoveAllCategories" type="checkbox" class="admin-products__checkbox" ) span Удалить существующие категории у всех товаров div(class="admin-products__modal-actions") button( @click="assignCategoryToAll" :disabled="!massAllCategory" class="admin-products__btn admin-products__btn--primary" ) Назначить всем button( @click="showMassCategoryAssign = false" class="admin-products__btn admin-products__btn--secondary" ) Отмена // Модальное окно массового изменения цен div(v-if="showMassPriceModal" class="admin-products__modal") div(class="admin-products__modal-content") h3(class="admin-products__modal-title") Массовое изменение цен div(class="admin-products__modal-form") div(class="admin-products__form-group") label(class="admin-products__label") Тип изменения select(v-model="priceChangeType" class="admin-products__select") option(value="fixed") Фиксированная цена option(value="percent") Изменить на процент option(value="increase") Увеличить на сумму option(value="decrease") Уменьшить на сумму div(class="admin-products__form-group") label(class="admin-products__label") Значение input( v-model="priceChangeValue" type="number" class="admin-products__input" placeholder="Введите значение" step="0.01" ) div(class="admin-products__form-group") label(class="admin-products__checkbox-label") input( v-model="applyToOldPrice" type="checkbox" class="admin-products__checkbox" ) span Применить к старой цене div(class="admin-products__modal-actions") button( @click="applyMassPriceChange" :disabled="!priceChangeValue" class="admin-products__btn admin-products__btn--primary" ) Применить button( @click="showMassPriceModal = false" class="admin-products__btn admin-products__btn--secondary" ) Отмена // Модальное окно редактирования товара div(v-if="showProductModal" class="admin-products__modal") div(class="admin-products__modal-content") h3(class="admin-products__modal-title") {{ editingProduct ? 'Редактирование' : 'Добавление' }} товара div(class="admin-products__modal-form") div(class="admin-products__form-group") label(class="admin-products__label") Название товара * input( v-model="productForm.name" type="text" class="admin-products__input" placeholder="Введите название товара" required ) div(class="admin-products__form-group") label(class="admin-products__label") Артикул * input( v-model="productForm.sku" type="text" class="admin-products__input" placeholder="Артикул товара" required ) div(class="admin-products__form-group") label(class="admin-products__label") Категория select(v-model="productForm.category" class="admin-products__select") option(value="") Выберите категорию option( v-for="category in categories" :key="category._id" :value="category._id" ) {{ category.name }} div(class="admin-products__form-group") label(class="admin-products__label") Цена * input( v-model="productForm.price" type="number" class="admin-products__input" placeholder="0.00" min="0" step="0.01" required ) div(class="admin-products__form-group") label(class="admin-products__label") Старая цена input( v-model="productForm.oldPrice" type="number" class="admin-products__input" placeholder="0.00" min="0" step="0.01" ) div(class="admin-products__form-group") label(class="admin-products__label") Бренд input( v-model="productForm.brand" type="text" class="admin-products__input" placeholder="Бренд производителя" ) div(class="admin-products__form-group") label(class="admin-products__label") Описание textarea( v-model="productForm.description" class="admin-products__textarea" placeholder="Описание товара" rows="4" ) div(class="admin-products__form-group") label(class="admin-products__label") Изображение товара div(class="admin-products__image-upload") div(v-if="productForm.image" class="admin-products__image-preview") img(:src="productForm.image" :alt="productForm.name" class="admin-products__preview-image") button( @click="removeProductImage" class="admin-products__btn admin-products__btn--danger" ) Удалить div(v-else class="admin-products__image-placeholder") Изображение не загружено input( type="file" ref="productImageInput" @change="onProductImageUpload" accept="image/*" class="admin-products__file-input" id="product-image-upload" ) label(for="product-image-upload" class="admin-products__btn admin-products__btn--secondary") Выбрать изображение div(class="admin-products__form-group") label(class="admin-products__checkbox-label") input( v-model="productForm.active" type="checkbox" class="admin-products__checkbox" ) span Активный товар div(class="admin-products__form-group") label(class="admin-products__label") Домены div(class="admin-products__domains-list") label( v-for="domain in availableDomains" :key="domain._id" class="admin-products__domain-label" ) input( type="checkbox" :value="domain.domain" v-model="productForm.domains" class="admin-products__domain-checkbox" ) span {{ domain.domain }} div(class="admin-products__modal-actions") button( @click="saveProduct" class="admin-products__btn admin-products__btn--primary" ) {{ editingProduct ? 'Обновить' : 'Создать' }} button( @click="showProductModal = false" class="admin-products__btn admin-products__btn--secondary" ) Отмена // Модальное окно импорта div(v-if="showImportModal" class="admin-products__modal") div(class="admin-products__modal-content") h3(class="admin-products__modal-title") Импорт товаров из CSV div(class="admin-products__import-form") div(class="admin-products__form-group") label(class="admin-products__label") Выберите CSV файл input( type="file" @change="onFileSelect" accept=".csv" class="admin-products__file-input" ) p(class="admin-products__help-text") Поддерживается формат CSV с разделителем ; и кодировкой UTF-8 div(v-if="selectedFile" class="admin-products__file-info") p Выбран файл: {{ selectedFile.name }} button( @click="importProducts" :disabled="importing" class="admin-products__btn admin-products__btn--primary" ) {{ importing ? 'Импорт...' : 'Начать импорт' }} div(v-if="importResults" class="admin-products__import-results") h4(v-if="importResults.success" class="admin-products__success") Импорт успешно завершен! h4(v-else class="admin-products__error") Ошибка импорта p Обработано товаров: {{ importResults.processed }} p(v-if="importResults.errors && importResults.errors.length") strong Ошибки: ul li(v-for="error in importResults.errors" :key="error") {{ error }} p(v-if="importResults.error") Ошибка: {{ importResults.error }} div(class="admin-products__modal-actions") button( @click="showImportModal = false" class="admin-products__btn admin-products__btn--secondary" ) Закрыть // Модальное окно управления категориями div(v-if="showCategoriesModal" class="admin-products__modal") div(class="admin-products__modal-content admin-products__modal-content--large") h3(class="admin-products__modal-title") Управление категориями div(class="admin-products__categories-tabs") button( @click="categoriesActiveTab = 'list'" :class="getCategoriesTabClass('list')" ) Список категорий button( @click="categoriesActiveTab = 'import'" :class="getCategoriesTabClass('import')" ) Импорт категорий // Список категорий div(v-if="categoriesActiveTab === 'list'" class="admin-products__categories-list") div(class="admin-products__categories-header") button( @click="showCategoryModal = true" class="admin-products__btn admin-products__btn--primary" ) Добавить категорию div(class="admin-products__categories-grid") div( v-for="category in categories" :key="category._id" class="admin-products__category-item" ) div(class="admin-products__category-preview") img( v-if="category.image" :src="category.image" :alt="category.name" class="admin-products__category-image" ) div(v-else class="admin-products__category-no-image") Нет изображения div(class="admin-products__category-info") h4(class="admin-products__category-name") {{ category.name }} p(class="admin-products__category-description") {{ category.description || 'Без описания' }} div(class="admin-products__category-meta") span(class="admin-products__category-products") Товаров: {{ getCategoryProductCount(category._id) }} span( :class="getStatusClass(category.active)" ) {{ category.active ? 'Активна' : 'Неактивна' }} div(class="admin-products__category-actions") button( @click="editCategory(category)" class="admin-products__btn admin-products__btn--edit" ) Редактировать button( @click="deleteCategory(category._id)" class="admin-products__btn admin-products__btn--delete" ) Удалить // Импорт категорий div(v-if="categoriesActiveTab === 'import'" class="admin-products__categories-import") div(class="admin-products__form-group") label(class="admin-products__label") Выберите CSV файл категорий input( type="file" @change="onCategoriesFileSelect" accept=".csv" class="admin-products__file-input" ) p(class="admin-products__help-text") Формат CSV с полями: name, slug, description, parentCategory, sortOrder, active div(v-if="selectedCategoriesFile" class="admin-products__file-info") p Выбран файл: {{ selectedCategoriesFile.name }} button( @click="importCategories" :disabled="importingCategories" class="admin-products__btn admin-products__btn--primary" ) {{ importingCategories ? 'Импорт...' : 'Импорт категорий' }} div(v-if="categoriesImportResults" class="admin-products__import-results") h4(v-if="categoriesImportResults.success" class="admin-products__success") Импорт категорий завершен! h4(v-else class="admin-products__error") Ошибка импорта категорий p Обработано категорий: {{ categoriesImportResults.processed }} p(v-if="categoriesImportResults.errors && categoriesImportResults.errors.length") strong Ошибки: ul li(v-for="error in categoriesImportResults.errors" :key="error") {{ error }} div(class="admin-products__modal-actions") button( @click="showCategoriesModal = false" class="admin-products__btn admin-products__btn--secondary" ) Закрыть // Модальное окно редактирования категории div(v-if="showCategoryModal" class="admin-products__modal") div(class="admin-products__modal-content") h3(class="admin-products__modal-title") {{ editingCategory ? 'Редактирование' : 'Добавление' }} категории div(class="admin-products__modal-form") div(class="admin-products__form-group") label(class="admin-products__label") Название категории * input( v-model="categoryForm.name" type="text" class="admin-products__input" placeholder="Введите название категории" required ) div(class="admin-products__form-group") label(class="admin-products__label") URL slug * input( v-model="categoryForm.slug" type="text" class="admin-products__input" placeholder="url-slug" required ) div(class="admin-products__form-group") label(class="admin-products__label") Описание textarea( v-model="categoryForm.description" class="admin-products__textarea" placeholder="Описание категории" rows="3" ) div(class="admin-products__form-group") label(class="admin-products__label") Родительская категория select(v-model="categoryForm.parentCategory" class="admin-products__select") option(value="") Без родительской категории option( v-for="cat in categories.filter(c => c._id !== editingCategory?._id)" :key="cat._id" :value="cat._id" ) {{ cat.name }} div(class="admin-products__form-group") label(class="admin-products__label") Порядок сортировки input( v-model="categoryForm.sortOrder" type="number" class="admin-products__input" placeholder="0" min="0" ) div(class="admin-products__form-group") label(class="admin-products__label") Изображение категории div(class="admin-products__image-upload") div(v-if="categoryForm.image" class="admin-products__image-preview") img(:src="categoryForm.image" :alt="categoryForm.name" class="admin-products__preview-image") button( @click="removeCategoryImage" class="admin-products__btn admin-products__btn--danger" ) Удалить div(v-else class="admin-products__image-placeholder") Изображение не загружено input( type="file" ref="categoryImageInput" @change="onCategoryImageUpload" accept="image/*" class="admin-products__file-input" id="category-image-upload" ) label(for="category-image-upload" class="admin-products__btn admin-products__btn--secondary") Выбрать изображение div(class="admin-products__form-group") label(class="admin-products__label") Иконка для меню div(class="admin-products__image-upload") div(v-if="categoryForm.icon" class="admin-products__image-preview admin-products__image-preview--small") img(:src="categoryForm.icon" :alt="categoryForm.name" class="admin-products__preview-image") button( @click="removeCategoryIcon" class="admin-products__btn admin-products__btn--danger" ) Удалить div(v-else class="admin-products__image-placeholder") Иконка не загружена input( type="file" ref="categoryIconInput" @change="onCategoryIconUpload" accept="image/*" class="admin-products__file-input" id="category-icon-upload" ) label(for="category-icon-upload" class="admin-products__btn admin-products__btn--secondary") Выбрать иконку div(class="admin-products__form-group") label(class="admin-products__checkbox-label") input( v-model="categoryForm.active" type="checkbox" class="admin-products__checkbox" ) span Активная категория div(class="admin-products__form-group") label(class="admin-products__label") Домены div(class="admin-products__domains-list") label( v-for="domain in availableDomains" :key="domain._id" class="admin-products__domain-label" ) input( type="checkbox" :value="domain.domain" v-model="categoryForm.domains" class="admin-products__domain-checkbox" ) span {{ domain.domain }} div(class="admin-products__modal-actions") button( @click="saveCategory" class="admin-products__btn admin-products__btn--primary" ) {{ editingCategory ? 'Обновить' : 'Создать' }} button( @click="showCategoryModal = false" class="admin-products__btn admin-products__btn--secondary" ) Отмена