Как программно настроить условное оформление в динамическом списке для выделения строк по временному интервалу

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

При разработке интерфейсов на управляемых формах 1С часто возникает задача визуального выделения строк в динамическом списке в зависимости от времени. Например, нам нужно подсветить задачи, срок которых истекает через 10 минут, или выделить просроченные документы. Основная сложность здесь заключается в том, что «текущее время» постоянно меняется, а условное оформление (УО) должно реагировать на эти изменения динамически.

В этой статье мы подробно разберем, как правильно реализовать такую задачу, проанализируем типичные ошибки новичков и рассмотрим наиболее эффективные методы с точки зрения производительности системы.

Проблема программного изменения условного оформления

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

Проанализируем пример кода, который часто используют начинающие разработчики:


&НаСервере
Процедура ОбновленияОтображенияПросрочкиНаСервере()
    // Получаем коллекцию элементов условного оформления
    УО = ЭтотОбъект.Список.КомпоновщикНастроек.ФиксированныеНастройки.УсловноеОформление.Элементы;

    // Удаляем старое оформление, чтобы не плодить дубли
    Для каждого Стр Из УО Цикл
        Если Стр.Представление = "Отбор_просрочки10" Тогда
            УО.Удалить(Стр);
            Прервать;
        КонецЕсли;
    КонецЦикла;

    // Создаем новый элемент оформления
    ЭлементУО10 = УО.Добавить();
    ЭлементУО10.Представление = "Отбор_просрочки10";
    ЭлементУО10.Использование = Истина;
    ЭлементУО10.Оформление.УстановитьЗначениеПараметра("ЦветФона", WebЦвета.Желтый);

    // Пытаемся задать интервал
    ЭлементУсловия10 = ЭлементУО10.Отбор.Элементы.Добавить(Тип("ЭлементОтбораКомпоновкиДанных"));
    ЭлементУсловия10.ЛевоеЗначение = Новый ПолеКомпоновкиДанных("ВремяСдачи");
    ЭлементУсловия10.ВидСравнения = ВидСравненияКомпоновкиДанных.ИнтервалВключаяГраницы;
    ЭлементУсловия10.ПравоеЗначение = Новый СтандартныйПериод(ТекущаяДата() - 600, ТекущаяДата());
КонецПроцедуры

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

Разбор ошибки «Несоответствие типов»

Часто программисты путают два похожих перечисления: ВидСравнения и ВидСравненияКомпоновкиДанных. Для настройки динамических списков (которые базируются на Системе Компоновки Данных) необходимо использовать исключительно ВидСравненияКомпоновкиДанных.

Кроме того, использование ВидСравненияКомпоновкиДанных.ИнтервалВключаяГраницы требует правильного заполнения правого значения. Если вы хотите использовать интервал в отборе, в ПравоеЗначение нельзя просто передать число или дату — система ожидает тип, поддерживающий границы (например, массив или специфический объект), либо вам нужно добавить два отдельных элемента отбора: один с видом «Больше или равно», другой — «Меньше или равно».

Решение 1: Использование параметров в запросе (Рекомендуемый способ)

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

Шаг 1. Изменим запрос динамического списка. Добавим в текст запроса вычисляемое поле или просто обеспечим наличие нужных полей для отбора. Но еще лучше — использовать параметры напрямую в настройках УО.

Шаг 2. Настроим условное оформление один раз. Это можно сделать в конфигураторе или программно при открытии формы. Мы установим условие, что ВремяСдачи должно быть больше или равно параметру &НачалоИнтервала и меньше или равно параметру &КонецИнтервала.

Шаг 3. Обновление параметров в обработчике ожидания. Теперь нам достаточно просто обновлять значения параметров.


&НаКлиенте
Процедура ПриОткрытии(Отказ)
    // Подключаем обновление каждые 60 секунд
    ПодключитьОбработчикОжидания("ОбновитьПараметрыВремени", 60);
КонецПроцедуры

&НаКлиенте
Процедура ОбновитьПараметрыВремени()
    ТекущийМомент = ТекущаяДатаСеанса();
    НачалоЖелтойЗоны = ТекущийМомент - 600; // 10 минут назад

    // Устанавливаем параметры в список
    Список.Параметры.УстановитьЗначениеПараметра("НачалоИнтервала", НачалоЖелтойЗоны);
    Список.Параметры.УстановитьЗначениеПараметра("КонецИнтервала", ТекущийМомент);
КонецПроцедуры

Решение 2: Программное создание сложного условия (Группа отбора)

Если вам все же необходимо создать условие программно, не используя параметры запроса, разберем, как правильно реализовать условие «МЕЖДУ» через добавление нескольких элементов отбора в одну группу.

Проанализируем ситуацию: нам нужно, чтобы выполнялись оба условия одновременно. Для этого в отборе условного оформления используется группа.


// Создаем элемент УО
ЭлементУО = Список.КомпоновщикНастроек.УсловноеОформление.Элементы.Добавить();
ЭлементУО.Оформление.УстановитьЗначениеПараметра("ЦветФона", WebЦвета.Желтый);

// Создаем группу условий (И)
ГруппаУсловий = ЭлементУО.Отбор.Элементы.Добавить(Тип("ГруппаЭлементовОтбораКомпоновкиДанных"));
ГруппаУсловий.ТипГруппы = ТипГруппыЭлементовОтбораКомпоновкиДанных.ГруппаИ;

// Условие 1: ВремяСдачи >= ТекущаяДата - 10 мин
Элемент1 = ГруппаУсловий.Элементы.Добавить(Тип("ЭлементОтбораКомпоновкиДанных"));
Элемент1.ЛевоеЗначение = Новый ПолеКомпоновкиДанных("ВремяСдачи");
Элемент1.ВидСравнения = ВидСравненияКомпоновкиДанных.БольшеИлиРавно;
Элемент1.ПравоеЗначение = ТекущаяДата() - 600;

// Условие 2: ВремяСдачи <= ТекущаяДата
Элемент2 = ГруппаУсловий.Элементы.Добавить(Тип("ЭлементОтбораКомпоновкиДанных"));
Элемент2.ЛевоеЗначение = Новый ПолеКомпоновкиДанных("ВремяСдачи");
Элемент2.ВидСравнения = ВидСравненияКомпоновкиДанных.МеньшеИлиРавно;
Элемент2.ПравоеЗначение = ТекущаяДата();

Оптимизация производительности и важные советы

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

  1. Используйте ТекущаяДатаСеанса(): В клиент-серверном варианте ТекущаяДата() возвращает время сервера. Если сервер находится в другом часовом поясе, расчет интервалов будет неверным. ТекущаяДатаСеанса() всегда учитывает часовой пояс пользователя.
  2. Приоритет оформления: Помните, что если строка удовлетворяет условиям нескольких элементов оформления, применится тот, который находится ниже в списке. Сначала настраивайте общие правила (например, для всех будущих дат — зеленый), а затем более частные (например, интервал в 10 минут — желтый).
  3. Частота обновлений: Не ставьте период обработчика ожидания слишком маленьким. Для задач мониторинга времени сдачи обычно достаточно 30 или 60 секунд. Посекундное обновление создаст ненужную нагрузку на базу данных.
  4. Вычисляемые поля в запросе: Для очень больших списков лучше всего вычислять «Статус» (0 — норма, 1 — внимание, 2 — просрочка) прямо в SQL-запросе динамического списка с помощью конструкции ВЫБОР КОГДА.... Тогда условное оформление будет максимально простым: Если Статус = 1 Тогда Цвет = Желтый.

Посмотрим на пример реализации через запрос:


// Текст запроса динамического списка
ВЫБОР
    КОГДА ВремяСдачи < &ТекущийМомент ТОГДА "Просрочено"
    КОГДА РАЗНОСТЬДАТ(&ТекущийМомент, ВремяСдачи, МИНУТА) МЕЖДУ 0 И 10 ТОГДА "Скоро"
    ИНАЧЕ "ВРаботе"
КОНЕЦ КАК СостояниеСрока

В этом случае вам остается только раз в минуту обновлять параметр &ТекущийМомент, а 1С автоматически перекрасит строки согласно настроенному в конфигураторе УО для поля СостояниеСрока.

Таким образом, мы проанализировали различные подходы к динамическому оформлению. Использование параметров и вычисляемых полей является наиболее надежным и «чистым» методом разработки, который позволит вашему приложению работать быстро даже при большом количестве данных в списке.

← На главную