При разработке интерфейсов на управляемых формах 1С часто возникает задача визуального выделения строк в динамическом списке в зависимости от времени. Например, нам нужно подсветить задачи, срок которых истекает через 10 минут, или выделить просроченные документы. Основная сложность здесь заключается в том, что «текущее время» постоянно меняется, а условное оформление (УО) должно реагировать на эти изменения динамически.
В этой статье мы подробно разберем, как правильно реализовать такую задачу, проанализируем типичные ошибки новичков и рассмотрим наиболее эффективные методы с точки зрения производительности системы.
Рассмотрим ситуацию, с которой столкнулся автор темы. Ему требовалось закрасить строку в желтый цвет, если ВремяСдачи находится в промежутке между текущей датой и текущей датой минус 10 минут. Первая попытка реализации заключалась в том, чтобы при каждом срабатывании обработчика ожидания полностью пересоздавать элементы условного оформления в коде.
Проанализируем пример кода, который часто используют начинающие разработчики:
&НаСервере
Процедура ОбновленияОтображенияПросрочкиНаСервере()
// Получаем коллекцию элементов условного оформления
УО = ЭтотОбъект.Список.КомпоновщикНастроек.ФиксированныеНастройки.УсловноеОформление.Элементы;
// Удаляем старое оформление, чтобы не плодить дубли
Для каждого Стр Из УО Цикл
Если Стр.Представление = "Отбор_просрочки10" Тогда
УО.Удалить(Стр);
Прервать;
КонецЕсли;
КонецЦикла;
// Создаем новый элемент оформления
ЭлементУО10 = УО.Добавить();
ЭлементУО10.Представление = "Отбор_просрочки10";
ЭлементУО10.Использование = Истина;
ЭлементУО10.Оформление.УстановитьЗначениеПараметра("ЦветФона", WebЦвета.Желтый);
// Пытаемся задать интервал
ЭлементУсловия10 = ЭлементУО10.Отбор.Элементы.Добавить(Тип("ЭлементОтбораКомпоновкиДанных"));
ЭлементУсловия10.ЛевоеЗначение = Новый ПолеКомпоновкиДанных("ВремяСдачи");
ЭлементУсловия10.ВидСравнения = ВидСравненияКомпоновкиДанных.ИнтервалВключаяГраницы;
ЭлементУсловия10.ПравоеЗначение = Новый СтандартныйПериод(ТекущаяДата() - 600, ТекущаяДата());
КонецПроцедуры
Важный момент: Такой подход крайне неэффективен. Постоянное удаление и добавление элементов в ФиксированныеНастройки заставляет платформу каждый раз пересчитывать оформление для всех строк списка, что может привести к «мерцанию» интерфейса и избыточной нагрузке на сервер.
Часто программисты путают два похожих перечисления: ВидСравнения и ВидСравненияКомпоновкиДанных. Для настройки динамических списков (которые базируются на Системе Компоновки Данных) необходимо использовать исключительно ВидСравненияКомпоновкиДанных.
Кроме того, использование ВидСравненияКомпоновкиДанных.ИнтервалВключаяГраницы требует правильного заполнения правого значения. Если вы хотите использовать интервал в отборе, в ПравоеЗначение нельзя просто передать число или дату — система ожидает тип, поддерживающий границы (например, массив или специфический объект), либо вам нужно добавить два отдельных элемента отбора: один с видом «Больше или равно», другой — «Меньше или равно».
Наиболее профессиональный и производительный способ — перенести логику во временные параметры динамического списка. Выясним причину, почему это лучше: при изменении параметра 1С не перерисовывает все оформление с нуля, а лишь обновляет данные в соответствии с новым значением переменной.
Шаг 1. Изменим запрос динамического списка. Добавим в текст запроса вычисляемое поле или просто обеспечим наличие нужных полей для отбора. Но еще лучше — использовать параметры напрямую в настройках УО.
Шаг 2. Настроим условное оформление один раз. Это можно сделать в конфигураторе или программно при открытии формы. Мы установим условие, что ВремяСдачи должно быть больше или равно параметру &НачалоИнтервала и меньше или равно параметру &КонецИнтервала.
Шаг 3. Обновление параметров в обработчике ожидания. Теперь нам достаточно просто обновлять значения параметров.
&НаКлиенте
Процедура ПриОткрытии(Отказ)
// Подключаем обновление каждые 60 секунд
ПодключитьОбработчикОжидания("ОбновитьПараметрыВремени", 60);
КонецПроцедуры
&НаКлиенте
Процедура ОбновитьПараметрыВремени()
ТекущийМомент = ТекущаяДатаСеанса();
НачалоЖелтойЗоны = ТекущийМомент - 600; // 10 минут назад
// Устанавливаем параметры в список
Список.Параметры.УстановитьЗначениеПараметра("НачалоИнтервала", НачалоЖелтойЗоны);
Список.Параметры.УстановитьЗначениеПараметра("КонецИнтервала", ТекущийМомент);
КонецПроцедуры
Если вам все же необходимо создать условие программно, не используя параметры запроса, разберем, как правильно реализовать условие «МЕЖДУ» через добавление нескольких элементов отбора в одну группу.
Проанализируем ситуацию: нам нужно, чтобы выполнялись оба условия одновременно. Для этого в отборе условного оформления используется группа.
// Создаем элемент УО
ЭлементУО = Список.КомпоновщикНастроек.УсловноеОформление.Элементы.Добавить();
ЭлементУО.Оформление.УстановитьЗначениеПараметра("ЦветФона", WebЦвета.Желтый);
// Создаем группу условий (И)
ГруппаУсловий = ЭлементУО.Отбор.Элементы.Добавить(Тип("ГруппаЭлементовОтбораКомпоновкиДанных"));
ГруппаУсловий.ТипГруппы = ТипГруппыЭлементовОтбораКомпоновкиДанных.ГруппаИ;
// Условие 1: ВремяСдачи >= ТекущаяДата - 10 мин
Элемент1 = ГруппаУсловий.Элементы.Добавить(Тип("ЭлементОтбораКомпоновкиДанных"));
Элемент1.ЛевоеЗначение = Новый ПолеКомпоновкиДанных("ВремяСдачи");
Элемент1.ВидСравнения = ВидСравненияКомпоновкиДанных.БольшеИлиРавно;
Элемент1.ПравоеЗначение = ТекущаяДата() - 600;
// Условие 2: ВремяСдачи <= ТекущаяДата
Элемент2 = ГруппаУсловий.Элементы.Добавить(Тип("ЭлементОтбораКомпоновкиДанных"));
Элемент2.ЛевоеЗначение = Новый ПолеКомпоновкиДанных("ВремяСдачи");
Элемент2.ВидСравнения = ВидСравненияКомпоновкиДанных.МеньшеИлиРавно;
Элемент2.ПравоеЗначение = ТекущаяДата();
Рассмотрим подробнее несколько нюансов, которые помогут сделать ваше решение стабильным:
ТекущаяДата() возвращает время сервера. Если сервер находится в другом часовом поясе, расчет интервалов будет неверным. ТекущаяДатаСеанса() всегда учитывает часовой пояс пользователя.ВЫБОР КОГДА.... Тогда условное оформление будет максимально простым: Если Статус = 1 Тогда Цвет = Желтый.Посмотрим на пример реализации через запрос:
// Текст запроса динамического списка
ВЫБОР
КОГДА ВремяСдачи < &ТекущийМомент ТОГДА "Просрочено"
КОГДА РАЗНОСТЬДАТ(&ТекущийМомент, ВремяСдачи, МИНУТА) МЕЖДУ 0 И 10 ТОГДА "Скоро"
ИНАЧЕ "ВРаботе"
КОНЕЦ КАК СостояниеСрока
В этом случае вам остается только раз в минуту обновлять параметр &ТекущийМомент, а 1С автоматически перекрасит строки согласно настроенному в конфигураторе УО для поля СостояниеСрока.
Таким образом, мы проанализировали различные подходы к динамическому оформлению. Использование параметров и вычисляемых полей является наиболее надежным и «чистым» методом разработки, который позволит вашему приложению работать быстро даже при большом количестве данных в списке.