Компонент расписания врачей на 1С-Битрикс: кеширование и интеграция

Наша компания занимается разработкой, поддержкой и обслуживанием решений на Битрикс и Битрикс24 любой сложности. От простых одностраничных сайтов до сложных интернет магазинов, CRM систем с интеграцией 1С и телефонии. Опыт разработчиков подтвержден сертификатами от вендора.
Услуги, которые мы предлагаем
Показано 1 из 1Все 1626 услуг
Компонент расписания врачей на 1С-Битрикс: кеширование и интеграция
Простой
~1 день
Часто задаваемые вопросы

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

Этапы разработки

Последние работы

  • image_website-b2b-advance_0.webp
    Разработка сайта компании B2B ADVANCE
    1357
  • image_bitrix-bitrix-24-1c_fixper_448_0.webp
    Разработка веб-сайта для компании ФИКСПЕР
    944
  • 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 Appointment Booking Widget for a Medical Center
    693
  • image_bitrix-bitrix-24-1c_mirsanbel_458_0.webp
    Разработка на базе 1С Предприятие для компании МИРСАНБЕЛ
    829
  • image_crm_dolbimby_434_0.webp
    Разработка сайта на CRM Битрикс24 для компании DOLBIMBY
    731
  • image_crm_technotorgcomplex_453_0.webp
    Разработка на базе Битрикс24 для компании ТЕХНОТОРГКОМПЛЕКС
    1074

Страница врача с текстом «Записаться по телефону» — это потерянный онлайн-трафик. Пользователь хочет видеть конкретные доступные дни и часы, а не звонить в регистратуру. Отображение расписания — отдельная задача от онлайн-записи: расписание должно быть наглядным, быстрым и актуальным, даже если кнопка «Записаться» ведет к звонку. Мы проектируем архитектуру так, чтобы данные подгружались из МИС или HL-блоков, кешировались с автоинвалидацией и отдавались в адаптивном UI. В этой статье — наш подход с реальным кодом и кейсами для клиник с 50+ врачами.

Почему готовые решения не подходят?

Большинство готовых модулей Маркетплейса либо показывают пустую таблицу, либо требуют ручного ввода слотов. Они не интегрируются с внутренней МИС, не учитывают сложные правила приёма (повторяющиеся шаблоны, отгулы). В результате — либо устаревшие данные, либо долгая загрузка страницы до 10 секунд.

Какие проблемы решаем?

  1. Консистентность данных. Расписание должно синхронизироваться с МИС (1С:Медицина, МедМикс, iMed) через REST или SQL. Если в МИС изменили график, на сайте изменения появляются в пределах TTL кеша (2–5 минут), а не через сутки.
  2. Производительность. Страница списка врачей (50+ специалистов) не должна грузиться 10 секунд. Используем один SQL-запрос для ближайшей даты, кешируем результат тегированно. При AJAX-навигации — фоновое обновление через \Bitrix\Main\Data\Cache.
  3. Мобильная адаптация. Слайдер дат на мобильных — не просто горизонтальный скролл, а компонент с touch-событиями. Для десктопа — недельная сетка с зелёными ячейками.

Как мы реализуем компонент расписания

Стек: PHP 8.1, Bitrix ORM, HL-блоки (local_doctor_slots), тегированный кеш. Компонент local:doctor.schedule с параметрами DOCTOR_ID, WEEKS_AHEAD, VIEW_TYPE. Алгоритм загрузки слотов: каждый слот — запись HL-блока с полями DOCTOR_ID, SLOT_DATE, SLOT_TIME, STATUS, PATIENT_ID (если занят), SOURCE (manual/api). HL-блоки проходят фильтрацию в 5–10 раз быстрее инфоблоков на больших выборках (50k+ записей).

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

Компонент расписания

/local/components/local/doctor.schedule/class.php:

class DoctorScheduleComponent extends CBitrixComponent
{
    public function executeComponent(): void
    {
        $doctorId  = (int)($this->arParams['DOCTOR_ID'] ?? 0);
        $weeksAhead = (int)($this->arParams['WEEKS_AHEAD'] ?? 2);

        if (!$doctorId) {
            $this->arResult = ['ERROR' => 'Doctor not specified'];
            $this->includeComponentTemplate();
            return;
        }

        $dateFrom = new \DateTime();
        $dateTo   = (clone $dateFrom)->modify("+{$weeksAhead} weeks");
        $slots = $this->loadSlots($doctorId, $dateFrom, $dateTo);
        $scheduleByDate = [];
        foreach ($slots as $slot) {
            $date = $slot['SLOT_DATE'];
            if (!isset($scheduleByDate[$date])) {
                $scheduleByDate[$date] = [
                    'date'        => $date,
                    'day_name'    => $this->getDayName(new \DateTime($date)),
                    'free_count'  => 0,
                    'slots'       => [],
                ];
            }
            $scheduleByDate[$date]['slots'][] = $slot;
            if ($slot['STATUS'] === 'free') {
                $scheduleByDate[$date]['free_count']++;
            }
        }
        $nextFreeSlot = $this->getNextFreeSlot($slots);
        $this->arResult = [
            'DOCTOR_ID'      => $doctorId,
            'SCHEDULE'       => $scheduleByDate,
            'NEXT_FREE_SLOT' => $nextFreeSlot,
            'DATE_FROM'      => $dateFrom->format('Y-m-d'),
            'DATE_TO'        => $dateTo->format('Y-m-d'),
        ];
        $this->setResultCacheKeys(['SCHEDULE', 'NEXT_FREE_SLOT']);
        $this->includeComponentTemplate();
    }

    private function loadSlots(int $doctorId, \DateTime $from, \DateTime $to): array
    {
        return LocalDoctorSlotsTable::getList([
            'filter' => [
                'DOCTOR_ID'   => $doctorId,
                '>=SLOT_DATE' => $from->format('Y-m-d'),
                '<=SLOT_DATE' => $to->format('Y-m-d'),
            ],
            'order'  => ['SLOT_DATE' => 'ASC', 'SLOT_TIME' => 'ASC'],
            'select' => ['ID', 'SLOT_DATE', 'SLOT_TIME', 'STATUS'],
        ])->fetchAll();
    }
}

Кеширование

Расписание — данные, которые меняются при новой записи. Кешируем с автоинвалидацией:

$this->arParams['CACHE_TYPE'] = 'A';
$this->arParams['CACHE_TIME'] = 120;
// При создании записи сбрасываем кеш компонента для врача
\CBitrixComponent::clearComponentCache('local:doctor.schedule', '', ['DOCTOR_ID' => $doctorId]);

Для AJAX-запросов при переключении недели используем отдельный кеш через \Bitrix\Main\Data\Cache.

Шаблон: недельная сетка

templates/.default/template.php:

$today = new \DateTime();
$daysOfWeek = ['Пн', 'Вт', 'Ср', 'Чт', 'Пт', 'Сб', 'Вс'];
?>
<div class="doctor-schedule" data-doctor-id="<?= $arResult['DOCTOR_ID'] ?>">
    <div class="schedule-nav">
        <button class="schedule-prev" data-offset="-7">← Предыдущая неделя</button>
        <button class="schedule-next" data-offset="7">Следующая неделя →</button>
    </div>
    <div class="schedule-grid">
        <?php foreach ($arResult['SCHEDULE'] as $dateStr => $dayData): ?>
            <?php
            $dateObj   = new \DateTime($dateStr);
            $isPast    = $dateObj < $today;
            $dayOfWeek = (int)$dateObj->format('N') - 1;
            ?>
            <div class="schedule-day <?= $isPast ? 'past' : '' ?> <?= $dayData['free_count'] > 0 ? 'has-slots' : 'no-slots' ?>">
                <div class="day-header">
                    <span class="day-name"><?= $daysOfWeek[$dayOfWeek] ?></span>
                    <span class="day-date"><?= $dateObj->format('d.m') ?></span>
                </div>
                <?php if ($dayData['free_count'] > 0): ?>
                    <div class="slots-container">
                        <?php foreach ($dayData['slots'] as $slot): ?>
                            <?php if ($slot['STATUS'] === 'free'): ?>
                                <button class="slot-btn free"
                                        data-slot-id="<?= $slot['ID'] ?>"
                                        data-time="<?= substr($slot['SLOT_TIME'], 0, 5) ?>">
                                    <?= substr($slot['SLOT_TIME'], 0, 5) ?>
                                </button>
                            <?php endif; ?>
                        <?php endforeach; ?>
                    </div>
                    <div class="day-free-count"><?= $dayData['free_count'] ?> места</div>
                <?php else: ?>
                    <div class="no-slots-label">Нет записи</div>
                <?php endif; ?>
            </div>
        <?php endforeach; ?>
    </div>
    <?php if ($arResult['NEXT_FREE_SLOT']): ?>
        <div class="next-available">
            Ближайшая свободная запись:
            <strong><?= date('d.m.Y', strtotime($arResult['NEXT_FREE_SLOT']['SLOT_DATE'])) ?></strong>
            в <strong><?= substr($arResult['NEXT_FREE_SLOT']['SLOT_TIME'], 0, 5) ?></strong>
        </div>
    <?php endif; ?>
</div>

AJAX-подгрузка при переключении недели

document.querySelectorAll('.schedule-prev, .schedule-next').forEach(btn => {
    btn.addEventListener('click', async function() {
        const doctorId  = document.querySelector('.doctor-schedule').dataset.doctorId;
        const offset    = parseInt(this.dataset.offset);
        const dateFrom  = new Date(currentDateFrom);
        dateFrom.setDate(dateFrom.getDate() + offset);
        const res = await fetch('/local/ajax/doctor-schedule.php', {
            method: 'POST',
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify({
                doctor_id: doctorId,
                date_from: dateFrom.toISOString().split('T')[0],
                sessid: BX.bitrix_sessid()
            })
        });
        const data = await res.json();
        renderScheduleGrid(data.schedule);
        currentDateFrom = dateFrom;
    });
});

Отображение расписания на странице списка врачей

На странице каталога врачей полное расписание не нужно — достаточно индикатора «Ближайшая запись: завтра». Это один SQL-запрос по всем врачам:

SELECT DOCTOR_ID, MIN(CONCAT(SLOT_DATE, ' ', SLOT_TIME)) as NEXT_FREE_SLOT
FROM local_doctor_slots
WHERE STATUS = 'free' AND SLOT_DATE >= CURDATE()
GROUP BY DOCTOR_ID

Как интегрировать расписание с МИС?

Интеграция с МИС — ключевой этап. Если МИС предоставляет REST API, настраиваем агент с периодичностью 1-5 минут. При прямом SQL-доступе — создаём материализованное представление или триггеры. В любом случае, после синхронизации сбрасываем тегированный кеш соответствующего врача.

Что входит в работу?

  • Проектирование схемы HL-блоков и системы кеширования.
  • Разработка компонента local:doctor.schedule с двумя шаблонами (недельная сетка и список).
  • Настройка AJAX-подгрузки и мобильного слайдера.
  • Интеграция с МИС (REST/SQL) и агент синхронизации.
  • Тестирование на реальных данных (от 50 врачей) и нагрузочное тестирование.
  • Документация по эксплуатации и администрированию.

Сравнение шаблонов отображения

Параметр Недельная сетка Список дат
Подходит для Плотное расписание (терапевты) Редкие слоты (хирурги)
Информативность Показывает все занятые и свободные слоты Фокусируется на доступных датах
Мобильная адаптация Слайдер дат с touch-событиями Вертикальный список
Скорость загрузки Требует больше данных (все слоты) Меньше данных (только даты)

Производительность: HL-блоки vs Инфоблоки

Параметр HL-блоки Инфоблоки
Время запроса 50k записей ~150 мс ~800 мс
Гибкость индексов Индексы на любые поля Только стандартные
Сложность интеграции Простая ORM Требует метаполей
Подходит для Табличных данных (слоты) Контентных данных (новости)

Согласно документации Битрикс, HL-блоки оптимизированы для табличных данных и выполняют выборку в 5–10 раз быстрее инфоблоков.

Типичные ошибки при реализации

  • Хранить расписание в инфоблоке (медленная фильтрация). Используем HL-блоки — ORM работает быстрее, индексы ставить проще.
  • Не инвалидировать кеш при записи через админку или API. Используем события OnAfterAdd/Update/Delete HL-блока.
  • Игнорировать часовые пояса. Врачи могут работать в разных филиалах — храним время в UTC, преобразуем на клиенте.

Как начать?

Мы реализовали 20+ проектов для клиник с гарантией производительности. Свяжитесь — обсудим ваш проект и покажем demo с вашими данными. Получите консультацию бесплатно.

Создание сайтов для медицины на 1С-Битрикс: клиники и врачи

Самая коварная интеграция в медицинских проектах — синхронизация расписания с МИС. МЕДИАЛОГ отдаёт слоты через SOAP, ИНФОКЛИНИКА — через REST с авторизацией по токену, 1С:Медицина — через COM-объект или веб-сервис. Каждая из них по-своему интерпретирует свободный слот: с учётом буферного времени или без, с блокировкой на обед или нет. Если не учесть эти нюансы — получаешь двойные бронирования и разъярённых пациентов в регистратуре. Мы строим медицинские решения на 1С-Битрикс с детальной проработкой именно этого слоя — интеграций с МИС, ЛИС и страховыми. За 10 лет мы запустили более 50 медицинских проектов, включая клиники со штатом 100+ врачей. Получите консультацию — свяжитесь с нами, приложите список используемых МИС, и мы назовём точные сроки в течение одного рабочего дня.

Почему интеграция с МИС — главный риск проекта?

70% сложности медицинского сайта — это слой синхронизации с внешними системами. Остальное — по сути обычный Битрикс с инфоблоками и ORM. Но если МИС отдаёт данные с задержкой или в своём формате, пациент видит «нет свободных окон» при пустом расписании. Мы решаем это двухуровневым кэшированием: данные из МИС кешируются тегированным кэшем на 2 минуты, а агент обновляет расписание каждые 3 минуты. Компромисс между нагрузкой на сервер и актуальностью доказан на проектах с 50+ врачами. Проверка показала, что такой подход снижает нагрузку на сервер на 40% по сравнению с прямыми запросами к МИС в реальном времени.

Типы медицинских проектов

Сайты клиник и медцентров. Не визитка, а рабочий инструмент записи:

  • Каталог услуг через инфоблок с привязкой к прайс-листу из 1С:Медицина.
  • Профили врачей: специализации, стаж, сертификаты — всё из справочника МИС, не дублируем вручную.
  • Онлайн-запись с реальным расписанием через двустороннюю синхронизацию.
  • Личный кабинет пациента: история визитов, результаты анализов, назначения. Данные тянутся по patient_id из МИС.
  • Калькулятор стоимости программ обследования — компонент с выборкой из b_iblock_element с ценами.
  • Раздел ДМС и профосмотров для корпоративных клиентов.

Лабораторные порталы. Главное — скорость выдачи результатов:

  • Каталог исследований с правилами подготовки и сроками.
  • Онлайн-заказ: выбор лаборатории или вызов на дом.
  • Личный кабинет с результатами в PDF и интерактивными графиками динамики показателей (chart.js по данным из ЛИС).
  • Интерпретация: нормы, отклонения, рекомендации — формируются автоматически по референсным значениям.
  • Интеграция с ЛИС для автопубликации результатов. Пациент получает push, а не ждёт звонка.
  • Чек-апы — комплексные программы из нескольких исследований.

Аптечные интернет-магазины. E-commerce с фармацевтической спецификой — нельзя просто прикрутить корзину:

  • Каталог с привязкой к ГРЛС (государственный реестр лекарственных средств) — обязательное требование.
  • Рецептурные vs безрецептурные: разная логика оформления. Рецептурные — только бронь с выдачей в аптеке, дистанционная продажа запрещена ФЗ-61.
  • Интеграция с «Честный ЗНАК» / МДЛП — маркировка, без неё аптека не работает.
  • Проверка наличия и цен в аптеках сети через API складской системы.
  • Аналоги и дженерики: сравнение по МНН (международное непатентованное наименование).

Телемедицина. Не перспективное направление, а обязательный канал:

  • Видеоконференции через WebRTC с шифрованием.
  • Электронные рецепты, направления.
  • Чат: текст, фото, документы — хранение в зашифрованном виде.
  • Интеграция с ЭМК (электронной медкартой).
  • Расписание онлайн-консультаций и оплата через sale.paysystem.

Онлайн-запись к врачу — главный камень преткновения

Именно здесь ломается большинство медицинских проектов. Пациент не дозвонился — ушёл к конкурентам. Модуль записи должен работать безупречно.

Расписание — свободные слоты с учётом длительности приёма по типу услуги. Не абстрактное «есть окошко», а конкретный интервал из МИС. Синхронизация каждые 2-3 минуты — компромисс между нагрузкой и актуальностью.

Многоканальная запись — сайт, мобильное приложение, Telegram-бот, виджет. Все каналы бьют в один эндпоинт API, который ставит блокировку слота через SELECT ... FOR UPDATE до подтверждения.

Напоминания — SMS через sms.ru или smsc.ru API за 24 часа и за 2 часа. Снижают неявки на 30-40%.

Отмена и перенос — из личного кабинета, без звонка. Слот освобождается в МИС автоматически.

Антиколлизии — двойные бронирования исключены на уровне транзакций БД. Если МИС и сайт одновременно пытаются занять слот — выигрывает тот, кто первый закоммитил.

Сравнение популярных МИС

Параметр МЕДИАЛОГ ИНФОКЛИНИКА 1С:Медицина
Протокол SOAP (WSDL) REST + OAuth COM-объект / CommerceML
Скорость синхронизации 5-10 сек на запрос 1-3 сек 2-5 сек (зависит от объёма)
Документация Закрытая, только по договору Открытая Swagger Корпоративная
Поддержка таймзон Нет, требует ручного учёта Есть, но с багами Встроенная
Типичные ошибки Разрыв соединения при больших выгрузках Неверный часовой пояс слотов Конфликт блокировок при параллельной записи

REST API ИНФОКЛИНИКИ быстрее SOAP МЕДИАЛОГа в 2-3 раза, но требует аккуратной обработки таймзон. Готовые модули на Битрикс сокращают время интеграции с МИС в 3-4 раза по сравнению с разработкой с нуля. Наша библиотека обёрток для этих МИС включает отлов 95% типовых ошибок.

Как обеспечить соответствие 152-ФЗ при разработке?

Медицинские данные — особая категория ПДн по 152-ФЗ. Утечка диагноза — не просто штраф, а уголовная ответственность по ст. 137 УК РФ.

Процедура получения согласия Согласно ст. 10 152-ФЗ, обработка специальных категорий ПДн допускается только при наличии согласия в письменной форме. Мы реализуем это через модуль согласий в Битрикс с привязкой к каждой записи. Форма включает checkbox «Согласие на обработку ПДн» и ссылку на политику. Данные согласия хранятся в отдельном HL-блоке с привязкой к пользователю и времени создания.
  • Федеральный закон 152-ФЗ — полный комплект: согласие на обработку, политика, уведомление Роскомнадзора. Не формальная галочка, а рабочие документы.
  • Врачебная тайна — разграничение через роли Битрикс: CUser::GetUserGroup(). Медкарту видит лечащий врач и заведующий отделением, регистратор — только расписание.
  • Шифрование — TLS 1.3, шифрование чувствительных полей в БД через pgcrypto (PostgreSQL) или AES в application layer.
  • Аудит доступа — журнал в b_event_log: кто, когда, к каким записям обращался. Обработчик на каждый SELECT к таблицам с медданными.
  • Проактивная защита — WAF Битрикс, контроль целостности filechecker, мониторинг аномалий.
  • Хостинг — ЦОД уровня Tier III, сертифицированный для обработки медицинских данных. Аттестованная ИСПДн.

Интеграции с медицинскими системами

Это 70% сложности проекта. Остальное — по сути обычный Битрикс.

МИС:

  • МЕДИАЛОГ — SOAP-сервисы, синхронизация расписания, записей, данных пациентов. Документация закрытая, работаем по WSDL.
  • ИНФОКЛИНИКА — REST API с OAuth. Более современный интерфейс, но свои особенности с таймзонами.
  • 1С:Медицина — обмен через веб-сервис или CommerceML. Прайс-листы, финансовые данные, отчётность.
  • N3.Здоровье (ЕГИСЗ) — передача данных в единую государственную систему. Обязательное требование для лицензированных ЛПУ.

ЛИС:

  • Автоматическая выгрузка результатов в ЛК — по webhook или polling. Пациент получает push-уведомление.
  • Графики динамики для регулярных анализов (глюкоза, холестерин) — визуализация трендов.

Страховые:

  • Проверка полиса ДМС и лимитов в реалтайме через API страховой.
  • Автосогласование услуг.
  • Выгрузка реестров для оплаты — формат зависит от страховой, у каждой свой XSD.

SEO для медицинских сайтов

YMYL-тематика. Google и Яндекс предъявляют повышенные требования, и текст с ключевиками тут не работает.

  • E-E-A-T — контент пишется или верифицируется врачами. Указаны квалификации, ссылки на источники (PubMed, клинические рекомендации).
  • Schema.org — разметка MedicalOrganization, Physician, MedicalProcedure, MedicalCondition. Реализуем через компонент, генерирующий JSON-LD из данных инфоблока.
  • Локальное SEO — Google Мой Бизнес, Яндекс.Бизнес, карты, агрегация отзывов.
  • ФЗ «О рекламе» — обязательное предупреждение о противопоказаниях на каждой странице услуги. Автоматическая вставка через шаблон компонента.

Мобильная адаптация

Более 70% пациентов ищут врача с телефона. Неудобная запись с мобильного = потерянный пациент.

  • Mobile-first дизайн, приоритет на формы записи.
  • Кнопки «Позвонить» и «Записаться» — sticky на экране.
  • Запись в 2-3 касания.
  • PWA с push-уведомлениями через Service Worker + FCM.
  • Оптимизация: Lighthouse Performance > 90 на мобильных сетях.

Что входит в результат

Каждый проект сопровождается комплектом документации и гарантийной поддержкой:

  • Техническое задание с описанием интеграций (подписанное обеими сторонами).
  • Доступы ко всем внешним сервисам (МИС, платежные шлюзы, СМС-провайдеры) — настройка и тестирование.
  • Обучение администраторов работе в админке Битрикс (2-3 сессии по 2 часа).
  • Схема БД с индексами, описание агентов и событий.
  • Гарантия 12 месяцев на выявленные ошибки интеграции.
  • Поддержка по SLA: критические инциденты — 4 часа.

Сроки и стоимость

Стоимость рассчитывается индивидуально в зависимости от числа интеграций и сложности бизнес-процессов. Основная часть времени уходит на интеграцию с МИС и тестирование пограничных сценариев записи. Сам сайт на Битриксе — типовая задача, но слой медицинской логики поверх него требует глубокого погружения в предметную область.

Тип проекта Сроки
Сайт-визитка клиники 2-4 недели
Сайт с онлайн-записью и интеграцией МИС 2-3 месяца
Лабораторный портал 2-4 месяца
Телемедицинская платформа 3-6 месяцев
Аптечный интернет-магазин 3-5 месяцев

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