Сторонний контрол для визуальной работы со штампом

89 4

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

Так, например бывают ситуации, когда пользователям необходимо проставить штамп по заданным координатам. Раньше такую задачу можно было решить несколькими вариантами. Например:

  1. Пользователь открывает документ на редактирование и ставит якорь в нужное ему место;
  2. Пользователь указывает координаты штампа, после чего генерирует версию с проставленным штампом. Но без визуального режима указать правильные координаты не так просто, из-за чего это могло повторятся не один раз.

Сейчас с новым функционалом можно реализовать контрол с помощью которого пользователь может сам выбрать место установки штампа в визуальном режиме.

Ниже показан пример преобразования страницы документа в изображение, вывод штампа и редактирование его расположения, с последующим наложением его на версию документа.

Рис.: Пример работы контрола (книжная ориентация)

Ниже показан пример того, что поддерживается как книжная, так и альбомная ориентация страницы.

Рис.: Пример работы контрола (альбомная ориентация)

Пошаговое руководство по созданию контрола

Для разработки стороннего контрола необходимо установить node.js, а также стороннюю среду разработки, для работы с JavaScript. Я использовал Visual Studio Code, соответственно все скриншоты будут именно оттуда.

Данный раздел статьи покажет общий концепт разработки стороннего контрола. Ссылки на исходные коды контрола для визуальной работы со штампом находятся в разделах Решение RX и Сторонний компонент.

На стороне DDS:

  1. В среде разработки DDS перекрываем или создаем свой тип сущности, в котором нам необходимо вывести страницу со штампом, в нашем примере это будет OfficialDocument.
  2. Для того, чтобы из стороннего контрола можно было получить всю нужную информацию о штампе, в тип документа OfficialDocument была добавлена коллекция StampInfo со следующими свойствами:
  • IsLandscape – признак альбомной ориентации;
  • CoordX – координаты по оси X;
  • CoordY – координаты по оси Y;
  • StampHtml – html текст штампа;
  • FirstPageAsImage – изображение первой страницы документы в виде строки base64.
  1. Добавляем логику по заполнению данной коллекции. В данном случае, для упрощения, были созданы 3 действия в типе документа OfficialDocument:
  • ConvertPageToImage – заполнение пустого контрола изображением страницы документа. Происходит преобразование страницы документа в строку base64, а также вычисление ориентации страницы, соответственно записываются свойства коллекции FirstPageAsImage и IsLandscape;
  • ShowStamp – запись данных о штампе, в виде строки, в свойство коллекции StampHtml;
  • PlaceStamp – простановка штампа на версию документа, в соответствии с расположением штампа на контроле. Для выполнения данного действия требуется выполнить 2 предыдущих действия, для заполнения коллекции данными.

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

Сторонняя IDE:

  1. Скачиваем или клонируем проект Directum для разработки контролов sungero-remote-component-example-react, включающий в себя примеры сторонних контролов.
  2. Установим пакеты проекта, для этого открываем проект в Visual Studio Code и вводим команду “npm I” в командную строку среды разработки. Это также можно сделать и через обычную командную строку системы, перейдя в каталог с проектом. После этого в папке с проектом должна появиться папка node_modules.

 

           Описание структуры проекта:

  • В папке dist находятся файлы, которые необходимо импортировать в RX, для работы стороннего компонента;
  • В папке locales находятся файлы локализации для английского и русского языков;
  • В папке /src/controls реализуются контролы;
  • В папке /src/loaders реализуются загрузчики контролов;
  • В файле component.loaders.ts перечисляются все загрузчики контролов, с указанием их имени для файла manifest;
  • В файле component.manifest.js описываются контролы;
  • В файле package.json указаны скрипты для сборки приложения;
  • В файле host-api-stub.ts указывается поведение карточки сущности для локальной отладки;
  • В файле host-context-stub задается контекст для локальной отладки;
  • В файле index.js указывается загрузчик, который будет вызван при локальной отладке.

Рис.: Файловая структура проекта

  1. Проверим, что все корректно выполнено, для этого в командной строке вводим команду “npm run start:dev:standalone”. После этого переходим по адресу http://localhost:3001/, на странице должна находится таблица с пред заполненными данными.

Рис.: Вид отладочной страницы

           Если открылась пустая страница, то необходимо доработать файл index.js.

Рис.: Код файла index.js до изменения

           В JavaScript типизация не важна, но вот в TypeScript типизация данных обязательна, из-за этого при передаче не типизированного объекта возникает ошибка и аргументы в обработчике loadApp не заполняются. В связи с этим нужно типизировать передаваемые данные, создав объект с явно заданными именами свойств и их данными.

Рис.: Код файла index.js после изменения

           Для того чтобы поменять порт необходимо открыть файл package.json и в скрипте serve заменить порт 3001 на новый.

Рис.: Скрипты из файла package.json

  1. После того как мы убедились, что все работает, можно приступать к разработке React элемента. В папке /src/controls нужно создать новую папку, в которой будет создан файл с расширением tsx, именно в нем будет реализация самого контрола.

           Основные моменты при реализации:

  • Для получения сущности (Entity) из которой был вызван данный контрол, используется метод api.getEntity(); Полученная сущность содержит основные свойства из RX, при необходимости список этих свойств можно дополнить, путем использования собственного интерфейса расширяющего базовый IEntity. Например:

Рис.: Интерфейс с явно заданным свойством

Рис.: Интерфейс с свойством, получаемым по наименованию

  • Для изменения свойств сущности используется метод changeProperty(имя свойства, значение)
  • Для работы с коллекциями используется интерфейс IChildEntityCollection. У коллекции есть ряд методов, который перечислен в файле “\node_modules\@directum\sungero-remote-component-types\host-api.ts”, а также IChildEntity, который описывает свойства строки коллекции. Например:

Рис.: Интерфейс, описывающий свойства коллекции

  • На вход контрол может принимать следующие аргументы:
    • IRemoteComponentContext - Контекст для стороннего контрола;

Рис.: Описание свойств интерфейса IRemoteComponentContext

    • IRemoteComponentCardApi - API сторонних компонентов для работы с карточкой;

Рис.: Описание методов интерфейса IRemoteComponentCardApi

    • IRemoteControlInfo – Параметры стороннего контрола.

Рис.: Описание свойств интерфейса IremoteControlInfo

  1. После создания React элемента, необходимо создать для него загрузчик. Для это создаем новый файл в папке /src/loaders. В данном файле мы указываем, какие аргументы будет передаваться в ранее созданный контрол.

Рис.: Пример загрузчика контрола

  1. Для тестирования контрола, необходимо выполнить ряд действий.
  • Доработать функционал в файле host-api-stub.ts, например в функции getEntity дописать доп свойства, которые необходимы для тестирования контрола;
  • В файле index.js изменить ссылку на загрузчик у loadApp.
  1. После создания загрузчика дорабатываем файл component.loaders.ts. В нем необходимо указать ранее созданный загрузчик, по типу “строковое название загрузчика : ссылка на сам загрузчик

Рис.: Пример указания имени для загрузчика

  1. Последним шагом разработки будет настройка в файле component.manifest.js. В нем мы должны описать наш контрол, а также указать vendorName и componentName. Важно, в свойстве loaders поле name должно соответствовать строковому названию загрузчика в файле component.loaders.ts. Поле scope имеет 2 параметра заполнения:
  • Cover – обложка модуля;
  • Card – карточка сущности.

Рис.: Пример описания контрола

  1. Собираем приложение при помощи команды “npm run build:release”. В результате в папке dist будет создан ряд файлов.

На стороне DDS:

  1. Переходим в сторонние компоненты решения и добавляем новый сторонний компонент. В качестве импортируемой папки выбираем папку dist, которая была создана после сборки приложения.
  2. После проделанных действий контрол будет доступен для выбора в списке сторонних котролов. Связанное свойство необходимо указывать, только если в аргументах React элемента используется IRemoteControlInfo.

Решение RX

Исходный код решения для RX: https://github.com/STARKOV-Group/DrxExternalControls

Структура решения:

  1. Решение Solution с настроенным сторонним компонентом;
  2. Модуль Common содержит изолированную область WorkWithAspose, которая содержит ряд функций для преобразования страницы в изображение, а также функционал для простановки штампа;
  3. Перекрытый тип документа OfficialDocument, в котором реализован функционал для работы со сторонним контролом.

Важная особенность:

Простановка штампа происходит в изолированной функции AddStampByCoords модуля Common. Основной момент связан с координатами X и Y, т.к. в Aspose вычисление координаты Y начинается с низа страницы, а в стороннем контроле с верху. Из-за этого для установки Yindent (координата Y объекта) необходимо из высоты страницы вычесть Y, полученный из стороннего контрола, а также вычесть высоту штампа.

Сторонний компонент

Исходный код стороннего компонента: https://github.com/STARKOV-Group/StampExternalControl

Основная работа контрола реализована в файле stamp-control.tsx. В этом файле выделено несколько регионов:

  • Entity – работа с сущностью;
  • DragControl – работа с перемещаемым по странице элементом;
  • Elements – работа с преобразованием html в штамп, установка фонового изображения страницы, а также настройка стартовых координат и ориентации страницы.

Важная особенность:

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

Рис.: Код функций по преобразованию пикселей в точки и обратно

Логика работы контрола

При открытии карточки с данным контролом выполняется следующая логика:

  1. Получаем сущность и первую строку коллекции, а также вычисляем возможность редактирования этого контрола

Рис.: Код, выполняющийся при инициализации контрола

  1. Выводим штамп на контрол, затем выводим изображение из коллекции в качестве фона для листа, настраиваем ориентацию страницы, а также устанавливаем координаты по умолчанию

Рис.: Код, выполняющийся при инициализации контрола

При изменении положения штампа на странице, выполняется следующая логика:

  1. Выводятся координаты штампа, а также происходит обновление координат в коллекции сущности

Рис.: Код, выполняющийся при перемещении штампа

Заключение

В дальнейшем планируется реализовать вывод всего документа целиком, либо отдельных его страниц, а также размещение сразу нескольких штампов.

Konstantin Bastylev

Мало того что статья полезна сама по себе, так ещё и реализован компонент, часто запрашиваемый

Артём Торгашин

Вижу это и понимаю, что это новое радужное будущее в разработке под Directum RX.

Андрей Касьянов

Крутое и нужное решение!

Юрий Минц

Как насчет идеи для включения в базовую систему ?
Штука то крайне нужная для пользователей.

Авторизуйтесь, чтобы написать комментарий