Как реализовать раскраску строк динамического списка в 1С при наличии данных в подчиненных таблицах?

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

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

Постановка задачи

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

Способ 1. Использование запроса динамического списка и условного оформления

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

Проанализируем структуру запроса. Нам нужно соединить основную таблицу документов с таблицей товаров и таблицей дополнительных реквизитов. Однако простое ЛЕВОЕ СОЕДИНЕНИЕ может привести к дублированию строк в списке, если в документе несколько подходящих товаров. Чтобы этого избежать, воспользуемся конструкцией ВЫБОР КОГДА ... В (ВЫБРАТЬ ...) или механизмом группировки.

Пример запроса для динамического списка:


ВЫБРАТЬ
    ДокументТаблица.Ссылка КАК Ссылка,
    ДокументТаблица.ПометкаУдаления КАК ПометкаУдаления,
    ДокументТаблица.Номер КАК Номер,
    ДокументТаблица.Дата КАК Дата,
    ДокументТаблица.Проведен КАК Проведен,
    // Добавляем вычисляемое поле-флаг
    ВЫБОР
        КОГДА ЕСТЬNULL(Подзапрос.ЕстьОсобыйТовар, ЛОЖЬ) ТОГДА
            ИСТИНА
        ИНАЧЕ
            ЛОЖЬ
    КОНЕЦ КАК СодержитОсобыйТовар
ИЗ
    Документ.ИсходящаяТранспортнаяОперацияВЕТИС КАК ДокументТаблица
        ЛЕВОЕ СОЕДИНЕНИЕ (
            ВЫБРАТЬ РАЗЛИЧНЫЕ
                ТЧ.Ссылка КАК Ссылка,
                ИСТИНА КАК ЕстьОсобыйТовар
            ИЗ
                Документ.ИсходящаяТранспортнаяОперацияВЕТИС.Товары КАК ТЧ
            ГДЕ
                ТЧ.Номенклатура.ДополнительныеРеквизиты.Свойство = &ЦелевоеСвойство
                И ТЧ.Номенклатура.ДополнительныеРеквизиты.Значение <> ЗНАЧЕНИЕ(Справочник.ЗначенияСвойствОбъектов.ПустаяСсылка)
        ) КАК Подзапрос
        ПО ДокументТаблица.Ссылка = Подзапрос.Ссылка

Разберем, что мы сделали. Мы создали вложенный запрос, который выбирает уникальные ссылки документов, где в табличной части есть номенклатура с нужным свойством. После этого мы соединили этот результат с основной таблицей. Теперь у нас в динамическом списке появилось поле СодержитОсобыйТовар.

Далее настроим условное оформление:

  1. Перейдем в свойства динамического списка Список на форме.
  2. Откроем настройки Условного оформления.
  3. Добавим новый элемент оформления: установим нужный Цвет фона.
  4. В условии укажем: СодержитОсобыйТовар Равно Истина.
  5. В области оформления выберем Вся строка.

Способ 2. Обработчик ПриПолученииДанныхНаСервере

Если логика определения цвета слишком сложна для написания на языке запросов 1С (например, требуется сложный расчет или обращение к внешним источникам), можно воспользоваться программным методом. Выясним причину, почему разработчики часто выбирают именно его.

Событие ПриПолученииДанныхНаСервере срабатывает тогда, когда платформа уже подготовила порцию данных (обычно 20–40 строк), которые будут отображены пользователю на экране. Это позволяет нам выполнить дополнительные запросы только для этих конкретных строк, что значительно быстрее, чем обрабатывать всю базу.

Рассмотрим пример реализации в модуле формы:


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

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

Сравнение подходов: производительность и ограничения

Выясним, какой метод лучше в конкретных условиях:

1. Метод с запросом в динамическом списке:

2. Метод ПриПолученииДанныхНаСервере:

Рекомендации по работе с Дополнительными реквизитами

Поскольку в задаче фигурирует ДопРеквизит1, важно помнить, что дополнительные реквизиты в системах на базе БСП (Библиотека стандартных подсистем) хранятся в отдельной табличной части справочника Номенклатура. Прямое обращение через точку в запросе (ТЧ.Номенклатура.ДопРеквизит1) может не сработать, если реквизит не является «обычным» реквизитом объекта.

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


// Пример добавления пользовательского поля программно
НовоеПоле = Список.КомпоновщикНастроек.Настройки.ПользовательскиеПоля.Элементы.Добавить(Тип("ВыбранноеПолеКомпоновкиДанных"));
НовоеПоле.Поле = Новый ПолеКомпоновкиДанных("Номенклатура.ДополнительныеРеквизиты.Значение");
НовоеПоле.Заголовок = "СпецСвойство";

Проблема «Множественности» (что красить?)

Разберем важный логический нюанс, упомянутый в обсуждении. Если в документе 10 строк номенклатуры, и только у одной есть ДопРеквизит1, мы красим всю строку документа. А что если нам нужно разное оформление для случаев «все товары особые» и «только часть товаров особые»? В этом случае в запросе динамического списка лучше использовать агрегатные функции, такие как КОЛИЧЕСТВО(РАЗЛИЧНЫЕ ...), и сравнивать его с общим количеством строк. Это позволит настроить более сложную градацию цветов (например, желтый — частичное соответствие, зеленый — полное).

Итоги

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

← На главную