Как реализовать отбор и сортировку по вычисляемым полям в динамическом списке 1С 8.3

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

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

Почему не работает отбор по полям, заполненным в коде?

Проанализируем механику работы динамического списка. Когда пользователь открывает форму, платформа формирует SQL-запрос к базе данных, получает порцию записей и отображает их. Событие ПриПолученииДанных срабатывает на стороне клиента уже после того, как данные были получены из СУБД. Вы программно меняете текст или значение в ячейке, но база данных об этом «не знает».

Когда пользователь нажимает «Сортировать» или устанавливает «Отбор» (например, используя расширение Подобно в списке), платформа отправляет новый запрос в СУБД, пытаясь выполнить команду на уровне индексов таблицы. Поскольку ваших вычисленных данных в таблице нет, СУБД не может их обработать, и результат оказывается пустым или некорректным. Рассмотрим способы решения этой проблемы.

Способ 1. Расчет простых значений непосредственно в запросе

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

Выясним, как рассчитать разницу дат. Для этого в настройках динамического списка (произвольный запрос) мы добавим вычисляемое поле. Разберем пример кода запроса:


ВЫБРАТЬ
    ДокументЗаказ.Ссылка КАК Ссылка,
    ДокументЗаказ.Дата КАК Дата,
    ДокументЗаказ.ДатаВыполнения КАК ДатаВыполнения,
    РАЗНОСТЬДАТ(ДокументЗаказ.ДатаВыполнения, &ТекущаяДата, ДЕНЬ) КАК ДнейПросрочено
ИЗ
    Документ.ЗаказКлиента КАК ДокументЗаказ
ГДЕ
    ДокументЗаказ.Проведен = ИСТИНА

Важный нюанс: Чтобы данные были актуальными, параметр &ТекущаяДата необходимо передавать при открытии формы и, желательно, обновлять его по таймеру или при обновлении списка. Посмотрим, как установить этот параметр в коде формы:


&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
    Список.Параметры.УстановитьЗначениеПараметра("ТекущаяДата", ТекущаяДатаСеанса());
КонецПроцедуры

При таком подходе поле ДнейПросрочено становится «настоящим» для платформы, и по нему автоматически заработают и сортировка, и стандартные отборы.

Способ 2. Денормализация данных через регистры сведений (для сложных статусов)

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

Проанализируем шаги реализации этой стратегии:

  1. Создадим непериодический регистр сведений ТекущиеСтатусыДокументов с измерением Документ и ресурсом Статус.
  2. В подписках на события или в процедурах ОбработкаПроведения всех влияющих документов (Заказ, Реализация, Корректировка) добавим код, который рассчитывает итоговый статус и записывает его в этот регистр.
  3. В запросе динамического списка добавим ЛЕВОЕ СОЕДИНЕНИЕ с этим регистром.

Рассмотрим пример соединения в запросе:


ВЫБРАТЬ
    ОсновнаяТаблица.Ссылка,
    ЕСТЬNULL(Статусы.Статус, ЗНАЧЕНИЕ(Перечисление.СтатусыЗаказов.ПустаяСсылка)) КАК СтатусОтгрузки
ИЗ
    Документ.ЗаказПоставщику КАК ОсновнаяТаблица
    ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ТекущиеСтатусыДокументов КАК Статусы
    ПО Статусы.Документ = ОсновнаяТаблица.Ссылка

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

Способ 3. Оптимизация работы со «Срезом последних»

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

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

Технические тонкости оформления

Иногда нам все же нужно использовать ПриПолученииДанных для визуального выделения (например, покрасить строку в красный, если просрочка > 5 дней). Помните, что правильное использование условного оформления подразумевает, что оно должно лишь дополнять данные, уже имеющиеся в запросе, а не создавать их. Также для улучшения UX может потребоваться программное перемещение колонки динамического списка в начало строки, если статус становится критическим.

Выясним, как правильно совместить расчет и оформление:

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

Использование основной таблицы

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

Если основная таблица не указана, платформа может попытаться считать все данные из запроса для выполнения сортировки, что приведет к длительному ожиданию (песочные часы) при открытии формы.

Резюме по шагам

Подведем итог нашего анализа. Чтобы ваши пользователи могли фильтровать и сортировать любые данные в списках, придерживайтесь следующего алгоритма:

  1. Всегда проверяйте, можно ли вычислить поле средствами языка запросов 1С. Если да — используйте РАЗНОСТЬДАТ, ВЫБОР КОГДА... и арифметические операции прямо в ТекстЗапроса.
  2. Если расчет требует обращения к другим таблицам или сложной бизнес-логики — используйте регистры сведений для хранения готового результата (кэширование данных).
  3. Обновляйте данные в этих регистрах в момент записи документов через Подписки на события.
  4. Используйте событие ПриПолученииДанных или УсловноеОформление только для визуализации (цвета, шрифты, картинки), но не для формирования самих данных.

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

← На главную