From 57d7dd2e6838c95b6219386505fc79c2312fc1a8 Mon Sep 17 00:00:00 2001 From: Mikhail Chechnev Date: Fri, 2 Aug 2024 15:32:38 +0300 Subject: [PATCH] =?UTF-8?q?=D0=97=D0=B0=D0=BA=D0=BB=D0=B0=D0=B4=D0=BA?= =?UTF-8?q?=D0=B0=20"=D0=9F=D1=80=D0=BE=D0=B3=D0=BD=D0=BE=D0=B7=D0=B8?= =?UTF-8?q?=D1=80=D0=BE=D0=B2=D0=B0=D0=BD=D0=B8=D0=B5"=20-=20=D1=81=D1=82?= =?UTF-8?q?=D1=80=D1=83=D0=BA=D1=82=D1=83=D1=80=D0=B0=20=D0=B8=20=D1=81?= =?UTF-8?q?=D0=BF=D0=B8=D1=81=D0=BE=D0=BA=20=D1=82=D0=B5=D1=85=D0=BD=D0=BE?= =?UTF-8?q?=D0=BB=D0=BE=D0=B3=D0=B8=D1=87=D0=B5=D1=81=D0=BA=D0=B8=D1=85=20?= =?UTF-8?q?=D0=BE=D0=B1=D1=8A=D0=B5=D0=BA=D1=82=D0=BE=D0=B2=20(=D0=BD?= =?UTF-8?q?=D0=B0=D1=87=D0=B0=D0=BB=D0=BE)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- db/UDO_PKG_EQUIPDS.pck | 34 +++ db/UDO_PKG_EQUIPTCF.pck | 224 ++++++++++++++++-- panels/eqs_tech_cond_forecast/forecast_tab.js | 57 ++++- .../forecast_tab_hooks.js | 97 ++++++-- 4 files changed, 373 insertions(+), 39 deletions(-) diff --git a/db/UDO_PKG_EQUIPDS.pck b/db/UDO_PKG_EQUIPDS.pck index e8493ed..6b0568a 100644 --- a/db/UDO_PKG_EQUIPDS.pck +++ b/db/UDO_PKG_EQUIPDS.pck @@ -1,6 +1,40 @@ create or replace package UDO_PKG_EQUIPDS as + + /* Код доступного действия с моделью по единице оборудования */ + function CMML_ACT_BY_EQCONFIG + ( + NEQCONFIG in number -- Рег. номер позиции состава оборудования + ) return number; -- Код действия с моделью (0 - нет доступных, 1 - запросить прогноз, 2 - обучить) + + /* Список моделей по единице оборудования */ + function CMML_LIST_BY_EQCONFIG + ( + NEQCONFIG in number -- Рег. номер позиции состава оборудования + ) return varchar2; -- Список моделей с системным разделителем по умолчанию + end UDO_PKG_EQUIPDS; / create or replace package body UDO_PKG_EQUIPDS as + + /* Код доступного действия с моделью по единице оборудования */ + function CMML_ACT_BY_EQCONFIG + ( + NEQCONFIG in number -- Рег. номер позиции состава оборудования + ) return number -- Код действия с моделью (0 - нет доступных, 1 - запросить прогноз, 2 - обучить) + is + begin + return 2; + end CMML_ACT_BY_EQCONFIG; + + /* Список моделей по единице оборудования */ + function CMML_LIST_BY_EQCONFIG + ( + NEQCONFIG in number -- Рег. номер позиции состава оборудования + ) return varchar2 -- Список моделей с системным разделителем по умолчанию + is + begin + return 'TCF;RUL;FP'; + end CMML_LIST_BY_EQCONFIG; + end UDO_PKG_EQUIPDS; / diff --git a/db/UDO_PKG_EQUIPTCF.pck b/db/UDO_PKG_EQUIPTCF.pck index a097497..44cb0a0 100644 --- a/db/UDO_PKG_EQUIPTCF.pck +++ b/db/UDO_PKG_EQUIPTCF.pck @@ -3,14 +3,23 @@ create or replace package UDO_PKG_EQUIPTCF as /* Формирование дерева состава оборудования */ procedure EQCONFIG_HIER ( - NPEQCONFIG in number, -- Рег. номер родительского узла состава оборудования + NEQPARENT in number, -- Рег. номер родительского узла состава оборудования COUT out clob -- Сериализованное XML-представление дерева ); + /* Условия отбора технических объектов */ + procedure EQCONFIG_THOBJ_LIST_COND; + /* Формирование списка технических объектов для выбранного узла состава оборудования */ - procedure EQCONFIG_THOBJ_DG + procedure EQCONFIG_THOBJ_LIST ( - NPEQCONFIG in number -- Рег. номер родительского узла состава оборудования + NEQPARENT in number, -- Рег. номер родительского узла состава оборудования + NPAGE_NUMBER in number, -- Номер страницы (игнорируется при NPAGE_SIZE=0) + NPAGE_SIZE in number, -- Количество записей на странице (0 - все) + CFILTERS in clob, -- Фильтры + CORDERS in clob, -- Сортировки + NINCLUDE_DEF in number, -- Признак включения описания колонок таблицы в ответ + COUT out clob -- Сериализованная таблица данных ); end UDO_PKG_EQUIPTCF; @@ -22,7 +31,7 @@ create or replace package body UDO_PKG_EQUIPTCF as ( NCUR in integer, -- Курсор документа для результата NCOMPANY in number, -- Рег. номер организации - NPEQCONFIG in number -- Рег. номер родительского узла состава оборудования + NEQPARENT in number -- Рег. номер родительского узла состава оборудования ) return PKG_XMAKE.TNODE -- XML-описание веток дерева is XLEAF PKG_XMAKE.TNODE; -- Текущий лист @@ -48,8 +57,9 @@ create or replace package body UDO_PKG_EQUIPTCF as where M.PR_OBJ_LEVEL = OL.RN(+) and ((M.FICT_REC = 0) or ((M.FICT_REC = 1) and (CMP_VC2(M.NAME, F_EQCONFIG_EXTRANAME(0)) = 1))) and exists (select null from V_USERPRIV_HIER_SINGL UP where UP.HIERARCHY = M.RN) - and COALESCE(M.EQPARENT, 0) = NPEQCONFIG - and M.COMPANY = NCOMPANY) + and COALESCE(M.EQPARENT, 0) = NEQPARENT + and M.COMPANY = NCOMPANY + order by 3) loop /* Если есть дочерние ветки */ if (C.NHASCHILDREN = 1) then @@ -88,7 +98,7 @@ create or replace package body UDO_PKG_EQUIPTCF as /* Формирование дерева состава оборудования */ procedure EQCONFIG_HIER ( - NPEQCONFIG in number, -- Рег. номер родительского узла состава оборудования + NEQPARENT in number, -- Рег. номер родительского узла состава оборудования COUT out clob -- Сериализованное XML-представление дерева ) is @@ -101,7 +111,7 @@ create or replace package body UDO_PKG_EQUIPTCF as /* Формируем XML-представление ветки для запрошенного родителя */ XDOC := PKG_XMAKE.ELEMENT(ICURSOR => NCUR, SNAME => 'XDATA', - RNODE00 => EQCONFIG_HIER_NODE(NCUR => NCUR, NCOMPANY => NCOMPANY, NPEQCONFIG => NPEQCONFIG)); + RNODE00 => EQCONFIG_HIER_NODE(NCUR => NCUR, NCOMPANY => NCOMPANY, NEQPARENT => NEQPARENT)); /* Конвертируем в CLOB */ COUT := PKG_XMAKE.SERIALIZE_TO_CLOB(ICURSOR => NCUR, ITYPE => PKG_XMAKE.CONTENT_, @@ -113,15 +123,199 @@ create or replace package body UDO_PKG_EQUIPTCF as PKG_XMAKE.CLOSE_CURSOR(ICURSOR => NCUR); end EQCONFIG_HIER; - /* Формирование списка технических объектов для выбранного узла состава оборудования */ - procedure EQCONFIG_THOBJ_DG - ( - NPEQCONFIG in number -- Рег. номер родительского узла состава оборудования - ) + /* Условия отбора технических объектов */ + procedure EQCONFIG_THOBJ_LIST_COND is begin - null; - end EQCONFIG_THOBJ_DG; + /* Установка главной таблицы */ + PKG_COND_BROKER.SET_TABLE(STABLE_NAME => 'EQCONFIG'); + /* Обозначение */ + PKG_COND_BROKER.ADD_CONDITION_CODE(SCOLUMN_NAME => 'CODE', SCONDITION_NAME => 'SCODEFrom'); + /* Наименование */ + PKG_COND_BROKER.ADD_CONDITION_CODE(SCOLUMN_NAME => 'NAME', SCONDITION_NAME => 'SNAMEFrom'); + /* Дата ввода в эксплуатацию */ + PKG_COND_BROKER.ADD_CONDITION_BETWEEN(SCOLUMN_NAME => 'OPER_DATE', + SCONDITION_NAME_FROM => 'DOPER_DATEFrom', + SCONDITION_NAME_TO => 'DOPER_DATETo'); + end EQCONFIG_THOBJ_LIST_COND; + + /* Формирование списка технических объектов для выбранного узла состава оборудования */ + procedure EQCONFIG_THOBJ_LIST + ( + NEQPARENT in number, -- Рег. номер родительского узла состава оборудования + NPAGE_NUMBER in number, -- Номер страницы (игнорируется при NPAGE_SIZE=0) + NPAGE_SIZE in number, -- Количество записей на странице (0 - все) + CFILTERS in clob, -- Фильтры + CORDERS in clob, -- Сортировки + NINCLUDE_DEF in number, -- Признак включения описания колонок таблицы в ответ + COUT out clob -- Сериализованная таблица данных + ) + is + NCOMPANY PKG_STD.TREF := GET_SESSION_COMPANY(); -- Организация сеанса + NIDENT PKG_STD.TREF := GEN_IDENT(); -- Идентификатор отбора + RF PKG_P8PANELS_VISUAL.TFILTERS; -- Фильтры + RO PKG_P8PANELS_VISUAL.TORDERS; -- Сортировки + RDG PKG_P8PANELS_VISUAL.TDATA_GRID; -- Описание таблицы + RDG_ROW PKG_P8PANELS_VISUAL.TROW; -- Строка таблицы + NROW_FROM PKG_STD.TREF; -- Номер строки с + NROW_TO PKG_STD.TREF; -- Номер строки по + CSQL clob; -- Буфер для запроса + ICURSOR integer; -- Курсор для исполнения запроса + begin + /* Читаем фильтры */ + RF := PKG_P8PANELS_VISUAL.TFILTERS_FROM_XML(CFILTERS => CFILTERS); + /* Читаем сортировки */ + RO := PKG_P8PANELS_VISUAL.TORDERS_FROM_XML(CORDERS => CORDERS); + /* Преобразуем номер и размер страницы в номер строк с и по */ + PKG_P8PANELS_VISUAL.UTL_ROWS_LIMITS_CALC(NPAGE_NUMBER => NPAGE_NUMBER, + NPAGE_SIZE => NPAGE_SIZE, + NROW_FROM => NROW_FROM, + NROW_TO => NROW_TO); + /* Инициализируем таблицу данных */ + RDG := PKG_P8PANELS_VISUAL.TDATA_GRID_MAKE(); + /* Добавляем в таблицу описание колонок */ + PKG_P8PANELS_VISUAL.TDATA_GRID_ADD_COL_DEF(RDATA_GRID => RDG, + SNAME => 'NRN', + SCAPTION => 'Рег. номер', + SDATA_TYPE => PKG_P8PANELS_VISUAL.SDATA_TYPE_NUMB, + BVISIBLE => false); + PKG_P8PANELS_VISUAL.TDATA_GRID_ADD_COL_DEF(RDATA_GRID => RDG, + SNAME => 'SCODE', + SCAPTION => 'Обозначение', + SDATA_TYPE => PKG_P8PANELS_VISUAL.SDATA_TYPE_STR); + PKG_P8PANELS_VISUAL.TDATA_GRID_ADD_COL_DEF(RDATA_GRID => RDG, + SNAME => 'SNAME', + SCAPTION => 'Наименование', + SDATA_TYPE => PKG_P8PANELS_VISUAL.SDATA_TYPE_STR); + PKG_P8PANELS_VISUAL.TDATA_GRID_ADD_COL_DEF(RDATA_GRID => RDG, + SNAME => 'DOPER_DATE', + SCAPTION => 'Дата ввода в эксплуатацию', + SDATA_TYPE => PKG_P8PANELS_VISUAL.SDATA_TYPE_DATE); + PKG_P8PANELS_VISUAL.TDATA_GRID_ADD_COL_DEF(RDATA_GRID => RDG, + SNAME => 'SUSE_KIND', + SCAPTION => 'Состояние', + SDATA_TYPE => PKG_P8PANELS_VISUAL.SDATA_TYPE_STR); + PKG_P8PANELS_VISUAL.TDATA_GRID_ADD_COL_DEF(RDATA_GRID => RDG, + SNAME => 'NOBJ_KIND', + SCAPTION => 'Рег. номер класса технического объекта', + SDATA_TYPE => PKG_P8PANELS_VISUAL.SDATA_TYPE_NUMB, + BVISIBLE => false); + PKG_P8PANELS_VISUAL.TDATA_GRID_ADD_COL_DEF(RDATA_GRID => RDG, + SNAME => 'SOBJ_KIND', + SCAPTION => 'Класс', + SDATA_TYPE => PKG_P8PANELS_VISUAL.SDATA_TYPE_STR); + PKG_P8PANELS_VISUAL.TDATA_GRID_ADD_COL_DEF(RDATA_GRID => RDG, + SNAME => 'SEQUIPDSCMML', + SCAPTION => 'Модели прогнозирования', + SDATA_TYPE => PKG_P8PANELS_VISUAL.SDATA_TYPE_STR); + PKG_P8PANELS_VISUAL.TDATA_GRID_ADD_COL_DEF(RDATA_GRID => RDG, + SNAME => 'NEQUIPDSCMML_ACTION', + SCAPTION => 'Действия с моделью', + SDATA_TYPE => PKG_P8PANELS_VISUAL.SDATA_TYPE_NUMB, + BVISIBLE => false); + /* Обходим данные */ + begin + /* Добавляем подсказку совместимости */ + CSQL := PKG_SQL_BUILD.COMPATIBLE(SSQL => CSQL); + /* Формируем запрос */ + PKG_SQL_BUILD.APPEND(SSQL => CSQL, SELEMENT1 => 'select *'); + PKG_SQL_BUILD.APPEND(SSQL => CSQL, SELEMENT1 => ' from (select D.*,'); + PKG_SQL_BUILD.APPEND(SSQL => CSQL, SELEMENT1 => PKG_SQL_BUILD.SQLROWNUM() || ' NROW'); + PKG_SQL_BUILD.APPEND(SSQL => CSQL, SELEMENT1 => ' from (select C.RN NRN,'); + PKG_SQL_BUILD.APPEND(SSQL => CSQL, SELEMENT1 => ' C.CODE SCODE,'); + PKG_SQL_BUILD.APPEND(SSQL => CSQL, SELEMENT1 => ' C."NAME" SNAME,'); + PKG_SQL_BUILD.APPEND(SSQL => CSQL, SELEMENT1 => ' C.OPER_DATE DOPER_DATE,'); + PKG_SQL_BUILD.APPEND(SSQL => CSQL, SELEMENT1 => ' ST.CODE SUSE_KIND,'); + PKG_SQL_BUILD.APPEND(SSQL => CSQL, SELEMENT1 => ' C.OBJ_KIND NOBJ_KIND,'); + PKG_SQL_BUILD.APPEND(SSQL => CSQL, SELEMENT1 => ' OK.CODE SOBJ_KIND,'); + PKG_SQL_BUILD.APPEND(SSQL => CSQL, SELEMENT1 => PKG_SQL_BUILD.PKG_NAME(SNAME => 'UDO_PKG_EQUIPDS.CMML_LIST_BY_EQCONFIG') || '(C.RN) SEQUIPDSCMML,'); + PKG_SQL_BUILD.APPEND(SSQL => CSQL, SELEMENT1 => PKG_SQL_BUILD.PKG_NAME(SNAME => 'UDO_PKG_EQUIPDS.CMML_ACT_BY_EQCONFIG') || '(C.RN) NEQUIPDSCMML_ACTION'); + PKG_SQL_BUILD.APPEND(SSQL => CSQL, SELEMENT1 => ' from EQCONFIG C'); + PKG_SQL_BUILD.APPEND(SSQL => CSQL, SELEMENT1 => ' left outer join EQOBJKIND OK on C.OBJ_KIND = OK.RN'); + PKG_SQL_BUILD.APPEND(SSQL => CSQL, SELEMENT1 => ' left outer join HLSTATETYPES ST on C.HLSTATETYPES = ST.RN'); + PKG_SQL_BUILD.APPEND(SSQL => CSQL, SELEMENT1 => ' where C.EQPARENT = :NEQPARENT'); + PKG_SQL_BUILD.APPEND(SSQL => CSQL, SELEMENT1 => ' and C.RN in (select ID from COND_BROKER_IDSMART where IDENT = :NIDENT) %ORDER_BY%) D) F'); + PKG_SQL_BUILD.APPEND(SSQL => CSQL, SELEMENT1 => ' where F.NROW between :NROW_FROM and :NROW_TO'); + /* Учтём сортировки */ + PKG_P8PANELS_VISUAL.TORDERS_SET_QUERY(RDATA_GRID => RDG, RORDERS => RO, SPATTERN => '%ORDER_BY%', CSQL => CSQL); + /* Учтём фильтры */ + PKG_P8PANELS_VISUAL.TFILTERS_SET_QUERY(NIDENT => NIDENT, + NCOMPANY => NCOMPANY, + SUNIT => 'EquipConfiguration', + SPROCEDURE => PKG_SQL_BUILD.PKG_NAME(SNAME => 'UDO_PKG_EQUIPTCF.EQCONFIG_THOBJ_LIST_COND'), + RDATA_GRID => RDG, + RFILTERS => RF); + /* Разбираем его */ + ICURSOR := PKG_SQL_DML.OPEN_CURSOR(SWHAT => 'SELECT'); + PKG_SQL_DML.PARSE(ICURSOR => ICURSOR, SQUERY => CSQL); + /* Делаем подстановку параметров */ + PKG_SQL_DML.BIND_VARIABLE_NUM(ICURSOR => ICURSOR, SNAME => 'NEQPARENT', NVALUE => NEQPARENT); + PKG_SQL_DML.BIND_VARIABLE_NUM(ICURSOR => ICURSOR, SNAME => 'NIDENT', NVALUE => NIDENT); + PKG_SQL_DML.BIND_VARIABLE_NUM(ICURSOR => ICURSOR, SNAME => 'NROW_FROM', NVALUE => NROW_FROM); + PKG_SQL_DML.BIND_VARIABLE_NUM(ICURSOR => ICURSOR, SNAME => 'NROW_TO', NVALUE => NROW_TO); + /* Описываем структуру записи курсора */ + PKG_SQL_DML.DEFINE_COLUMN_NUM(ICURSOR => ICURSOR, IPOSITION => 1); + PKG_SQL_DML.DEFINE_COLUMN_STR(ICURSOR => ICURSOR, IPOSITION => 2); + PKG_SQL_DML.DEFINE_COLUMN_STR(ICURSOR => ICURSOR, IPOSITION => 3); + PKG_SQL_DML.DEFINE_COLUMN_DATE(ICURSOR => ICURSOR, IPOSITION => 4); + PKG_SQL_DML.DEFINE_COLUMN_STR(ICURSOR => ICURSOR, IPOSITION => 5); + PKG_SQL_DML.DEFINE_COLUMN_NUM(ICURSOR => ICURSOR, IPOSITION => 6); + PKG_SQL_DML.DEFINE_COLUMN_STR(ICURSOR => ICURSOR, IPOSITION => 7); + PKG_SQL_DML.DEFINE_COLUMN_STR(ICURSOR => ICURSOR, IPOSITION => 8); + PKG_SQL_DML.DEFINE_COLUMN_NUM(ICURSOR => ICURSOR, IPOSITION => 9); + PKG_SQL_DML.DEFINE_COLUMN_NUM(ICURSOR => ICURSOR, IPOSITION => 10); + /* Делаем выборку */ + if (PKG_SQL_DML.EXECUTE(ICURSOR => ICURSOR) = 0) then + null; + end if; + /* Обходим выбранные записи */ + while (PKG_SQL_DML.FETCH_ROWS(ICURSOR => ICURSOR) > 0) + loop + /* Добавляем колонки с данными */ + PKG_P8PANELS_VISUAL.TROW_ADD_CUR_COLN(RROW => RDG_ROW, + SNAME => 'NRN', + ICURSOR => ICURSOR, + NPOSITION => 1, + BCLEAR => true); + PKG_P8PANELS_VISUAL.TROW_ADD_CUR_COLS(RROW => RDG_ROW, SNAME => 'SCODE', ICURSOR => ICURSOR, NPOSITION => 2); + PKG_P8PANELS_VISUAL.TROW_ADD_CUR_COLS(RROW => RDG_ROW, SNAME => 'SNAME', ICURSOR => ICURSOR, NPOSITION => 3); + PKG_P8PANELS_VISUAL.TROW_ADD_CUR_COLD(RROW => RDG_ROW, + SNAME => 'DOPER_DATE', + ICURSOR => ICURSOR, + NPOSITION => 4); + PKG_P8PANELS_VISUAL.TROW_ADD_CUR_COLS(RROW => RDG_ROW, + SNAME => 'SUSE_KIND', + ICURSOR => ICURSOR, + NPOSITION => 5); + PKG_P8PANELS_VISUAL.TROW_ADD_CUR_COLN(RROW => RDG_ROW, + SNAME => 'NOBJ_KIND', + ICURSOR => ICURSOR, + NPOSITION => 6); + PKG_P8PANELS_VISUAL.TROW_ADD_CUR_COLS(RROW => RDG_ROW, + SNAME => 'SOBJ_KIND', + ICURSOR => ICURSOR, + NPOSITION => 7); + PKG_P8PANELS_VISUAL.TROW_ADD_CUR_COLS(RROW => RDG_ROW, + SNAME => 'SEQUIPDSCMML', + ICURSOR => ICURSOR, + NPOSITION => 8); + PKG_P8PANELS_VISUAL.TROW_ADD_CUR_COLN(RROW => RDG_ROW, + SNAME => 'NEQUIPDSCMML_ACTION', + ICURSOR => ICURSOR, + NPOSITION => 9); + /* Добавляем строку в таблицу */ + PKG_P8PANELS_VISUAL.TDATA_GRID_ADD_ROW(RDATA_GRID => RDG, RROW => RDG_ROW); + end loop; + /* Освобождаем курсор */ + PKG_SQL_DML.CLOSE_CURSOR(ICURSOR => ICURSOR); + exception + when others then + PKG_SQL_DML.CLOSE_CURSOR(ICURSOR => ICURSOR); + raise; + end; + /* Сериализуем описание */ + COUT := PKG_P8PANELS_VISUAL.TDATA_GRID_TO_XML(RDATA_GRID => RDG, NINCLUDE_DEF => NINCLUDE_DEF); + end EQCONFIG_THOBJ_LIST; end UDO_PKG_EQUIPTCF; / diff --git a/panels/eqs_tech_cond_forecast/forecast_tab.js b/panels/eqs_tech_cond_forecast/forecast_tab.js index 3d69309..43c0f57 100644 --- a/panels/eqs_tech_cond_forecast/forecast_tab.js +++ b/panels/eqs_tech_cond_forecast/forecast_tab.js @@ -10,7 +10,9 @@ import React, { useState } from "react"; //Классы React import { Box, Grid } from "@mui/material"; //Интерфейсные компоненты import { RichTreeView } from "@mui/x-tree-view/RichTreeView"; //Дерево -import { useEqConfigTree, needLoadLevel } from "./forecast_tab_hooks"; //Вспомогательные хуки +import { P8PDataGrid, P8P_DATA_GRID_SIZE } from "../../components/p8p_data_grid"; //Таблица данных +import { P8P_DATA_GRID_CONFIG_PROPS } from "../../config_wrapper"; //Подключение компонентов к настройкам приложения +import { useEqConfigTree, useEqConfigTechObjTable, needLoadLevel } from "./forecast_tab_hooks"; //Вспомогательные хуки //--------- //Константы @@ -22,6 +24,9 @@ const APP_BAR_HEIGHT = "64px"; //Высота закладок const TABS_HEIGHT = "49px"; +//Высота кнопки "Ещё" +const TABLE_MORE_HEIGHT = "47px"; + //Стили const STYLES = { LEFT_SIDE_GRID: { backgroundColor: "red" }, @@ -34,9 +39,13 @@ const STYLES = { overflowY: "auto", scrollbarWidth: "thin", scrollbarColor: "red blue" - } + }, + TECH_OBJ_TABLE: { height: `calc(100vh - ${APP_BAR_HEIGHT} - ${TABS_HEIGHT} - ${TABLE_MORE_HEIGHT})` } }; +//Начальное состояние спецификации техничких объектов +const TECH_OBJ_SPEC_INIT = { parent: null, filters: null, orders: null, pageNumber: 1 }; + //----------- //Тело модуля //----------- @@ -46,15 +55,35 @@ const ForecastTab = () => { //Собственное состояние - текущая загружаемая ветка const [loadingTreeItem, setLoadingTreeItem] = useState(0); + //Собственное состояние - спецификация технических объектов + const [techObjSpec, setTechObjSpec] = useState({ ...TECH_OBJ_SPEC_INIT }); + //Загрузчик веток дерева const { tree } = useEqConfigTree(loadingTreeItem); + //Загрузчик технических объектов для выбранной ветки + const { techObjsDataGrid, techObjsDataGridIsLoading } = useEqConfigTechObjTable( + techObjSpec.parent, + techObjSpec.filters, + techObjSpec.orders, + techObjSpec.pageNumber + ); + //Обработка развёртывания/свёртывания уровня дерева const handleTreeItemExpansionToggle = (event, itemId, isExpanded) => isExpanded && needLoadLevel(tree, itemId) ? setLoadingTreeItem(parseInt(itemId)) : null; //Обработка фокусировки на элементе дерева - const handleTreeItemFocus = (event, itemId, isExpanded) => console.log(event, itemId, isExpanded); + const handleTreeItemFocus = (event, itemId) => setTechObjSpec({ ...TECH_OBJ_SPEC_INIT, parent: parseInt(itemId) }); + + //При изменении состояния фильтров спецификации технических объектов + const handleTechObjSpecFilterChanged = ({ filters }) => setTechObjSpec(pv => ({ ...pv, filters: [...filters], pageNumber: 1 })); + + //При изменении состояния сортировки спецификации технических объектов + const handleTechObjSpecOrderChanged = ({ orders }) => setTechObjSpec(pv => ({ ...pv, orders: [...orders], pageNumber: 1 })); + + //При изменении количества отображаемых страниц спецификации технических объектов + const handleTechObjSpecPagesCountChanged = () => setTechObjSpec(pv => ({ ...pv, pageNumber: pv.pageNumber + 1 })); //Генерация содержимого return ( @@ -66,7 +95,27 @@ const ForecastTab = () => { - ОБОРУДОВАНИЕ + {techObjsDataGrid.init ? ( + + ) : null} diff --git a/panels/eqs_tech_cond_forecast/forecast_tab_hooks.js b/panels/eqs_tech_cond_forecast/forecast_tab_hooks.js index f5f01bf..fabee55 100644 --- a/panels/eqs_tech_cond_forecast/forecast_tab_hooks.js +++ b/panels/eqs_tech_cond_forecast/forecast_tab_hooks.js @@ -9,35 +9,40 @@ import { useState, useEffect, useContext } from "react"; //Классы React import { BackEndСtx } from "../../context/backend"; //Контекст взаимодействия с сервером -import { deepCopyObject } from "../../core/utils"; //Утилиты +import { deepCopyObject, object2Base64XML } from "../../core/utils"; //Вспомогательные функции + +//--------- +//Константы +//--------- + +//Размер страницы данных +const DATA_GRID_PAGE_SIZE = 5; //----------------------- //Вспомогательные функции //----------------------- +//Поиск элемента в дереве +const findTreeItem = (tree, id) => { + for (let i = 0; i < tree.length; i++) { + if (tree[i].id == id) return tree[i]; + if (Array.isArray(tree[i].children)) { + let childRes = findTreeItem(tree[i].children, id); + if (childRes) return childRes; + } + } +}; + //Проверка необходимости загрузки уровня для указанного родителя const needLoadLevel = (tree, parent) => { - let res = false; - tree.forEach(treeItem => { - if (treeItem.id == parent) { - if (treeItem.children && treeItem.children.length == 1 && treeItem.children[0].id.endsWith("loader")) res = true; - } - if (treeItem.children && treeItem.children.length > 0 && !treeItem.children[0].id.endsWith("loader")) - res = needLoadLevel(treeItem.children, parent); - }); - return res; + let item = findTreeItem(tree, parent); + return !item ? false : item.children && item.children.length == 1 && item.children[0].id.endsWith("loader") ? true : false; }; //Встраивание уровня в указанного родителя const appendLevel = (tree, parent, children) => { - tree.forEach(treeItem => { - if (treeItem.id == parent) { - treeItem.children = children; - return; - } - if (treeItem.children && treeItem.children.length > 0 && !treeItem.children[0].id.endsWith("loader")) - appendLevel(treeItem.children, parent, children); - }); + let item = findTreeItem(tree, parent); + if (item) item.children = children; }; //----------- @@ -63,7 +68,7 @@ const useEqConfigTree = parent => { const data = await executeStored({ stored: "UDO_PKG_EQUIPTCF.EQCONFIG_HIER", args: { - NPEQCONFIG: parent + NEQPARENT: parent }, respArg: "COUT", isArray: name => ["children"].includes(name), @@ -89,8 +94,60 @@ const useEqConfigTree = parent => { return { tree, isLoading }; }; +//Загрузка списка технических объектов +const useEqConfigTechObjTable = (parent, filters, orders, pageNumber) => { + //Собственное состояние - флаг загрузки + const [isLoading, setLoading] = useState(false); + + //Собственное состояние - таблица данных + const [data, setData] = useState({ + init: false, + columnsDef: [], + rows: [], + morePages: true + }); + + //Подключение к контексту взаимодействия с сервером + const { executeStored, SERV_DATA_TYPE_CLOB } = useContext(BackEndСtx); + + //Загрузка данных при изменении зависимостей + useEffect(() => { + const loadData = async () => { + try { + setLoading(true); + const data = await executeStored({ + stored: "UDO_PKG_EQUIPTCF.EQCONFIG_THOBJ_LIST", + args: { + NEQPARENT: parent, + CFILTERS: { VALUE: object2Base64XML(filters, { arrayNodeName: "filters" }), SDATA_TYPE: SERV_DATA_TYPE_CLOB }, + CORDERS: { VALUE: object2Base64XML(orders, { arrayNodeName: "orders" }), SDATA_TYPE: SERV_DATA_TYPE_CLOB }, + NPAGE_NUMBER: pageNumber, + NPAGE_SIZE: DATA_GRID_PAGE_SIZE, + NINCLUDE_DEF: pageNumber == 1 ? 1 : 0 + }, + respArg: "COUT", + loader: false + }); + setData(pv => ({ + ...pv, + columnsDef: data.XCOLUMNS_DEF ? [...data.XCOLUMNS_DEF] : pv.columnsDef, + rows: pageNumber == 1 ? [...(data.XROWS || [])] : [...pv.rows, ...(data.XROWS || [])], + morePages: DATA_GRID_PAGE_SIZE == 0 ? false : (data.XROWS || []).length >= DATA_GRID_PAGE_SIZE, + init: true + })); + } finally { + setLoading(false); + } + }; + if (parent) loadData(); + }, [parent, filters, orders, pageNumber, executeStored, SERV_DATA_TYPE_CLOB]); + + //Вернём данные + return { techObjsDataGrid: data, techObjsDataGridIsLoading: isLoading }; +}; + //---------------- //Интерфейс модуля //---------------- -export { useEqConfigTree, needLoadLevel }; +export { useEqConfigTree, useEqConfigTechObjTable, needLoadLevel };