P8-Panels/app/components/editors/p8p_data_source_hooks.js

230 lines
11 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
Парус 8 - Панели мониторинга - Редакторы панелей
Пользовательские хуки компонента "Источник данных"
*/
//---------------------
//Подключение библиотек
//---------------------
import { useState, useContext, useEffect, useRef } from "react"; //Классы React
import client from "../../core/client"; //Клиент взаимодействия с сервером приложений
import { ERRORS } from "../../../app.text"; //Общие текстовые ресурсы
import { formatErrorMessage } from "../../core/utils"; //Общие вспомогательные функции
import { BackEndСtx } from "../../context/backend"; //Контекст взаимодействия с сервером
import { P8P_DATA_SOURCE_TYPE, P8P_DATA_SOURCE_ARGUMENT_DATA_TYPE } from "./p8p_data_source_common"; //Общие ресурсы источника данных
import { getConditionsValues } from "./p8p_component_condition/util"; //Вспомогательные ресурсы условий
import { getHandlersByActions } from "./p8p_component_action/util"; //Вспомогательные ресурсы действий
import { ApplicationСtx } from "../../context/application"; //Контекст приложения
//-----------
//Тело модуля
//-----------
//Описание пользовательской процедуры
const useUserProcDesc = ({ code, refresh }) => {
//Собственное состояние - флаг загрузки
const [isLoading, setLoading] = useState(false);
//Собственное состояние - данные
const [data, setData] = useState(null);
//Подключение к контексту взаимодействия с сервером
const { executeStored } = useContext(BackEndСtx);
//При необходимости обновить данные компонента
useEffect(() => {
//Загрузка данных с сервера
const loadData = async () => {
try {
setLoading(true);
const data = await executeStored({
stored: "PKG_P8PANELS_PE.USERPROCS_DESC",
args: { SCODE: code },
respArg: "COUT",
isArray: name => name === "arguments",
loader: false
});
setData(data?.XUSERPROC || null);
} finally {
setLoading(false);
}
};
//Если надо обновить и есть для чего получать данные
if (refresh > 0)
if (code) loadData();
else setData(null);
}, [refresh, code, executeStored]);
//Возвращаем интерфейс хука
return [data, isLoading];
};
//Получение данных из источника
const useDataSource = ({ dataSource, values, componentRespArg = "" }) => {
//Контроллер для прерывания запросов
const abortController = useRef(null);
//Собственное состояние - параметры исполнения
const [state, setState] = useState({ stored: null, storedArgs: [], respArg: null, reqSet: false });
//Собственное состояние - флаг загрузки
const [isLoading, setLoading] = useState(false);
//Собственное состояние - данные
const [data, setData] = useState({ componentData: {}, init: false });
//Собственное состояние - ошибка получения данных
const [error, setError] = useState(null);
//Собственное состояние - наличие настроек
const [haveConfing, setHaveConfig] = useState(false);
//Собственное состояние - наличие данных
const [haveData, setHaveData] = useState(false);
//Подключение к контексту взаимодействия с сервером
const { executeStored } = useContext(BackEndСtx);
//При необходимости обновление информации о наличии данных
useEffect(() => {
setHaveData(data.init === true && !error ? true : false);
}, [data.init, error]);
//При необходимости обновить данные
useEffect(() => {
//Загрузка данных с сервера
const loadData = async () => {
try {
setLoading(true);
abortController.current?.abort?.();
abortController.current = new AbortController();
const data = await executeStored({
stored: state.stored,
args: { ...(state.storedArgs ? state.storedArgs : {}) },
respArg: state.respArg,
loader: false,
signal: abortController.current.signal,
showErrorMessage: false
});
setError(null);
setData({ componentData: { ...data[componentRespArg] }, init: true });
} catch (e) {
if (e.message !== client.ERR_ABORTED) {
setError(formatErrorMessage(e.message).text);
setData({ componentData: {}, init: false });
}
} finally {
setLoading(false);
}
};
if (state.reqSet) {
if (state.stored) loadData();
} else setData({ componentData: {}, init: false });
return () => abortController.current?.abort?.();
}, [state.stored, state.storedArgs, state.respArg, state.reqSet, executeStored, componentRespArg]);
//При изменении свойств
useEffect(() => {
//Устанавливаем признак наличия настроек
setHaveConfig(dataSource?.stored ? true : false);
//Устанавливаем параметры исполнения
setState(pv => {
if (dataSource?.type == P8P_DATA_SOURCE_TYPE.USER_PROC) {
const { stored, respArg } = dataSource;
let reqSet = true;
const storedArgs = {};
dataSource.arguments.forEach(argument => {
let v = argument.valueSource ? values[argument.valueSource] : argument.value;
storedArgs[argument.name] =
argument.dataType == P8P_DATA_SOURCE_ARGUMENT_DATA_TYPE.NUMB
? isNaN(parseFloat(v))
? null
: parseFloat(v)
: argument.dataType == P8P_DATA_SOURCE_ARGUMENT_DATA_TYPE.DATE
? new Date(v)
: String(v === undefined ? "" : v);
if (argument.req === true && [undefined, null, ""].includes(storedArgs[argument.name])) reqSet = false;
});
if (pv.stored != stored || pv.respArg != respArg || JSON.stringify(pv.storedArgs) != JSON.stringify(storedArgs)) {
if (!reqSet) {
setError(ERRORS.DATA_SOURCE_NO_REQ_ARGS);
setData({ componentData: {}, init: false });
}
return { stored, respArg, storedArgs, reqSet };
} else return pv;
} else return pv;
});
}, [dataSource, values]);
//Возвращаем интерфейс хука
return [data.componentData, error, haveConfing, haveData, isLoading];
};
//Изменение данных компонента с учетом условий
const useConditions = ({ componentData, conditions }) => {
//Собственное состояние - текущие условия компонента
const [currentConditions, setCurrentConditions] = useState([]);
//Собственное состояние - данные
const [data, setData] = useState();
//При обновлении условий компонента
useEffect(() => {
//Если условия изменились
if (JSON.stringify(currentConditions) != JSON.stringify(conditions)) {
//Устанавливаем новые условия
setCurrentConditions(conditions);
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [conditions]);
//При обновлении данных или условий компонента
useEffect(() => {
//Если есть текущие условия
if (currentConditions.length !== 0) {
//Устанавливаем данные с учетом условий
setData({ ...componentData, ...getConditionsValues(componentData, currentConditions) });
} else {
//Оставляем данные компонента
setData({ ...componentData });
}
}, [currentConditions, componentData]);
//Возвращаем интерфейс хука
return [data];
};
//Получение обработчиков компонента
const useComponentHandlers = ({ actions = [], onValuesChange = null, getCustomTypeValue = null }) => {
//Контроллер для текущего состояния действий
const currentActions = useRef([]);
//Собственное состояние - обработчики компонента
const [handlers, setHandlers] = useState({});
//Подключение к контексту приложения
const { configUrlBase, pOnlineShowTab, pOnlineShowUnit } = useContext(ApplicationСtx);
//При необходимости обновления информации об обработчиках
useEffect(() => {
//Если изменились действия или параметры
if (JSON.stringify(currentActions.current) != JSON.stringify(actions)) {
//Считываем обработчики компонента
setHandlers(getHandlersByActions(actions, pOnlineShowUnit, configUrlBase, pOnlineShowTab, onValuesChange, getCustomTypeValue));
//Устанавливаем контроллер текущих действий
currentActions.current = actions;
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [actions]);
//Возвращаем интерфейс хука
return [handlers];
};
//----------------
//Интерфейс модуля
//----------------
export { useUserProcDesc, useDataSource, useConditions, useComponentHandlers };