diff --git a/frontend/admin.html b/frontend/admin.html index 3d19e9a..91d8689 100644 --- a/frontend/admin.html +++ b/frontend/admin.html @@ -1318,23 +1318,61 @@
+ +
+
+ История изменений прав ролей + +
+
+
+
Магазин
-
+
-
Товары
-
+
+ + +
- + - +
IDНазваниеТипЦенаПроданоАктивенДействияТоварТипЦенаПроданоАктивенДействия
diff --git a/frontend/js/admin/sections/shop.js b/frontend/js/admin/sections/shop.js index 7f86e9b..54486e3 100644 --- a/frontend/js/admin/sections/shop.js +++ b/frontend/js/admin/sections/shop.js @@ -4,6 +4,13 @@ 'use strict'; let inited = false; let _shopItems = []; + let _filterType = ''; + let _search = ''; + + const TYPE_LABELS = { frame:'Рамка', title:'Титул', theme:'Тема', effect:'Эффект', background:'Фон' }; + const TYPE_ICONS = { frame:'square', title:'award', background:'image', effect:'sparkles', theme:'palette' }; + const typeCls = t => ['frame','title','background','effect'].includes(t) ? 't-' + t : 't-other'; + const typeIcon = t => TYPE_ICONS[t] || 'tag'; async function load() { try { @@ -12,27 +19,19 @@ LS.adminShopGetItems() ]); const topName = stats.topItems?.[0]?.name || '—'; - document.getElementById('shop-stats-grid').innerHTML = ` -
-
-
${stats.activeItems}/${stats.totalItems}
-
Товаров
-
-
-
-
${stats.totalPurchases}
-
Покупок
-
-
-
-
${stats.totalCoinsInCirculation}
-
Монет в обороте
-
-
-
-
${esc(topName)}
-
Топ товар
+ const stat = (cls, icon, ic, val, label, sm) => ` +
+ + + ${val} + ${label} +
`; + document.getElementById('shop-stats-grid').innerHTML = + stat('var(--violet)', 'shopping-bag', 'rgba(155,93,229,0.12)', `${stats.activeItems}/${stats.totalItems}`, 'товаров активно') + + stat('var(--cyan)', 'receipt', 'rgba(6,214,224,0.12)', stats.totalPurchases, 'покупок') + + stat('var(--green)', 'coins', 'rgba(6,214,100,0.12)', stats.totalCoinsInCirculation, 'монет в обороте') + + stat('#d98a17', 'star', 'rgba(255,179,71,0.16)', esc(topName), 'топ-товар', true); _shopItems = items; renderShopItems(); if (window.lucide) lucide.createIcons(); @@ -41,15 +40,36 @@ } } + function shopApplyFilters() { + _filterType = document.getElementById('shop-filter-type')?.value || ''; + _search = (document.getElementById('shop-search')?.value || '').trim().toLowerCase(); + renderShopItems(); + } + function renderShopItems() { const body = document.getElementById('shop-items-body'); - if (!_shopItems.length) { body.innerHTML = 'Нет товаров'; return; } - const typeLabels = { frame:'Рамка', title:'Титул', theme:'Тема', effect:'Эффект', background:'Фон' }; - body.innerHTML = _shopItems.map(it => ` - ${it.id} - ${esc(it.name)} - ${typeLabels[it.type] || esc(it.type)} - ${it.price} + const countEl = document.getElementById('shop-count'); + const filtered = _shopItems.filter(it => + (!_filterType || it.type === _filterType) && + (!_search || (it.name || '').toLowerCase().includes(_search)) + ); + if (countEl) countEl.textContent = filtered.length === _shopItems.length + ? `${_shopItems.length} товаров` + : `${filtered.length} из ${_shopItems.length}`; + if (!_shopItems.length) { body.innerHTML = 'Нет товаров'; return; } + if (!filtered.length) { body.innerHTML = 'Ничего не найдено'; return; } + body.innerHTML = filtered.map(it => ` + +
+ + + ${esc(it.name)} + ${it.description ? esc(it.description) : '#' + it.id} + +
+ + ${TYPE_LABELS[it.type] || esc(it.type)} + ${it.price} ${it.sold_count || 0}