Розробка інтерактивної таблиці цін на Vue.js для 1С-Бітрікс
Прайс-лист на Бітрікс — задача, яка на перший погляд вирішується через bitrix:catalog.section із шаблоном таблиці. Проблеми з'являються одразу, як до статичного виведення додаються вимоги: фільтрація рядків без перезавантаження, сортування за колонками, перемикання типів цін (роздріб/опт/дилер), розрахунок підсумкової суми при виборі позицій. Серверний рендеринг і jQuery-постобробка тут масштабуються погано — кожен новий інтерактивний елемент вимагає окремого обробника та ручної синхронізації DOM.
Архітектура таблиці цін
Vue-компонент PriceTable отримує масив позицій з Бітрікса через window.BX_STATE.products. Дані формуються в result_modifier.php з модуля catalog:
$priceIterator = \Bitrix\Catalog\PriceTable::getList([
'filter' => ['=CATALOG_GROUP_ID' => $priceTypeId, '=PRODUCT_ID' => $productIds],
'select' => ['PRODUCT_ID', 'PRICE', 'CURRENCY'],
]);
Кожна позиція в масиві містить: id, name, article, unit, набір цін за типами, залишок на складі, характеристики для фільтрації.
Реактивні можливості таблиці:
Фільтрація рядків через computed:
const filteredProducts = computed(() => {
return products.value
.filter(p => selectedCategory.value ? p.categoryId === selectedCategory.value : true)
.filter(p => searchQuery.value
? p.name.toLowerCase().includes(searchQuery.value.toLowerCase())
|| p.article.toLowerCase().includes(searchQuery.value.toLowerCase())
: true
)
.filter(p => showInStock.value ? p.stock > 0 : true);
});
Все обчислюється локально — немає запитів до сервера при кожній взаємодії. Для прайс-листа на 500–2000 позицій це працює миттєво.
Сортування через sortKey та sortDirection refs. Клік по заголовку колонки перемикає напрямок. Числові та рядкові колонки обробляються окремо.
Перемикання типів цін. Бітрікс зберігає кілька цін на товар у таблиці b_catalog_price (поле CATALOG_GROUP_ID). Усі типи цін передаються в JSON:
const activePriceType = ref('retail'); // 'retail' | 'wholesale' | 'dealer'
const displayPrice = (product) => product.prices[activePriceType.value];
Зміна типу ціни — миттєва реактивна заміна без сервера.
Вибір позицій і розрахунок суми
Для B2B-прайсів часто потрібна можливість відмітити позиції та отримати підсумкову суму або відправити запит. Чекбокси на кожному рядку, selectedIds — Set у ref():
const total = computed(() =>
[...selectedIds.value]
.map(id => products.value.find(p => p.id === id))
.filter(Boolean)
.reduce((sum, p) => sum + displayPrice(p) * (quantities[p.id] || 1), 0)
);
Поле кількості на рядку — v-model на quantities[product.id]. Зміна кількості миттєво перераховує підсумок. При натисканні «Відправити запит» — POST на бітриксовий обробник із масивом {id, qty, price}.
Віртуальний скрол для великих прайсів
Прайс-лист на 5000+ позицій не можна рендерити повністю — браузер гальмує. Віртуалізація через @vueuse/virtual-list або vue-virtual-scroller: у DOM одночасно присутньо лише 50–100 видимих рядків, решта обчислюються на льоту. Фільтрація та пошук працюють по повному масиву в пам'яті — лише рендер віртуальний.
Кейс: інтерактивний прайс дистриб'ютора
Дистриб'ютор будівельних матеріалів, прайс на 3800 позицій, три типи цін (роздріб, дрібний опт, великий опт), фільтр за брендом і категорією, пошук за артикулом.
Попереднє рішення: Excel-файл для завантаження, оновлювався вручну раз на тиждень. Спроба зробити HTML-таблицю через bitrix:catalog.section упиралася в те, що сторінка вантажилася 8 секунд (3800 рядків у DOM), а пошуку не було взагалі.
Рішення: Vue-компонент із віртуальним скролом. Дані завантажуються одним AJAX-запитом при монтуванні компонента — Бітрікс-контролер повертає JSON із повним прайсом (~400 КБ, gzip ~80 КБ). Запит кешується в sessionStorage — повторне відкриття сторінки миттєве.
Перемикання типу ціни доступне лише авторизованим користувачам із потрібною групою — перевірка у Vue через window.BX_STATE.userGroups, додатково на сервері при кожному запиті. Неавторизованим показується лише роздрібна ціна.
Результат: час до інтерактивності — 1,2 секунди (завантаження JSON + рендер). Пошук за артикулом — миттєвий. Менеджери перестали розсилати Excel.
Експорт і друк
«Завантажити прайс» — не окрема сторінка, а генерація CSV у браузері з поточного відфільтрованого та відсортованого набору:
function exportCsv() {
const rows = filteredProducts.value.map(p =>
[p.article, p.name, displayPrice(p), p.unit].join(';')
);
const blob = new Blob(['\uFEFF' + rows.join('\n')], { type: 'text/csv;charset=utf-8' });
// ... download link
}
BOM \uFEFF — обов'язковий для коректного відкриття в Excel на Windows.
Етапи та терміни
| Функціональність | Орієнтовний термін |
|---|---|
| Базова таблиця з сортуванням і пошуком | 2-3 дні |
| Фільтрація + перемикання типів цін | 3-5 днів |
| Вибір позицій + розрахунок суми + відправка | 4-6 днів |
| Віртуалізація для 3000+ позицій | +2-3 дні |
| Експорт CSV/Excel | +1 день |
Розробка ведеться ітераційно — базові функції в першу чергу, розширення після погодження.







