Как вывести справочник с иерархией в табличный документ с возможностью сворачивания групп?

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

При формировании отчетов или печатных форм часто возникает задача вывести данные справочника не плоским списком, а в виде дерева, чтобы пользователь мог разворачивать и сворачивать подчиненные элементы. Несмотря на кажущуюся простоту, начинающие разработчики часто сталкиваются с тем, что группировки в табличном документе не появляются, а метод Уровень() всегда возвращает 0. Разберем по шагам, как правильно реализовать этот механизм, особенно если в справочнике используется тип «Иерархия элементов».

Шаг 1: Правильная структура запроса

Первая и самая важная деталь: использование предложения СГРУППИРОВАТЬ ПО в запросе не создает иерархических итогов. Оно предназначено для агрегации данных по конкретным полям. Для получения уровней вложенности (родитель — дети) в языке запросов 1С предусмотрено предложение ИТОГИ ПО ... ИЕРАРХИЯ.

Проанализируем, как должен выглядеть запрос, чтобы система «понимала» структуру вложенности:


Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ
    |   ЦФО.Ссылка КАК Ссылка,
    |   ЦФО.Наименование КАК Наименование
    |ИЗ
    |   Справочник.ЦФО КАК ЦФО
    |ГДЕ
    |   НЕ ЦФО.ПометкаУдаления
    |ИТОГИ ПО
    |   Ссылка ИЕРАРХИЯ
    |АВТОУПОРЯДОЧИВАНИЕ";

Обратим внимание на ключевое слово ИЕРАРХИЯ. Именно оно заставляет систему построить дерево итогов. Также крайне рекомендуется использовать АВТОУПОРЯДОЧИВАНИЕ, чтобы записи в выборке шли в логической последовательности: сначала родитель, затем его непосредственные потомки.

Шаг 2: Выбор метода обхода результата

После выполнения запроса важно правильно выбрать данные. Если мы будем использовать обычную выборку через Выбрать(), мы получим плоский список. Чтобы сохранить структуру дерева, необходимо использовать параметр ОбходРезультатаЗапроса.ПоГруппировкамСИерархией.

Рассмотрим пример кода для получения выборки:


РезультатЗапроса = Запрос.Выполнить();
// Важно использовать правильный тип обхода
Выборка = РезультатЗапроса.Выбрать(ОбходРезультатаЗапроса.ПоГруппировкамСИерархией);

Шаг 3: Вывод в табличный документ и создание группировок

Для того чтобы в табличном документе появились кнопки «плюс» и «минус», необходимо использовать методы управления группировками. Существует два основных подхода: использование «автогруппировки» и ручное управление через НачатьГруппуСтрок. Рассмотрим наиболее лаконичный способ — через параметр метода Вывести().

Проанализируем алгоритм вывода:

  1. Вызываем ТабДок.НачатьАвтогруппировкуСтрок() перед началом цикла.
  2. В методе ТабДок.Вывести(Область, Уровень) передаем второй параметр — числовое значение уровня.
  3. Завершаем процесс методом ТабДок.ЗакончитьАвтогруппировкуСтрок().

Пример реализации в коде:


ТабДок.НачатьАвтогруппировкуСтрок();

Пока Выборка.Следующий() Цикл
    
    ОбластьСтрока = Макет.ПолучитьОбласть("Строка");
    ОбластьСтрока.Параметры.Заполнить(Выборка);
    
    // Выводим область, указывая уровень вложенности из выборки
    ТабДок.Вывести(ОбластьСтрока, Выборка.Уровень());
    
КонецЦикла;

ТабДок.ЗакончитьАвтогруппировкуСтрок();

Шаг 4: Решение проблемы дублей в иерархии элементов

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

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

Исправленный код с фильтрацией дублей:


ТабДок.НачатьАвтогруппировкуСтрок();

Пока Выборка.Следующий() Цикл
    
    // Для иерархии элементов пропускаем детальные записи, 
    // оставляя только итоги по иерархии
    Если Выборка.ТипЗаписи() = ТипЗаписиЗапроса.ДетальнаяЗапись Тогда
        Продолжить;
    КонецЕсли;
    
    ОбластьСтрока = Макет.ПолучитьОбласть("Строка");
    ОбластьСтрока.Параметры.Заполнить(Выборка);
    
    // Передаем уровень для формирования кнопок свертки
    ТабДок.Вывести(ОбластьСтрока, Выборка.Уровень());
    
КонецЦикла;

ТабДок.ЗакончитьАвтогруппировкуСтрок();

Альтернативный подход: Рекурсивный вывод

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


Процедура ВывестиСтрокиИерархии(Выборка, ТабДок, Макет)
    
    Пока Выборка.Следующий() Цикл
        
        Область = Макет.ПолучитьОбласть("Строка");
        Область.Параметры.Заполнить(Выборка);
        ТабДок.Вывести(Область, Выборка.Уровень());
        
        // Рекурсивно вызываем функцию для подчиненных элементов
        ВывестиСтрокиИерархии(Выборка.Выбрать(ОбходРезультатаЗапроса.ПоГруппировкамСИерархией), ТабДок, Макет);
        
    КонецЦикла;
    
КонецПроцедуры

Важный момент: при использовании рекурсии или иерархических выборок всегда проверяйте свойство ПоказатьУровниГруппировок у объекта ТабличныйДокумент. Если группировки созданы, но не отображаются, возможно, стоит программно раскрыть их до нужного уровня с помощью метода ПоказатьУровниГруппировокСтрок(Значение).

Резюме

Для успешного вывода иерархии в 1С необходимо соблюсти три условия:

  1. Использовать ИТОГИ ПО ... ИЕРАРХИЯ в запросе.
  2. Выбирать данные с параметром ПоГруппировкамСИерархией.
  3. Использовать метод Вывести() с указанием Уровень() внутри блока автогруппировки.

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

← На главную