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