При работе с типовыми конфигурациями 1С, особенно в розничной торговле, часто возникает потребность в визуализации данных отчетов. Один из распространенных запросов — вывод изображений товаров прямо в отчете, причем с учетом их характеристик, таких как цвет. Стандартный функционал Системы Компоновки Данных (СКД) не предоставляет встроенных инструментов для вывода картинок напрямую, особенно с учетом дополнительных свойств объекта. Однако, мы можем реализовать эту функциональность программными средствами, используя возможности обработки табличного документа, генерируемого СКД.
Рассмотрим подробнее, как мы можем решить эту задачу, комбинируя программные подходы и механизмы СКД.
Для реализации вывода картинок в отчетах СКД ключевым моментом является программное формирование или постобработка табличного документа, который получается в результате работы СКД. Основная точка входа для такой постобработки — процедура ПриКомпоновкеРезультата() в модуле отчета. Эта процедура выполняется уже после того, как СКД сформировала данные и разместила их в макете, но до того, как результат будет показан пользователю.
ПриКомпоновкеРезультата(): Эта процедура находится в модуле объекта отчета СКД. Если мы хотим полностью контролировать процесс вывода, нам необходимо установить параметр СтандартнаяОбработка = Ложь в начале этой процедуры. Это отменит стандартный вывод отчета и позволит нам сформировать табличный документ программно, используя полученные от СКД данные, или модифицировать уже скомпонованный СКД табличный документ.ТабличныйДокумент: Результатом компоновки СКД всегда является объект ТабличныйДокумент. Мы можем получить к нему доступ, обходить его ячейки, изменять их свойства (например, высоту строки) и, что самое главное, вставлять в него графические объекты.Одной из главных сложностей в этой задаче является определение, к какому товару и какой характеристике (например, цвету) относится текущая строка или ячейка отчета. Произвольный отчет подразумевает, что пользователь может изменять его структуру, добавлять или удалять колонки, группировки. В такой ситуации простой обход по индексам колонок становится ненадежным. Здесь на помощь приходит механизм расшифровки.
Номенклатура), может иметь связанные с ней данные расшифровки. Эти данные позволяют получить исходный объект, который был выведен в ячейке. Для получения данных расшифровки мы можем использовать свойства и методы табличного документа, например, Область.Расшифровка. При обходе табличного документа мы можем проверять, содержит ли текущая ячейка расшифровку, и если да, то извлекать из нее необходимую информацию.Область.Расшифровка), мы можем использовать объект ДанныеРасшифровки (который хранится во временном хранилище, если речь идет об управляемых формах) для получения конкретных полей и их значений, таких как ссылка на Номенклатуру или значение Характеристики. Это позволяет нам точно определить, какой товар и с какой характеристикой находится в данной строке отчета, независимо от ее визуального расположения.Номенклатура и значение Характеристики, которое в нашем случае является ссылкой на элемент справочника "ЗначенияСвойствОбъектов" или "ВидыНоменклатуры". Из этого элемента мы уже можем получить наименование цвета.КомпоновщикМакета). Это позволяет программно определить, какие поля были выведены в какие колонки и группировки, что может быть полезно для более сложной логики размещения изображений, но часто менее гибко при произвольных изменениях отчета пользователем.Когда мы определили, для какой номенклатуры и какого цвета нам нужна картинка, следующим шагом будет ее получение и вставка в табличный документ.
Номенклатура есть реквизит ФайлКартинки или аналогичный, который ссылается на присоединенные файлы (например, из справочника НоменклатураПрисоединенныеФайлы)."сайт.ру/images/" + Артикул + "_" + Цвет + ".jpg").ХранилищеЗначения.РисунокТабличногоДокумента: Для вставки изображения в табличный документ используется объект РисунокТабличногоДокумента. Мы создаем новый экземпляр этого объекта, устанавливаем его свойство Картинка и позиционируем его в нужной области.Картинка: Объект Картинка может быть создан из двоичных данных (полученных из файла, из базы данных или по HTTP) с помощью метода Новый Картинка(<ДвоичныеДанные>) или из общих картинок конфигурации.Расположить() объекта РисунокТабличногоДокумента позволяет указать область ячеек, в которой будет размещено изображение. Мы также можем настраивать его размер, пропорции, привязку к ячейкам и другие свойства.Рассмотрим по шагам, как можно реализовать эту функциональность.
Прежде всего, в схеме компоновки данных (СКД) необходимо убедиться, что в запрос включены следующие поля:
Номенклатура (или его код/артикул, если он уникален и используется для формирования URL картинки).Номенклатуре.Пример фрагмента запроса (псевдокод):
ВЫБРАТЬ
Номенклатура.Ссылка КАК Номенклатура,
Номенклатура.Артикул КАК Артикул,
ЗначенияСвойствОбъектов.Значение КАК Цвет
ИЗ
Справочник.Номенклатура КАК Номенклатура
ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ЗначенияСвойствОбъектов КАК ЗначенияСвойствОбъектов
ПО Номенклатура.Ссылка = ЗначенияСвойствОбъектов.Объект
И ЗначенияСвойствОбъектов.Свойство = &ВидСвойстваЦвет
Здесь &ВидСвойстваЦвет – это параметр, который будет содержать ссылку на элемент справочника "ВидыСвойствОбъектов" с наименованием "Цвет".
Откроем модуль объекта нашего отчета СКД и найдем процедуру ПриКомпоновкеРезультата().
Процедура ПриКомпоновкеРезультата(ДокументРезультат, ДанныеРасшифровки, СтандартнаяОбработка)
// Отменяем стандартную обработку, чтобы вручную сформировать или модифицировать отчет
СтандартнаяОбработка = Ложь;
// Сначала формируем стандартный отчет, чтобы получить его структуру и данные
// Можно использовать КомпоновщикМакета и ПроцессорКомпоновки,
// или же позволить СКД скомпоновать, а потом модифицировать.
// Для простоты, здесь мы предполагаем, что СКД уже скомпоновала ДокументРезультат
// (если не устанавливать СтандартнаяОбработка = Ложь сразу, а только после получения результата).
// Более правильный подход:
// 1. Получаем макет компоновки
МакетКомпоновки = КомпоновщикМакета.Выполнить(СхемаКомпоновкиДанных, КомпоновщикНастроек.Настройки, ДанныеРасшифровки);
// 2. Инициализируем процессор компоновки
ПроцессорКомпоновки = Новый ПроцессорКомпоновкиДанных;
ПроцессорКомпоновки.Инициализировать(МакетКомпоновки, ВнешниеНаборыДанных, ДанныеРасшифровки);
// 3. Инициализируем процессор вывода
ПроцессорВывода = Новый ПроцессорВыводаРезультатаКомпоновкиДанныхВТабличныйДокумент;
ПроцессорВывода.УстановитьДокумент(ДокументРезультат);
// 4. Выполняем вывод
ПроцессорВывода.НачатьВывод();
Пока Истина Цикл
ЭлементРезультата = ПроцессорКомпоновки.Следующий();
Если ЭлементРезультата = Неопределено Тогда
Прервать;
КонецЦикла;
ПроцессорВывода.ВывестиЭлемент(ЭлементРезультата);
КонецЦикла;
ПроцессорВывода.ЗакончитьВывод();
// Теперь ДокументРезультат содержит отчет, сгенерированный СКД.
// Мы можем его обходить и добавлять картинки.
// Вызовем нашу функцию для добавления картинок
ДобавитьКартинкиВОтчет(ДокументРезультат, ДанныеРасшифровки, КомпоновщикНастроек.Настройки);
КонецПроцедуры
В этой процедуре мы сначала программно формируем ТабличныйДокумент, а затем передаем его в нашу вспомогательную функцию ДобавитьКартинкиВОтчет, где будет происходить основная логика.
Создадим вспомогательную функцию, которая будет обходить сгенерированный отчет и искать места для вставки картинок.
// Вспомогательная процедура для добавления картинок в табличный документ
Процедура ДобавитьКартинкиВОтчет(ТабДок, ДанныеРасшифровки, НастройкиОтчета)
// Проверяем, включена ли опция "с картинками"
Если Не НастройкиОтчета.ДополнительныеСвойства.Свойство("ВыводитьКартинки") ИЛИ
Не НастройкиОтчета.ДополнительныеСвойства.ВыводитьКартинки Тогда
Возврат; // Если опция не включена, выходим
КонецЕсли;
Для Каждого ОбластьСтрок ИЗ ТабДок.Области Цикл
// Проверяем, является ли текущая область строкой или группировкой
Если ОбластьСтрок.ТипОбласти <> ТипОбластиТабличногоДокумента.Строка Тогда
Продолжить;
КонецЕсли;
// Обходим ячейки в текущей строке
Для ИндексКолонки = 0 ПО ОбластьСтрок.Ширина - 1 Цикл
Ячейка = ОбластьСтрок.ПолучитьОбласть(ОбластьСтрок.Верх + 1, ОбластьСтрок.Лево + ИндексКолонки + 1,
ОбластьСтрок.Верх + 1, ОбластьСтрок.Лево + ИндексКолонки + 1);
// Если ячейка содержит расшифровку
Если Ячейка.Расшифровка <> Неопределено Тогда
// Получаем данные расшифровки для этой ячейки
ЭлементРасшифровки = ДанныеРасшифровки.Элементы.Получить(Ячейка.Расшифровка);
Если ЭлементРасшифровки = Неопределено Тогда
Продолжить;
КонецЕсли;
// Получаем поля из элемента расшифровки
ПоляРасшифровки = ЭлементРасшифровки.ПолучитьПоля();
Если ПоляРасшифровки.Количество() = 0 Тогда
Продолжить;
КонецЕсли;
// Ищем Номенклатуру и Цвет среди полей расшифровки
Номенклатура = Неопределено;
ЦветНаименование = Неопределено;
Для Каждого ПолеРасшифровки ИЗ ПоляРасшифровки Цикл
Если ПолеРасшифровки.Поле = "Номенклатура" Тогда // Имя поля, которое мы вывели в СКД
Номенклатура = ПолеРасшифровки.Значение;
ИначеЕсли ПолеРасшифровки.Поле = "Цвет" Тогда // Имя поля для характеристики "Цвет"
ЦветНаименование = ПолеРасшифровки.Значение;
КонецЕсли;
КонецЦикла;
Если Номенклатура <> Неопределено И ЦветНаименование <> Неопределено Тогда
// Здесь мы нашли Номенклатуру и Цвет.
// Теперь нужно получить картинку и вставить ее.
ВставитьКартинкуВЯчейку(ТабДок, Ячейка, Номенклатура, ЦветНаименование);
КонецЕсли;
КонецЕсли;
КонецЦикла;
КонецЦикла;
КонецПроцедуры
Создадим функцию, которая будет получать двоичные данные картинки на основе номенклатуры и цвета. Этот пример покажет получение из внешней ссылки.
// Вспомогательная функция для получения двоичных данных картинки
Функция ПолучитьДвоичныеДанныеКартинки(НоменклатураСсылка, ЦветНаименование)
// Формируем URL для картинки (пример: Артикул + _ + Цвет.jpg)
Артикул = НоменклатураСсылка.Артикул;
Если ЗначениеЗаполнено(Артикул) И ЗначениеЗаполнено(ЦветНаименование) Тогда
// Пример формирования URL с внешнего сайта
URLКартинки = "https://example.com/images/" + СокрЛП(Артикул) + "_" + СокрЛП(ЦветНаименование) + ".jpg";
Попытка
HTTPЗапрос = Новый HTTPЗапрос(URLКартинки);
HTTPСоединение = Новый HTTPСоединение("example.com"); // Указываем домен сайта
HTTPОтвет = HTTPСоединение.Получить(HTTPЗапрос);
Если HTTPОтвет.КодСостояния = 200 Тогда // Успешный ответ
Возврат HTTPОтвет.ПолучитьТелоКакДвоичныеДанные();
Иначе
ЗаписатьЖурналРегистрации("Не удалось получить картинку: " + URLКартинки + ". Код состояния: " + HTTPОтвет.КодСостояния, УровеньЖурналаРегистрации.Ошибка);
КонецЕсли;
Исключение
ЗаписатьЖурналРегистрации("Ошибка при получении картинки: " + ОписаниеОшибки(), УровеньЖурналаРегистрации.Ошибка);
КонецПопытки;
КонецЕсли;
Возврат Неопределено;
КонецФункции
// Пример для получения из справочника присоединенных файлов (НоменклатураПрисоединенныеФайлы)
Функция ПолучитьДвоичныеДанныеКартинкиИзБазы(НоменклатураСсылка, ЦветСсылка = Неопределено)
// Здесь нужна более сложная логика, т.к. в типовых нет прямого связывания "картинка + характеристика".
// Обычно основная картинка хранится в НоменклатураПрисоединенныеФайлы для самой Номенклатуры.
// Если есть отдельные картинки для характеристик, их придется хранить в отдельном регистре
// с привязкой к Номенклатуре и Характеристике.
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ ПЕРВЫЕ 1
| Файлы.ДвоичныеДанныеФайла КАК ДвоичныеДанныеФайла
|ИЗ
| Справочник.НоменклатураПрисоединенныеФайлы КАК Файлы
|ГДЕ
| Файлы.ВладелецФайла = &НоменклатураСсылка
| И Файлы.ПометкаУдаления = ЛОЖЬ
| И Файлы.ЭтоКартинка = ИСТИНА
|{ГДЕ
| Файлы.Описание = &ОписаниеЦвета}"; // Можно использовать поле "Описание" для указания цвета
Запрос.УстановитьПараметр("НоменклатураСсылка", НоменклатураСсылка);
Если ЗначениеЗаполнено(ЦветСсылка) Тогда
// Если цвет тоже ссылка, используем ее.
// Или если 'Описание' содержит наименование цвета.
Запрос.УстановитьПараметр("ОписаниеЦвета", ЦветСсылка.Наименование);
КонецЕсли;
РезультатЗапроса = Запрос.Выполнить();
Если Не РезультатЗапроса.Пуст() Тогда
Выборка = РезультатЗапроса.Выбрать();
Выборка.Следующий();
Возврат Выборка.ДвоичныеДанныеФайла;
КонецЕсли;
Возврат Неопределено;
КонецФункции
И наконец, функция для вставки полученной картинки в отчет.
// Вспомогательная процедура для вставки картинки в ячейку
Процедура ВставитьКартинкуВЯчейку(ТабДок, Ячейка, Номенклатура, ЦветНаименование)
ДвоичныеДанные = ПолучитьДвоичныеДанныеКартинки(Номенклатура, ЦветНаименование); // Используем внешнее получение
Если ДвоичныеДанные = Неопределено Тогда
Возврат;
КонецЕсли;
Попытка
КартинкаОбъект = Новый Картинка(ДвоичныеДанные);
Исключение
ЗаписатьЖурналРегистрации("Ошибка при создании объекта Картинка: " + ОписаниеОшибки(), УровеньЖурналаРегистрации.Ошибка);
Возврат;
КонецПопытки;
// Определяем область для вставки картинки (например, после ячейки с номенклатурой)
// Можно создать новую колонку специально для картинок или вставить в существующую
// Предположим, мы хотим вставить картинку в ячейку рядом с номенклатурой
// Если мы хотим вставить в саму ячейку или создать новую колонку:
// Для примера, увеличим высоту строки и вставим картинку в новую колонку справа от текущей ячейки
ТабДок.ВысотаСтроки(Ячейка.Верх, Ячейка.Высота + 5); // Увеличим высоту строки для картинки
// Создаем новый рисунок
НовыйРисунок = ТабДок.Рисунки.Добавить(ТипРисункаТабличногоДокумента.Картинка);
НовыйРисунок.Картинка = КартинкаОбъект;
// Располагаем картинку. Например, в следующей колонке справа от текущей ячейки
// Или в самой ячейке, если она достаточно широкая
// Здесь мы создадим новую область, которая занимает 2 колонки и такую же высоту как текущая строка
// Сдвинем все ячейки справа от Номенклатуры на 2 колонки
// Более простой вариант - найти пустую колонку или добавить новую
// Для простоты, разместим картинку в текущей ячейке, если она пуста или если мы хотим заменить текст
// Или создадим новую область, если хотим добавить картинку отдельно.
// Пример: вставка картинки в новую, пустую область справа от ячейки с товаром
ЛевоКартинки = Ячейка.Лево + Ячейка.Ширина;
ВерхКартинки = Ячейка.Верх;
ШиринаКартинки = 5; // Условная ширина в ячейках
ВысотаКартинки = Ячейка.Высота + 5; // Высота картинки
// Добавляем ячейки, если нужно, чтобы создать место для картинки
// ТабДок.ВставитьКолонки(ЛевоКартинки, ШиринаКартинки);
НовыйРисунок.Расположить(ТабДок.Область(ВерхКартинки, ЛевоКартинки, ВерхКартинки + ВысотаКартинки -1, ЛевоКартинки + ШиринаКартинки - 1));
// Настройки отображения
НовыйРисунок.РазмерКартинки = РазмерКартинки.АвтоРазмер; // Или Пропорционально, РеальныйРазмер
НовыйРисунок.ГраницаСлева = Новый Линия(ТипЛинииРисунка.Нет);
НовыйРисунок.ГраницаСверху = Новый Линия(ТипЛинииРисунка.Нет);
НовыйРисунок.ГраницаСправа = Новый Линия(ТипЛинииРисунка.Нет);
НовыйРисунок.ГраницаСнизу = Новый Линия(ТипЛинииРисунка.Нет);
// Можно также очистить текст в ячейке, если картинка вставляется вместо него
// Ячейка.Текст = "";
КонецПроцедуры
РисунокТабличногоДокумента, такие как РазмерКартинки и ПривязкаКОбласти, чтобы они адекватно отображались в отчете и не "разъезжались". Возможно, потребуется программно регулировать высоту строк или ширину колонок под размер изображения.Таким образом, хотя вывод изображений с учетом характеристик в отчетах СКД требует значительной программной доработки, используя событие ПриКомпоновкеРезультата() и механизмы расшифровки табличного документа, мы можем добиться желаемого результата, делая отчеты более информативными и наглядными.