Долгий путь к мечте
Где хотелось бы применять механизм открытия вложенных форм? Например, если вы создаете обработку АРМ, на основной форме которой нужно поместить другие существующие формы. Или есть какая-то универсальная вспомогательная форма, например, инструмент подбора, и ее хочется просто вставлять в формы документов. Сейчас, чтобы добавить функционал одной формы в другую, нужно, во-первых, перенести все реквизиты, элементы формы в отдельную группу, преодолеть дублирование имен и потерю связей... А потом еще нужно аккуратно объединить модули форм. Ну и, конечно, это будет копия формы, и, если необходимо сделать исправления, нужно это будет сделать везде, никакого повторного использования. Это как писать код через копи-паст, не используя процедур и функций.
Первым шагом к светлому будущему был перевод поля HTML-документа на движок WebKit. Кроме различных плюшек появилась знаковая возможность: запуск 1С внутри самой себя! Вы можете опубликовать базу, положить адрес публикации в поле HTML - и вуаля! - вы сделали небольшую рекурсию. Запуская веб-клиент с различными параметрами, можно сразу открывать нужные формы и выполнять другие действия. Это то, что нужно? К сожалению, не совсем... Так мы можем только открывать новый сеанс, но не влиять на существующий, нет "общения" между формами. Т.е. чтобы открыть новую форму, нужно заново запускать базу, а что-то сделать в открытой вообще, можно сказать, невозможно.
Но в версии платформы 8.3.16 появилась возможность запускать 1С в режиме ВстроенноеРабочееМесто, встраивать веб-клиент в отдельные области (фреймы) страниц сайтов. Подробнее об этом механизме можно почитать здесь. 1С может не только запуститься внутри сайта, но взаимодействовать с ним посредством сообщений. "Это то, что нужно!" - подумал я. Почему бы этим внешним сайтом не стать самой 1С с полем HTML? Сказано, сделано. Так появилась подсистема ФормаНаФорме (...и формою погоняет).
Описание подсистемы
Давайте посмотрим, что за объекты есть в подсистеме:
- ФНФ_ПовтИсп - содержит пока одну функцию, которая возвращает код HTML для вставки;
- ФНФ_Клиент - основной функционал реализован именно здесь;
- ФНФ_Сервер - здесь лежат функции сериализации значений (к сожалению, они не доступны в веб-клиенте), а также настройки интерфейса;
- ФНФ_ТекстHTML - в макете записан шаблон кода HTML + JS для реализации нового функционала;
- ФНФ_АдресПубликацииБазы - единственная настройка с путем запуска базы.
Весь программный интерфейс находится в одном модуле. Под катом находится описание всех методов, которые нужны для использования системы.
Основными методами для передачи управления вложенной форме являются ОткрытьСсылкуВоВложенной и ОткрытьФормуВоВложенной для открытия объектов, процедура ВыполнитьОповещениеВложенной для реализации произвольной логики. Для обратной связи используется процедура отправки ОтправитьСообщениеВнешней и функция СообщениеОтВложенной для приема.
Но давайте перейдем от скучной теории к примерам!
Пример № 1
Сделаем список номенклатуры в котором карточка текущей номенклатуры сразу отображается в поле справа. Вот как выглядит результат:
Что есть на этом скрине:
- сама внешняя форма, стандартный динамический список;
- поле HTML-документа, 99% которого занимает фрейм с запущенной 1С, в ней открыта форма объекта;
- в новом режиме запуска приложения убраны все меню и панели 1С, кроме этого значка. Чтобы знали!
- это вспомогательная однопиксельная кнопка, которая нажимается автоматически при отправке сообщения от внутренней. Иначе я срабатывание события поля HTML сделать не смог. Если у вас есть какое-то решение, подскажите.
При открытии формы списка в поле справа отображается загрузка 1С, потом открывается форма текущей номенклатуры. Дальше при смене активной строки списка, просто открывается нужная форма. Чтобы реализовать этот функционал, на форме списка нужно было сделать всего две вещи:
- Добавить на форму списка строковый реквизит и поле HTML-документа, в котором будет открываться вложенная 1С. Единственное условие: реквизит и поле должны иметь одно имя (по-умолчанию так и будет), для корректной связи.
- После активизации строки списка вызвать метод ФНФ_Клиент.ОткрытьСсылкуВоВложенной(Элементы.ТекущаяНоменклатура, Элементы.Список.ТекущаяСтрока). Здесь первый параметр - это поле HTML, а второй - текущая номенклатура.
На форме же объекта номенклатуры ничего не делать не нужно, это может быть абсолютно стандартная форма.
Проверим еще один функционал. Пусть при нажатии на кнопку сверху списка поле Описание текущей номенклатуры красится в выбранный цвет (Да, тупость какая-то, ну что первое придумал!). Тогда при нажатии после выбора цвета надо вызвать метод ФНФ_Клиент.ВыполнитьОповещениеВложенной(Элементы.ТекущаяНоменклатура, "Форма", "ПокраситьОписание", ФНФ_Сервер.СтрокаXML(Цвет)). Получается, у формы номенклатуры должна быть реализована экспортная процедура ПокраситьОписание. Этот метод будет вызван и в него передастся строка, представляющая цвет.
Так можно реализовывать произвольный функционал. Думал еще сделать вообще передачу кода для метода Выполнить, чтобы вообще можно было обойтись без обработчиков на вложенных формах, но пока отказался, потому что это не безопасно, не объектно и вообще не комильфо.
Вот такой вот простой пример. Кстати, в открывшейся номенклатуре можно выполнить команду "Показать в списке" и увязнуть в матрице рекурсии. Я сделал пять переходов, работало нормально, только место на экране закончилось:
Пример № 2
Допустим, у нас есть универсальная форма подбора номенклатуры в ТЧ товаров документов. Добавим эту форму на форму Заказа. Вот, что получилось:
Для реализации нужно также расположить поле HTML в заказе и открыть при открытии самого заказа:
ФНФ_Клиент.ОткрытьФормуВоВложенной(Элементы.ПодборНоменклатуры, "Справочник.Номенклатура.Форма.ФормаПодбора");
При нажатии на номенклатуру формы подбора нам надо показать ввод устанавливаемого количества. Сделаем так, что в окошке по умолчанию было введено количество уже добавленной в документ выбранной номенклатуры, если такая там есть. Следовательно, нам надо сделать запрос количества во внешней:
ФНФ_Клиент.ОтправитьСообщениеВнешней(Строка(ВыбраннаяСтрока.УникальныйИдентификатор()) + ":");
Передаем уникальный идентификатор запрашиваемой номенклатуры. Переданное сообщение можно поймать в событии ПриНажатии поля HTML- контейнера вложенной формы:
Сообщение = ФНФ_Клиент.СообщениеОтВложенной(Элемент, ДанныеСобытия);
Параметры для функции берутся просто из параметров события ПриНажатии. Если строка Сообщение не пустая, значит пришло именно сообщение от вложенной, нужно его обработать.
Дальше уже дело техники. Узнаем количество номенклатуры в документе, передаем обратно во вложенную. В ней открываем ввод количества. После ввода передаем во внешнюю уже GUID с количеством для установки. Используются методы, которые уже упоминались выше.
Варианты поставки
К этой публикации приложен файл выгрузки демо-базы с подсистемой. Чтобы опробовать ее в деле, вам надо сделать несколько простых шагов:
- скачать приложенный файл;
- развернуть dt в новую ИС;
- опубликовать базу на веб-сервере, можно локальном;
- задать адрес публикации в константе.
И все, можете погонять примеры, что описаны выше, можете придумать свои. Но еще раз, нужна платформа 8.3.16.
Можно вытащить отдельную подсистему из этой конфигурации и объединить со своей. Это будут только новые объекты подсистемы, но и еще вставки кода в событиях модуля приложения. К счастью, режим совместимости роли не играет, только платформа, ну и интерфейс Такси. Я тестировал в УТ 11.4, все работало. Можно превратить подсистему в расширение и, в принципе, отказаться от единственных хранимых данных, перенеся константу в хранилище настроек.
Вопросы аутентификации
В демо-базе все просто: нет пользователей - нет проблем. Но что делать в обычной ситуации? Ведь происходит запуск нового сеанса 1С, значит, надо произвести аутентификацию. Какие есть варианты в этом случае:
- Самый лучший вариант - это аутентификация ОС. Здесь окно логина не возникнет.
- Можно спросить пароль в первый раз, потом сохранить его в параметрах сеанса и подставлять при следующих подключениях. Но тут вопрос с безопасностью.
- Вариант использовать какого-то специального пользователя, и открывать вложенную 1С всегда под ним. Но тогда это только для просмотра определенных данных. Понятное дело, наделять такого пользователя полномочиями изменения не стоит.
- Можно подставлять при подключении только имя пользователя, спрашивать пароль. Понятное дело, это не очень удобно.
Может, есть какой-то механизм аутентификации для таких случаев? Поделитесь, если знаете.
Минусы решения
Хоть подсистема и предоставляет довольно интересный функционал (Мне, например, очень нравится!), но у него есть ряд серьезных проблем, из-за которых это решение так и может остаться просто экспериментом. Большинство их, конечно связано с тем, что запускается отдельный сеанс 1С:
- При первом запуске происходит загрузка 1С, необходимо подождать.
- Проблемы с аутентификацией, которые я описал выше.
- Отдельный сеанс забирает отдельную лицензию для веб-клиента. Очень жирный минус.
- Сервер и клиент должны обслуживать больше экземпляров приложения.
- При некорректном завершении работы могут остаться зависшие сеансы.
- Вложенная 1С запускается в режиме веб-клиента со своими особенностями.
В принципе, последний пункт не должен быть недостатком, в современной разработке правилом хорошего тона считается написания клиентской части с учетом веба.
Варианты развития подсистемы
Если вам прям понравилось решение, но у вас версия платформы меньше 8.3.16, то, в принципе, есть другой вариант реализации. На митапе в Краснодаре я немного рассказывал о механизме UDP для связи нескольких запущенных приложений 1С на одном компе со стороны клиента. Этот же механизм, думаю, можно прикрутить и сюда. Внешняя и вложенная 1С будут использовать свои порты, кидать пакеты друг другу для передачи данных и управления. Если кому интересно, могу попробовать реализовать такое.
И, кстати, про разные базы... В текущей подсистеме у меня заложена работа с формами в одной ИС, но ничего не запрещает так связать разные базы. Например, вы сидите в Документообороте, и вам пришла задача с предметом, который является заказом в УТ. У вас откроется форма заказа внутри формы задачи. Такое вот совсем бесшовное онлайн взаимодействие. Можно придумать еще много разных примеров.
Заключение
Платформа 1С развивается и в последнее время довольно бурно. Появляется много таких вот фишек, интеграций, механизмов... Но вот как-то часто пропускаются, как по мне, довольно базовые вещи. Как, например, открытие формы в форме. И в итоге получаются такие решения с кандибобером на голове. Надеюсь, что нативное открытие вложенных форм появится в какой-нибудь будущей версии платформы.