| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531 |
- div(class="admin-products")
- div(class="admin-products__header")
- h1(class="admin-products__title") Управление товарами
- div(class="admin-products__actions")
- button(
- @click="createProduct"
- class="admin-products__button admin-products__button--primary"
- ) Добавить товар
- button(
- @click="showImportModal = true"
- class="admin-products__button admin-products__button--secondary"
- ) Импорт из CSV
- button(
- @click="showCategoriesManager"
- class="admin-products__button admin-products__button--secondary"
- ) Управление категориями
- button(
- v-if="selectedProducts.length > 0"
- @click="showMassActionsModal = true"
- class="admin-products__button admin-products__button--warning"
- ) Массовые действия ({{ selectedProducts.length }})
- div(class="admin-products__filters")
- div(class="admin-products__search")
- input(
- type="text"
- v-model="searchQuery"
- placeholder="Поиск по названию или артикулу..."
- class="admin-products__search-input"
- )
- div(class="admin-products__filter-group")
- select(v-model="selectedCategory" class="admin-products__select")
- option(value="") Все категории
- option(
- v-for="category in categories"
- :value="category._id"
- ) {{ category.name }} ({{ getCategoryProductCount(category._id) }})
- select(v-model="selectedStatus" class="admin-products__select")
- option(value="") Все статусы
- option(value="active") Активные
- option(value="inactive") Неактивные
- div(class="admin-products__content")
- 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") Действия
- tbody
- tr(
- v-for="product in filteredProducts"
- :key="product._id"
- :class="['admin-products__tr', { 'admin-products__tr--inactive': !product.active }]"
- )
- td(class="admin-products__td admin-products__td--checkbox")
- input(
- type="checkbox"
- :checked="isProductSelected(product._id)"
- @change="toggleProductSelection(product._id)"
- class="admin-products__checkbox"
- )
- td(class="admin-products__td admin-products__td--sku") {{ product.sku }}
- td(class="admin-products__td admin-products__td--name") {{ product.name }}
- td(class="admin-products__td") {{ getCategoryName(product.category) }}
- td(class="admin-products__td admin-products__td--price")
- span(v-if="product.oldPrice" class="admin-products__old-price") {{ product.oldPrice }} ₽
- span(class="admin-products__current-price") {{ product.price }} ₽
- td(class="admin-products__td")
- span(
- :class="['admin-products__status', product.active ? 'admin-products__status--active' : 'admin-products__status--inactive']"
- ) {{ product.active ? 'Активен' : 'Неактивен' }}
- td(class="admin-products__td admin-products__td--actions")
- button(
- @click="editProduct(product)"
- class="admin-products__action-button admin-products__action-button--edit"
- ) Редактировать
- button(
- @click="toggleProductStatus(product)"
- :class="['admin-products__action-button', product.active ? 'admin-products__action-button--deactivate' : 'admin-products__action-button--activate']"
- ) {{ product.active ? 'Деактивировать' : 'Активировать' }}
- div(v-if="filteredProducts.length === 0" class="admin-products__empty")
- p(class="admin-products__empty-text") Товары не найдены
- //- Модальное окно редактирования/создания товара
- div(
- v-if="showProductModal"
- class="admin-products__modal"
- )
- div(class="admin-products__modal-content admin-products__modal-content--large")
- div(class="admin-products__modal-header")
- h2(class="admin-products__modal-title") {{ isEditing ? 'Редактирование товара' : 'Создание товара' }}
- button(
- @click="showProductModal = false"
- class="admin-products__modal-close"
- ) ×
-
- div(class="admin-products__modal-body")
- div(class="admin-products__form")
- div(class="admin-products__form-row")
- div(class="admin-products__form-group")
- label(class="admin-products__label") Название товара *
- input(
- type="text"
- v-model="productForm.name"
- class="admin-products__input"
- placeholder="Введите название товара"
- )
- div(class="admin-products__form-group")
- label(class="admin-products__label") Артикул *
- input(
- type="text"
- v-model="productForm.sku"
- class="admin-products__input"
- placeholder="Введите артикул"
- )
-
- div(class="admin-products__form-row")
- 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"
- :value="category._id"
- ) {{ category.name }}
- div(class="admin-products__form-group")
- label(class="admin-products__label") Бренд
- input(
- type="text"
- v-model="productForm.brand"
- class="admin-products__input"
- placeholder="Введите бренд"
- )
-
- div(class="admin-products__form-row")
- div(class="admin-products__form-group")
- label(class="admin-products__label") Цена *
- input(
- type="number"
- v-model="productForm.price"
- class="admin-products__input"
- placeholder="0.00"
- step="0.01"
- min="0"
- )
- div(class="admin-products__form-group")
- label(class="admin-products__label") Старая цена
- input(
- type="number"
- v-model="productForm.oldPrice"
- class="admin-products__input"
- placeholder="0.00"
- step="0.01"
- min="0"
- )
-
- 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__attributes")
- div(
- v-for="attr in attributesList"
- :key="attr.key"
- class="admin-products__attribute"
- )
- div(class="admin-products__attribute-key") {{ attr.key }}
- input(
- type="text"
- :value="attr.value"
- @input="updateAttribute(attr.key, $event.target.value)"
- class="admin-products__input admin-products__input--small"
- placeholder="Значение"
- )
- button(
- @click="removeAttribute(attr.key)"
- class="admin-products__attribute-remove"
- ) ×
-
- div(class="admin-products__attribute-add")
- input(
- type="text"
- v-model="newAttributeKey"
- class="admin-products__input admin-products__input--small"
- placeholder="Название атрибута"
- @keyup.enter="addAttribute"
- )
- input(
- type="text"
- v-model="newAttributeValue"
- class="admin-products__input admin-products__input--small"
- placeholder="Значение"
- @keyup.enter="addAttribute"
- )
- button(
- @click="addAttribute"
- class="admin-products__button admin-products__button--secondary"
- ) Добавить
-
- //- Управление тегами
- div(class="admin-products__form-group")
- label(class="admin-products__label") Теги
- div(class="admin-products__tags")
- span(
- v-for="(tag, index) in productForm.tags"
- :key="index"
- class="admin-products__tag"
- )
- | {{ tag }}
- button(
- @click="removeTag(index)"
- class="admin-products__tag-remove"
- ) ×
-
- div(class="admin-products__tag-add")
- input(
- type="text"
- v-model="newTag"
- class="admin-products__input admin-products__input--small"
- placeholder="Новый тег"
- @keyup.enter="addTag"
- )
- button(
- @click="addTag"
- class="admin-products__button admin-products__button--secondary"
- ) Добавить
-
- //- Загрузка основного изображения
- 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" class="admin-products__preview-img")
- div(class="admin-products__image-info") Основное изображение
- div(class="admin-products__upload-controls")
- input(
- type="text"
- v-model="newImageUrl"
- class="admin-products__input"
- placeholder="Введите URL изображения"
- )
- button(
- @click="uploadMainImage"
- :disabled="uploadingImages || !newImageUrl"
- class="admin-products__button admin-products__button--secondary"
- ) {{ uploadingImages ? 'Загрузка...' : 'Загрузить' }}
-
- //- Загрузка дополнительных изображений
- div(class="admin-products__form-group")
- label(class="admin-products__label") Дополнительные изображения
- div(class="admin-products__additional-images")
- div(
- v-for="(image, index) in productForm.additionalImages"
- :key="index"
- class="admin-products__additional-image"
- )
- img(:src="image" class="admin-products__preview-img")
- button(
- @click="removeAdditionalImage(index)"
- class="admin-products__image-remove"
- ) ×
-
- div(class="admin-products__upload-controls")
- input(
- type="text"
- v-model="newAdditionalImageUrl"
- class="admin-products__input"
- placeholder="Введите URL дополнительного изображения"
- )
- button(
- @click="uploadAdditionalImage"
- :disabled="uploadingImages || !newAdditionalImageUrl"
- class="admin-products__button admin-products__button--secondary"
- ) {{ uploadingImages ? 'Загрузка...' : 'Добавить' }}
-
- div(class="admin-products__form-row")
- div(class="admin-products__form-group")
- label(class="admin-products__label admin-products__label--checkbox")
- input(
- type="checkbox"
- v-model="productForm.active"
- class="admin-products__checkbox"
- )
- span Активный товар
-
- div(class="admin-products__modal-footer")
- button(
- @click="saveProduct"
- :disabled="!productForm.name || !productForm.sku || !productForm.price"
- class="admin-products__button admin-products__button--primary"
- ) {{ isEditing ? 'Обновить' : 'Создать' }}
- button(
- @click="showProductModal = false"
- class="admin-products__button admin-products__button--secondary"
- ) Отмена
- //- Модальное окно управления категориями
- div(
- v-if="showCategoriesModal"
- class="admin-products__modal"
- )
- div(class="admin-products__modal-content admin-products__modal-content--large")
- div(class="admin-products__modal-header")
- h2(class="admin-products__modal-title") Управление категориями
- button(
- @click="showCategoriesModal = false"
- class="admin-products__modal-close"
- ) ×
-
- div(class="admin-products__modal-body")
- div(class="admin-products__categories-header")
- button(
- @click="createCategory"
- class="admin-products__button admin-products__button--primary"
- ) Создать категорию
-
- div(class="admin-products__categories-list")
- div(
- v-for="category in categories"
- :key="category._id"
- class="admin-products__category-item"
- )
- div(class="admin-products__category-info")
- div(class="admin-products__category-name") {{ category.name }}
- div(class="admin-products__category-meta")
- span Товаров: {{ getCategoryProductCount(category._id) }}
- span(v-if="category.slug") Slug: {{ category.slug }}
- div(class="admin-products__category-actions")
- button(
- @click="editCategory(category)"
- class="admin-products__action-button admin-products__action-button--edit"
- ) Редактировать
- button(
- @click="deleteCategory(category)"
- class="admin-products__action-button admin-products__action-button--danger"
- ) Удалить
- //- Модальное окно редактирования/создания категории
- div(
- v-if="showCategoryModal"
- class="admin-products__modal"
- )
- div(class="admin-products__modal-content")
- div(class="admin-products__modal-header")
- h2(class="admin-products__modal-title") {{ editingCategory ? 'Редактирование категории' : 'Создание категории' }}
- button(
- @click="showCategoryModal = false"
- class="admin-products__modal-close"
- ) ×
-
- div(class="admin-products__modal-body")
- div(class="admin-products__form")
- div(class="admin-products__form-group")
- label(class="admin-products__label") Название категории *
- input(
- type="text"
- v-model="categoryForm.name"
- class="admin-products__input"
- placeholder="Введите название категории"
- )
-
- div(class="admin-products__form-group")
- label(class="admin-products__label") Slug
- input(
- type="text"
- v-model="categoryForm.slug"
- class="admin-products__input"
- placeholder="Автоматически сгенерируется из названия"
- )
-
- 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-row")
- 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="category in categories"
- :value="category._id"
- v-if="category._id != editingCategory?._id"
- ) {{ category.name }}
-
- div(class="admin-products__form-group")
- label(class="admin-products__label") Порядок сортировки
- input(
- type="number"
- v-model="categoryForm.sortOrder"
- class="admin-products__input"
- placeholder="0"
- )
-
- div(class="admin-products__form-group")
- label(class="admin-products__label admin-products__label--checkbox")
- input(
- type="checkbox"
- v-model="categoryForm.active"
- class="admin-products__checkbox"
- )
- span Активная категория
-
- div(class="admin-products__modal-footer")
- button(
- @click="saveCategory"
- :disabled="!categoryForm.name"
- class="admin-products__button admin-products__button--primary"
- ) {{ editingCategory ? 'Обновить' : 'Создать' }}
- button(
- @click="showCategoryModal = false"
- class="admin-products__button admin-products__button--secondary"
- ) Отмена
- //- Модальное окно импорта
- div(
- v-if="showImportModal"
- class="admin-products__modal"
- )
- div(class="admin-products__modal-content")
- div(class="admin-products__modal-header")
- h2(class="admin-products__modal-title") Импорт товаров из CSV
- button(
- @click="showImportModal = false"
- class="admin-products__modal-close"
- ) ×
-
- div(class="admin-products__modal-body")
- div(v-if="importing" class="admin-products__import-progress")
- div(class="admin-products__progress-bar")
- div(
- :style="{ width: importProgress + '%' }"
- class="admin-products__progress-fill"
- )
- p(class="admin-products__progress-text") Обработано: {{ processedCount }} из {{ totalCount }} ({{ importProgress }}%)
-
- div(v-else class="admin-products__import-form")
- input(
- type="file"
- @change="onFileSelect"
- accept=".csv"
- class="admin-products__file-input"
- )
- p(class="admin-products__help-text") Поддерживается формат CSV с разделителем ";" и кодировкой UTF-8
-
- div(v-if="importResults" class="admin-products__import-results")
- div(
- v-if="importResults.success"
- class="admin-products__result admin-products__result--success"
- )
- h3 Успешно импортировано!
- p Обработано товаров: {{ importResults.processed }} из {{ importResults.total }}
- ul(v-if="importResults.errors.length > 0")
- li(v-for="error in importResults.errors") {{ error }}
- div(
- v-else
- class="admin-products__result admin-products__result--error"
- )
- h3 Ошибка импорта!
- p {{ importResults.error }}
-
- div(class="admin-products__modal-footer")
- button(
- @click="importProducts"
- :disabled="!selectedFile || importing"
- class="admin-products__button admin-products__button--primary"
- ) {{ importing ? 'Импорт...' : 'Начать импорт' }}
- button(
- @click="showImportModal = false"
- class="admin-products__button admin-products__button--secondary"
- ) Отмена
- //- Модальное окно массовых действий
- div(
- v-if="showMassActionsModal"
- class="admin-products__modal"
- )
- div(class="admin-products__modal-content")
- div(class="admin-products__modal-header")
- h2(class="admin-products__modal-title") Массовые действия ({{ selectedProducts.length }} товаров)
- button(
- @click="showMassActionsModal = false"
- class="admin-products__modal-close"
- ) ×
-
- div(class="admin-products__modal-body")
- div(class="admin-products__mass-actions")
- button(
- @click="activateSelected"
- class="admin-products__button admin-products__button--success"
- ) Активировать
- button(
- @click="deactivateSelected"
- class="admin-products__button admin-products__button--warning"
- ) Деактивировать
- button(
- @click="deleteSelected"
- class="admin-products__button admin-products__button--danger"
- ) Удалить
-
- div(class="admin-products__modal-footer")
- button(
- @click="showMassActionsModal = false"
- class="admin-products__button admin-products__button--secondary"
- ) Закрыть
|