При формировании отчетов или печатных форм часто возникает задача вывести данные справочника не плоским списком, а в виде дерева, чтобы пользователь мог разворачивать и сворачивать подчиненные элементы. Несмотря на кажущуюся простоту, начинающие разработчики часто сталкиваются с тем, что группировки в табличном документе не появляются, а метод Уровень() всегда возвращает 0. Разберем по шагам, как правильно реализовать этот механизм, особенно если в справочнике используется тип «Иерархия элементов».
Первая и самая важная деталь: использование предложения СГРУППИРОВАТЬ ПО в запросе не создает иерархических итогов. Оно предназначено для агрегации данных по конкретным полям. Для получения уровней вложенности (родитель — дети) в языке запросов 1С предусмотрено предложение ИТОГИ ПО ... ИЕРАРХИЯ.
Проанализируем, как должен выглядеть запрос, чтобы система «понимала» структуру вложенности:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ЦФО.Ссылка КАК Ссылка,
| ЦФО.Наименование КАК Наименование
|ИЗ
| Справочник.ЦФО КАК ЦФО
|ГДЕ
| НЕ ЦФО.ПометкаУдаления
|ИТОГИ ПО
| Ссылка ИЕРАРХИЯ
|АВТОУПОРЯДОЧИВАНИЕ";
Обратим внимание на ключевое слово ИЕРАРХИЯ. Именно оно заставляет систему построить дерево итогов. Также крайне рекомендуется использовать АВТОУПОРЯДОЧИВАНИЕ, чтобы записи в выборке шли в логической последовательности: сначала родитель, затем его непосредственные потомки.
После выполнения запроса важно правильно выбрать данные. Если мы будем использовать обычную выборку через Выбрать(), мы получим плоский список. Чтобы сохранить структуру дерева, необходимо использовать параметр ОбходРезультатаЗапроса.ПоГруппировкамСИерархией.
Рассмотрим пример кода для получения выборки:
РезультатЗапроса = Запрос.Выполнить();
// Важно использовать правильный тип обхода
Выборка = РезультатЗапроса.Выбрать(ОбходРезультатаЗапроса.ПоГруппировкамСИерархией);
Для того чтобы в табличном документе появились кнопки «плюс» и «минус», необходимо использовать методы управления группировками. Существует два основных подхода: использование «автогруппировки» и ручное управление через НачатьГруппуСтрок. Рассмотрим наиболее лаконичный способ — через параметр метода Вывести().
Проанализируем алгоритм вывода:
ТабДок.НачатьАвтогруппировкуСтрок() перед началом цикла.ТабДок.Вывести(Область, Уровень) передаем второй параметр — числовое значение уровня.ТабДок.ЗакончитьАвтогруппировкуСтрок().Пример реализации в коде:
ТабДок.НачатьАвтогруппировкуСтрок();
Пока Выборка.Следующий() Цикл
ОбластьСтрока = Макет.ПолучитьОбласть("Строка");
ОбластьСтрока.Параметры.Заполнить(Выборка);
// Выводим область, указывая уровень вложенности из выборки
ТабДок.Вывести(ОбластьСтрока, Выборка.Уровень());
КонецЦикла;
ТабДок.ЗакончитьАвтогруппировкуСтрок();
Если ваш справочник имеет вид иерархии «Иерархия элементов» (где каждый элемент может быть родителем), вы столкнетесь с особенностью работы итогов: элемент будет выведен сначала как узел (группировка), а затем — как детальная запись внутри самого себя. Это создает визуальные дубли.
Чтобы этого избежать, мы должны проверить тип записи в цикле обхода. Выясним причину: в иерархии элементов запись является одновременно и итогом, и детальной записью. Нам нужно выводить только «иерархическую» часть.
Исправленный код с фильтрацией дублей:
ТабДок.НачатьАвтогруппировкуСтрок();
Пока Выборка.Следующий() Цикл
// Для иерархии элементов пропускаем детальные записи,
// оставляя только итоги по иерархии
Если Выборка.ТипЗаписи() = ТипЗаписиЗапроса.ДетальнаяЗапись Тогда
Продолжить;
КонецЕсли;
ОбластьСтрока = Макет.ПолучитьОбласть("Строка");
ОбластьСтрока.Параметры.Заполнить(Выборка);
// Передаем уровень для формирования кнопок свертки
ТабДок.Вывести(ОбластьСтрока, Выборка.Уровень());
КонецЦикла;
ТабДок.ЗакончитьАвтогруппировкуСтрок();
Иногда плоский цикл не дает нужной гибкости. В таких случаях мы можем применить рекурсию. Это позволяет более точно управлять выводом каждого уровня. Рассмотрим, как это работает:
Процедура ВывестиСтрокиИерархии(Выборка, ТабДок, Макет)
Пока Выборка.Следующий() Цикл
Область = Макет.ПолучитьОбласть("Строка");
Область.Параметры.Заполнить(Выборка);
ТабДок.Вывести(Область, Выборка.Уровень());
// Рекурсивно вызываем функцию для подчиненных элементов
ВывестиСтрокиИерархии(Выборка.Выбрать(ОбходРезультатаЗапроса.ПоГруппировкамСИерархией), ТабДок, Макет);
КонецЦикла;
КонецПроцедуры
Важный момент: при использовании рекурсии или иерархических выборок всегда проверяйте свойство ПоказатьУровниГруппировок у объекта ТабличныйДокумент. Если группировки созданы, но не отображаются, возможно, стоит программно раскрыть их до нужного уровня с помощью метода ПоказатьУровниГруппировокСтрок(Значение).
Для успешного вывода иерархии в 1С необходимо соблюсти три условия:
ИТОГИ ПО ... ИЕРАРХИЯ в запросе.ПоГруппировкамСИерархией.Вывести() с указанием Уровень() внутри блока автогруппировки.Эти простые правила позволят создавать удобные и функциональные отчеты, которые легко анализировать благодаря структурированному представлению данных.