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