Разработка интерактивных интерфейсов в системе "1С:Предприятие" с использованием поля HTML-документа открывает перед разработчиками огромные возможности. Мы можем создавать современные, отзывчивые и визуально привлекательные рабочие места прямо внутри учетной системы. Однако при реализации таких решений часто возникают специфические проблемы, особенно при переходе с тонкого клиента на веб-клиент или мобильное приложение. В этой статье мы подробно разберем три важнейших вопроса: как правильно подключать внешние JS-скрипты, где и в каком виде лучше всего хранить исходные HTML-макеты, а также как гарантировать корректное отображение графических изображений на мобильных устройствах.
Начнем с первой проблемы, с которой сталкиваются разработчики при попытке оживить свою HTML-страницу с помощью JavaScript. Довольно часто при динамической сборке документа теги script, указывающие на внешние файлы во временном хранилище (например, по ссылкам вида e1cib/tempstorage/...), попросту игнорируются браузерным движком. Выясним причину этого поведения.
Современная платформа "1С:Предприятие" использует веб-движок WebKit (встроенный Chromium). Из соображений безопасности в нем действуют строгие правила изоляции (песочница) и политика CORS (Cross-Origin Resource Sharing). Когда мы динамически переопределяем свойство Текст поля HTML-документа, базовым адресом страницы часто становится about:blank. Браузер блокирует запросы к ресурсам с другими протоколами или адресами, считая их небезопасными. Кроме того, при динамической перезаписи HTML-кода парсер браузера не всегда инициирует повторную загрузку и выполнение скриптов, объявленных через внешние файлы.
Проанализируем несколько надежных архитектурных подходов, которые позволяют обойти эти ограничения и заставить JS-код работать стабильно.
Метод 1. Прямое внедрение кода (Inlining)
Самый простой и отказоустойчивый способ для автономной работы — отказаться от подключения внешних файлов JavaScript и внедрять весь исполняемый код непосредственно в тело HTML-документа. Для этого мы можем создать шаблон страницы с "плейсхолдерами" (специальными текстовыми метками) и на стороне сервера 1С заменять их на реальное содержимое JS-файлов, полученных из макетов или временного хранилища. Посмотрим на практический пример реализации такого подхода:
Функция СформироватьHTMLДокумент(АдресСкриптаВоВременномХранилище) Экспорт
// Получаем базовый шаблон HTML из макета
ШаблонHTML = ПолучитьОбщийМакет("ИмяМакетШаблонаHTML").ПолучитьТекст();
// Получаем двоичные данные скрипта из временного хранилища
ДвоичныеДанныеJS = ПолучитьИзВременногоХранилища(АдресСкриптаВоВременномХранилище);
ТекстСкрипта = ПолучитьТекстИзДвоичныхДанных(ДвоичныеДанныеJS);
// Внедряем скрипт в тело HTML-шаблона вместо специального маркера
ИтоговыйHTML = СтрЗаменить(ШаблонHTML, "[ВнедряемыйJSКод]", ТекстСкрипта);
Возврат ИтоговыйHTML;
КонецФункции
В самом шаблоне HTML-документа это место будет выглядеть следующим образом:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<script>
// [ВнедряемыйJSКод]
</script>
</head>
<body>
<h1>Интерфейс 1С в HTML</h1>
</body>
</html>
Данный метод гарантирует, что весь исполняемый код загрузится одновременно с разметкой страницы, исключая задержки и блокировки со стороны системы безопасности браузера.
Метод 2. Использование объектного взаимодействия через defaultView
Если цель подключения скрипта — передача данных или выполнение определенных функций из контекста 1С, нам совсем не обязательно перезагружать весь HTML-документ или динамически пересобирать скрипты. Мы можем напрямую взаимодействовать с глобальным контекстом окна браузера (объектом window). Для этого используется свойство defaultView документа поля HTML. Разберем пример отправки команды в JS:
&НаКлиенте
Процедура ПередатьДанныеВБраузер(ИмяФункции, ПараметрыПередачи)
// Получаем доступ к документу и его окну управления
ДокументHTML = Элементы.ПолеHTMLИнтерфейса.Документ;
Если ДокументHTML <> Неопределено Тогда
ОкноБраузера = ДокументHTML.defaultView;
Если ОкноБраузера <> Неопределено Тогда
// Напрямую вызываем функцию, определенную внутри JS-кода страницы
ОкноБраузера[ИмяФункции](ПараметрыПередачи);
КонецЕсли;
КонецЕсли;
КонецПроцедуры
Этот подход избавляет нас от необходимости постоянной генерации и парсинга тяжелых текстовых строк, существенно повышая отзывчивость и производительность веб-интерфейса.
Перейдем ко второму вопросу: способам организации хранения шаблонов и ресурсов веб-страниц. Существует три основных подхода к проектированию такой архитектуры.
Вариант 1. Встроенный тип макета "HTML-документ"
Платформа 1С предоставляет специализированный тип макета — HTML-документ. Главное его достоинство заключается в удобстве разработки внутри конфигуратора 1С. Разработчику доступны две вкладки: "Редактирование" (визуальный WYSIWYG-редактор) и "Текст" (редактор исходного HTML-кода с подсветкой синтаксиса). Программный доступ к такому макету крайне прост:
МакетHTML = ПолучитьОбщийМакет("МойИнтерактивныйМакет");
ТекстHTML = МакетHTML.ПолучитьТекст();
Вариант 2. Модульный подход с использованием ZIP-архивов (Двоичные данные)
Если ваш веб-интерфейс достаточно сложный и включает в себя множество связанных файлов (CSS-стили, JS-фреймворки вроде Vue.js или React, кастомные шрифты и изображения), хранить их по отдельности в текстовых макетах становится крайне неудобно. В таких случаях мы рекомендуем использовать модульный подход.
Проанализируем этот метод подробнее. Все файлы веб-приложения упаковываются в единый ZIP-архив и загружаются в общий макет 1С с типом Двоичные данные. При открытии формы в 1С мы программно распаковываем этот архив во временный каталог на локальном компьютере или мобильном устройстве пользователя и загружаем стартовый файл index.html. Рассмотрим пример реализации:
&НаКлиенте
Процедура ИнициализироватьСложныйИнтерфейс()
// Получаем архив из макета двоичных данных
ДвоичныеДанныеАрхива = ПолучитьМакетДвоичныхДанныхНаСервере();
// Определяем путь во временном каталоге клиента
КаталогНазначения = КаталогВременныхФайлов() + "WebInterface/";
ИмяФайлаАрхива = КаталогВременныхФайлов() + "web_assets.zip";
// Записываем архив на диск и распаковываем его
ДвоичныеДанныеАрхива.Записать(ИмяФайлаАрхива);
Архиватор = Новый ЧтениеZipФайла(ИмяФайлаАрхива);
Архиватор.ИзвлечьВсе(КаталогНазначения, РежимВосстановленияПутейФайловZIP.Восстанавливать);
Архиватор.Закрыть();
// Загружаем стартовую страницу в поле HTML-документа
ПутьКСтартовойСтранице = КаталогНазначения + "index.html";
Элементы.ПолеHTML.Навигация(ПутьКСтартовойСтранице);
КонецПроцедуры
Благодаря этому методу вы можете вести полноценную профессиональную веб-разработку, сохраняя относительные пути к файлам стилей и скриптов (например, <link rel="stylesheet" href="styles.css">), и вся структура проекта останется целостной.
Перейдем к наиболее острому вопросу: почему адреса временного хранилища 1С (вида e1cib/tempstorage/...) отказываются работать в мобильном клиенте и как правильно реализовать вывод графики?
Причина кроется в архитектуре исполнения кода на мобильных устройствах. В то время как настольный тонкий клиент работает в рамках одной операционной системы и имеет прямой доступ к локальным службам платформы, мобильный клиент функционирует внутри системного контейнера WebView (на базе Android System WebView или iOS WebKit). Ссылка на временное хранилище является относительной. Локальный браузер смартфона не понимает, по какому сетевому протоколу и к какому именно серверу нужно обратиться, чтобы извлечь эти данные, поэтому картинка отображается как "битая".
Давайте подробно разберем несколько проверенных способов решения этой проблемы.
Для небольших иконок, элементов оформления и логотипов идеальным и самым надежным решением является преобразование бинарных данных изображения в текстовую строку Base64 и внедрение ее прямо в HTML-тег img. Это исключает необходимость отправки дополнительных запросов к серверу.
Рассмотрим, как выглядит алгоритм подготовки такой строки на стороне сервера 1С:
&НаСервере
Функция ПолучитьИзображениеВФорматеBase64(СсылкаНаНоменклатуру)
КартинкаОригинал = СсылкаНаНоменклатуру.ФайлКартинки.Получить();
Если КартинкаОригинал = Неопределено Тогда
Возврат "";
КонецЕсли;
ДвоичныеДанные = КартинкаОригинал.ПолучитьДвоичныеДанные();
СтрокаBase64 = Base64Строка(ДвоичныеДанные);
// Очищаем строку от символов переноса строк, чтобы HTML-парсер не выдал ошибку
СтрокаBase64 = СтрЗаменить(СтрокаBase64, Символ(10), "");
СтрокаBase64 = СтрЗаменить(СтрокаBase64, Символ(13), "");
// Формируем готовый Data URL
Возврат "data:image/png;base64," + СтрокаBase64;
КонецФункции
Далее полученную строку мы просто подставляем в атрибут src тега изображения:
// В коде формирования HTML-документа:
СтрокаКартинки = ПолучитьИзображениеВФорматеBase64(ВыбранныйТовар);
HTMLКодИзображения = "<img src=""" + СтрокаКартинки + """ alt=""Товар"" />";
Важное предупреждение: Помните, что кодирование в Base64 увеличивает размер исходного файла примерно на 33%. Для крупных картинок высокого разрешения этот способ использовать не рекомендуется, так как это приведет к раздуванию HTML-кода, повышенному потреблению оперативной памяти мобильным устройством и отключению встроенного кэширования в мобильном браузере.
Если мобильный клиент работает в режиме постоянного подключения к сети (онлайн), мы можем заставить WebView запрашивать картинки напрямую с веб-сервера публикации базы 1С. Для этого необходимо преобразовать относительную ссылку временного хранилища в абсолютную URL-ссылку:
&НаСервере
Функция СформироватьАбсолютнуюСсылкуНаКартинку(АдресВХ)
АдресПубликации = ПолучитьНавигационнуюСсылкуИнформационнойБазы();
Если ПустаяСтрока(АдресПубликации) Тогда
// Обработка ситуации, когда база не опубликована на веб-сервере
Возврат АдресВХ;
КонецЕсли;
// Соединяем адрес веб-публикации и относительный адрес ресурса в 1С
ПолныйURL = АдресПубликации + "/" + АдресВХ;
Возврат ПолныйURL;
КонецФункции
При таком подходе мобильный клиент отправит полноценный HTTP-запрос к веб-серверу 1С, пройдет автоматическую авторизацию и успешно отобразит запрашиваемый медиа-файл.
Для тяжелых изображений самым производительным и правильным решением является их предварительное скачивание на устройство и чтение из локальной файловой системы мобильного приложения. Это позволяет интерфейсу работать мгновенно и без задержек.
Разберем данный алгоритм по шагам:
ПолучитьИмяВременногоФайла().file:// и подставляем его в HTML.
&НаКлиенте
Процедура ЗагрузитьКартинкуЛокально(АдресВХ)
// Получаем двоичные данные изображения с сервера
ДвоичныеДанныеИзображения = ПолучитьИзВременногоХранилища(АдресВХ);
// Генерируем уникальный путь к файлу на мобильном устройстве
ЛокальныйПуть = ПолучитьИмяВременногоФайла("png");
// Сохраняем файл в локальную память устройства
ДвоичныеДанныеИзображения.Записать(ЛокальныйПуть);
// Преобразуем системный путь в формат URI для HTML-поля
HTMLСсылкаНаФайл = "file:///" + СтрЗаменить(ЛокальныйПуть, "\", "/");
// Теперь эту ссылку можно использовать в разметке: <img src="file:///...">
ОбновитьИзображениеВHTML(HTMLСсылкаНаФайл);
КонецПроцедуры
Полезный совет: Не забывайте своевременно удалять созданные временные файлы при закрытии формы или завершении работы сессии, чтобы не засорять свободную память мобильного телефона пользователя.
Если перед вами стоит задача отображения интерфейсных иконок, кнопок управления или простых графических схем, настоятельно рекомендуем отказаться от растровых форматов (PNG, JPG) в пользу векторного формата SVG. Код формата SVG — это структурированный XML-текст, который легко внедряется непосредственно внутрь разметки HTML (Inline SVG):
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M12 2L2 22H22L12 2Z" fill="#FF9900"/>
</svg>
Это полностью решает проблему передачи графики: файлы весят доли килобайта, не требуют кодирования в Base64, мгновенно обрабатываются браузером и идеально масштабируются под любое разрешение экрана мобильного телефона без потери качества.
Мы проанализировали ключевые аспекты работы с HTML в 1С. Подведем итоги нашей совместной работы. Для достижения максимальной скорости работы интерфейса на любых типах клиентов придерживайтесь следующих правил: