Как в дереве значений вывести список проектов через запятую в строке группировки?

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

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

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

Анализ проблемы

Изначально колонка "Проект" в дереве значений обычно имеет тип СправочникСсылка.Проекты. Если вы попытаетесь программно записать в ячейку группировки строку вида "Проект А, Проект Б", платформа выдаст ошибку несоответствия типов, так как строка не является ссылкой.

Рассмотрим два основных способа решения этой задачи: "визуальный" (через условное оформление) и "структурный" (через изменение типа данных).

Способ 1: Использование Условного оформления (Рекомендуемый)

Этот метод является наиболее правильным с точки зрения архитектуры управляемых форм. Мы не ломаем типы данных в основной колонке, а лишь подменяем отображаемый текст.

Алгоритм действий:

  1. Добавим в дерево значений новую колонку, назовем её, например, СтрокаПроектов. Тип значения — Строка.
  2. Эту колонку не обязательно выводить на форму, она может оставаться служебной в реквизитах формы.
  3. При формировании дерева (или после его заполнения) программно обойдем группировки, соберем проекты из подчиненных строк и запишем полученную строку в колонку СтрокаПроектов.
  4. Настроим Условное оформление формы.

Настройка Условного оформления:

В конфигураторе или программно (в процедуре ПриСозданииНаСервере) создадим элемент условного оформления:

Таким образом, платформа будет хранить в колонке "Проект" пустую ссылку (для группировки), но пользователю покажет текст из служебной колонки.

Способ 2: Использование Составного типа данных

Если по каким-то причинам условное оформление не подходит, можно изменить тип самой колонки "Проект", чтобы она могла хранить и ссылки, и строки.

Это делается программно при инициализации дерева. Если дерево создается на основе запроса или выгружается из ТаблицыЗначений, колонки изначально имеют жесткий тип.

Рассмотрим, как изменить тип колонки программно:


// Создаем описание типов, содержащее и Ссылку, и Строку
МассивТипов = Новый Массив;
МассивТипов.Добавить(Тип("СправочникСсылка.Проекты"));
МассивТипов.Добавить(Тип("Строка"));

// Присваиваем описание типов квалификаторам строки (длина, допустимая длина)
КвалификаторыСтроки = Новый КвалификаторыСтроки(0); // 0 - неограниченная длина
ОписаниеТиповПроект = Новый ОписаниеТипов(МассивТипов, , КвалификаторыСтроки);

// Изменяем тип колонки дерева значений (если работаем с объектом ДеревоЗначений на сервере)
ДеревоОбъект.Колонки.Проект.ТипЗначения = ОписаниеТиповПроект;

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

Алгоритм сбора данных (Постобработка)

Поскольку язык запросов 1С не имеет функции агрегации строк (аналога GROUP_CONCAT из SQL), собирать строку с проектами придется постобработкой дерева. Это делается на сервере после того, как дерево уже заполнено данными из базы.

Давайте напишем универсальный алгоритм, который обходит дерево, собирает уникальные проекты и формирует строку.


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

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

Важные нюансы реализации

При внедрении этого решения обратите внимание на следующие моменты:

1. Рекурсия для многоуровневых деревьев
В примере выше мы рассмотрели дерево с одним уровнем вложенности. Если у вас многоуровневое дерево и группировки могут быть вложены друг в друга, вам потребуется вынести логику обхода в отдельную процедуру и вызывать её рекурсивно для каждого уровня.

2. Ограничение длины строки
Если заявок у контрагента очень много, строка с перечислением проектов может получиться огромной. Имеет смысл ограничить количество выводимых элементов или обрезать строку, добавляя многоточие. Пример:


Если СписокПроектов.Количество() > 5 Тогда
    // Оставим первые 5 и добавим "..."
    // ... код обрезки массива ...
    ИтоговаяСтрока = ИтоговаяСтрока + "... и еще " + (Всего - 5);
КонецЕсли;

3. Интерактивность
Если вы используете Способ 2 (Составной тип), помните, что при клике на ячейку группировки платформа не откроет карточку проекта (так как там текст), но может войти в режим редактирования строки. Рекомендуется установить для группировок свойство ТолькоПросмотр в значение Истина при выводе строк.

Заключение

Для вывода агрегированных строковых данных в группировках дерева значений используйте постобработку данных на сервере. Наиболее элегантное решение — использование механизма Условного оформления в связке со служебной колонкой. Это сохраняет типизацию данных и гибкость интерфейса.

← На главную