Руководство Melbis Shop: оглавление
Веб-модули — это особый механизм интеграции серверной платформы Melbis с её Windows-клиентом Melbis Shop. Суть механизма: внутри программы встроен полноценный браузер на базе Chromium, который умеет открывать страницы сайта прямо внутри окон программы и общаться с ними в обе стороны — передавать контекст текущей работы менеджера на сервер и получать обратно результат. Разработчик создаёт обычный Melbis-модуль, а программа открывает его внутри своего окна.
Это позволяет расширять функциональность программы без изменения её кода: аналитика, отчёты, инструменты управления — всё это можно реализовать на PHP и подключить через настройки.
Встроенные модули работают прямо внутри рабочих окон программы — окон
товаров, заказов, покупателей, планировщика и переводов. Чтобы открыть
встроенный веб-модуль в любом из этих окон, нажмите Ctrl+W
— появится панель со встроенным браузером.
Ключевая особенность: когда менеджер перемещается по записям (выбирает товар, открывает заказ, переходит к покупателю), программа автоматически отправляет POST-запрос в модуль с контекстом текущего окна. Модуль всегда знает, с каким объектом сейчас работает менеджер, и может показать релевантную информацию — без каких-либо дополнительных действий с его стороны.
Этих модулей может быть несколько для каждого раздела — они переключаются вкладками. Для каждого модуля можно задать права доступа: какие группы пользователей его видят.
Примеры встроенных модулей для раздела «Товары / Цены»:
Примеры для раздела «Бизнес / Заказы» и «Бизнес / Покупатели»:
Встроенные модули настраиваются в программе: «Проектирование → Модули и опции», закладка «Встроенные модули». Выберите место — товары, заказы, покупатели, планировщик или переводчик — и добавьте модуль со следующими параметрами:
http://my-shop.com/?mod=melbis_web_sample.melbis_web_sample). Используется для проверки прав
доступа.login, stamp и sign — логин,
время и подпись входа. Это позволяет модулю авторизовать пользователя и
проверить его права.При каждом обращении к встроенному модулю программа отправляет
POST-запрос с контекстом текущего окна. Поле уходит, только когда в окне
выбрана его запись; если выделено несколько строк, их номера идут через
; в поле с окончанием _set.
| Место | Окно | Поля |
|---|---|---|
| товары | «Расположение», «Цены», «Обозреватель», «Выбор товаров», «Описания» | melbis — пустое поле, с него начинается запрос окна;
topic_id — раздел; store_id — товар;
store_set — выделенные товары |
| товары | «Описания», панель значений характеристик | те же поля и ещё info_id — характеристика,
info_value_id — значение, info_value_set —
выделенные значения |
| заказы | «Заказы» | order_id — заказ; order_version_id —
версия заказа; order_version_client_id — покупатель версии;
order_version_user_id — менеджер версии;
order_client_field_id — выбранная строка полей покупателя
заказа; order_store_id — выбранная строка товаров заказа;
order_option_id — выбранная строка опций заказа;
order_set — выделенные заказы |
| заказы | «Редактирование заказа» | order_id, parent_version_id — родительская
версия, order_version_id,
order_version_client_id,
order_version_user_id, order_client_field_id,
client_field_id — поле покупателя,
order_store_id, store_id — товар выбранной
строки, store_option_id — опция товара,
order_option_id — опция заказа, и order —
заказ в правке целиком |
| покупатели | «Покупатели» | client_id — покупатель; client_field_id —
выбранная строка полей покупателя; client_set — выделенные
покупатели |
| планировщик | «Планировщик» | melbis; task_id — задача;
note_id — запись задачи |
| переводчик | «Переводы» | melbis; trans_id — раздел переводов;
origin_id — исходная строка; origin_set —
выделенные строки; lang_id — выбранная строка перевода,
номер строки trans_lang, а не языка |
В «Описаниях» номера товаров и значений — номера основного каталога,
а не строк рабочего раздела. Поле order окна
«Редактирование заказа» — JSON с несохранёнными строками заказа: ключи
new_orders_version, new_orders_client_field,
new_orders_store, new_orders_store_option и
new_orders_option, у каждого — список строк со всеми
полями.
С флажком «Требуется идентификация пользователя» к любому набору
добавляются login, stamp и sign:
stamp — время по GMT, sign — подпись строки
логин|время|WEB ключом, вычисленным из пароля. Сам пароль
из программы не уходит. Так выглядит $mVars модуля в окне
«Заказы»:
// $mVars в модуле:
[
'get' => ['mod' => 'melbis_web_sample'],
'post' => [
'order_id' => '1',
'order_version_id' => '2',
'order_version_client_id' => '1',
'order_version_user_id' => '1',
'order_client_field_id' => '3',
'order_store_id' => '2',
'order_option_id' => '3',
'login' => 'admin',
'stamp' => '2026-10-27 09:15:00',
'sign' => 'RjaLSFiSrdVFBXJ/r+Ud+TtICKvNeF5s3s/hlQwXatv37woccBwsDvduIBM6fh0Pp2lJxA4PvA0zzwwCVYvODw==',
]
]AI-помощник открывает модуль так же — инструментом shop_module: поля окна он
передаёт сам, а login, stamp и
sign пользователя сессии добавляет MCP-сервер.
Браузер программы работает на языке, выбранном в программе, и ставит
его первым в заголовок Accept-Language каждого запроса.
Модуль узнаёт его тем же методом, что и язык посетителя витрины (см. «Посетитель», раздел «Язык браузера»):
$lang = MELBIS()->AgentLanguage(['ru', 'uk', 'en'], 'en');Внешний модуль, открытый в обычном браузере, получает так язык этого браузера, поэтому один и тот же код работает в обоих случаях. Когда модуль открывает AI-помощник, заголовка нет, и метод возвращает значение по умолчанию.
Для веб-модулей в стандартную поставку демо-магазина включена
библиотека melbis_inc_logic_auth. Она берёт на себя весь
рутинный код: авторизацию пользователя по подписи (login,
stamp, sign), хранение состояния авторизации в
PHP-сессии, проверку прав доступа к модулю и маршрутизацию POST-вызовов
между функциями модуля.
Центральная функция —
MELBIS_INC_LOGIC_AUTH\Router($mModule, $mVars) —
выполняет следующее по порядку:
logout в POST).login, stamp и
sign из POST — через SysUserSignCheck, — или
по ранее сохранённой сессии.GlobalAssign('PAGE', [...]) глобальные
переменные, доступные во всех шаблонах: статус авторизации
(auth), user_id и mod — URL
текущего модуля. Переменная {PAGE:MOD} используется в
шаблонах как базовый URL для AJAX-запросов.func
— вызывает функцию модуля с этим именем (GetCataloge),
передавая ей $userId и $mVars. Без
func вызывается Page. Любая функция, кроме
Page, работает только после входа и с правом на модуль —
иначе ответ Access denied.Благодаря этому вся главная функция модуля сводится к одной строке:
namespace MELBIS_WEB_SAMPLE;
use MELBIS_INC_LOGIC_AUTH as LOGIC_AUTH;
function Main($mVars)
{
return LOGIC_AUTH\Router(MELBIS()->UnitName(), $mVars);
}MELBIS()->UnitName() возвращает имя текущего модуля —
оно передаётся в маршрутизатор для проверки прав и поиска функций
модуля.
Имя функции приходит данными, из POST, поэтому маршрутизатор зовёт её
через UnitFunc: тот собирает полное имя от выполняющегося
модуля — MELBIS_WEB_SAMPLE\GetCataloge, а в модуле прежней
формы, без пространства имён,
MELBIS_WEB_SAMPLE_GetCataloge. Один и тот же маршрутизатор
обслуживает обе формы.
Функция Page выводит страницу модуля: маршрутизатор
зовёт её, когда func не передан. Это единственная функция,
которую он зовёт и без входа, — она же показывает форму авторизации. Она
получает $mUserId (или null, если вход не
состоялся) и полный массив $mVars.
function Page($mUserId, $mVars)
{
$tpl = MELBIS()->TplCreate();
if ( $mUserId > 0 )
{
// Передать входные переменные в шаблон
MELBIS()->TplAssign($tpl, 'VARS', var_export($mVars, true));
// Передать данные заказа для механизма обратной передачи
MELBIS()->TplAssign($tpl, 'ORDER', $mVars['post']['order'] ?? '{}');
MELBIS()->TplParse($tpl, 'CONTENT', 'page');
}
else
{
// Пользователь не авторизован — показать форму входа
MELBIS()->TplAssign($tpl, 'ORDER', '{}');
MELBIS()->TplParse($tpl, 'CONTENT', 'auth');
}
MELBIS()->GlobalAppend('PAGE:TITLE', 'Sample Web module');
return MELBIS()->TplFinal($tpl, 'main');
}Шаблон auth.htm содержит вызов модуля
melbis_web_auth — он выводит форму логина. После отправки
формы маршрутизатор LOGIC_AUTH\Router снова обрабатывает
POST, авторизует пользователя и на этот раз Page разбирает
основной шаблон page.htm.
Для интерактивных действий внутри модуля JavaScript передаёт параметр
func в POST. Маршрутизатор найдёт и вызовет соответствующую
функцию — при условии что пользователь авторизован и имеет доступ к
модулю.
В шаблоне переменная {PAGE:MOD} содержит готовый URL
текущего модуля (/?mod=melbis_web_sample) — его удобно
использовать как точку для всех AJAX-запросов:
$('#melbis_table_cataloge').bootstrapTable({
url: '{PAGE:MOD}',
method: 'post',
queryParams: function(params) {
params.func = 'GetCataloge'; // маршрутизатор вызовет GetCataloge этого модуля
return params;
},
pagination: true,
sidePagination: 'server',
pageSize: 20,
sortName: 'absindex',
sortOrder: 'asc'
});На стороне PHP функция получает управление только если пользователь авторизован, выполняет запрос и возвращает JSON:
function GetCataloge($mUserId, $mVars)
{
$limit = (int) $mVars['post']['limit'];
$offset = (int) $mVars['post']['offset'];
$sort = preg_replace('/[^a-z_]/', '', $mVars['post']['sort']);
$sort .= ($mVars['post']['order'] == 'asc') ? ' ASC' : ' DESC';
$command = "SELECT t.id, t.name, t.tlevel, COUNT(ts.id) AS amount
FROM {DBNICK}_topic t
LEFT JOIN {DBNICK}_topic_store ts ON t.id = ts.topic_id
GROUP BY t.id
ORDER BY $sort";
$data = MELBIS()->SqlSelectLimit(__LINE__, $command, $offset, $limit);
return json_encode($data);
}Такой же принцип применяется для любых других функций модуля — поиска, фильтрации, сохранения данных в БД, отправки уведомлений и т.п.
Наиболее уникальная возможность встроенных веб-модулей — передача данных из браузера обратно в Windows-программу без дополнительных HTTP-запросов.
Страница отправляет программе сообщение методом
window.chrome.webview.postMessage: объект с именем события
в поле event и данными в поле data.
window.chrome.webview.postMessage({ event: 'MELBIS_ORDER_UPDATE', data: update });Программа понимает два события:
| Событие | Где работает | Что делает программа |
|---|---|---|
MELBIS_ORDER_UPDATE |
окно редактирования заказа | применяет data к полям редактируемого заказа |
MELBIS_PRINT |
любой браузер программы | открывает для страницы диалог печати Windows |
Объект window.chrome.webview есть только в браузере
программы. Модуль, который открывают и в обычном браузере, проверяет его
перед отправкой (пример — в разделе «Печать» ниже).
MELBIS_ORDER_UPDATE работает, пока заказ ещё не
сохранён. В остальных разделах (товары, покупатели) веб-модуль при
необходимости пишет изменения напрямую в базу данных через обычные
SQL-методы парсера.
Практический пример: модуль получает от программы все данные открытого заказа в JSON-формате, отображает их в интерактивных таблицах, и позволяет менеджеру редактировать отдельные поля прямо в браузере.
// PHP: получить данные заказа, переданные программой, и отдать в шаблон
MELBIS()->TplAssign($tpl, 'ORDER', $mVars['post']['order'] ?? '{}');// Шаблон: распарсить JSON и построить таблицы
var melbis_order = {ORDER};
function melbis_init_back() {
for (var table in melbis_order) {
var data = melbis_order[table];
var columns = [];
for (var c in data[0]) {
columns.push({field: c, title: c});
}
$('.melbis_table_order[data-table="' + table + '"]').bootstrapTable({
columns: columns,
data: data
});
}
}
// Клик по ячейке — диалог редактирования
$('.melbis_table_order').on('click-cell.bs.table', function(event, field, value, row) {
var table = event.target.dataset.table;
bootbox.prompt({
title: 'Edit value of "' + field + '"',
value: value,
callback: function(result) {
if (result != null) {
var update = {};
update[table] = [{id: row.id, [field]: result}];
// Передать изменение в программу
window.chrome.webview.postMessage({ event: 'MELBIS_ORDER_UPDATE', data: update });
}
}
});
});Программа получает событие MELBIS_ORDER_UPDATE и
применяет изменения к полям заказа в своём интерфейсе.
Событие MELBIS_PRINT открывает для страницы классический
диалог печати Windows: выбор принтера, числа копий и страниц.
Стандартный window.print() показывает вместо него
предпросмотр браузера внутри самой панели модуля.
Кнопка печати, которая работает и в программе, и в обычном браузере:
function melbis_print() {
if (window.chrome && window.chrome.webview) {
window.chrome.webview.postMessage({ event: 'MELBIS_PRINT' });
} else {
window.print();
}
}Внешние модули отличаются от встроенных принципиально одним: они не
привязаны к конкретному окну программы и не получают контекст текущей
записи. Вместо этого при открытии из программы передаются только
параметры авторизации пользователя (login,
stamp, sign).
Доступ к внешним модулям открывается через раздел «Бизнес / Веб-модули» — здесь расположен браузер с каталогом всех доступных модулей в левой панели. Кроме того, любой из таких модулей можно открыть в обычном браузере на любом устройстве — планшете, смартфоне, рабочем месте без программы.
Это делает внешние модули универсальным инструментом для дашбордов, аналитических отчётов и административных панелей — всего, что не требует привязки к конкретному товару или заказу. На скриншоте выше — пример реального внешнего модуля с аналитикой продаж, финансовым учётом, складским анализом и инструментами управления, встроенными прямо в программу.
Настройка внешних модулей — «Проектирование → Модули и опции», закладка «Внешние веб-модули»: задаётся название, URL и символьный ключ каждого модуля, а также права доступа по группам пользователей.
Поскольку внешние модули открываются в том числе из обычного браузера, авторизация здесь работает в двух режимах автоматически:
При открытии из программы — Melbis Shop передаёт
login, stamp и sign в POST.
LOGIC_AUTH\Router авторизует пользователя без участия формы
и сразу показывает содержимое.
При открытии в браузере напрямую — POST не содержит
учётных данных, маршрутизатор передаёт $mUserId = null, и
функция Page подставляет шаблон формы авторизации. После
успешного входа данные сохраняются в PHP-сессии, и при последующих
запросах форма больше не показывается.
Форма входа подписывает сама: функция melbis_crypto_sign
из statics/melbis/main.js вычисляет в браузере ключ из
пароля и отправляет те же login, stamp и
sign — пароль из браузера не уходит. Подпись делает
встроенный в браузер WebCrypto, поэтому форма работает только по https и
в браузерах с Ed25519: Chrome 137, Firefox 129, Safari 17 и новее.
Один и тот же код модуля работает в обоих случаях — разветвление
происходит полностью автоматически внутри библиотеки
melbis_inc_logic_auth. Разработчику достаточно корректно
обработать случай $mUserId == null в функции
Page.
Windows Melbis Shop
│
│ POST: store_id / order_id / login / stamp / sign
▼
index.php → Run('melbis_web_sample')
│
▼
MELBIS_WEB_SAMPLE\Main($mVars)
│
▼
MELBIS_INC_LOGIC_AUTH\Router(...)
├─ авторизация + проверка прав
├─ func отсутствует → MELBIS_WEB_SAMPLE\Page($userId, $mVars) → HTML
├─ func = 'GetCataloge' → MELBIS_WEB_SAMPLE\GetCataloge($userId, $mVars) → JSON
└─ func = 'GetGoods' → MELBIS_WEB_SAMPLE\GetGoods($userId, $mVars) → JSON
HTML-страница в браузере программы
│ (только для окна редактирования заказа)
▼
postMessage({ event: 'MELBIS_ORDER_UPDATE', data: {"version":[...]} })
│
▼
Windows Melbis Shop — применяет изменения к заказу