Как настроить условное оформление в динамическом списке РМК 1С:Розница для выделения товаров по остаткам и добавить новые колонки?

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

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

Добавление новых колонок в динамический список товаров РМК

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

  1. Изменение произвольного запроса: Первым шагом будет изменение вашего произвольного запроса таким образом, чтобы он включал поле с общим остатком товаров. Например, вы можете добавить соединение с регистром накопления, хранящим остатки.
  2. Особенности формы РМК: Обратите внимание, что в форме подбора товаров РМК часто используется не основная таблица формы Товары, а вспомогательная таблица ТоварыРасширение. Именно в этой таблице вам и нужно создавать новые поля, которые будут отображать данные из вашего произвольного запроса. Если вы добавили поле ОбщийОстаток в запрос, вам нужно создать соответствующую колонку в таблице ТоварыРасширение и указать, что ее данные берутся из этого поля запроса.

Таким образом, для отображения новых колонок необходимо:

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

Программная настройка условного оформления динамического списка

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

Важность ПриСозданииНаСервере()

Основное правило — старайтесь настраивать условное оформление в обработчике формы ПриСозданииНаСервере(). Этот обработчик выполняется один раз при открытии формы, что обеспечивает максимальную производительность. Изменения, внесенные в условное оформление после создания формы, могут привести к повторным расчетам и замедлению работы.

Подход 1: Настройка через компоновщик настроек в ПриСозданииНаСервере()

Этот подход является наиболее предпочтительным, если поле, по которому устанавливается условие оформления (в нашем случае — остаток товара), уже присутствует в основном запросе динамического списка. Мы будем работать со свойством КомпоновщикНастроек динамического списка.

Чтобы условное оформление работало по умолчанию у всех пользователей и не перекрывалось их индивидуальными настройками, рекомендуется использовать ФиксированныеНастройки компоновщика настроек.

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

Рассмотрим пример кода:


&НаСервере
Процедура ПриСозданииНаСервере(Отказ)
    // ... ваш код инициализации формы ...

    // Получаем динамический список
    Перем ДинамическийСписок;
    Если ЭтаФорма.Элементы.Найти("СписокТоваров") <> Неопределено Тогда // Замените на имя вашего динамического списка
        ДинамическийСписок = ЭтаФорма.Элементы.СписокТоваров;
    Иначе
        Возврат;
    КонецЕсли;

    // Очищаем существующие фиксированные настройки (опционально, если хотите перезаписать)
    ДинамическийСписок.КомпоновщикНастроек.ФиксированныеНастройки.УсловноеОформление.Элементы.Очистить();

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

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

    // Устанавливаем оформление
    ЭлементОформления.Оформление.УстановитьЗначениеПараметра("ЦветТекста", Новый Цвет(255, 0, 0)); // Красный цвет текста
    // Или, например, цвет фона
    // ЭлементОформления.Оформление.УстановитьЗначениеПараметра("ЦветФона", Новый Цвет(255, 220, 220)); // Светло-красный фон

    // Область применения оформления - для всего списка (для всех колонок строки)
    // Если нужно применить только к одной колонке, добавьте ее в СписокПолей:
    // ЭлементОформления.Поля.Элементы.Добавить().Поле = Новый ПолеКомпоновкиДанных("Наименование");

    // Для применения ко всей строке, этот шаг не нужен, так как по умолчанию применяется к полям, которые отображаются
    // Можно также указать конкретные поля, если оформление должно затрагивать не все ячейки строки
    // ЭлементОформления.Поля.Элементы.Добавить().Поле = Новый ПолеКомпоновкиДанных("ОбщийОстаток");
    // ЭлементОформления.Поля.Элементы.Добавить().Поле = Новый ПолеКомпоновкиДанных("Наименование");

    // ... остальной код ПриСозданииНаСервере ...
КонецПроцедуры

После применения этих изменений при нулевом остатке строка в динамическом списке будет отображаться красным цветом. Убедитесь, что имя поля "ОбщийОстаток" соответствует тому имени, которое вы дали полю в вашем произвольном запросе.

Подход 2: Использование обработчика ПриПолученииДанныхНаСервере()

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

Однако есть и обратная сторона: частое выполнение дополнительных запросов для каждой порции данных может замедлить прокрутку списка. Автор исходной темы как раз столкнулся с замедлением при использовании этого подхода.

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

Рассмотрим пример кода:


&НаСервере
Процедура СписокТоваровПриПолученииДанныхНаСервере(Элемент, Настройки, Данные, Отказ)
    // Элемент - динамический список
    // Настройки - настройки компоновщика (можно передавать параметры)
    // Данные - коллекция строк, полученных динамическим списком
    // Отказ - позволяет отказаться от обработки (редко используется)

    Если Данные.Количество() = 0 Тогда
        Возврат;
    КонецЕсли;

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

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

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

    Перем РезультатЗапроса;
    РезультатЗапроса = Запрос.Выполнить().Выгрузить();

    Перем КартаОстатков;
    КартаОстатков = Новый Соответствие;
    Для Каждого СтрокаРезультата Из РезультатЗапроса Цикл
        КартаОстатков.Вставить(СтрокаРезультата.Номенклатура, СтрокаРезультата.ОбщийОстаток);
    КонецЦикла;

    // Применяем оформление к строкам списка
    Для Каждого СтрокаСписка Из Данные Цикл
        Перем Остаток;
        Остаток = КартаОстатков.Получить(СтрокаСписка.Номенклатура);

        Если Остаток = 0 Тогда
            // Применяем оформление ко всем ячейкам строки
            Для Каждого Ячейка Из СтрокаСписка.Ячейки Цикл
                Ячейка.Оформление.ЦветТекста = Новый Цвет(255, 0, 0); // Красный цвет
                Ячейка.Оформление.Шрифт = Новый Шрифт(Ячейка.Оформление.Шрифт, Истина); // Жирный шрифт
                // Можно также установить ЦветФона, Видимость и т.д.
            КонецЦикла;
            // Или только к конкретной ячейке, если она есть в списке
            // Если СтрокаСписка.Ячейки.Найти("Наименование") <> Неопределено Тогда
            //     СтрокаСписка.Ячейки.Наименование.Оформление.ЦветТекста = Новый Цвет(255, 0, 0);
            // КонецЕсли;
        КонецЕсли;
    КонецЦикла;

    // Для передачи параметров из формы во внеконтекстный обработчик ПриПолученииДанныхНаСервере
    // можно использовать свойство Настройки.ДополнительныеСвойства
    // Например: Настройки.ДополнительныеСвойства.Вставить("ИспользоватьСклад", ИспользоватьСкладФлажок);
    // Тогда в обработчике можно получить: Настройки.ДополнительныеСвойства.Получить("ИспользоватьСклад")
КонецПроцедуры

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

Интерактивная настройка условного оформления

Необходимо упомянуть, что пользователи также могут настроить условное оформление в режиме 1С:Предприятие через стандартные функции "Все действия" -> "Настроить список" -> "Условное оформление". Однако такие настройки сохраняются индивидуально для каждого пользователя и могут быть перекрыты программными настройками, особенно если вы используете ФиксированныеНастройки в ПриСозданииНаСервере().

Оптимизация производительности динамических списков

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

  1. Индексы: Убедитесь, что все поля, используемые в условиях соединения и отбора в вашем запросе, проиндексированы. Это значительно ускоряет выборку данных.
  2. Сложность запроса: Избегайте вложенных запросов, большого количества соединений таблиц, а также использования ресурсоемких функций в условиях (например, ПОДСТРОКА, МЕСЯЦ, ВЫБОР КОГДА) и вычисляемых полей в секции ГДЕ.
  3. RLS (Row-Level Security): Проверяйте производительность динамического списка под пользователем с ограниченными правами. Условия RLS могут сильно замедлять запросы, поскольку накладывают дополнительные фильтры.
  4. Флаг "Динамическое считывание данных": Этот флаг в свойствах динамического списка (если он произвольный и установлена основная таблица) влияет на размер порций данных.
    • Включен: Данные забираются маленькими порциями (около 45 строк), что может вызывать "подвисания" при активной прокрутке.
    • Отключен: Получаются большие порции данных (около 1000 строк), что улучшает плавность прокрутки, но увеличивает время первоначального выполнения запроса. Выбирайте настройку в зависимости от сценария использования.

Анализ ситуации автора и рекомендации

Автор столкнулся с проблемой, что в одной базе "Розница" условное оформление работает быстро, а в его новой реализации с использованием ПриПолученииДанныхНаСервере() происходит замедление. Это указывает на то, что в "быстрой" базе, скорее всего, использован другой, более производительный подход.

Наиболее вероятные причины высокой производительности в "другой" базе:

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

Рекомендации автору:

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

Выяснив, как именно реализован расчет остатков в "быстрой" базе, вы сможете выбрать наиболее подходящий и производительный подход для вашей конфигурации.

← На главную