/* Парус 8 - Панели мониторинга Хуки для таблиц данных */ //--------------------- //Подключение библиотек //--------------------- import { useState, useCallback, useEffect, useContext, useRef, useMemo } from "react"; //Классы React import { BackEndСtx } from "../context/backend"; //Контекст взаимодействия с сервером import { object2Base64XML } from "../core/utils"; //Вспомогательные функции //--------- //Константы //--------- //Константы - значения по умолчанию const DG_PAGE_SIZE_DEF = 10; //Размер страницы const DG_NODE_NAME_DEF = "XDATA_GRID"; //Наименование узла, содержащего информацию о таблице const FILTERS_NODE_NAME_DEF = "filters"; //Наименование узла отборов const ORDERS_NODE_NAME_DEF = "orders"; //Наименование узла сортировок const RESP_ARG_DEF = "COUT"; //Имя параметра, содержащего информацию о таблице //----------- //Тело модуля //----------- //Хук для P8PDataGrid const useP8PDataGrid = ({ stored, respArg = RESP_ARG_DEF, contentNodeName = DG_NODE_NAME_DEF, filtersNodeName = FILTERS_NODE_NAME_DEF, ordersNodeName = ORDERS_NODE_NAME_DEF, pageSize = DG_PAGE_SIZE_DEF, reloadDef = false, initFilters = [], initOrders = [], storedArgs = {}, executeStoredArgs = {}, allowDataLoad = () => true }) => { //Собственное состояние - таблица данных const [dataGrid, setDataGrid] = useState({ columnsDef: [], groups: [], rows: [], filters: Array.isArray(initFilters) ? [...initFilters] : [], orders: Array.isArray(initOrders) ? [...initOrders] : [], pageNumber: 1, pagesAlign: null, pagesPosition: null, pagesCount: 0, fixedColumns: 0, fixedHeader: false, morePages: true }); //Собственное состояние - признак загрузки данных const [isDataLoaded, setIsDataLoaded] = useState(false); //Собственное состояние - флаг загрузки const [isLoading, setLoading] = useState(false); //Собственное состояние - необходимость обновления данных const [reload, setReload] = useState(true); //Собственное состояние - дополнительные параметры процедуры const refStoredArgs = useRef(storedArgs); //Собственное состояние - дополнительные параметры вызова процедуры const refExecuteStoredArgs = useRef(executeStoredArgs); //Признак допустимости обновления данных const isAllowDataLoad = useMemo(() => { return allowDataLoad(); }, [allowDataLoad]); //Подключение к контексту взаимодействия с сервером const { executeStored, SERV_DATA_TYPE_CLOB, isRespErr } = useContext(BackEndСtx); //Загрузка данных таблицы с сервера const loadData = useCallback(async () => { try { setLoading(true); const data = await executeStored({ stored, args: { CFILTERS: { VALUE: object2Base64XML(dataGrid.filters, { arrayNodeName: filtersNodeName }), SDATA_TYPE: SERV_DATA_TYPE_CLOB }, CORDERS: { VALUE: object2Base64XML(dataGrid.orders, { arrayNodeName: ordersNodeName }), SDATA_TYPE: SERV_DATA_TYPE_CLOB }, NPAGE_NUMBER: dataGrid.pageNumber, NPAGE_SIZE: pageSize, NINCLUDE_DEF: reloadDef ? 1 : dataGrid.dataLoaded ? 0 : 1, ...refStoredArgs.current }, respArg, ...refExecuteStoredArgs.current }); setDataGrid(pv => ({ ...pv, ...data[contentNodeName], columnsDef: data[contentNodeName].columnsDef ? [...data[contentNodeName].columnsDef] : pv.columnsDef || [], rows: data[contentNodeName].pagesCount > 0 || pv.pageNumber == 1 ? [...(data[contentNodeName].rows || [])] : [...(pv.rows || []), ...(data[contentNodeName].rows || [])], groups: data[contentNodeName].groups ? data[contentNodeName].pagesCount > 0 || pv.pageNumber == 1 ? [...(data[contentNodeName].groups || [])] : [...(pv.groups || []), ...data[contentNodeName].groups.filter(g => !pv.groups.find(pg => pg.name == g.name))] : [...(pv.groups || [])], morePages: data[contentNodeName].morePages && (data[contentNodeName].rows || []).length >= pageSize })); //Устанавливаем признак загрузки данных с учетом возможных ошибок setIsDataLoaded(!isRespErr(data)); } catch (e) { //Если произошла ошибка - данные не загружены setIsDataLoaded(false); } finally { //Сбрасываем признаки загрузки и перезагрузки данных setLoading(false); setReload(false); } }, [ SERV_DATA_TYPE_CLOB, contentNodeName, dataGrid.dataLoaded, dataGrid.filters, dataGrid.orders, dataGrid.pageNumber, executeStored, filtersNodeName, isRespErr, ordersNodeName, pageSize, reloadDef, respArg, stored ]); //При изменении состояния фильтра const handleFilterChanged = useCallback(({ filters }) => { setDataGrid(pv => ({ ...pv, filters: [...filters], pageNumber: 1 })); setReload(true); }, []); //При изменении состояния сортировки const handleOrderChanged = useCallback(({ orders }) => { setDataGrid(pv => ({ ...pv, orders: [...orders], pageNumber: 1 })); setReload(true); }, []); //При изменении количества отображаемых страниц const handlePagesCountChanged = useCallback(() => { setDataGrid(pv => ({ ...pv, pageNumber: pv.pageNumber + 1 })); setReload(true); }, []); //При изменении страницы отображения const handlePageChange = useCallback(({ page }) => { setDataGrid(pv => ({ ...pv, pageNumber: page })); setReload(true); }, []); //При необходимости обновления таблицы const doReload = useCallback( ({ returnOnFirstPage = false }) => { //Если это не страничный вывод или установлен признак возврата на первую страницу if (dataGrid.pagesCount <= 0 || returnOnFirstPage) { setDataGrid(pv => ({ ...pv, pageNumber: 1 })); } setReload(true); }, [dataGrid.pagesCount] ); //Проверка изменений параметров const isArgsChanged = useCallback( (currentArgs, args) => { //Если дополнительные параметры изменились (и сейчас не происходит загрузка данных с сервера) return !isLoading && JSON.stringify(currentArgs) != JSON.stringify(args); }, [isLoading] ); //При изменение дополнительных параметров процедуры useEffect(() => { //Если параметры изменились if (isArgsChanged(refStoredArgs.current, storedArgs)) { //Устанавливаем новые дополнительные параметры refStoredArgs.current = storedArgs; //При изменении дополнительных параметров необходимо перезагрузить данные setReload(true); } }, [storedArgs, isArgsChanged]); //При изменение дополнительных параметров вызова процедуры useEffect(() => { //Если параметры изменились if (isArgsChanged(refExecuteStoredArgs.current, executeStoredArgs)) { //Устанавливаем новые дополнительные параметры refExecuteStoredArgs.current = executeStoredArgs; //При изменении дополнительных параметров необходимо перезагрузить данные setReload(true); } }, [executeStoredArgs, isArgsChanged]); //При необходимости обновить данные таблицы useEffect(() => { if (isAllowDataLoad && reload) { loadData(); } }, [isAllowDataLoad, reload, loadData]); //Возвращаем данные таблицы return { dataGrid, isDataLoaded, isLoading, handleFilterChanged, handleOrderChanged, handlePagesCountChanged, handlePageChange, doReload }; }; //---------------- //Интерфейс модуля //---------------- export { useP8PDataGrid };