P8-Panels
"Панели" расширение к "ПАРУС 8 Онлайн"
Оглавление
Термины и сокращения
I. Назначение
II. Состав
III. Требования к разработчику
IV. Установка
V. Подключение панелей
VI. Разработка панелей
Термины и сокращения
Система - "ПАРУС 8 Предприятие"
БД - База Данных
СУБД - Система Управления Базами Данных
Расширение - программный комплекс, дополняющий функциональность той или иной программной системы. В контексте данного документа (если не указано иное) - описываемое расширение "Панели".
Фреймворк - программная платформа, определяющая структуру программной системы, программное обеспечение, облегчающее разработку и объединение разных компонентов большого программного проекта. В контексте данного документа (если не указано иное) - описываемое расширение "Панели".
Панель - представление данных и функций Системы, реализованное с применением описываемого фреймворка
SPA - Single Page Application - технология разработки WEB-приложений, предполагающая динамическую генерацию интерфейса внутри одного HTML-документа, отображаемого браузером
HTML - HyperText Markup Language — язык гипертекстовой разметки
CSS - Cascading Style Sheets - каскадные таблицы стилей
DOM - Document Object Model - объектная модель документа (в контексте данного документа - HTML)
JS - JavaScript — мультипарадигменный интерпретируемый язык программирования
JSX - JavaScript eXtension - расширение JavaScript, которое позволяет создавать деревья DOM с использованием синтаксиса, подобного XML
АРМ - Автоматизированное Рабочее Место
I. Назначение
Расширение представляет собой фреймворк, основной задачей которого является сокращение времени разработки нестандартных графических интерфейсов и панелей мониторинга, работающих в составе WEB-приложения "ПАРУС 8 Онлайн".
II. Состав
В расширение входят:
- Библиотека расширения "P8-Panels-ParusOnlineExt.dll" для сервера приложений "ПАРУС 8 Онлайн" - обеспечивает низкоуровневое взаимодействие разрабатываемых панелей с Системой
- Хранимые объекты сервера БД Системы, обеспечивающие обмен данными между панелями и учётными регистрами Системы
- API для высокоуровневого взаимодействия с сервером БД Системы
- API для взаимодействия разрабатываемых панелей с WEB-приложением "ПАРУС 8 Онлайн"
- WEB-приложение "Парус 8 - Панели мониторинга", являющееся "точкой входа" для подключения реализуемых панелей, включающее в себя:
- Подключенные и настроенные библиотеки "React", "React-Router", "MUI"
- Настроенный транспайлер "Babel"
- Настроенный сборщик WEB-приложений "WebPack"
- Настроенный статический анализатор кода "ESLint"
- Настройки среды разработки "Visual Studio Code"
- Готовый контекст React-приложения
- Компоненты для отображения единого бокового меню подключенных панелей, галереи подключенных панелей, интеграции в рабочий стол WEB-приложения "ПАРУС 8 Онлайн"
- Готовые панели мониторинга для ряда прикланых приложений Системы
III. Требования к разработчику
Для успешной разработки собственных панелей, с применением описываемого фреймворка потребуются знания следующих технологий:
- HTML, CSS, JS, JSX
- Разработка SPA WEB-приложений
- Знакомство с основами работы перечисленных выше библиотек и системных средств (в первую очередь "React")
- Знание архитектуры Системы, принципов работы и организации её серверной части
На видеохостинге YouTube можно ознакомиться с уроками и обучающими курсами по большинству из перечисленных технологий. Например, с этими.
IV. Установка
- Установите сервер приложений "ПАРУС 8 Онлайн" согласно документации (см. "Парус-Онлайн 2. Часть 1. Установка ГГГГ.ММ.docx").
- Разместите на диске сервера приложений библиотеку расширения "P8-Panels-ParusOnlineExt", для этого скопируйте содержимое папки "bin" из репозитория расширения "P8-Panels-ParusOnlineExt", например, в каталог "C:\p8web20\Ext\P8-Panels-ParusOnlineExt".
- Подключите библиотеку расширения к серверу приложений "ПАРУС 8 Онлайн". Для этого добавьте ссылку на библиотеку в файл "Config\extensions.config" сервера приложений:
<?xml version="1.0"?>
<parus.extensions enabled="true" resolveKind="Static" viewsMode="Shared" rootPath="c:\p8web20\Ext\">
<extensions>
<extension assembly="P8PanelsParusOnlineExt" path="P8-Panels-ParusOnlineExt\bin\P8-Panels-ParusOnlineExt.dll"/>
</extensions>
</parus.extensions>
Где:
rootPath="c:\p8web20\Ext\"
- атрибут, указывающий на корневой каталог хранения расширений для сервера приложений "ПАРУС 8 Онлайн"path="P8-Panels-ParusOnlineExt\bin\P8-Panels-ParusOnlineExt.dll"
- атрибут, указывающий на каталог размещения библиотеки расширения "Панели" относительного коревогоrootPath
- Установите в файле конфигурации "PrecompiledApp.config" сервера приложений атрибут
updatable
вtrue
:
<precompiledApp version="2" updatable="true"/>
- Разместите WEB-приложение "Парус 8 - Панели мониторинга" на сервере приложений "ПАРУС 8 Онлайн". Для этого в каталоге "Modules" сервера приложений создайте подкаталог "P8-Panels" и проведите клонирование репозитория "P8-Panels" в него:
git clone https://github.com/CITKParus/P8-Panels.git
-
Проведите компиляцию хранимых объектов БД из каталога "db" клонированного репозитория (компиляцию проводить под пользователем-владельцем схемы серверной части Системы, с последующей перекомпиляцией зависимых инвалидных объектов), затем исполните скрипт "grants.sql", размещённый в этом же каталоге.
-
Перезапустите сервер приложений "ПАРУС 8 Онлайн"
V. Подключение панелей
Файл "p8panels.config", располагаемый в каталоге "Config" сервера приложений "ПАРУС 8 Онлайн", определяет какие панели подключены к WEB-приложению, порядок формирования пунктов главного меню "ПАРУС 8 Онлайн" для доступа к подключенным панелям, состав галереи панелей и бокового меню навигации WEB-приложения "Парус 8 - Панели мониторинга", работающего в контексте "ПАРУС 8 Онлайн".
В корневом каталоге репозитория "P8-Panels" расположен файл "p8panels.config", содержащий конфигурацию поставляемых с расширением типовых панелей.
Данный файл конфигурации необходимо разместить локально, в каталоге "Config" сервера приложений "ПАРУС 8 Онлайн". Например, если сервер приложений установлен в "c:\p8web20\WebClient", то путь к "p8panels.config" должен быть "c:\p8web20\WebClient\Config\p8panels.config".
Рассмотрим формат файла конфигурации панелей на примере. Ниже приведён фрагмет "p8panels.config" из поставки расширения.
<CITK.P8Panels>
<MenuItems>
<App name="ProjectPlanning">
<MenuItem parent="{BA073333-DFBC-4BA3-8EA7-172F3F6B4FEE}" separator="true"/>
<MenuItem parent="{BA073333-DFBC-4BA3-8EA7-172F3F6B4FEE}" name="ShowPrjPanelsRoot" caption="Панели мониторинга" url="Modules/p8-panels/"/>
<MenuItem parent="{BA073333-DFBC-4BA3-8EA7-172F3F6B4FEE}" separator="true"/>
<MenuItem parent="{BA073333-DFBC-4BA3-8EA7-172F3F6B4FEE}" name="ShowPrjPanelFin" caption="Экономика проектов" panelName="PrjFin"/>
...
</App>
</MenuItems>
<Panels urlBase="Modules/p8-panels/#/">
<Panel
name="PrjFin"
group="Планирование и учёт в проектах"
caption="Экономика проектов"
desc="Мониторинг калькуляции проекта, графиков финансирования, договоров с поставщиками материалов и ПКИ"
url="prj_fin"
path="prj_fin"
icon="bar_chart"
showInPanelsList="true"
preview="./img/prj_fin.png"/>
...
</Panels>
</CITK.P8Panels>
Настройки хранятся в формате XML. Корневым тэгом документа должен быть CITK.P8Panels
. Дочерними для него могут быть две ветки конфигурации:
MenuItems
- настройка пунктов главного меню WEB-приложения "ПАРУС 8 Online"Panels
- общий список панелей, подключаемых к приложению (не все панели обязательно выводить в виде пунктов меню)
MenuItems
состоит из элементов App
, каждый из которых определяет для какого из приложений Системы описываются пункты меню. MenuItems
может содержать несколько элементов App
. Каждый элемент App
должен иметь обязательный атрибут name
, определяющий код приложения Системы (см. колонку APPCODE
в таблице APPLIST
), в которое будут добавлены пункты меню. Дочерними для элемента App
являются элементы MenuItem
, каждый из которых описывает создаваемый расширением пункт меню. App
может содержать несколько MenuItem
. Каждый из MenuItem
может иметь следующие атрибуты:
parent
- обязательный, содержит GUID родительского пункта меню, к которому будет добавлен описываемый дочерний пункт (см.P_MENUS_CREATE_*_MENU
, где*
- код приложения Системы)separator
- необязательный, принимает значения "true" или "false", если "true" - создаваемый пункт меню будет разделителем, остальные атрибуты, описанные ниже будут проигнорированыname
- необязательный дляseparator="true"
, в прочих случаях - обязательный, уникальное имя пункта менюcaption
- необязательный дляseparator="true"
, в прочих случаях - обязательный, видимый текст пункта менюpanelName
- необязательный дляseparator="true"
или если указан атрибутurl
, в прочих случаях - обязательный, определяет код панели, открываемой при выборе данного пункта меню конечным пользователем (коды панелей объявляются в секцииPanels
данного файла конфигурации, описана ниже)url
- необязательный дляseparator="true"
или если указан атрибутpanelName
, в прочих случаях - обязательный, определяет URL, который будет открыт в отдельной закладке "ПАРУС 8 Онлайн" при выборе данного пункта меню конечным пользователем (в приведённом примере, для пункта меню "ShowPrjPanelsRoot" открывает домашнюю страницу WEB-приложения "Парус 8 - Панели мониторинга", отображающую галерею доступных панелей, см. ниже описание атрибутаurlBase
элементаPanels
)
Panels
- содержит список элементов Panel
, описывающих подключенные панели. Элемент Panels
имеет атрибут urlBase
, определяющий корневой URL WEB-приложения "Парус 8 - Панели мониторинга", относительно него формируются URL панелей. Значение urlBase
определяется физическим расположением WEB-приложения "Парус 8 - Панели мониторинга" на диске сервера приложений (см. пункт 5 в главе "IV. Установка"). В данном примеры, файлы WEB-приложения распологаются в каталоге "Modules/p8-panels" сервера приложений. Каждый из элементов Panel
, дочерних для Panels
, описывает одну панель и имеет следующие атрибуты:
name
- обязательный, строка, указывается латиницей, определяет уникальное имя панелиgroup
- необязательный, строка, указывается кириллицей, определяет имя группы, в которую входит панель (применяется при формировании галереи панелей, главного меню панелей и ссылок на рабочем столе)caption
- обязательный, строка, видимое наименование панели (применяется в галереи панелей, главном меню панелей, ссылках на рабочем столе, заголовках закладок)desc
- необязательный, строка,url
- обязательный, строка, указывается латиницей, относительй URL панели (по адресуPanel.urlBase
+Panel.Panels.url
сервер приложений "ПАРУС 8 Онлайн" будет выдавать HTML-страницу панели), для простоты навигации может повторять значение атрибутаpath
path
- обязательный, строка, путь к исходному коду панели в структуре каталогов WEB-приложения "Парус 8 - Панели мониторинга" (панели должны размещаться в "app/panels", в данном атрибуте указыватся только имя каталога, созданного для панели в "app/panels")icon
- обязательный, строка, код иконки панели из символов шрифта Google Material Icons (применяется при формировании галереи панелей, главного меню панелей и ссылок на рабочем столе)showInPanelsList
- обязательный, принимает значения "true" или "false", определяет отображение ссылки на панель в галереи панелей, главном меню панелей, виджете рабочего столаpreview
- полный путь и имя файла из каталога "img" WEB-приложения "Парус 8 - Панели мониторинга" (в каталог могут быть добавлены пользовательские изображения), служит в качестве изображения панели в галерее панелей
На рисунках ниже проиллюстрировано применение атрибутов элемента Panel
.
Подключение разработанных пользователем панелей осуществляется путём добавления элементов Panels
в файл конфигурации (при необходимости и элементов App\MenuItems
, если предполагается открытие панели через главное меню WEB-приложения "ПАРУС 8 Онлайн").
Изменения файла конфигурации в части элементов MenuItems
требуют перезапуска сервера приложений "ПАРУС 8 Онлайн" и завершения/начала сеансов конечных пользователей.
Будьте внимательны при обновлении: если в локальном файле "p8panels.config" содержится конфигурация пользовательских панелей, то его нельзя заменять копированием дистрибутивной версии файла при обновлении - будут утеряны сделанные настройки. В этом случае файл следует модифицировать экспертным путём, добавив в локальный "p8panels.config" изменения из дистрибутивного вручную.
VI. Разработка панелей
Внимание: данное руководство не является обучающим курсом по WEB-разработке как таковой. Изложенные ниже сведения о порядке реализации пользовательских панелей, даны с учётом приведённых ранее требований к разработчику.
Общие сведения
Расширение "Панели" позволяет подключать нестандартные интерфейсы разрабатываемые на местах, без привлечения вендора. Это могут быть не только панели мониторинга, но и формы ввода данных, различные АРМ, выполняющие бизнес-функции в Системе.
С точки зрения клиенсткой части, Панели представляют собой функциональные компоненты React, автоматически (благодаря описанному выше файлу конфигурации) встраиваемые в систему маршрутизации WEB-приложения "Парус 8 - Панели мониторинга" (далее "приложения" или "WEB-приложения", если контекст явно не указывает на иное). Каждая панель состоит из:
- Набора JS-объектов и функций, управляющих состоянием панели
- Функций для обмена данными с сервером БД Системы и выполнения бизнес-процедур в ней
- JSX разметки, отражающей смену состояния панели
Такая структура исходного кода панели продиктована архитектурными требованиями к функциональным React-компонентам. Каждая панель (и все необходимые для её функционирования JS-модули и вспомогательный файлы) размещается в отдельном каталоге (см. выше - "app/panels", здесь и далее каталоги указаны относительно корневого каталога размещения приложения, если явно не указано иное) WEB-приложения "Парус 8 - Панели мониторинга".
Каждая панель должна иметь в составе "index.js" - точку входа по умолчанию. "index.js" должен экспортировать фунциональный React-компонент панели с имененем RootClass
(см. для примера "app/panels/prj_fin/index.js").
После добавления новых панелей в состав приложения необходима его "пересборка". Для этого предусмотрены преднастроенные скрипты dev
и build
. Скрипты размещены в секции scripts
файла зависимостей package.json
WEB-приложения. Исполнение скриптов сборки выполняется через пакетный менеджер npm
из корневого каталога приложения:
REM Запуск скрипта для отладочной сборки
c:\inetpub\p8web20\WebClient\Modules\P8-Panels>npm run dev
REM Запуск скрипта финальной сборки
c:\inetpub\p8web20\WebClient\Modules\P8-Panels>npm run build
Скрипт финальной сборки формирует обновлённое WEB-приложение в каталоге "dist" и завершает работу. Скрипт отладочной сборки обновляет WEB-приложение в каталоге "dist" и остаётся в активном режиме, "слушая" измнения файлов исходного кода приложения и автоматически обновляя "dist", если таковые изменения будут зафиксированы. Это позволяет отлаживать панели не выполняя пересборку вручную.
После пересборки обновлённые/новые панели доступны конечному пользователю для эксплуатации через WEB-приложение "ПАРУС 8 Онлайн".
Серверная часть любой из панелей - набор хранимых процедур/функций/пакетов БД Системы. Состав объектов, их алгоритмы, входные параметры и выходные данные зависят от специфики панели и специально не регламентируются. Необходимо понимать, что с помощью специального API из клиентской JS-функции панели можно обращаться к хранимым объектам БД - исполнять их, передавать значения входных параметров (например, считанные из форм ввода, размещённых на панели), получать и отображать на панели значения выходных параметров исполненного серверного объекта (в виде таблиц, карточек, графиков и прочими способами, отвечающими функциональным требованиям реализуемой панели).
API для взаимодействия с сервером "ПАРУС 8 Предприятие"
Для исполнения хранимых процедур/функций БД Системы в составе расширения предусмотрен специальный API. Его подключение к компоненте панели осуществляется через контекст BackEndСtx
("app/context/backend.js").
В состав API входят:
SERV_DATA_TYPE_STR
- константа для типа данных "строка", при описании параметров исполняемых хранимых объектовSERV_DATA_TYPE_NUMB
- константа для типа данных "число", при описании параметров исполняемых хранимых объектовSERV_DATA_TYPE_DATE
- константа для типа данных "дата", при описании параметров исполняемых хранимых объектовSERV_DATA_TYPE_CLOB
- константа для типа данных "текст", при описании параметров исполняемых хранимых объектовisRespErr
- проверка результата исполнения серверного объекта на наличие ошибокgetRespErrMessage
- получение ошибки исполнения серверного объектаgetRespPayload
- получение выходных значений, полученных после успешного исполненияexecuteStored
- асинхронное исполнение хранимой процедуры/функции БД СистемыgetConfig
- асинхронное считывание параметров конфигурации, определённых в "p8panels.config" (возвращает их JSON-представление)
При формировании ответов, функции, получающие данные с сервера, возвращают типовые значения:
//Типовой успех
{
SSTATUS: "OK",
XPAYLOAD: Object
}
//Типовая ошибка
{
SSTATUS: "ERR",
SMESSAGE: String
}
Где:
SSTATUS
- строка, состояние исполнения ("OK"
- успех или"ERR"
- ошибка)XPAYLOAD
- объект, полезная нагрузка, данные полученные от серверного объекта (отсутствует, еслиSSTATUS = "ERR"
)SMESSAGE
- строка, текст сообщения об ошибке (отсутствует, еслиSSTATUS = "OK"
)
boolean isRespErr(Object)
Входные параметры: обязательный, объект, результат вызова executeStored
Результат: true
- если полученный на вход результат исполнения executeStored
содержит ошибку, false
- в остальных случаях
String getRespErrMessage(Object)
Входные параметры: обязательный, объект, результат вызова executeStored
Результат: текст сообщения об ошибке - если полученный на вход результат исполнения executeStored
содержит ошибку, пустая строка (""
) - в остальных случаях
Object getRespPayload(Object)
Входные параметры: обязательный, объект, результат вызова executeStored
(вызов должен осуществляться с параметром fullResponse = true
)
Результат: объект с данными, размещёнными в XPAYLOAD
ответа сервера - если полученный на вход результат исполнения executeStored
содержит полезную нагрузку, null
- в остальных случаях
async Object executeStored(Object)
Входные параметры:
{
stored,
args,
respArg,
isArray,
tagValueProcessor,
attributeValueProcessor,
loader = true,
loaderMessage = "",
throwError = true,
showErrorMessage = true,
fullResponse = false,
spreadOutArguments = true
}
stored
- обязательный, строка, имя исполняемого хранимого объекта (для пакетных - "ПАКЕТ.ОБЪЕКТ")
args
- необязательный, объект, описание параметров исполняемого хранимого объета вида: {"ПАРАМЕТР": "ЗНАЧЕНИЕ"|{VALUE: "ЗНАЧЕНИЕ", SDATA_TYPE: SERV_DATA_TYPE_*}}
(если тип данных параметров не указан явно - произойдёт попытка их автоматического определения, с CLOB-параметрами это не всегда может произойти корректно)
respArg
- необязательный, строка, имя выходного параметра исполняемого объекта, значение которого необходимо вернуть как данные ответа (если не указан - возвращвется типовой ответ)
isArray
, tagValueProcessor
, attributeValueProcessor
- необязательны, функции, позволяющие провести корректировку парсинга XML-ответа сервера в JSON (сигнатура и назначение функций описаны в документации к fast-xml-parser)
loader
- необязательный, логический, признак отображения типового индикатора процесса
loaderMessage
- необязательный, строка, текст индикатора процесса (при отсутствии будет использован типовой)
throwError
- необязательный, логический, признак генерации исключения, если false
- возвращает ошибку в типовом формате
showErrorMessage
- необязательный, логический, признак отображения типового клиентского сообщение об ошибке, в случае её возникновения (только если throwError = true
)
fullResponse
- необязательный, логический, признак возврата полного типового ответа сервера, если false
- возвращается только содержимое XPAYLOAD
spreadOutArguments
- необязательный, логический, признак "разделения" значений выходных параметров исполняемого обхекта (игнорируется при наличии respArg
), если true
- XPAYLOAD
будет содержать ответ в виде {"ВЫХОДНОЙ_ПАРАМЕТР1": "ЗНАЧЕНИЕ", "ВЫХОДНОЙ_ПАРАМЕТР2": "ЗНАЧЕНИЕ", ...}
, если false
- XPAYLOAD
будет содержать ответ в виде {XOUT_ARGUMENTS: [{SNAME: "ВЫХОДНОЙ_ПАРАМЕТР1", VALUE: "ЗНАЧЕНИЕ"}, {SNAME: "ВЫХОДНОЙ_ПАРАМЕТР2", VALUE: "ЗНАЧЕНИЕ"}, ...]}
Результат: объект с данными, размещёнными в XPAYLOAD
ответа сервера (если fullResponse = false
) или полный типовой ответ (описан выше).
Пример:
import React, { useState, useContext } from "react"; //Классы React
import { BackEndСtx } from "../../context/backend"; //Контекст взаимодействия с сервером
//Функциональный компонент панели (или её части)
const MyPanel = () => {
//Собственное состояние
const [state, setState] = useState({ dataLoaded: false, data: [], filters: null, orders: null });
//Подключение к контексту взаимодействия с сервером
const { executeStored, SERV_DATA_TYPE_CLOB } = useContext(BackEndСtx);
//Загрузка данных проектов с сервера
const loadProjects = async (agentName) => {
//Исполняем процедуру
const data = await executeStored({
stored: "UDO_P_GET_MY_DATA",
args: {
CFILTERS: { VALUE: state.filters, SDATA_TYPE: SERV_DATA_TYPE_CLOB },
CORDERS: { VALUE: state.orders, SDATA_TYPE: SERV_DATA_TYPE_CLOB },
SAGENT: agentName
},
respArg: "COUT"
});
//Отражаем данные в состоянии
setState(pv => ({ ...pv, data: [...data], dataLoaded: true }));
}
};
async Object getConfig(Object)
Входные параметры:
{
loader = true,
loaderMessage = "",
throwError = true,
showErrorMessage = true
}
loader
- необязательный, логический, признак отображения типового индикатора процесса
loaderMessage
- необязательный, строка, текст индикатора процесса (при отсутствии будет использован типовой)
throwError
- необязательный, логический, признак генерации исключения, если false
- возвращает ошибку в типовом формате
showErrorMessage
- необязательный, логический, признак отображения типового клиентского сообщения об ошибке, в случае её возникновения (только если throwError = true
)
Результат: объект, типовой ответ, где XPAYLOAD
объект вида (см. описание атрибутов выше, в описании "p8panels.config"):
{
"MenuItems": {
"App": [
{
"MenuItem": [
{
"parent": ...,
"name": ...,
"caption": ...,
"url": ...,
"separator": ...
},
...
],
"name": "Realiz"
},
...
]
},
"Panels": {
"Panel": [
{
"name": ...,
"group": ...,
"caption": ...,
"desc": ...,
"url": ...,
"path": ...,
"icon": ...,
"showInPanelsList": ...,
"preview": ...
},
...
],
"urlBase": ...
}
}