Как отобразить табличную часть документа в виде дерева на управляемой форме 1С?

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

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

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

Ограничения платформы и архитектура решения

Проанализируем технические особенности работы с деревьями на управляемых формах:

  1. Хранение в базе данных: В метаданных табличная часть всегда остается плоской. Чтобы сохранить иерархию (родительские и дочерние узлы), в табличную часть добавляются служебные реквизиты связи.
  2. Клиент-серверное разделение: Объект ДеревоЗначений доступен исключительно на сервере. На клиенте работа с деревом осуществляется через коллекции типа ДанныеФормыДерево и ДанныеФормыЭлементДерева.
  3. Связывание с формой: На управляемой форме создается отдельный реквизит формы с типом ДеревоЗначений, который связывается с таблицей формы. При чтении объекта данные из табличной части преобразуются в дерево, а перед записью — обратно разворачиваются в плоскую таблицу.

Шаг 1. Настройка метаданных табличной части

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

  1. ИдентификаторСтроки — тип Число (длина 10) или Строка (для GUID). Хранит уникальный ключ текущей строки.
  2. ИдентификаторРодителя — тип, полностью аналогичный типу идентификатора строки. Для корневых узлов значение остается пустым (или равным 0), а для подчиненных строк сюда записывается ИдентификаторСтроки вышестоящего узла.
  3. Прикладные реквизиты: Сотрудник, Поручение, Статус и другие необходимые поля.

Шаг 2. Настройка элементов управляемой формы

Рассмотрим структуру реквизитов и элементов управляемой формы документа:

  1. На вкладке Реквизиты создаем новый реквизит формы, назовем его ДеревоМаршрута, и укажем тип ДеревоЗначений.
  2. Внутри реквизита ДеревоМаршрута создаем колонки, повторяющие состав табличной части: ИдентификаторСтроки, ИдентификаторРодителя, Сотрудник, Поручение.
  3. Перетаскиваем реквизит ДеревоМаршрута в окно элементов формы. Платформа создаст элемент управления Таблица с типом отображения «Дерево».
  4. У элемента таблицы на форме при необходимости настраиваем видимость колонок (служебные идентификаторы делаем невидимыми для пользователя).

Шаг 3. Заполнение дерева при чтении данных

Разберем алгоритм построения дерева из плоской таблицы при открытии или чтении документа. Процедура выполняется на сервере в обработчиках ПриСозданииНаСервере или ПриЧтенииНаСервере.

Посмотрим на пример рекурсивного заполнения узлов дерева на сервере:


&НаСервере
Процедура ЗаполнитьДеревоМаршрутаНаСервере()

	ДеревоОбъект = Новый ДеревоЗначений;
	ДеревоОбъект.Колонки.Добавить("ИдентификаторСтроки", Новый ОписаниеТипов("Число"));
	ДеревоОбъект.Колонки.Добавить("ИдентификаторРодителя", Новый ОписаниеТипов("Число"));
	ДеревоОбъект.Колонки.Добавить("Сотрудник", Новый ОписаниеТипов("СправочникСсылка.Сотрудники"));
	ДеревоОбъект.Колонки.Добавить("Поручение", Новый ОписаниеТипов("Строка", Новый КвалификаторыСтроки(150)));

	ТаблицаИсточника = Объект.МаршрутПоручений.Выгрузить();

	// Добавляем строки верхнего уровня (у которых нет родителя)
	ОтборКорня = Новый Структура("ИдентификаторРодителя", 0);
	СтрокиКорня = ТаблицаИсточника.НайтиСтроки(ОтборКорня);

	Для Каждого СтрИсточника Из СтрокиКорня Цикл
		НоваяСтрокаДерева = ДеревоОбъект.Строки.Добавить();
		ЗаполнитьЗначенияСвойств(НоваяСтрокаДерева, СтрИсточника);
		
		// Рекурсивно заполняем подчиненные узлы
		ДобавитьДочерниеСтроки(НоваяСтрокаДерева, ТаблицаИсточника);
	КонецЦикла;

	// Переносим сформированное дерево в реквизит управляемой формы
	ЗначениеВРеквизитФормы(ДеревоОбъект, "ДеревоМаршрута");

КонецПроцедуры

&НаСервере
Процедура ДобавитьДочерниеСтроки(РодительскийУзел, ТаблицаИсточника)

	Отбор = Новый Структура("ИдентификаторРодителя", РодительскийУзел.ИдентификаторСтроки);
	ПодчиненныеСтроки = ТаблицаИсточника.НайтиСтроки(Отбор);

	Для Каждого СтрПодчиненная Из ПодчиненныеСтроки Цикл
		НоваяСтрока = РодительскийУзел.Строки.Добавить();
		ЗаполнитьЗначенияСвойств(НоваяСтрока, СтрПодчиненная);
		
		ДобавитьДочерниеСтроки(НоваяСтрока, ТаблицаИсточника);
	КонецЦикла;

КонецПроцедуры

Шаг 4. Выгрузка дерева обратно в табличную часть перед записью

Перед сохранением документа в базу данных необходимо выполнить обратную операцию: обойти все уровни дерева и перенести строки в табличную часть объекта Объект.МаршрутПоручений.

Рассмотрим код обработчика ПередЗаписьюНаСервере:


&НаСервере
Процедура ПередЗаписьюНаСервере(Отказ, ТекущийОбъект, ПараметрыЗаписи)

	ДеревоОбъект = РеквизитФормыВЗначение("ДеревоМаршрута");
	
	ТекущийОбъект.МаршрутПоручений.Очистить();
	ВыгрузитьУзлыДереваВТабличнуюЧасть(ДеревоОбъект.Строки, ТекущийОбъект.МаршрутПоручений);

КонецПроцедуры

&НаСервере
Процедура ВыгрузитьУзлыДереваВТабличнуюЧасть(КоллекцияСтрок, ТабличнаяЧасть)

	Для Каждого СтрокаДерева Из КоллекцияСтрок Цикл
		НоваяСтрокаТЧ = ТабличнаяЧасть.Добавить();
		ЗаполнитьЗначенияСвойств(НоваяСтрокаТЧ, СтрокаДерева);
		
		// Рекурсивный обход всех вложенных уровней
		Если СтрокаДерева.Строки.Количество() > 0 Тогда
			ВыгрузитьУзлыДереваВТабличнуюЧасть(СтрокаДерева.Строки, ТабличнаяЧасть);
		КонецЕсли;
	КонецЦикла;

КонецПроцедуры

Особенности интерактивной работы и добавления строк

При интерактивном добавлении элементов пользователем в дерево управляемой формы важно учитывать следующие моменты:

  1. Генерация идентификаторов: Для обеспечения уникальности ключей связей при создании новых строк на клиенте можно вычислять максимальный существующий номер либо генерировать строковый GUID через Строка(Новый УникальныйИдентификатор).
  2. Определение родителя: При нажатии кнопки добавления подчиненной строки значение ИдентификаторРодителя берется из реквизита Элементы.ДеревоМаршрута.ТекущиеДанные.ИдентификаторСтроки.
  3. Автоматическое разворачивание узлов: Чтобы пользователь сразу видел иерархию, после программного заполнения дерева на клиенте можно вызвать метод элемента управления Элементы.ДеревоМаршрута.Развернуть().

Альтернативные варианты реализации

Если задача заключается исключительно в визуализации процессов или маршрутов, проанализируем другие типовые механизмы платформы 1С:

  1. Механизм «Бизнес-процессы и Задачи»: Использование стандартных объектов конфигурации БизнесПроцесс и ЗадачаИсполнителя со встроенным элементом формы Поле графической схемы, где маршрут строится автоматически по карте маршрута.
  2. Иерархические справочники: Хранение цепочки подчиненных поручений в виде отдельных элементов иерархического справочника или связанных документов с реквизитом ДокументОснование, отображаемых через динамический список с включенной иерархией.
  3. Поле HTML документа: Трансляция маршрута в виде графа или древовидной диаграммы с использованием HTML5/SVG и отображением через элемент формы ПолеHTMLДокумента.
← На главную