Разработчики часто сталкиваются с задачей отображения графического индикатора или вычисляемого статуса в форме списка справочника или документа. Хорошо, когда статус хранится в реквизите объекта и его можно легко вытащить обычным запросом. Но как быть, если статус — это результат сложного алгоритма, который зависит от множества факторов (истории согласования, наличия прикрепленных файлов, состояния задач) и вычисляется тяжелой процедурой?
В этой статье мы подробно разберем, как решить эту задачу оптимальным способом, проанализируем архитектурные ошибки и рассмотрим различные варианты реализации: от быстрого вывода «на лету» до правильного проектирования системы с кэшированием данных.
Прежде чем перейти к коду, давайте выясним причину, почему разработчики часто совершают грубую архитектурную ошибку. В попытках быстро решить задачу многие прибегают к обработчику события динамического списка ПриПолученииДанныхНаСервере и вызывают в нем тяжелые экспортные функции (например, генерацию печатных форм или сложные запросы по всей базе данных) для каждой строки списка.
Почему так делать нельзя:
ПриПолученииДанныхНаСервере срабатывает каждый раз при открытии списка, его прокрутке (скроллинге), активизации строки или обновлении.Рассмотрим по шагам три основных метода решения этой задачи: от архитектурно правильного до быстрых визуальных обходных путей.
---
Самый надежный способ вывести статус в динамический список без потери производительности — сделать так, чтобы этот статус всегда был готов для чтения в запросе. Для этого применяется механизм кэширования данных.
Мы создаем вспомогательный объект метаданных, куда записываем вычисленный статус один раз при изменении состояния документа, а динамический список просто считывает готовое значение.
Разберем этот процесс по шагам:
Шаг 1. Создание регистра сведений
Создадим непериодический независимый регистр сведений СостоянияДокументов:
Документ (тип: ДокументСсылка.ВнутреннийДокумент).Статус (тип: ПеречислениеСсылка.СтатусыСогласования или Строка);ИндексКартинки (тип: Число) — для быстрого вывода иконки.Шаг 2. Запись актуального статуса (кэширование)
Необходимо внедрить вызов функции расчета статуса в транзакцию записи или изменения бизнес-процесса. Например, в подписку на событие ПриЗаписи документа или в обработчики завершения задач согласования:
Процедура ЗаписатьСтатусДокументаВКэш(СсылкаНаДокумент) Экспорт
// Получаем статус с помощью нашей сложной тяжелой функции
ПараметрыПечати = Новый Структура;
ВычисленныйСтатус = ИнтеграцияСогласования.ВычислитьСтатусДокумента(СсылкаНаДокумент);
// Определяем индекс картинки для динамического списка
ИндексКартинки = 0;
Если ВычисленныйСтатус = "Согласовано" Тогда
ИндексКартинки = 1; // Зеленая галочка
ИначеЕсли ВычисленныйСтатус = "НаСогласовании" Тогда
ИндексКартинки = 2; // Желтый маркер
ИначеЕсли ВычисленныйСтатус = "Отказ" Тогда
ИндексКартинки = 3; // Красный крестик
КонецЕсли;
// Записываем данные в регистр сведений
МенеджерЗаписи = РегистрыСведений.СостоянияДокументов.СоздатьМенеджерЗаписи();
МенеджерЗаписи.Документ = СсылкаНаДокумент;
МенеджерЗаписи.Статус = ВычисленныйСтатус;
МенеджерЗаписи.ИндексКартинки = ИндексКартинки;
МенеджерЗаписи.Записать(Истина);
КонецПроцедуры
Шаг 3. Интеграция в Динамический список
Теперь мы можем изменить текст запроса динамического списка. Свяжем основную таблицу документов с нашим регистром сведений по левому соединению:
ВЫБРАТЬ
Документ.Ссылка КАК Ссылка,
Документ.Номер КАК Номер,
Документ.Дата КАК Дата,
ЕСТЬNULL(КэшСостояний.ИндексКартинки, 0) КАК ИндексКартинки,
ЕСТЬNULL(КэшСостояний.Статус, "Новый") КАК Статус
ИЗ
Документ.ВнутреннийДокумент КАК Документ
ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.СостоянияДокументов КАК КэшСостояний
ПО КэшСостояний.Документ = Документ.Ссылка
При таком подходе производительность формы списка останется максимальной. Система мгновенно получает готовое число и строку из БД без выполнения тяжелого программного кода при каждом скроллинге.
---
Если кэширование внедрить сложно или расчет статуса все-таки достаточно легковесный (например, простая проверка реквизитов связанных объектов без тяжелых циклов), мы можем использовать стандартный обработчик динамического списка ПриПолученииДанныхНаСервере.
Разберем, как вывести полноценную иконку (картинку) вместо текстового статуса.
Шаг 1. Создание общей картинки
В конфигураторе создайте новую общую картинку (например, КоллекцияСтатусовСогласования). Она должна представлять собой вертикальный или горизонтальный набор картинок одинакового размера (например, 16x16 пикселей), идущих друг за другом.
Шаг 2. Настройка элемента формы
СтатусКартинка с типом значения Число).ОбщаяКартинка.КоллекцияСтатусовСогласования.Шаг 3. Программное заполнение индекса картинки
В модуле формы списка определим обработчик события динамического списка:
&НаСервере
Процедура СписокПриПолученииДанныхНаСервере(ИмяЭлемента, Настройки, Строки)
Для Каждого СтрокаСписка Из Строки Цикл
ТекущаяСсылка = СтрокаСписка.Ключ;
ДанныеСтроки = СтрокаСписка.Значение;
// Получаем статус (если функция быстрая)
ВычисленныйСтатус = ИнтеграцияСогласования.ПолучитьЛегкийСтатус(ТекущаяСсылка);
// Заполняем индекс картинки из коллекции (начиная с 0)
ИндексКартинки = 0; // По умолчанию
Если ВычисленныйСтатус = "Согласовано" Тогда
ИндексКартинки = 1;
ИначеЕсли ВычисленныйСтатус = "НаСогласовании" Тогда
ИндексКартинки = 2;
ИначеЕсли ВычисленныйСтатус = "Отказ" Тогда
ИндексКартинки = 3;
КонецЕсли;
// Устанавливаем значение в данные строки списка
ДанныеСтроки.Данные.СтатусКартинка = ИндексКартинки;
КонецЦикла;
КонецПроцедуры
---
Если в конфигурацию нельзя добавлять новые картинки (например, конфигурация находится на поддержке без возможности изменения), можно воспользоваться интересным хаком: выводить специальные символы шрифтов Wingdings или Webdings через оформление строки.
Применим этот метод на практике:
&НаСервереБезКонтекста
Процедура СписокПриПолученииДанныхНаСервере(ИмяЭлемента, Настройки, Строки)
Для Каждого КлючИЗначение Из Строки Цикл
СтрокаСписка = КлючИЗначение.Значение;
СсылкаНаОбъект = КлючИЗначение.Ключ;
// Быстрое определение статуса
Статус = ИнтеграцияСогласования.ПолучитьЛегкийСтатус(СсылкаНаОбъект);
// Получаем оформление нужной ячейки (колонка должна быть добавлена на форму)
ОформлениеЯчейки = СтрокаСписка.Оформление["КолонкаСтатус"];
Если ОформлениеЯчейки = Неопределено Тогда
Продолжить;
КонецЕсли;
// Настраиваем шрифт Wingdings для вывода графических символов
ОформлениеЯчейки.УстановитьЗначениеПараметра("Шрифт", Новый Шрифт("Wingdings", 10, Истина));
Если Статус = "Согласовано" Тогда
// Символ 252 в шрифте Wingdings — это галочка "OK"
ОформлениеЯчейки.УстановитьЗначениеПараметра("Текст", Символ(252));
ОформлениеЯчейки.УстановитьЗначениеПараметра("ЦветТекста", WebЦвета.Зеленый);
ИначеЕсли Статус = "НаСогласовании" Тогда
// Символ 108 — это круглая точка-маркер
ОформлениеЯчейки.УстановитьЗначениеПараметра("Текст", Символ(108));
ОформлениеЯчейки.УстановитьЗначениеПараметра("ЦветТекста", WebЦвета.Оранжевый);
ИначеЕсли Статус = "Отказ" Тогда
// Символ 251 — это крестик
ОформлениеЯчейки.УстановитьЗначениеПараметра("Текст", Символ(251));
ОформлениеЯчейки.УстановитьЗначениеПараметра("ЦветТекста", WebЦвета.Красный);
Иначе
ОформлениеЯчейки.УстановитьЗначениеПараметра("Текст", "");
КонецЕсли;
КонецЦикла;
КонецПроцедуры
---
Если вы работаете на современных версиях платформы, у вас есть дополнительные инструменты упрощения разработки:
Статус равно "Согласовано", то установить картинку из библиотеки картинок конфигурации.| Критерий сравнения | Кэширование в Регистр сведений | Оформление ПриПолученииДанных | Шрифты Wingdings |
|---|---|---|---|
| Скорость работы списка | Максимальная (мгновенно) | Зависит от сложности расчетов | Зависит от сложности расчетов |
| Влияние на дисковую память | Минимальное (создается кэш-таблица) | Отсутствует | Отсутствует |
| Сложность внедрения | Средняя (нужно писать логику инвалидации кэша) | Низкая | Низкая |
| Возможность сортировки и отборов | Полная (как по любому обычному полю) | Невозможно штатным образом | Невозможно штатным образом |
Таким образом, мы выяснили: для простых баз данных с редким обновлением списков допустимо использовать событие ПриПолученииДанныхНаСервере с заполнением индекса картинок. Однако для промышленных высоконагруженных систем единственным верным решением является кэширование вычисляемых данных в регистр сведений.