Учим БСП печатать активные ссылки и подложку в документе WORD

13.03.23

Разработка - БСП (Библиотека стандартных подсистем)

Небольшое расширение БСП для печати в WORD. Добавлена печать активных ссылок, подложки документа, и фона страницы.

Файлы

ВНИМАНИЕ: Файлы из Базы знаний - это исходный код разработки. Это примеры решения задач, шаблоны, заготовки, "строительные материалы" для учетной системы. Файлы ориентированы на специалистов 1С, которые могут разобраться в коде и оптимизировать программу для запуска в базе данных. Гарантии работоспособности нет. Возврата нет. Технической поддержки нет.

Наименование Скачано Купить файл
Учим БСП печатать активные ссылки и подложку в документе WORD:
.cfe 10,05Kb ver:1.0.1
7 2 500 руб. Купить

Подписка PRO — скачивайте любые файлы со скидкой до 85% из Базы знаний

Оформите подписку на компанию для решения рабочих задач

Оформить подписку и скачать решение со скидкой

Вы можете заказать платную доработку или адаптацию этой разработки под вашу конфигурацию на «Бирже заказов».

  • 0% комиссии — оплата напрямую исполнителю;
  • Исполнители любого масштаба — от отдельных специалистов до команд под проект;
  • Прямой обмен контактами между заказчиком и исполнителем;
  • Безопасная сделка — при необходимости;
  • Рейтинги, кейсы и прозрачная система откликов.

Стандартный функционал БСП при печати делает все гиперссылки неактивными, оставляя их оформление, а также теряет оформление страницы документа (фон и подложку). Данное расширение исправляет эти проблемы. Для чего это нужно, например для красивых прайсов, с последующим их преобразование в PDF и рассылки клиентам.

В расширении были модифицированы следующие общего модуля "УправлениеПечатьюСлужебный":

  • ОбработатьРазделДокумента()
  • РазбитьТекстШаблонаНаОбласти()
  • СобратьФайлДокументаDOCX()
  • ИнициализироватьСтруктуруПечатнойФормы()

 

Разберем доработки в порядке вызова их при печати.
При инициализации макета происходит вызов процедуры РазбитьТекстШаблонаНаОбласти() именно в ней теряется вся "магия" ссылок. Проблема в том, что БСП при разборе текста делит его на два типа "параграф" и все остальное. Научим ее понимать ссылки, комментариям с "{","}" обозначен доработанный код.

&Вместо("РазбитьТекстШаблонаНаОбласти")
Процедура Расш1_РазбитьТекстШаблонаНаОбласти(ЧтениеXML, СтруктураДокумента, ПараметрыАнализа)
	
	УровеньТэгаБлок       = -1;
	УровеньТэгаОбласть    = -1;
	УровеньАбзаца         = "0";
	ТекущийУровень        = 0;
	ПропуститьТэг         = Ложь;
	ТекстРаздела          = ""; 
    //{
	ЭтоСсылка		  = Ложь; // Флаг разбора ссылки
	текБлокРазбора		  = "";   // возможные значения "Блок", "АбзацХ", где Х - порядковый номер
	//}
	
	СтруктураРазбораXML = ИнициализироватьРазборXML();
	
	СброситьСтатусыТэгов1С(СтруктураРазбораXML);
	
	ИнициализироватьЗаписьВПоток(СтруктураРазбораXML, "Заголовок", "");
		
	Если ПараметрыАнализа.ТипАнализа <> 1 Тогда
		ИнициализироватьЗаписьВПоток(СтруктураРазбораXML, "Блок", "");
		УровеньТэгаБлок = 0;
	КонецЕсли;
	
	Пока ЧтениеXML.Прочитать() Цикл
		
...		
		Если ЧтениеНачалаРаздела(СтруктураРазбораXML, ЧтениеXML) Тогда
			СтруктураРазбораXML.БлокирующийПоток = "Раздел";
			ИнициализироватьЗаписьВПоток(СтруктураРазбораXML, "Раздел", "", Ложь);
			ПеренестиОткрывающиеТэгиЗаписиВПоток(СтруктураРазбораXML, "Заголовок", "Раздел", "w:body");
		КонецЕсли;
		
		// начало разбора ссылки {
		Если ЧтениеНачалаБлокаСсылки(СтруктураРазбораXML, ЧтениеXML) Тогда
			ИнициализироватьЗаписьВПоток(СтруктураРазбораXML, "Ссылка");   
			//ОстановитьЗаписьВПоток(СтруктураРазбораXML, "Абзац" + УровеньАбзаца);
						
			ОстановитьЗаписьВПоток(СтруктураРазбораXML, текБлокРазбора);
			ЭтоСсылка = Истина;
			
		КонецЕсли;  
		// }
		
		Если ЧтениеНачалаЛюбогоБлокаКромеПараграфа(СтруктураРазбораXML, ЧтениеXML) И ТекущийУровень = УровеньТэгаБлок Тогда
			ИнициализироватьЗаписьВПоток(СтруктураРазбораXML, "Блок");   
			текБлокРазбора = "Блок";   // укажем текущий блок {}
		КонецЕсли;
		
		Если ЧтениеНачалаПараграфа(СтруктураРазбораXML, ЧтениеXML) Тогда
			УровеньАбзаца = Формат(Число(УровеньАбзаца) + 1, "ЧН=0; ЧГ=0");
			СтруктураРазбораXML.ТекущийУровеньАбзаца = УровеньАбзаца;
			
			СброситьСтатусыТэгов1С(СтруктураРазбораXML, Истина);
			ИнициализироватьЗаписьВПоток(СтруктураРазбораXML, "Абзац" + УровеньАбзаца);
			ИнициализироватьЗаписьВПоток(СтруктураРазбораXML, "Строки" + УровеньАбзаца);
			ОстановитьЗаписьВПоток(СтруктураРазбораXML, "Строки" + УровеньАбзаца); 
			текБлокРазбора = "Абзац" + УровеньАбзаца;   // укажем текущий блок {}
		КонецЕсли;
		
...		
		// учтем флаг разбора ссылки {
		//Если ЧтениеНачалаСтроки(СтруктураРазбораXML, ЧтениеXML) Тогда
		Если ЧтениеНачалаСтроки(СтруктураРазбораXML, ЧтениеXML) И НЕ ЭтоСсылка Тогда
		// }			
			ВозобновитьЗаписьВПоток(СтруктураРазбораXML, "Строки" + УровеньАбзаца);
			ИнициализироватьЗаписьВПоток(СтруктураРазбораXML, "СтрокаПарам" + УровеньАбзаца);
			ОстановитьЗаписьВПоток(СтруктураРазбораXML, "Абзац" + УровеньАбзаца);
			СтруктураРазбораXML.ИмяПотокаФормата = "СтрокаПарам" + УровеньАбзаца;
		КонецЕсли;
		
...		
		// учтем флаг разбора ссылки {
		//Если ЧтениеКонцаСтроки(СтруктураРазбораXML, ЧтениеXML) Тогда
		Если ЧтениеКонцаСтроки(СтруктураРазбораXML, ЧтениеXML) И НЕ ЭтоСсылка Тогда
		// }	
			Если СтруктураРазбораXML.СтатусТэга1С = 0 И СтруктураРазбораXML.РазобранныеСтроки.Количество() = 0 Тогда
				ПеренестиЗаписьВПоток(СтруктураРазбораXML, "Строки" + УровеньАбзаца, "Абзац" + УровеньАбзаца);
			ИначеЕсли СтруктураРазбораXML.РазобранныеСтроки.Количество() > 0 Тогда
...
			КонецЕсли;
			
...
		КонецЕсли;
		
		Если ЧтениеКонцаПараграфа(СтруктураРазбораXML, ЧтениеXML) Тогда
...
		КонецЕсли;
		
		// завершение разбора ссылки {
		Если ЧтениеКонцаБлокаСсылки(СтруктураРазбораXML, ЧтениеXML) Тогда 
			
			Если текБлокРазбора = "" Тогда 
				текБлокРазбора = "Строки" + УровеньАбзаца;
			КонецЕсли;	
			
			ВозобновитьЗаписьВПоток(СтруктураРазбораXML, текБлокРазбора);
			ЗавершитьЗаписьВПоток(СтруктураРазбораXML, "Ссылка");
			ПеренестиЗаписьВПоток(СтруктураРазбораXML, "Ссылка", текБлокРазбора); 
			ЭтоСсылка = Ложь;
		КонецЕсли;	
		// }
		
...	
КонецПроцедуры
С помощью двух простых функций определяем начало и конец блока ссылки, листинг ниже:
Функция ЧтениеНачалаБлокаСсылки(СтруктураРазбораXML, ЧтениеXML)
	
	Если Не ПустаяСтрока(СтруктураРазбораXML.БлокирующийПоток) Тогда
		Возврат Ложь;
	КонецЕсли;
	
	Возврат ЧтениеXML.ТипУзла = ТипУзлаXML.НачалоЭлемента И ЧтениеXML.Имя = "w:hyperlink";
	
КонецФункции

Функция ЧтениеКонцаБлокаСсылки(СтруктураРазбораXML, ЧтениеXML)
	
	Если Не ПустаяСтрока(СтруктураРазбораXML.БлокирующийПоток) Тогда
		Возврат Ложь;
	КонецЕсли;
	
	Возврат ЧтениеXML.ТипУзла = ТипУзлаXML.КонецЭлемента И ЧтениеXML.Имя = "w:hyperlink";
	
КонецФункции

 

После инициализации макета, происходит инициализация печатной формы, в процессе которой данные макета копируются.

В процедуре ИнициализироватьСтруктуруПечатнойФормы() нужно закомментировать очистку текста колонтитулов получаемую из макета. Это нужно чтобы не потерять подложку страницы, т.к. она хранится в колонтитулах. БСП учитывает только те колонтитулы которые привязаны к разделам документа, а остальные безжалостно очищает.

 

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

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

После того, как мы сформируем макет, и заполним его данными произойдет вызов функции СобратьФайлДокументаDOCX(). Внутри нее происходит формирование структуры документа. Здесь нужно заменить обработку колонтитулов из разделов документа на структуру. Так же здесь происходит вызов последней интересующей нас функции ОбработатьРазделДокумента()

&Вместо("СобратьФайлДокументаDOCX")
Функция Расш1_СобратьФайлДокументаDOCX(ПечатнаяФорма)
	
	ИзменяемыеФайлы = Новый Соответствие;
	ИзменяемыеФайлы.Вставить("СвязиКонтента", ПечатнаяФорма.ИмяКаталога + УстановитьРазделительПути("\word\_rels\document.xml.rels"));
	ИзменяемыеФайлы.Вставить("ТипыКонтента",  ПечатнаяФорма.ИмяКаталога + УстановитьРазделительПути("\[Content_Types].xml"));
	ИзменяемыеФайлы.Вставить("Документ",      ПечатнаяФорма.ИмяКаталога + УстановитьРазделительПути("\word\document.xml"));
	
	// обработка колонтитулов {

	КолонтитулВыведен = Новый Соответствие;
	Для Каждого ЭлементКолонтитула Из ПечатнаяФорма.СтруктураДокумента.Колонтитулы Цикл
		
		Колонтитул = ЭлементКолонтитула.Значение;
		
		ИмяФайла = ПечатнаяФорма.ИмяКаталога + УстановитьРазделительПути("\word\") + Колонтитул.ИмяВнутр + ".xml";
		Если ПустаяСтрока(Колонтитул.Текст) Тогда
			Продолжить;
		КонецЕсли;
		
		ЗаписьXML = Новый ЗаписьТекста(ИмяФайла, КодировкаТекста.UTF8);
		ЗаписьXML.Записать(Колонтитул.Текст);
		ЗаписьXML.Закрыть();
		
		КолонтитулВыведен.Вставить(ЭлементКолонтитула.Ключ, ИСТИНА);
		
	КонецЦикла;
	
	////// Удаляем файлы пустых колонтитулов
	////КолонтитулВыведен = Новый Соответствие;
	////
	////Для Каждого Раздел Из ПечатнаяФорма.СтруктураДокумента.Разделы Цикл
	////	
	////	Для Каждого ЭлементКолонтитула Из Раздел.Значение.Колонтитулы Цикл
	////		
	////		Колонтитул = ЭлементКолонтитула.Значение;
	////		
	////		ИмяФайла = ПечатнаяФорма.ИмяКаталога + УстановитьРазделительПути("\word\") + Колонтитул.ИмяВнутр + ".xml";
	////		Если ПустаяСтрока(Колонтитул.Текст) Тогда
	////			Продолжить;
	////		КонецЕсли;
	////		
	////		ЗаписьXML = Новый ЗаписьТекста(ИмяФайла, КодировкаТекста.UTF8);
	////		ЗаписьXML.Записать(Колонтитул.Текст);
	////		ЗаписьXML.Закрыть();
	////		
	////		КолонтитулВыведен.Вставить(ЭлементКолонтитула.Ключ, ИСТИНА);
	////		
	////	КонецЦикла;
	////	
	////КонецЦикла;           

	// обработка колонтитулов }
	
...
	
	ПечатнаяФорма.СтруктураДокумента.ТипыКонтента = ЗаписьXML.Закрыть(); 
	
	// Формирование документа печатной формы
	
	ПорядковыйНомер = 1;
	
	ЗаписьXML = ИнициализироватьЗаписьXML("", ИзменяемыеФайлы.Получить("Документ"));
	
	НомерРаздела           = Неопределено;
	КоличествоОбластей     = ПечатнаяФорма.СтруктураДокумента.ПрисоединенныеОбласти.Количество();
	ИдентификаторДокумента = ПечатнаяФорма.СтруктураДокумента.ИдентификаторДокумента;
	
	Для Каждого Область Из ПечатнаяФорма.СтруктураДокумента.ПрисоединенныеОбласти Цикл
		
	...		
		Если ВывестиПромежуточныйРаздел = Истина И ЭтоПоследняяОбласть = Ложь Тогда
			
			РазделКВыводу = ПечатнаяФорма.СтруктураДокумента.Разделы.Получить(НомерРаздела);
			
			Если РазделКВыводу <> Неопределено Тогда
				
				ТекстРаздела = ОбработатьРазделДокумента(ПечатнаяФорма.СтруктураДокумента, РазделКВыводу);
				
	...				
			КонецЕсли;
			
		КонецЕсли;
		
	...
		
		// Запись заключительного раздела
		
		Если ЭтоПоследняяОбласть Тогда
			
			РазделКВыводу = ПечатнаяФорма.СтруктураДокумента.Разделы.Получить(Область.НомерРаздела);
			Если РазделКВыводу <> Неопределено Тогда
				ТекстРаздела = ОбработатьРазделДокумента(ПечатнаяФорма.СтруктураДокумента, РазделКВыводу);
				ЗаписьXML.ЗаписатьБезОбработки(ТекстРаздела);
			КонецЕсли;
			
		КонецЕсли;
		
		ПорядковыйНомер = ПорядковыйНомер + 1;
		НомерРаздела = Область.НомерРаздела;
		
	КонецЦикла;
	
	ЗаписьXML.ЗаписатьКонецЭлемента(); // Закрытие тэга </w:body>
	ЗаписьXML.ЗаписатьКонецЭлемента(); // Закрытие тэга </w:document>
	
	ЗаписьXML.Закрыть();
	
	ПутьКДокументу = ПолучитьИмяВременногоФайла("DOCX");
	
	СобратьКонтейнерДокументаDOCX(ПутьКДокументу, ПечатнаяФорма.ИмяКаталога);
	
	Возврат ПутьКДокументу;

КонецФункции

В этой функции нужно добавить пропуск обработки тэгов background. Формирование итогового документа происходит из xml-блоков, количество которых равно количеству областей добавленных в макете при выводе. А каждый такой блок представляет собой полноценный xml-документ, xml-заголовок которого формируется путем копирования заголовка макета. Сам тег background отвечающий за фон страницы располагается до секции body, и если его не удалять, то нарушается xml-структура получаемого документа.

&Вместо("ОбработатьРазделДокумента")
Функция Расш1_ОбработатьРазделДокумента(СтруктураДокумента, Раздел)
	
	ТипыКолонтитулов = ТипыКолонтитулов();
	
	ЧтениеXML = ИнициализироватьЧтениеXML(Раздел.Текст);
	ЗаписьXML = ИнициализироватьЗаписьXML("",,,Ложь);
	
	ПропуститьТэг = Ложь;
	Пока ЧтениеXML.Прочитать() Цикл
		
		Если ПропуститьТэг = Истина Тогда
			ПропуститьТэг = Ложь;
			Продолжить;
		КонецЕсли;
		
		Если ЧтениеXML.ТипУзла = ТипУзлаXML.НачалоЭлемента И (ЧтениеXML.Имя = "w:document" ИЛИ ЧтениеXML.Имя = "w:body") Тогда
			Продолжить;
		КонецЕсли;

		// обработка цвета фона {
		Если ЧтениеXML.ТипУзла = ТипУзлаXML.НачалоЭлемента И (ЧтениеXML.Имя = "w:background") Тогда
			Продолжить;
		КонецЕсли;
		// }
		
...		
		Если ЧтениеXML.ТипУзла = ТипУзлаXML.КонецЭлемента И (ЧтениеXML.Имя = "w:document" ИЛИ ЧтениеXML.Имя = "w:body") Тогда
			Продолжить;
		КонецЕсли;   
		
		// обработка цвета фона {
		Если ЧтениеXML.ТипУзла = ТипУзлаXML.КонецЭлемента И (ЧтениеXML.Имя = "w:background") Тогда
			Продолжить;
		КонецЕсли;
		// }
		
		ЗаписатьЭлементXML(ЧтениеXML, ЗаписьXML);
		
	КонецЦикла;
	
	ТекстРаздела = ЗаписьXML.Закрыть();
	
	Возврат ТекстРаздела;

КонецФункции

В результате на выходе мы можем получить документ с любым цветом фона и фоновым рисунком, а также активными ссылками, по  которым можно перейти с помощью CTRL.

PS. Не проверял работоспособность при использовании колонтитулов в макете.

Проверено на БСП 3.1.5.306.

Вступайте в нашу телеграмм-группу Инфостарт

См. также

Адаптация типовых решений БСП (Библиотека стандартных подсистем) Кадровый учет ЭДО и ОФД 1C:Бухгалтерия 1С:Зарплата и кадры 7.7 1C:ERP 1С:ЗУП 1С:УТ 1С:ДО Платные (руб)

Наше расширение 1С Госключ обеспечивает интеграцию любой конфигурации 1С на базе БСП с мобильным приложением «Госключ», позволяя сотрудникам подписывать кадровые документы (КЭДО) и документы материальной ответственности (МОЛ, ПБ) усиленной электронной подписью прямо со смартфона. Решение автоматизирует формирование и отправку документов на подпись, отслеживает статусы подписания и хранит подписанные файлы непосредственно в базе 1С

25000 руб.

06.03.2026    1305    4    0    

3

БСП (Библиотека стандартных подсистем) Программист Платные (руб)

Синтакс-помощник БСП - cправочник по библиотекам стандартных подсистем и электронных документов. В состав справочника входит описание экспортных процедур и функций, размещенных в областях кода ПрограммныйИнтерфейс БСП и БЭД.

3254 руб.

21.11.2024    13599    49    26    

56

БСП (Библиотека стандартных подсистем) Программист 1С 8.3 1С:Библиотека стандартных подсистем Бесплатно (free)

Каждый раз, когда разработчик 1С пишет очередной цикл для свертки массива или использует конструкцию Попытка / Исключение для проверки наличия реквизита, где-то грустит один архитектор фирмы «1С». Мы привыкли изобретать велосипеды там, где в Библиотеке стандартных подсистем (БСП) уже давно лежат готовые, оптимизированные и протестированные на тысячах баз решения. Ниже — практическая подборка из 8 методов актуальных релизов БСП (3.X), которые сделают ваш код чище, быстрее и профессиональнее. Разберем на примерах «Было / Стало».

04.06.2026    9096    Kaliostr0    16    

35

БСП (Библиотека стандартных подсистем) Универсальные функции Программист 1С 8.3 1С:Библиотека стандартных подсистем Бесплатно (free)

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

06.02.2026    15066    manul1c    6    

25

Рефакторинг и качество кода БСП (Библиотека стандартных подсистем) Механизмы платформы 1С Программист 1С:Предприятие 8 1С:Библиотека стандартных подсистем Бесплатно (free)

Использование Библиотеки стандартных подсистем позволяет разработчикам 1С значительно ускорить процесс создания решений за счет готового универсального кода, поддерживаемого и обновляемого официальным вендором. В статье рассказывается про роль и применение «Библиотеки стандартных подсистем» (БСП), примеры интеграции и подключения подсистем.

23.09.2025    15034    AlexeyPROSTO_1C    1    

18

БСП (Библиотека стандартных подсистем) Программист 1С:Предприятие 8 1С:Библиотека стандартных подсистем Бесплатно (free)

Уже заезженная тема с выводом в Word макетов при помощи БСП, но некоторые коллеги все равно спрашивают. Поэтому размещаю тут материал, как это сделать за три простых шага. Решение, которым я успешно пользуюсь в случаях, когда не нужна универсальность подключаемых внешних печатных форм.

16.09.2025    7400    _seerco2002    0    

36
Комментарии
Подписаться на ответы Инфостарт бот Сортировка: Древо развёрнутое
Свернуть все
1. Serg O. 324 25.02.25 20:04 Сейчас в теме
спасибо за статью, огромный +

тексты процедур немного другие, поэтому лучше использовать
не &Вместо а &ИзменениеИКонтроль

а текст, который надо вставить/удалить помещать в блоки:

	#Вставка
	#КонецВставки
или
	#Удаление
	#КонецУдаления
2. AmTa 15 08.10.25 10:21 Сейчас в теме
для подложки работает, надо только изменить размер его
Для отправки сообщения требуется регистрация/авторизация