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