1c + vis js(web app timeline)

Публикация № 894080

Программирование - Практика программирования

vis js web app backend chrome python active x управляемые формы

26
Пример замены диаграммы Ганта(1С) на web app(python, js(vis js)) в форме 1С. Данная статья может быть полезна разработчикам, оптимизаторам, дизайнерам.

Шаг 0. Зачем? Почему так?

Нужно было сделать:

1. работало быстро(не замороживало контекст пользователя, быстрый отклик)

2. было открыто для переиспользования в других инхаус поделках(фронт, бэк)

3. добавить фичи в которые штатная диаграмма не может(закраска на пересечении, выделить регламентированные фрагменты)

4. выглядело нормально

Технологический стэк:

1. 1с 8.3.8(3 сторона, источник событий)

2. ms sql(бд)

3. python 36(бэк)

4. js(фронт)

5. active x(фронт)

6. chromiumembedded(в статье особо не фигурирует, но он есть)(фронт)

Общая схемы работы:

бэкенд отвечает за данные, обрабатывает события об изменениях, инапп статистика, выполняет запросы в бд к view (with no lock)(ORM Model в этот раз), отдает актуальные данные(json, XML(XDTO), да тот самый который 1С понимает полностью и может после прогона через фабрику принять за свой объект(по этой части будет сказано ниже более подробно), можно отдавать например диаграмму Ганта целиком, что и было сделано)

1С изменяет данные(штатно)(условно ,проводит документы), триггерит в бэкенд, дергает методы фронт( обновить)

фронт( вм(то что исполняет код) chromium ) запрашивает из бэкенд данные, отрисовывает форму, обрабатывает события пользователя( отркыть, перетащить, удалить), триггерит в 1с(не обработка внешнего события!) при необходимости(сменить форму, изменить данные)

active x(фронт) - позволяет chromium(chromiumembedded) работать в IE(те еще раз, в ИЕ(тот что в 1с) работает chrome(chromiumembedded), с devtools и  отладкой из клиентского сеанса 1с и прочими своими функциями, и проблемами)

Шаг 1. Пишем backend.

Структура:

start.py - страртер

common\common.py - общие функции

common\external_record_log.py - основной модуль

common\ones_xml_types.py - модуль формирования xml(xdto)

common\orm\base.py - орм база(класс)

common\orm\fields.py - орм описание полей

common\orm\models.py - орм описание таблиц

 
 start.py

В данном модуле происходит парсинг входных параметров, стартует поток HTTP сервер, вешается хендлер(то что будет обрабатывать запросы)

 
 ones_xml_types.py

собирает строку xml с подстановкой параметров. важные момент здесь конструкции вида:

... 
<details xmlns:d3p1="http://v8.1c.ru/8.1/data/core" xsi:type="d3p1:Structure"> 
            <d3p1:Property name="Сотрудник">
                <d3p1:Value xmlns:d5p1="http://v8.1c.ru/8.1/data/enterprise/current-config" xsi:type="d5p1:CatalogRef.Сотрудники">"""+data['m_ref_ones']+"""</d3p1:Value>
            </d3p1:Property>
...

именно так потом, когда строка придет в 1с и прогонить через фабрику, 1с поймет что это ее объект(типа структура с полем сотрудник и тд...). Больше ничего интересного тут нет. Для тех кто не понял откуда брать текст: в 1с дергаете сериализатор xdto(тем и публикаций куча), сохраняете в xml, разбираетесь со структурой. В моем случае был затык с магическими числами при установке интревалов. База числа 4294967297. Об этом ниже будет. Про то что здесь xml собирается текстом и именно так, и то что так (на конкатенацию) подставляются параметры, давайте не будем. 

В качестве ORM используется ORM(peewee) http://docs.peewee-orm.com/en/latest/

 
 common\orm\base.py

передача параметров со стартера для установки соединения с базой, и описание базовых классов (документ, справочник и тд)

 
 common\orm\fields.py

преобразование типов ms sql,  описание логической связи(например ссылка)

 
 models.py(весь листинг тащить смысла не вижу, приведу ряд примеров)

тут думаю без меня всё и так понятно. описывается связь логики с физическим хранением. Могу добавить лишь то что в 1с есть регламентное задание которое создает view(create view ... with nolock ... и так далее, отсюда и имена таблиц s_, r_, e_  и прочие) этим же самым решается проблема внутреннего именование таблиц, вида   db_table = '_InfoRg2828 -> 'db_table = 's_Автомобили

 
 external_record_log.py

стартер создает сохдает как мы помним объект ExternalRecordLog. Вот так он инициализируется. ExternalRecordLog_Handler - обработчик запросов http, do_GET - функция обработки(туда попадет когда пакет прилетит), выражение res = self.callback(path, qs, self) - выполнить логику, вернуть ответ.

 
  external_record_log.py

переход в обработку запроса, разбираются параметры запроса, его путь, и да срабатывает евал (по роутинг в курсе), (про кваргс тоже). Собственно отсюда и дергаются методы типа localhost\get?dep='asda'&date='2018.02.03' - что перерастает в self.get(dep, date), то что вернет метод (данные без оформления) упаковывается в json(для vis js), или xml( для 1с) 

 
  external_record_log.py

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

 
 external_record_log.py

фоновое задание если в терминах 1с, крутится с тайм аутом. Читает массив для обновления данных(туда данные добавляются с триггеров), ну и выполняет обновление(дергает get), триггерит в инхаус вэб апп, которая в конечном счете придет в get и получит обновленные данные.

 
 external_record_log.py

прочие функции

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

 
  external_record_log.py

обработка триггеров 3-й стороны(1с)

ну тут всё понятно и так прилетал тригер, добавили структуру параметров для обновления в upd_event_list через add_to_upd_event_list. Обратите внимание на конструкцию вида:

 

Не напоминает запрос в 1с? а потом РезультатЗапроса.Выгрузить()? Доп логика запроса вынесена из 1с, это когда нужно доп запрос сделать, чтобы например найти по заказ наряду  ссылку на другой объект.

 
 external_record_log.py

выполняет запрос к бд, возвращает данные без оформления, если коротко то это бизнес логика(1с)

далее идут служебные функция вида получить доп данные запросом(например время приемки,  время начала приемки ну и тд, выполняются по аналогии как выше)

 
  external_record_log.py

преобразует результат запроса в xml строку для 1с. Обратите внимание на _var_a = 4294967297 это базовое число с которого начинается индекс=0  для вставки интервалов.

 
   external_record_log.py

Преобразует результат запроса для загрузки данных в vis js на фронте.

запускается всё это дело строкой вида: python36 start.py -port 2032 -ip 192.168.777.888 -sql_host localhost -sql_base my_db -sql_user my_sql_user -sql_pass my_sql_user_password

 
 Код в 1С

Подписка на событие(триггер), который вызывает обновление данных в кэше. Есть вариант асинхронного выполнения get запросов (winapi) приводить здесь не буду.

Шаг 2. Пишем загрузку XDTO.

Для загрузки XML(XDTO)  и преобразования в диаграмму ганта используется следующий код:

 
 Код в 1с

Данный вариант пришлось отложить от использования, потому что нужно было установить при определенных условиях фон ячейки диаграммы Ганта на пересечении(время - сотрудник). Для решения данного вопроса было принято решение уйти от штатной диаграммы, и реализовать ее в front end части web app.

Шаг 3. Пишем front end.

За основу реализации диаграммы была взята либа vis.js http://visjs.org. Обзор делать здесь не буду, либа очень крутая!

В качестве фронта используется html страница отдаваемая nginx по гет запросу.

 
 HTML

Получаем данные с backend, формируем диаграмму, подписываемся на события(удаление, изменение, добавление, перенос и др), отправляем события 3 стороне(1C).

Естественно штатный механизм поля html не смог отобразить страницу, хотя в Opera (chromium) всё работало нормально.

Шаг 4. Встраиваем chromium (chromiumembedded ) в 1С.

Есть такая штука(chromiumembedded ) https://bitbucket.org/chromiumembedded/cef . Обзор здесь делать не буду.

И так ядро(для выполнения кода фронта) нашли. Вспоминаем что, штатный браузер 1С (поле html) это обертка над MS IE(active x web browser) , ну раз active-x, значит нужно обернуть cef в active-x и собственно всё. Далее немного погуглив находится готовое решение https://www.webkitx.com это для cef3, и https://github.com/mobileFX/WebKitX для тех кто всё сам. Делать свой врапер cef3 особого желания не было, взял для cef3.

Чтение доки нам говорит что он более чем на 100 процентов подходит нам и умеет генерировать события из js, делать калбэки, делать евал в jsк коде, имеет встроенную поддержку devtools!. ок, берем.

Для запуска active x в управляемых формах есть только один ход:

 
 Код 1С

где AxControl - реквизит формы

 
 Код 1С

Инициализация webkitax

 
 Код 1С

Обработка событий front end в 1С

 
 вызов dev tools из 1С
 
 вызов js кода из 1c

Тест на пустой форме,  тест событий, dev tools

https://yadi.sk/d/NiXGSN0H3aMvxJ

 

26

См. также

Специальные предложения

Комментарии
Избранное Подписка Сортировка: Древо
1. Infactum 281 03.09.18 13:09 Сейчас в теме
Картинки к статье в bmp - это нечто. Лучи "добра" надо послать как автору, так и разработчикам ИС (картинки не перекодируются при публикации? Серьезно?).
Да и простыню кода не помешало бы убрать под кат. Читать просто невозможно.
2. dmarenin 228 03.09.18 13:30 Сейчас в теме
(1) ты чем конкретно не доволен?
3. creatermc 2 05.09.18 12:38 Сейчас в теме
За труд автору публикации 5 баллов
Alpha-Bit.ru; acanta; +2 Ответить
4. Igorrrr 05.09.18 17:04 Сейчас в теме
Выглядело бы приятнее, если бы для скриншотов использовалась специальная база, а не закрашенная рабочая...
Сама публикация интересная.
5. tanat74 30 19.03.19 14:17 Сейчас в теме
Ссылка яндекс диск поломалась. Почините пожалуйста, или прикрепите к публикации файл.
Оставьте свое сообщение