Система розыгрышей среди бустеров вашего канала или группы

В данной статье мы разберём создание системы розыгрышей за голоса (бусты) на ваши ресурсы через мини-приложение на PuzzleBot. Рассмотрим оформление дизайна, техническая реализация и настройка баз данных для запуска системы.

Система розыгрышей среди бустеров вашего канала или группы

В качестве среды разработки мы используем сервис PuzzleBot, а в качестве базы данных – NocoDB. При желании можно выбрать другую базу данных.

Демонстрация визуальной части

Опробовать функционал можно тут - t.me/StructurePuzzleBot/contest

Разработка

NocoDB

Для начала создадим базу данных NocoDB (назовём её "Розыгрыш") с двумя таблицами:

1. Создадим таблицу "Участники". Она будет содержать следующие столбцы:

  • user_id — число — данный столбец будет содержать ID участника розыгрыша.
  • user_name — текст — данный столбец будет содержать имя участника.
  • number — число — данный столбец будет содержать порядковый номер участника, что будет необходимо для определения победителя случайным образом.
Система розыгрышей среди бустеров вашего канала или группы

2. Создадим таблицу "Победители" со столбцами:

  • user_id — число — данный столбец будет содержать ID победителя.
  • user_name — текст — данный столбец будет содержать имя победителя.
Система розыгрышей среди бустеров вашего канала или группы

Переменные

Создадим следующие переменные:

Глобальные:

  • members_num – числовая – значение по умолчанию "0" – эта переменная позволит задавать порядковый номер участникам.
Система розыгрышей среди бустеров вашего канала или группы

Персональные:

  • winners_list – интегрированная: NocoDB – значение по умолчанию "none" (кавычки писать не надо):

Выберите базу данных "Розыгрыш"
Выберите таблицу "Победители"
Откройте дополнительные настройки и переключите параметр "Вариант поиска" на "Все"
В поле "Значение" выберите тип "Строка"
В качестве разделителя укажите "\n" (без кавычек)
В поле "Шаблон" введите:

[[user_name]] – Название приза
Система розыгрышей среди бустеров вашего канала или группы
  • contest_decription – формула:
if({{winners_list}} != "none" , {{winners_list}}, "Произвольный текст описания конкурса.")

Я же использовал формулу:

if({{winners_list}} != "none" , {{winners_list}}, "1 мая в 15:00 бот определит одного победителя среди отдавших голос каналу <a href=\"https://t.me/RDGlessons?boost\">RDG :// Lessons</a> пользователей, который получит <a href=\"tg://premium_offer\" target=\"_blank\">Telegram Premium на 6 месяцев</a>.")
  • member_num – текстовая
  • random_member – формула:
random({{members_num}})
Система розыгрышей среди бустеров вашего канала или группы
  • get_random_member_id – интегрированная: NocoDB:

Выберите базу данных "Розыгрыш"
Выберите таблицу "Участники"
Добавьте фильтр соответствия столбца number и переменной {{member_num}}
В поле "Название столбца" выберите "user_id"

Система розыгрышей среди бустеров вашего канала или группы
  • get_random_member_name – интегрированная: NocoDB:

Выберите базу данных "Розыгрыш"
Выберите таблицу "Участники"
Добавьте фильтр соответствия столбца number и переменной {{member_num}}
В поле "Название столбца" выберите "user_name"

Система розыгрышей среди бустеров вашего канала или группы

Конструктор

Для разработки достаточно 5 команд.
Для разработки достаточно 5 команд.

1. Создадим мини-приложение "Вступление в розыгрыш"
Данное мини-приложение будет нести ознакомительный характер, поэтому его можно заполнить любой информацией. Я же заполнил следующими несколькими HTML блоками:

<head> <script src="https://unpkg.com/@lottiefiles/lottie-player@1.7.0/dist/lottie-player.js"></script> <style> .container { width: 100%; height: 250px; background: radial-gradient(circle, #96D9FF, #34A2FA); display: flex; flex-direction: column; align-items: center; justify-content: center; text-align: center; position: absolute; left: 0; right: 0; top: 0; overflow: hidden; } .lottie-animation { width: 160px; height: auto; z-index: 2; } .text { color: #FFFFFF; font-weight: 500; letter-spacing: -0.5px; margin-top: 12px; z-index: 2; } .title { font-size: 15px; } .date { font-size: 13px; color: rgba(255, 255, 255, 0.6); } .particle, .star { position: absolute; top: 50%; left: 50%; width: 6px; height: 6px; background: rgba(255, 255, 255, 0.5); border-radius: 50%; pointer-events: none; animation: float 3s linear forwards; z-index: 1; } .star { width: 8px; height: 8px; background: rgba(255, 255, 255, 0.7); transform: rotate(45deg); border-radius: 2px; } @keyframes float { 0% { transform: translate(0, 0) scale(1); opacity: 1; } 100% { transform: translate(var(--x), var(--y)) scale(0.5); opacity: 0; } } </style> </head> <body> <div class="container"> <lottie-player class="lottie-animation" src="https://s3.pxsto.re/static/bluegift.json" background="transparent" speed="1" autoplay></lottie-player> <div class="text title">Розыгрыш Telegram Premium</div> <div class="text date">1 мая 2025 в 15:00</div> </div> <script> const container = document.querySelector('.container'); function createParticle(isStar = false) { const particle = document.createElement('div'); particle.className = isStar ? 'star' : 'particle'; const angle = Math.random() * 2 * Math.PI; const radius = 100 + Math.random() * 50; const x = Math.cos(angle) * radius + 'px'; const y = Math.sin(angle) * radius + 'px'; particle.style.setProperty('--x', x); particle.style.setProperty('--y', y); particle.style.animationDuration = (2 + Math.random() * 2) + 's'; container.appendChild(particle); setTimeout(() => { particle.remove(); }, 4000); } setInterval(() => { createParticle(Math.random() < 0.3); }, 200); </script> </body>

Этот HTML-блок создаёт красивое вступление с Lottie-анимацией, градиентным фоном и частицами на заднем плане. Также в text title и text date можно указать заголовок и дату окончания розыгрыша соответственно.

<head> <style> .winner-title { font-size: 14px; font-weight: bold; color: rgba(0, 0, 0, 0.5); margin-bottom: 10px; } .winner-description { font-size: 15px; color: #000000; line-height: 22px; } .winner-description a { color: #007AFF; font-weight: inherit; } </style> </head> <body> <div style="margin-top: 230px;"> <div class="winner-title">1 ПОБЕДИТЕЛЬ</div> <div class="winner-description">{{contest_decription}}</div> </div> </body>

Этот HTML-блок будет отображать дополнительную информацию о розыгрыше. Если розыгрыш завершён в этом блоке будет отображаться список победителей. Заголовок winner-title можно изменить, а описание советую менять в формуле переменной contest_decription.

Добавьте фиксированную клавиатуру с двумя кнопками:

  • "Отдать голос" – ссылка (браузер по умолчанию). Укажите ссылку на ресурс формата https://t.me/username?boost. Нажатие на эту кнопку откроет окно "Голосов" ресурса.
  • "Участвовать" — кнопка-условие. Введите название кнопки-условия: "Участвовать в конкурсе". Ниже мы разберём её настройку.
Система розыгрышей среди бустеров вашего канала или группы

2. Создадим кнопку-условие "Участвовать в конкурсе" со следующими правилами:

Правило 1:

Создайте условие проверки значения переменной.
Укажите следующее выражение: winners_list – полное совпадение – "-none" (кавычки писать не надо).
В "Название кнопки" введите "Розыгрыш завершён"
В действиях выберите: "Без действия"

Правило 2:

Создайте условие проверки строки NocoDB.
Выберите базу данных "Розыгрыш"
Выберите таблицу "Участники"
Добавьте фильтр с выражением, проверяющим соответствие поля user_id с переменной {{USER_ID_TEXT}}
В "Название кнопки" введите "Вы уже участвуете"
В действиях выберите: "Без действия"

Исключающее правило:

В "Название кнопки" введите "Участвовать"
В действиях добавьте "Отправить команду или условие" и введите условие "Проверка голоса". Создание и настройку этого условия мы разберём ниже.

Система розыгрышей среди бустеров вашего канала или группы
Система розыгрышей среди бустеров вашего канала или группы

3. Создадим условие "Проверка голоса"

В правиле добавим проверку "Голос для ресурсов (Boost)"
Выберите ресурсы, которым необходимо будет дать голос
Дополнительно можно указать количество голосов на каждый ресурс или в сумме.

В действиях:
Добавим действие изменение переменной members_num по выражению +1

Добавим действие "Создать строку (NocoDB)"

Выберем базу "Розыгрыш"
Выберем таблицу "Участники"
Заполним поля следующим образом:

  • user_id: {{USER_ID_TEXT}}
  • user_name: {{FIRST_AND_LAST_NAME}}
  • number: {{members_num}}

Добавим действие "Переход к мини-приложению" и укажите мини-приложение "Теперь в розыгрыше". Позже мы разберём её создание.

Исключающее правило:
Добавим действие "Переход к мини-приложению" и укажите мини-приложение "Условия не выполнены". Ниже мы разберём её создание.

Система розыгрышей среди бустеров вашего канала или группы

4. Создадим два мини-приложения: "Теперь в розыгрыше" и "Условия не выполнены". Технически эти мини-приложения очень похожи – единственное, что в них будет отличаться, это текст попапа.

Создайте в обоих мини-приложениях HTML блок с кодом:

<head> <style> .popup { position: fixed; top: 0; left: 0; width: 100%; height: 100%; background-color: rgba(0, 0, 0, 0.5); display: flex; justify-content: center; align-items: center; z-index: 9999; visibility: visible; opacity: 1; transition: opacity 0.3s ease, visibility 0.3s ease; } /* Стиль содержимого попапа */ .popup-content { background-color: rgba(242, 242, 242, 1); border-radius: 14px; padding: 16px 0; text-align: center; width: 300px; /* Можно настроить ширину по желанию */ } .popup-info h2 { font-size: 17px; font-weight: bold; margin-bottom: 8px; } .popup-info p { font-size: 13px; font-weight: regular; margin-bottom: 16px; } .popup-divider { border: none; border-top: 1px solid rgba(0, 0, 0, 0.1); margin: 16px 0; } .popup-button { font-size: 17px; color: rgba(0, 122, 255, 1); text-decoration: none; display: block; cursor: pointer; font-weight: inherit; } .popup-button:hover { text-decoration: underline; } </style> </head> <body> <div id="popup" class="popup"> <div class="popup-content"> <div class="popup-info" style="padding: 0 16px;"> <h2>Успешно!</h2> <p>Теперь вы участвуете в розыгрыше. О результатах сообщим в день окончания розыгрыша.</p> </div> <hr class="popup-divider"> <a goto_web_page="miniAppId" class="popup-button">Закрыть</a> </div> </div> <script> window.onload = function() { const popup = document.getElementById('popup'); setTimeout(() => { popup.style.visibility = 'visible'; popup.style.opacity = 1; }, 0); }; </script> </body>

Замените в этом коде miniAppId на ID мини-приложения "Вступление в розыгрыш". Чтобы получить данный ID, необходимо опубликовать изменения, открыть мини-приложение "Вступление в розыгрыш" и скопировать значение после startapp= в ссылке для его открытия. Оно выглядит примерно так: c3a4efad48231cd3.

Затем измените тексты попапа в полях h2 и p в мини-приложении "Условия не выполнены" на тексты, подобные: "Условия не выполнены. Повторите попытку, выполнив условия."

Добавьте в обоих мини-приложениях блок "Подставновка" и в поле "Название Мини-приложения" введите "Вступление в розыгрыш". Это позволит сделать эффект всплывающего попапа над основным мини-приложением.

Система розыгрышей среди бустеров вашего канала или группы

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

Действия:
Добавьте действие "Изменить переменную" и введите выражение member_num = {{random_member}}
Добавьте действие "Создать строку (NocoDB)":

Выберите базу данных "Розыгрыш"
Выберите таблицу "Победители"
Введите следующие значения для столбцов:

  • user_id: {{get_random_member_id}}
  • user_name: {{get_random_member_name}}

По желанию можно добавить действие отправки команды с поздравлением с включенной опцией "Выполнить другому пользователю", в поле получателя введите {{get_random_member_id}}. Таким образом победитель получит уведомление.

Система розыгрышей среди бустеров вашего канала или группы

Всё готово 🎉

Больше уроков, кейсов и познавательных материалов:

Мой личный телеграм:

44
11
11