Как создать простую систему напоминаний для пользователя в 1С без использования БСП

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

В процессе разработки самописных конфигураций на платформе 1С часто возникает задача внедрения механизмов уведомлений или напоминаний. Использование Библиотеки стандартных подсистем (БСП) не всегда оправдано: это может перегрузить конфигурацию лишними объектами или потребовать сложного процесса внедрения. Рассмотрим, как реализовать эффективную и легкую систему напоминаний, используя только базовые возможности платформы 1С:Предприятие 8.3.

Архитектура решения: где хранить данные

Первый вопрос, который возникает при проектировании: какой объект метаданных использовать для хранения текста и времени напоминания? В обсуждении предлагались варианты с использованием ХранилищаЗначений, однако для клиент-серверной базы на SQL это не самый оптимальный путь. Регистр Сведений (РС) является идеальным кандидатом для этой задачи.

Проанализируем структуру нашего регистра. Для того чтобы система работала быстро даже при большом количестве пользователей, нам необходимо создать непериодический независимый регистр сведений (назовем его НапоминанияПользователей) со следующими полями:

  1. Измерение: Пользователь (Тип: СправочникСсылка.Пользователи). Индексация по этому полю обязательна.
  2. Измерение: ВремяНапоминания (Тип: Дата, состав даты: Дата и время). Это позволит нам быстро выбирать записи, срок которых наступил.
  3. Ресурс: ТекстСообщения (Тип: Строка, неограниченной длины или фиксированной, если сообщения короткие).
  4. Ресурс: Идентификатор (Тип: УникальныйИдентификатор или Строка). Поможет нам точно удалять или изменять конкретное напоминание.

Важно помнить, что использование индексов по полям Пользователь и ВремяНапоминания критически важно для производительности SQL-запроса, который будет выполняться в цикле каждые 20-30 секунд.

Настройка проверки напоминаний на клиенте

Для того чтобы напоминание всплыло у пользователя вовремя, необходимо периодически опрашивать сервер. Мы разберем, как реализовать это через ПодключитьОбработчикОжидания. Эту процедуру лучше всего инициировать при старте системы.

В модуле управляемого приложения пропишем следующий код:


Процедура ПриНачалеРаботыСистемы()
    // Подключаем проверку каждые 30 секунд. 
    // Интервал можно регулировать в зависимости от нагрузки на сервер.
    ПодключитьОбработчикОжидания("ПроверитьНаличиеНапоминаний", 30, Ложь);
КонецПроцедуры

Процедура ПроверитьНаличиеНапоминаний() Экспорт
    // Вызываем серверную функцию для получения данных
    ДанныеНапоминания = ОбщегоНазначенияСервер.ПолучитьАктуальноеНапоминание();
    
    Если ДанныеНапоминания = Неопределено Тогда
        Возврат;
    КонецЕсли;
    
    // Если данные получены, выводим их пользователю
    ПоказатьОповещениеПользователя("Напоминание!", , ДанныеНапоминания.Текст, БиблиотекаКартинок.Информация);
    
    // Если нужно интерактивное окно с кнопкой "ОК" или "Отложить"
    // ОткрытьФорму("Обработка.Напоминания.Форма.ФормаУведомления", ДанныеНапоминания);
КонецПроцедуры

Реализация серверной логики поиска сообщений

Теперь выясним причину, по которой серверный вызов должен быть максимально "легким". Поскольку 30 и более пользователей будут одновременно стучаться к базе каждые полминуты, запрос должен выполняться мгновенно. Рассмотрим пример серверной функции в общем модуле (с установленной галочкой Вызов сервера):


Функция ПолучитьАктуальноеНапоминание() Экспорт
    Запрос = Новый Запрос;
    Запрос.Текст = 
        "ВЫБРАТЬ ПЕРВЫЕ 1
        |	НапоминанияПользователей.ТекстСообщения КАК Текст,
        |	НапоминанияПользователей.ВремяНапоминания КАК Время
        |ИЗ
        |	РегистрСведений.НапоминанияПользователей КАК НапоминанияПользователей
        |ГДЕ
        |	НапоминанияПользователей.Пользователь = &ТекущийПользователь
        |	И НапоминанияПользователей.ВремяНапоминания <= &ТекущаяДата";
    
    Запрос.УстановитьПараметр("ТекущийПользователь", Пользователи.ТекущийПользователь());
    Запрос.УстановитьПараметр("ТекущаяДата", ТекущаяДата());
    
    РезультатЗапроса = Запрос.Выполнить();
    
    Если РезультатЗапроса.Пустой() Тогда
        Возврат Неопределено;
    КонецЕсли;
    
    Выборка = РезультатЗапроса.Выбрать();
    Выборка.Следующая();
    
    СтруктураДанных = Новый Структура("Текст, Время", Выборка.Текст, Выборка.Время);
    
    // Сразу удаляем запись, чтобы она не всплывала повторно
    НаборЗаписей = РегистрыСведений.НапоминанияПользователей.СоздатьНаборЗаписей();
    НаборЗаписей.Отбор.Пользователь.Установить(Пользователи.ТекущийПользователь());
    НаборЗаписей.Отбор.ВремяНапоминания.Установить(Выборка.Время);
    НаборЗаписей.Записать();
    
    Возврат СтруктураДанных;
КонецФункции

Методы оптимизации и улучшения пользовательского опыта

Рассмотрим подробнее несколько важных нюансов, которые сделают вашу систему более профессиональной:

1. Использование всплывающих окон (Оповещений). Вместо блокирующего модального окна лучше использовать метод ПоказатьОповещениеПользователя. Это позволяет пользователю продолжить ввод данных в текущем документе, не отвлекаясь на закрытие лишних форм.

2. Обработка пропущенных событий. Проанализируем ситуацию: пользователь выключил компьютер в 17:00, а напоминание было назначено на 18:00. При входе в систему на следующее утро в 09:00 программа должна сразу показать это сообщение. Наше условие в запросе ВремяНапоминания <= &ТекущаяДата успешно решает эту задачу.

3. Снижение нагрузки через параметры сеанса. Чтобы не делать запрос к таблицам SQL при каждом срабатывании таймера, можно использовать кэширование. Например, при записи нового напоминания устанавливать в параметре сеанса ЕстьАктивныеНапоминания = Истина. Обработчик ожидания сначала проверит этот параметр, и только если он Истина, пойдет в базу данных.

4. Функционал "Отложить". Разберем по шагам, как это работает:

Особенности работы в клиент-серверном варианте

Посмотрим на ситуацию, когда один и тот же пользователь работает в нескольких сеансах (например, на компьютере и на терминальном сервере). В стандартной реализации напоминание всплывет во всех окнах. Если это критично, добавим в Регистр Сведений измерение НомерСеанса. При создании напоминания будем записывать туда НомерСеансаИнформационнойБазы(), а в запросе на получение данных добавлять фильтр по этому номеру. Так сообщение придет именно в то окно, где оно было инициировано.

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

← На главную