К содержанию

Оптовый каталог стройхимии на 617 позиций

Сайт-каталог для оптового склада: прайс из Excel превращается в рабочий каталог одной командой, заявка собирается списком, а фотографии не нужны, чтобы всё заработало.

Год
2026
Роль
Дизайн, разработка, инструменты
Стек
HTML · CSS · JavaScript · Python · Cloudflare Workers
617
позиций в каталоге, 19 товарных групп
5 мс
фильтрация всего прайса при вводе
1
команда для обновления цен из Excel
0
фотографий нужно, чтобы запуститься

Что это

Сайт оптового поставщика строительной химии: монтажные пены, герметики, клеи, скотчи — 617 позиций, девятнадцать товарных групп, тридцать один бренд. Клиенты — розничные магазины, монтажные бригады и подрядчики, которые закупаются коробами, а не штуками.

Заказчик и его реквизиты в этом разборе не называются: проект клиентский, и я показываю только инженерную часть — с чем пришли, что мешало и как решилось. Скриншоты сделаны на копии с обезличенными данными.

С чем пришли

Прайс жил в Excel и рассылался файлом. Клиент открывал таблицу на 617 строк, искал нужное глазами, выписывал позиции в мессенджер, менеджер вручную считал сумму. На каждой заявке терялось время с обеих сторон, а половина запросов приходила в виде «а есть пена 65-я? а сколько?».

Отдельная сложность: фотографий товара не было почти ни на что. Ждать, пока поставщики пришлют контент на шестьсот позиций, значило не запуститься никогда.

Что сделано

Каталог собирается из прайса скриптом. Обновились цены — запускается одна команда, и скрипт на Python перечитывает исходный Excel, разбирает категории, фасовку и наличие, и перезаписывает файл данных. Никакой ручной переноски: файл прайса остаётся единственным источником правды, а сайт — его отражением.

Поиск и фильтры работают мгновенно. Весь каталог лежит в одном файле данных и фильтруется прямо в браузере: ввод в строку поиска отсекает лишнее за пять миллисекунд. Никакого сервера, никаких запросов при каждом нажатии клавиши. Есть фильтр по брендам, по группам и переключатель «только то, что на складе».

Заявка собирается списком. Клиент отмечает позиции кнопкой «В заявку», проставляет количество коробов и отправляет весь список одним сообщением — менеджер получает готовый перечень, а не переписку в двадцать реплик. Заявка уходит в Telegram через ретранслятор на Cloudflare Workers, токен бота при этом в код сайта не попадает.

Фотографии перестали быть условием запуска. Каждой позиции рисуется этикетка её товарной группы: цветная пиктограмма с цифрой фасовки. Выглядит намеренно, весит ноль, каталог выглядит целым с первого дня. Реальные фото добавляются по одной — файл кладётся в папку, скрипт сам сопоставляет его с позицией по имени или по названию товара.

Где было больно

Прайс оказался не таблицей, а документом. В нём встречались строки-заголовки категорий, объединённые ячейки, разнобой в написании фасовки и позиции без цены. Разбор пришлось делать терпимым к грязи: строка, где заполнено только наименование, считается заголовком группы; позиция без цены не выбрасывается, а помечается как «под заказ». Скрипт, который падает на реальном файле заказчика, бесполезен, каким бы правильным он ни был.

Две разные аудитории на одном сайте. Главная должна продавать — там тёмная сцена склада с паллетой и крупные цифры. Каталог должен работать — там светлый плотный список, где на экран влезает максимум строк. Попытка сделать их в едином оформлении портила и то, и другое, поэтому страницы намеренно разошлись по стилю: витрина отдельно, рабочий инструмент отдельно.

Что получилось

Каталог грузится меньше чем за секунду и весит около 140 КБ вместе со шрифтами — на телефоне в поле, где связь плохая, это разница между «открылось» и «закрыл».

Обновление цен занимает одну команду вместо ручной правки шестисот строк. Сайт остаётся статикой: его можно положить на любой хостинг, он не требует базы данных, панели администратора и обслуживания.

Отдельно сделаны оферта и политика обработки данных — для оптовой торговли с юрлицами это не формальность, а условие работы.

Экраны

Снимки рабочей системы, а не макеты. Нажмите на любой — откроется во весь экран.