How-to: Фронтенд
Наиболее простым способом организации взаимодействия React приложения с приложением на базе lsFusion является общение через HTTP-протокол посредством JSON API. Для выгрузки списка объектов по заданному условию удобнее всего использовать интерфейс, который находится по Url'у eval/action. На него в BODY можно передать программный код lsFusion, который будет выполнен. При необходимости вернуть данные по запросу необходимо использовать оператор EXPORT
. По умолчанию, он возвращает данные в формате JSON, которые затем легко обрабатываются при помощи JavaScript.
В данных примерах мы будем делать запросы без авторизации. Для того, чтобы сервер начал принимать запросы без авторизации, в форме Администрирование > Настройки
на вкладке Параметры
нужно установить опцию enableAPI
в значение 2
.
Более безопасным способом будет создание для каждого запроса отдельного действия с пометкой @@api и установкой enableAPI
в значение 0
. В таком случае, сервером будут приниматься запросы только к этим действиям и при авторизованном пользователе. Внутри этих действий перед началом обработки можно проверять на доступность его пользователю, которого можно получить при помощи свойства currentUser()
.
Пример 1
Для наглядности реализуем простую форму из примера Турнир ная таблица (без возможности редактирования).
Оформим считывание плоского набора данных при помощи функции с одним параметром : текстом запроса, к которому добавляется слева EXPORT FROM
:
const url = "https://demo.lsfusion.org/hockeystats/eval/action";
function select(script) {
const params = {
method: "post",
body: "EXPORT FROM " + script
}
return fetch(url, params).then(response => response.json());
}
Например, запрос следующего содержания
select("date(Game g), hostTeamName(g), hostGoals(g), guestGoals(g), guestTeamName(g), resultName(g)")
вернет JSON вида
[
{
"date":"05.02.19",
"hostGoals":3,
"guestTeamName":"New York Rangers",
"hostTeamName":"Detroit Red Wings",
"guestGoals":2,
"resultName":"ПО"
},
{
"date":"13.02.19",
"hostGoals":2,
"guestTeamName":"Toronto Maple Leafs",
"hostTeamName":"Montreal Canadiens",
"guestGoals":0,
"resultName":"П"
},
{
"date":"15.02.19",
"hostGoals":3,
"guestTeamName":"Montreal Canadiens",
"hostTeamName":"New York Rangers",
"guestGoals":5,
"resultName":"П"
},
{
"date":"17.02.19",
"hostGoals":2,
"guestTeamName":"Detroit Red Wings",
"hostTeamName":"Toronto Maple Leafs",
"guestGoals":1,
"resultName":"ПБ"
}
]
Остается только подложить эти данные в качестве состояний для React компонент (например, с использованием Material-UI) :
Пример 2
Рассмотрим немного более сложный случай, когда нужно делать параметризованные запросы, в зависимости от выбранных пользователем данных. В качестве логики backend'а возьмем пример Управление материальными потоками.
Предположим, что нужно построить форму, в которой нужно показать расходные документы, с возможностью фильтровать по дате и складу. При этом, когда пользователь выбирает конкретный документ, должны отобразиться его строки.
Для реализации запроса к backend'у по получению расходных д окументов с фильтрацией объявим функцию:
const url = "https://demo.lsfusion.org/mm/eval/action";
function select(script, data) {
var formData = new FormData();
formData.append("script", "EXPORT FROM " + script);
for (var name in data) {
formData.append(name, data[name]);
}
const params = {
method: "post",
headers: {
"Content-type": "multipart/form-data"
},
body: formData
};
return fetch(url, params).then(response => response.json());
}
Первая функция select
будет д елать POST запрос с типом содержимого multipart/form-data, передавая первым параметром на сервер текст запроса, а остальными параметрами - значения запроса.
Например, вызов функции вида
select("id = Shipment s, number(s) WHERE date(s) = $1", { date: new Date().toISOString().substr(0, 10) })
вернет все расходные документы за сегодняшнее число. Следует отметить, что название параметра date не используется на backend'е и может быть абсолютно любым. Важен только порядок следования параметров.
Для удобства также объявим функцию, которая будет формировать запрос, добавляя в фильтр только те параметры, значения которых не являются null
:
function selectWhere(script, wheres) {
var exprs = [], params = {};
for (var i = 0; i < wheres.length; i++) {
if (wheres[i].value != null) {
exprs.push(wheres[i].expr + "=$" + (i + 1));
params = { ...params, ...{ ["p" + i]: wheres[i].value } };
}
}
return select(script + (exprs.length > 0 ? " WHERE " : "") + exprs.join(" AND "), params);
}
Соответствующий вызов функции выше может быть заменен на:
selectWhere("id = Shipment s, number(s)", [{ expr: "date(s)", value : new Date().toISOString().substr(0, 10) }])
Используя описанные выше запросы реализуем требуемую логику. Для этого определим две компоненты:
Shipments
, которая будет отображать при помощи компонента List (из упомянутого Material-UI) список документов. Также в ней будет содержаться компонентFilters
, при помощи которого пользователь будет задавать параметры для фильтрации.Details
, который будет отображать строки выбранного документа. При желании его можно было бы вложить в компонентShipments
.
Остальной код будет выглядеть следующим образом: