Как в отчете СКД при клике на сумму получить значения сотрудника и организации?

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

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

Почему стандартно возвращается только значение ячейки?

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

Рассмотрим подробнее три основных способа реализации этой задачи.

---

Способ 1. Программный обход дерева расшифровки на сервере

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

На управляемых формах реквизит ДанныеРасшифровки на клиенте представляет собой строку — адрес во временном хранилище. Сами данные расшифровки доступны только на сервере. Поэтому процесс обработки мы разделим на два этапа.

Шаг 1. Перехватываем событие на клиенте. В модуле формы отчета находим событие РезультатОбработкаРасшифровки для поля табличного документа:


&НаКлиенте
Процедура РезультатОбработкаРасшифровки(Элемент, Расшифровка, СтандартнаяОбработка)
    
    // Отменяем стандартное действие (например, открытие меню по умолчанию)
    СтандартнаяОбработка = Ложь;
    
    // Передаем обработку на сервер, так как данные расшифровки лежат во временном хранилище
    СтруктураПараметров = ПолучитьПараметрыСтрокиНаСервере(ДанныеРасшифровки, Расшифровка);
    
    // Анализируем полученный результат
    Если СтруктураПараметров.Свойство("Сотрудник") И ЗначениеЗаполнено(СтруктураПараметров.Сотрудник) Тогда
        ПоказатьЗначение(, СтруктураПараметров.Сотрудник);
    КонецЕсли;
    
КонецПроцедуры

Шаг 2. Реализуем серверную функцию обхода дерева. Нам потребуется рекурсивно подняться вверх по родительским элементам расшифровки, чтобы собрать значения всех полей, влияющих на данную строку:


&НаСервереБезКонтекста
Функция ПолучитьПараметрыСтрокиНаСервере(Знач АдресРасшифровки, Знач ИдентификаторРасшифровки)
    
    Результат = Новый Структура("Сотрудник, Организация");
    
    // Получаем объект данных расшифровки из временного хранилища
    Данные = ПолучитьИзВременногоХранилища(АдресРасшифровки);
    Если ТипЗнч(Данные) <> Тип("ДанныеРасшифровкиКомпоновкиДанных") Тогда
        Возврат Результат;
    КонецЕсли;
    
    // Запускаем рекурсивный поиск параметров по дереву расшифровки
    ИскатьРодительскиеПоля(Данные, ИдентификаторРасшифровки, Результат);
    
    Возврат Результат;
    
КонецФункции

&НаСервереБезКонтекста
Процедура ИскатьРодительскиеПоля(Данные, Идентификатор, Результат)
    
    Элемент = Данные.Элементы[Идентификатор];
    Если Элемент = Неопределено Тогда
        Возврат;
    КонецЕсли;
    
    // Проверяем, содержит ли текущий элемент непосредственно поля
    Если ТипЗнч(Элемент) = Тип("ЭлементРасшифровкиКомпоновкиДанныхПоля") Тогда
        Для Каждого Поле Из Элемент.ПолучитьПоля() Цикл
            Если Поле.Поле = "Сотрудник" Тогда
                Результат.Вставить("Сотрудник", Поле.Значение);
            ИначеЕсли Поле.Поле = "Организация" Тогда
                Результат.Вставить("Организация", Поле.Значение);
            КонецЕсли;
        КонецЦикла;
    КонецЕсли;
    
    // Рекурсивно переходим к родительским элементам (группировкам выше по иерархии)
    Родители = Элемент.ПолучитьРодителей();
    Для Каждого Родитель Из Родители Цикл
        ИскатьРодительскиеПоля(Данные, Родитель.Идентификатор, Результат);
    КонецЦикла;
    
КонецПроцедуры

Этот код надежно соберет значения полей Сотрудник и Организация, на пересечении которых находится кликнутая ячейка с суммой.

---

Способ 2. Использование собственного макета компоновки

Если структура отчета жестко фиксирована и вы не хотите писать сложный программный обход дерева на сервере, можно воспользоваться возможностями макетов СКД. Этот метод позволяет связать ячейку с параметрами напрямую на этапе проектирования схемы.

Разберем этот вариант по шагам:

  1. Откройте схему компоновки данных и перейдите на вкладку Макеты.
  2. Добавьте новый макет поля. Выберите поле, для которого настраивается связь (в нашем случае это ресурс Сумма).
  3. В созданной области макета выделите ячейку и в её свойствах укажите имя параметра расшифровки (например, РасшифровкаСуммы).
  4. В таблице настройки параметров макета для созданного параметра РасшифровкаСуммы добавьте связи. Укажите, что вместе с этим параметром должны передаваться поля Сотрудник и Организация.

После такой настройки при клике на ячейку суммы платформа сразу упакует связанные поля в элемент расшифровки. Процедура получения значений на сервере значительно упростится:


&НаСервереБезКонтекста
Функция ПолучитьПараметрыИзМакета(Знач АдресРасшифровки, Знач ИдентификаторРасшифровки)
    
    Результат = Новый Структура("Сотрудник, Организация");
    Данные = ПолучитьИзВременногоХранилища(АдресРасшифровки);
    
    Элемент = Данные.Элементы[ИдентификаторРасшифровки];
    Если ТипЗнч(Элемент) = Тип("ЭлементРасшифровкиКомпоновкиДанныхПоля") Тогда
        Для Каждого Поле Из Элемент.ПолучитьПоля() Цикл
            Если Поле.Поле = "Сотрудник" Тогда
                Результат.Вставить("Сотрудник", Поле.Значение);
            ИначеЕсли Поле.Поле = "Организация" Тогда
                Результат.Вставить("Организация", Поле.Значение);
            КонецЕсли;
        КонецЦикла;
    КонецЕсли;
    
    Возврат Результат;
    
КонецФункции

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

---

Способ 3. Использование свойства «Выражение расшифровки» в СКД

Еще один альтернативный вариант без программирования сложных алгоритмов — использование стандартного свойства полей СКД на вкладке Наборы данных.

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

---

Что делать с полученными значениями далее?

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

Для реализации меню выбора используйте следующий шаблон кода на клиенте:


&НаКлиенте
Процедура РезультатОбработкаРасшифровки(Элемент, Расшифровка, СтандартнаяОбработка)
    
    СтандартнаяОбработка = Ложь;
    ПараметрыСтроки = ПолучитьПараметрыСтрокиНаСервере(ДанныеРасшифровки, Расшифровка);
    
    Если ПараметрыСтроки.Сотрудник = Неопределено Тогда
        Возврат;
    КонецЕсли;
    
     Меню = Новый СписокЗначений;
     Меню.Добавить("ОткрытьКарточку", "Открыть карточку сотрудника");
     Меню.Добавить("ОткрытьОтчет", "Показать детальный отчет по сотруднику");
     
     Оповещение = Новый ОписаниеОповещения("ПослеВыбораИзМеню", ЭтотОбъект, ПараметрыСтроки);
     ПоказатьВыборИзМеню(Оповещение, Меню, Элемент);
     
КонецПроцедуры

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

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

← На главную