| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495 |
- 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"
- ) Управление категориями
- 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__list")
- div(class="admin-products__table-container")
- table(class="admin-products__table")
- thead
- tr
- 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"
- )
- 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="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"
- ) Отмена
|