При разработке отчетов на системе компоновки данных (СКД) программисты часто сталкиваются с тем, что стандартный вывод отборов в шапке отчета выглядит избыточно техническим или "некрасивым" для конечного пользователя. Например, вместо понятного заголовка "Выбранные подразделения: Администрация" пользователь может увидеть "Отбор: Подразделение Равно Администрация". Кроме того, стандартный механизм выводит все активные фильтры в одну кучу, что затрудняет чтение.
В этой статье мы подробно разберем, как взять управление выводом отборов в свои руки, сформировать красивую строку с описанием условий и вывести ее в конкретное место вашего макета.
Самый гибкий способ — это создание специального параметра в схеме компоновки данных, который мы будем заполнять программно перед выводом отчета. Рассмотрим этот процесс по шагам.
Во-первых, в схеме СКД на вкладке Параметры создадим новый параметр, например, с именем СтрокаОтборов. Установим для него тип "Строка" и включим флаг "Доступные значения", если это необходимо, но обычно достаточно просто оставить его пустым. Важно: снимите галочку "Ограничение доступности", если хотите видеть его в настройках, или оставьте, если будете заполнять его только кодом.
Во-вторых, в настройках отчета (вкладка Настройки) добавим группировку в самый верх отчета. Тип группировки выберем "Детальные записи" или создадим группировку без полей. В макете для этой группировки (или через макет оформления) укажем использование нашего параметра СтрокаОтборов.
Теперь перейдем в Модуль объекта отчета и переопределим процедуру ПриКомпоновкеРезультата. Проанализируем следующий код:
Процедура ПриКомпоновкеРезультата(ДокументРезультат, ДанныеРасшифровки, СтандартнаяОбработка)
// Отключаем стандартный вывод, так как будем управлять процессом вручную
СтандартнаяОбработка = Ложь;
ДокументРезультат.Очистить();
// Получаем текущие настройки компоновщика (с учетом пользовательских)
НастройкиОтчета = КомпоновщикНастроек.ПолучитьНастройки();
// Ищем наш параметр в настройках
ПараметрСтрокаОтбор = НастройкиОтчета.ПараметрыДанных.НайтиЗначениеПараметра(Новый ПараметрКомпоновкиДанных("СтрокаОтборов"));
Если ПараметрСтрокаОтбор <> Неопределено Тогда
ТекстВсехОтборов = "";
КоллекцияОтборов = НастройкиОтчета.Отбор.Элементы;
// Обходим элементы отбора
Для Каждого Элемент Из КоллекцияОтборов Цикл
// Проверяем, включен ли отбор пользователем
Если ТипЗнч(Элемент) = Тип("ЭлементОтбораКомпоновкиДанных") И Элемент.Использование Тогда
// Формируем строковое представление (Поле + Вид сравнения + Значение)
ИмяПоля = Строка(Элемент.ЛевоеЗначение);
ВидСравнения = Строка(Элемент.ВидСравнения);
Значение = Строка(Элемент.ПравоеЗначение);
ТекстВсехОтборов = ТекстВсехОтборов + ИмяПоля + " " + ВидСравнения + " " + Значение + "; ";
КонецЕсли;
КонецЦикла;
// Записываем результат в параметр
Если Не ПустаяСтрока(ТекстВсехОтборов) Тогда
ПараметрСтрокаОтбор.Значение = "Установленные фильтры: " + ТекстВсехОтборов;
ПараметрСтрокаОтбор.Использование = Истина;
Иначе
ПараметрСтрокаОтбор.Использование = Ложь; // Если отборов нет, скрываем параметр
КонецЕсли;
КонецЕсли;
// Стандартный цикл вывода результата с нашими измененными настройками
КомпоновщикМакета = Новый КомпоновщикМакетаКомпоновкиДанных;
МакетКомпоновки = КомпоновщикМакета.Выполнить(СхемаКомпоновкиДанных, НастройкиОтчета, ДанныеРасшифровки);
ПроцессорКомпоновки = Новый ПроцессорКомпоновкиДанных;
ПроцессорКомпоновки.Инициализировать(МакетКомпоновки, , ДанныеРасшифровки, Истина);
ПроцессорВывода = Новый ПроцессорВыводаРезультатаКомпоновкиДанныхВТабличныйДокумент;
ПроцессорВывода.УстановитьДокумент(ДокументРезультат);
ПроцессорВывода.Вывести(ПроцессорКомпоновки);
КонецПроцедуры
Рассмотрим более сложную ситуацию. В СКД отборы могут быть иерархическими (группы "И", "ИЛИ", "НЕ"). Обычный цикл по Элементы пропустит элементы, находящиеся внутри групп. Для корректного отображения всех условий разберем рекурсивный метод получения текста.
Выясним причину, почему это важно: если пользователь сгруппирует условия "Склад Равно Основной" И "Товар В списке...", то простой перебор выдаст только название группы или вообще ничего. Нам нужно создать вспомогательную функцию.
Функция ПолучитьТекстОтбораРекурсивно(ЭлементыОтбора)
Текст = "";
Для Каждого Элемент Из ЭлементыОтбора Цикл
Если Не Элемент.Использование Тогда
Продолжить;
КонецЕсли;
Если ТипЗнч(Элемент) = Тип("ГруппаЭлементовОтбораКомпоновкиДанных") Тогда
// Рекурсивно заходим внутрь группы
ВнутреннийТекст = ПолучитьТекстОтбораРекурсивно(Элемент.Элементы);
Если Не ПустаяСтрока(ВнутреннийТекст) Тогда
Текст = Текст + "(" + ВнутреннийТекст + ") " + Строка(Элемент.ТипГруппы) + " ";
КонецЕсли;
ИначеЕсли ТипЗнч(Элемент) = Тип("ЭлементОтбораКомпоновкиДанных") Тогда
// Формируем строку для конкретного элемента
Текст = Текст + Строка(Элемент.ЛевоеЗначение) + " " +
Строка(Элемент.ВидСравнения) + " " +
Строка(Элемент.ПравоеЗначение) + "; ";
КонецЕсли;
КонецЦикла;
Возврат Текст;
КонецФункции
Использование этой функции в процедуре ПриКомпоновкеРезультата позволит получить полную картину всех условий, которые наложил пользователь, независимо от их вложенности.
Проанализируем еще одну проблему: Строка(Элемент.ЛевоеЗначение) часто возвращает путь к данным, например, "Контрагент.Код". Для пользователя это выглядит непрофессионально. Нам нужно получить заголовок поля, определенный в схеме.
Для этого можно обратиться к доступным полям отбора компоновщика настроек. Рассмотрим, как это реализовать:
// Вместо Строка(Элемент.ЛевоеЗначение) используем поиск заголовка
ПолеОтбора = Элемент.ЛевоеЗначение;
ДоступноеПоле = КомпоновщикНастроек.Настройки.Отбор.ДоступныеПоляОтбора.НайтиПоле(ПолеОтбора);
Если ДоступноеПоле <> Неопределено Тогда
ЗаголовокПоля = ДоступноеПоле.Заголовок;
Иначе
ЗаголовокПоля = Строка(ПолеОтбора);
КонецЕсли;
Важный момент: если вы используете Библиотеку стандартных подсистем (БСП), в ней есть общие модули, такие как ОбщегоНазначения или специализированные модули для отчетов, которые умеют формировать "представление" отбора одной строкой. Если ваша конфигурация типовая, поищите функцию ПредставлениеОтбора — это сэкономит массу времени.
Посмотрим на пример, когда пользователь выбирает вид сравнения "В списке". Обычное преобразование Строка(ПравоеЗначение) выдаст системное описание объекта "СписокЗначений". Чтобы вывести элементы списка красиво через запятую, разберем следующий фрагмент кода:
Если ТипЗнч(Элемент.ПравоеЗначение) = Тип("СписокЗначений") Тогда
ЗначенияСписком = "";
Для Каждого ЭлементСписка Из Элемент.ПравоеЗначение Цикл
ЗначенияСписком = ЗначенияСписком + Строка(ЭлементСписка.Значение) + ", ";
КонецЦикла;
// Удаляем последнюю запятую
ПредставлениеЗначения = Лев(ЗначенияСписком, СтрДлина(ЗначенияСписком) - 2);
ИначеЕсли ТипЗнч(Элемент.ПравоеЗначение) = Тип("Дата") Тогда
ПредставлениеЗначения = Формат(Элемент.ПравоеЗначение, "ДФ=dd.MM.yyyy");
Иначе
ПредставлениеЗначения = Строка(Элемент.ПравоеЗначение);
КонецЕсли;
Чтобы ваш кастомный заголовок не дублировался со стандартным системным блоком "Отбор:", необходимо внести изменения в настройки компоновки данных. Рассмотрим, как это сделать:
Теперь в шапке отчета останется только ваш программно сформированный параметр СтрокаОтборов, размещенный в нужной области макета с использованием выбранных вами шрифтов и стилей оформления.
Используя эти методы, мы превращаем технический отчет в качественный продукт, удобный для восприятия бизнес-пользователями. Помните, что аккуратное оформление параметров и отборов — это признак высокого уровня профессионализма разработчика 1С.