Розробка опитувальника на сайті 1С-Бітрікс

Наша компанія займається розробкою, підтримкою та обслуговуванням рішень на Бітрікс та Бітрікс24 будь-якої складності. Від простих односторінкових сайтів до складних інтернет-магазинів, CRM систем з інтеграцією 1С та телефонії. Досвід розробників підтверджено сертифікатами від вендора.
Пропоновані послуги
Показано 1 з 1 послугУсі 1626 послуг
Розробка опитувальника на сайті 1С-Бітрікс
Середня
~1-2 тижні
Часті питання

Наші компетенції:

Етапи розробки

Останні роботи

  • image_website-b2b-advance_0.png
    Розробка сайту компанії B2B ADVANCE
    1262
  • image_bitrix-bitrix-24-1c_fixper_448_0.png
    Розробка веб-сайту для компанії ФІКСПЕР
    851
  • image_bitrix-bitrix-24-1c_development_of_an_online_appointment_booking_widget_for_a_medical_center_594_0.webp
    Розробка на базі Бітрікс, Бітрікс24, 1С для компанії Development of an Online
    585
  • image_bitrix-bitrix-24-1c_mirsanbel_458_0.webp
    Розробка на базі 1С Підприємство для компанії МИРСАНБЕЛ
    751
  • image_crm_dolbimby_434_0.webp
    Розробка сайту на CRM Бітрікс24 для компанії DOLBIMBY
    657
  • image_crm_technotorgcomplex_453_0.webp
    Розробка на базі Бітрікс24 для компанії ТЕХНОТОРГКОМПЛЕКС
    989

Розробка опитувальника на сайті 1С-Бітрікс

Опитувальник — інструмент збору зворотного зв'язку та дослідження аудиторії. На відміну від квізу, він не продає і не кваліфікує лідів — він вивчає: що думають клієнти про продукт, чому пішли, як оцінюють сервіс. Для бізнесу це цінні дані для прийняття рішень. Бітрікс не має готового інструмента для опитувань гідного рівня — вбудований модуль iblock можна використовувати для зберігання, але логіку опитування потрібно писати з нуля.

Типи опитувальників

NPS (Net Promoter Score) — «Наскільки ви готові рекомендувати нас?» Шкала 0–10, відкрите запитання для пояснення. Найпростіший у реалізації.

CSAT (Customer Satisfaction) — оцінка конкретної взаємодії (покупка, дзвінок підтримки). Короткий: 1 запитання + опціональний коментар.

Повноцінний опитувальник — кілька сторінок запитань, різні типи (шкала, множинний вибір, відкрита відповідь, матриця), розгалуження.

Структура даних

Зберігання через HL-блоки:

// Опитувальник
class SurveyTable extends \Bitrix\Main\ORM\Data\DataManager
{
    public static function getTableName(): string { return 'b_hl_surveys'; }

    public static function getMap(): array
    {
        return [
            new IntegerField('ID', ['primary' => true, 'autocomplete' => true]),
            new StringField('TITLE'),
            new StringField('SLUG'),
            new StringField('TYPE'),           // nps | csat | full
            new TextField('QUESTIONS_JSON'),   // Конфігурація запитань
            new StringField('TRIGGER'),        // page_load | exit_intent | scroll_50 | after_order
            new IntegerField('SHOW_DELAY'),    // Затримка показу в секундах
            new BooleanField('IS_ACTIVE', ['values' => [false, true]]),
            new DatetimeField('DATE_FROM'),
            new DatetimeField('DATE_TO'),
        ];
    }
}

// Відповіді
class SurveyResponseTable extends \Bitrix\Main\ORM\Data\DataManager
{
    public static function getTableName(): string { return 'b_hl_survey_responses'; }

    public static function getMap(): array
    {
        return [
            new IntegerField('ID', ['primary' => true, 'autocomplete' => true]),
            new IntegerField('SURVEY_ID'),
            new IntegerField('USER_ID'),       // NULL — анонімний
            new StringField('SESSION_ID'),
            new StringField('USER_IP'),
            new TextField('ANSWERS_JSON'),     // {question_id: answer}
            new IntegerField('COMPLETION_SEC'), // Час проходження
            new DatetimeField('CREATED_AT'),
        ];
    }
}

NPS-опитувальник: простий випадок

NPS найпростіший — одна сторінка, одна дія:

// /local/components/local/survey.nps/template.php
?>
<div class="nps-widget" id="nps-widget" style="display:none;">
    <div class="nps-container">
        <button class="nps-close" onclick="NPS.dismiss()">×</button>
        <p class="nps-question">
            Наскільки ви готові рекомендувати нас своїм знайомим?
        </p>
        <div class="nps-scale">
            <?php for ($i = 0; $i <= 10; $i++): ?>
                <button class="nps-score" data-score="<?= $i ?>"><?= $i ?></button>
            <?php endfor; ?>
        </div>
        <div class="nps-labels">
            <span>Точно не буду рекомендувати</span>
            <span>Обов'язково порекомендую</span>
        </div>
        <div class="nps-comment" style="display:none;">
            <textarea placeholder="Розкажіть детальніше..." id="nps-comment-text"></textarea>
            <button onclick="NPS.submit()">Надіслати</button>
        </div>
    </div>
</div>

<script>
const NPS = {
    surveyId: <?= (int)$arResult['SURVEY']['ID'] ?>,
    selectedScore: null,

    init() {
        // Показати через delay
        setTimeout(() => {
            if (!this.wasShown()) {
                document.getElementById('nps-widget').style.display = 'flex';
                this.markShown();
            }
        }, <?= (int)$arResult['SURVEY']['SHOW_DELAY'] * 1000 ?>);

        document.querySelectorAll('.nps-score').forEach(btn => {
            btn.addEventListener('click', e => {
                this.selectScore(parseInt(e.target.dataset.score));
            });
        });
    },

    selectScore(score) {
        this.selectedScore = score;
        document.querySelectorAll('.nps-score').forEach(b => b.classList.remove('selected'));
        document.querySelector(`[data-score="${score}"]`).classList.add('selected');
        document.querySelector('.nps-comment').style.display = 'block';
    },

    async submit() {
        if (this.selectedScore === null) return;

        await fetch('/local/ajax/survey_submit.php', {
            method: 'POST',
            headers: {'Content-Type': 'application/json'},
            body: JSON.stringify({
                survey_id: this.surveyId,
                answers: {
                    nps_score: this.selectedScore,
                    comment:   document.getElementById('nps-comment-text').value,
                },
                sessid: BX.bitrix_sessid(),
            }),
        });

        document.getElementById('nps-widget').innerHTML =
            '<p class="nps-thanks">Дякуємо за ваш відгук!</p>';
        setTimeout(() => document.getElementById('nps-widget').style.display = 'none', 3000);
    },

    dismiss() {
        document.getElementById('nps-widget').style.display = 'none';
        this.markShown();
    },

    wasShown() {
        return !!localStorage.getItem('nps_shown_' + this.surveyId);
    },

    markShown() {
        localStorage.setItem('nps_shown_' + this.surveyId, Date.now());
    },
};

NPS.init();
</script>

Тригери показу

Опитувальник має з'являтися в потрібний момент, а не одразу при завантаженні:

const SurveyTriggers = {
    exitIntent(callback) {
        document.addEventListener('mouseleave', e => {
            if (e.clientY <= 0) callback();
        }, {once: true});
    },

    scrollDepth(percent, callback) {
        const listener = () => {
            const scrolled = (window.scrollY / (document.body.scrollHeight - window.innerHeight)) * 100;
            if (scrolled >= percent) {
                window.removeEventListener('scroll', listener);
                callback();
            }
        };
        window.addEventListener('scroll', listener);
    },

    afterOrder(callback) {
        // Показати, якщо поточний URL — сторінка успішного оформлення замовлення
        if (window.location.href.includes('/order/success/')) {
            setTimeout(callback, 2000);
        }
    },
};

Аналітика відповідей

Для NPS — автоматично рахувати категорії:

class NpsAnalytics
{
    public static function calculate(int $surveyId): array
    {
        $responses = SurveyResponseTable::getList([
            'filter' => ['SURVEY_ID' => $surveyId],
            'select' => ['ANSWERS_JSON'],
        ])->fetchAll();

        $detractors = 0; // 0–6
        $passives   = 0; // 7–8
        $promoters  = 0; // 9–10
        $total      = 0;

        foreach ($responses as $r) {
            $answers = json_decode($r['ANSWERS_JSON'], true);
            $score   = (int)($answers['nps_score'] ?? -1);
            if ($score < 0) continue;
            $total++;

            if ($score <= 6) $detractors++;
            elseif ($score <= 8) $passives++;
            else $promoters++;
        }

        if ($total === 0) return ['nps' => 0, 'total' => 0];

        $nps = round(($promoters / $total - $detractors / $total) * 100);

        return [
            'nps'        => $nps,
            'total'      => $total,
            'promoters'  => $promoters,
            'passives'   => $passives,
            'detractors' => $detractors,
        ];
    }
}

Захист від повторних відповідей

  • Cookie/localStorage: не показувати повторно на тому ж пристрої (30 днів).
  • За user_id: якщо користувач авторизований — перевірити, чи немає вже запису в b_hl_survey_responses з цим USER_ID та SURVEY_ID.
  • За email: якщо потрібна анонімна, але без повторів — запросити email перед опитуванням і перевірити.

Терміни розробки

Варіант Склад Термін
NPS-віджет Шкала 0–10, коментар, аналітика 2–3 дні
CSAT-опитування Після замовлення/звернення, оцінка + текст 2–4 дні
Повноцінний опитувальник Різні типи запитань, тригери, звіти 8–14 днів