document.head.insertAdjacentHTML('beforeend','') PouchDB = require 'app/utils/pouch' Papa = require 'papaparse' module.exports = name: 'AdminProducts' render: (new Function '_ctx', '_cache', renderFns['app/pages/Admin/Products/index.pug'])() data: -> return { products: [] categories: [] searchQuery: '' selectedCategory: '' selectedStatus: '' showProductModal: false showImportModal: false editingProduct: null selectedFile: null importing: false importResults: null } computed: filteredProducts: -> products = @products # Фильтр по поиску if @searchQuery query = @searchQuery.toLowerCase() products = products.filter (product) => product.name?.toLowerCase().includes(query) || product.sku?.toLowerCase().includes(query) # Фильтр по категории if @selectedCategory products = products.filter (product) => product.category == @selectedCategory # Фильтр по статусу if @selectedStatus == 'active' products = products.filter (product) => product.active else if @selectedStatus == 'inactive' products = products.filter (product) => !product.active return products methods: loadProducts: -> PouchDB.queryView('admin', 'products', { include_docs: true }) .then (result) => @products = result.rows.map (row) -> row.doc .catch (error) => console.error 'Ошибка загрузки товаров:', error @showNotification 'Ошибка загрузки товаров', 'error' loadCategories: -> PouchDB.queryView('admin', 'categories', { include_docs: true }) .then (result) => @categories = result.rows.map (row) -> row.doc .catch (error) => console.error 'Ошибка загрузки категорий:', error getCategoryName: (categoryId) -> category = @categories.find (cat) -> cat._id == categoryId category?.name || 'Без категории' editProduct: (product) -> @editingProduct = product @showProductModal = true toggleProductStatus: (product) -> updatedProduct = { ...product active: !product.active updatedAt: new Date().toISOString() } PouchDB.saveToRemote(updatedProduct) .then (result) => @loadProducts() @showNotification 'Статус товара обновлен' .catch (error) => console.error 'Ошибка обновления статуса:', error @showNotification 'Ошибка обновления статуса', 'error' deleteProduct: (productId) -> if confirm('Вы уверены, что хотите удалить этот товар?') PouchDB.getDocument(productId) .then (doc) -> PouchDB.saveToRemote({ ...doc, _deleted: true }) .then (result) => @loadProducts() @showNotification 'Товар удален' .catch (error) => console.error 'Ошибка удаления товара:', error @showNotification 'Ошибка удаления товара', 'error' onFileSelect: (event) -> @selectedFile = event.target.files[0] @importResults = null importProducts: -> if !@selectedFile @showNotification 'Выберите файл для импорта', 'error' return @importing = true @importResults = null reader = new FileReader() reader.onload = (e) => try results = Papa.parse e.target.result, { header: true delimiter: ';' skipEmptyLines: true encoding: 'UTF-8' } products = results.data.filter (row) => row && row['Артикул*'] && row['Название товара'] && row['Цена, руб.*'] couchProducts = products.map (product, index) => @transformProductData(product, index) # Пакетное сохранение PouchDB.bulkDocs(couchProducts) .then (result) => @importResults = { success: true, processed: couchProducts.length } @importing = false @loadProducts() @showNotification "Импортировано #{couchProducts.length} товаров" .catch (error) => @importResults = { success: false, error: error.message, processed: 0 } @importing = false @showNotification "Ошибка импорта: #{error.message}", 'error' catch error @importResults = { success: false, error: error.message, processed: 0 } @importing = false @showNotification "Ошибка обработки файла: #{error.message}", 'error' reader.readAsText(@selectedFile, 'UTF-8') transformProductData: (product, index) -> # Базовые поля productData = { _id: "product:#{Date.now()}-#{index}" type: 'product' name: product['Название товара'] sku: product['Артикул*'] price: parseFloat(product['Цена, руб.*'].replace(/\s/g, '').replace(',', '.')) || 0 active: true createdAt: new Date().toISOString() updatedAt: new Date().toISOString() } # Дополнительные поля if product['Цена до скидки, руб.'] productData.oldPrice = parseFloat(product['Цена до скидки, руб.'].replace(/\s/g, '').replace(',', '.')) if product['Ссылка на главное фото*'] productData.image = product['Ссылка на главное фото*'] if product['Бренд*'] productData.brand = product['Бренд*'] if product['Тип*'] productData.productType = product['Тип*'] # Rich content преобразование if product['Rich-контент JSON'] try richContent = JSON.parse(product['Rich-контент JSON']) productData.description = @richContentToMarkdown(richContent) catch productData.description = product['Аннотация'] || '' else productData.description = product['Аннотация'] || '' # Домены (все товары доступны на всех доменах по умолчанию) productData.domains = @availableDomains?.map((d) -> d.domain) || [] return productData richContentToMarkdown: (richContent) -> # Простое преобразование rich content в markdown return JSON.stringify(richContent) # Временная реализация formatPrice: (price) -> return '0 ₽' if !price new Intl.NumberFormat('ru-RU', { style: 'currency' currency: 'RUB' minimumFractionDigits: 0 }).format(price) getStatusClass: (isActive) -> baseClass = 'admin-products__status' if isActive return "#{baseClass} admin-products__status--active" else return "#{baseClass} admin-products__status--inactive" showNotification: (message, type = 'success') -> @$root.showNotification?(message, type) || debug.log("#{type}: #{message}") mounted: -> @loadProducts() @loadCategories()