diff --git a/db/UDO_PKG_EQUIPTCF.pck b/db/UDO_PKG_EQUIPTCF.pck index 44cb0a0..bb6c437 100644 --- a/db/UDO_PKG_EQUIPTCF.pck +++ b/db/UDO_PKG_EQUIPTCF.pck @@ -21,11 +21,23 @@ create or replace package UDO_PKG_EQUIPTCF as NINCLUDE_DEF in number, -- Признак включения описания колонок таблицы в ответ COUT out clob -- Сериализованная таблица данных ); + + /* Формирование карточки технического объекта */ + procedure EQCONFIG_THOBJ_CARD + ( + NEQCONFIG in number, -- Рег. номер технического объекта + COUT out clob -- Сериализованная карточка + ); end UDO_PKG_EQUIPTCF; / create or replace package body UDO_PKG_EQUIPTCF as +/* +TODO: owner="root" created="02.08.2024" +text="Проверка прав доступа при формировании таблицы и карточки ТО" +*/ + /* Формирование ветки дерева состава оборудования */ function EQCONFIG_HIER_NODE ( @@ -51,7 +63,9 @@ create or replace package body UDO_PKG_EQUIPTCF as 1 else 0 - end NHASCHILDREN + end NHASCHILDREN, + M.OBJ_KIND NOBJ_KIND, + 0 NSHOW_CARD from EQCONFIG M, EQOBJLEVEL OL where M.PR_OBJ_LEVEL = OL.RN(+) @@ -77,6 +91,10 @@ create or replace package body UDO_PKG_EQUIPTCF as else XCHILD := null; end if; + /* Для технического объекта, не имеющего дочерних - соберём признак отображения карточки */ + if ((C.NHASCHILDREN = 0) and (C.NOBJ_KIND is not null)) then + C.NSHOW_CARD := 1; + end if; /* Соберём лист */ XLEAF := PKG_XMAKE.ELEMENT(ICURSOR => NCUR, SNAME => 'children', @@ -86,7 +104,10 @@ create or replace package body UDO_PKG_EQUIPTCF as SVALUE => C.NRN), RATTRIBUTE01 => PKG_XMAKE.ATTRIBUTE(ICURSOR => NCUR, SNAME => 'label', - SVALUE => C.SNAME)), + SVALUE => C.SNAME), + RATTRIBUTE02 => PKG_XMAKE.ATTRIBUTE(ICURSOR => NCUR, + SNAME => 'showCard', + NVALUE => C.NSHOW_CARD)), RNODE00 => XCHILD); /* Соберём листы в ветку */ XRES := PKG_XMAKE.CONCAT(ICURSOR => NCUR, RNODE00 => XRES, RNODE01 => XLEAF); @@ -231,9 +252,10 @@ create or replace package body UDO_PKG_EQUIPTCF as 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 => ' left outer join HLSTATETYPES ST on C.HLSTATETYPES = ST.RN,'); + PKG_SQL_BUILD.APPEND(SSQL => CSQL, SELEMENT1 => ' EQOBJKIND OK'); PKG_SQL_BUILD.APPEND(SSQL => CSQL, SELEMENT1 => ' where C.EQPARENT = :NEQPARENT'); + PKG_SQL_BUILD.APPEND(SSQL => CSQL, SELEMENT1 => ' and C.OBJ_KIND = OK.RN'); 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'); /* Учтём сортировки */ @@ -316,6 +338,57 @@ create or replace package body UDO_PKG_EQUIPTCF as /* Сериализуем описание */ COUT := PKG_P8PANELS_VISUAL.TDATA_GRID_TO_XML(RDATA_GRID => RDG, NINCLUDE_DEF => NINCLUDE_DEF); end EQCONFIG_THOBJ_LIST; + + /* Формирование карточки технического объекта */ + procedure EQCONFIG_THOBJ_CARD + ( + NEQCONFIG in number, -- Рег. номер технического объекта + COUT out clob -- Сериализованная карточка + ) + is + NCUR integer; -- Курсор документа для результата + XDOC PKG_XMAKE.TNODE; -- Документ для результата + XCARD PKG_XMAKE.TNODE; -- XML-карточка + begin + /* Открываем документ */ + NCUR := PKG_XMAKE.OPEN_CURSOR(); + /* Обратимся к данным технического объекта */ + for C in (select T.RN NRN, + T.CODE SCODE, + T.NAME SNAME, + T.OPER_DATE DOPER_DATE + from EQCONFIG T + where T.RN = NEQCONFIG) + loop + /* Соберем карточку */ + XCARD := PKG_XMAKE.ELEMENT(ICURSOR => NCUR, + SNAME => 'techObj', + RATTRIBUTES => PKG_XMAKE.ATTRIBUTES(ICURSOR => NCUR, + RATTRIBUTE00 => PKG_XMAKE.ATTRIBUTE(ICURSOR => NCUR, + SNAME => 'NRN', + NVALUE => C.NRN), + RATTRIBUTE01 => PKG_XMAKE.ATTRIBUTE(ICURSOR => NCUR, + SNAME => 'SCODE', + SVALUE => C.SCODE), + RATTRIBUTE02 => PKG_XMAKE.ATTRIBUTE(ICURSOR => NCUR, + SNAME => 'SNAME', + SVALUE => C.SNAME), + RATTRIBUTE03 => PKG_XMAKE.ATTRIBUTE(ICURSOR => NCUR, + SNAME => 'DOPER_DATE', + DVALUE => C.DOPER_DATE))); + end loop; + /* Формируем XML-представление документа ответа */ + XDOC := PKG_XMAKE.ELEMENT(ICURSOR => NCUR, SNAME => 'XDATA', RNODE00 => XCARD); + /* Сериализуем документ */ + COUT := PKG_XMAKE.SERIALIZE_TO_CLOB(ICURSOR => NCUR, + ITYPE => PKG_XMAKE.CONTENT_, + RNODE => XDOC, + RHEADER => PKG_XHEADER.WRAP_ALL(SVERSION => PKG_XHEADER.VERSION_1_0_, + SENCODING => PKG_XHEADER.ENCODING_UTF_, + SSTANDALONE => PKG_XHEADER.STANDALONE_YES_)); + /* Закрываем документ */ + PKG_XMAKE.CLOSE_CURSOR(ICURSOR => NCUR); + end EQCONFIG_THOBJ_CARD; 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 43c0f57..ac92e4c 100644 --- a/panels/eqs_tech_cond_forecast/forecast_tab.js +++ b/panels/eqs_tech_cond_forecast/forecast_tab.js @@ -12,7 +12,8 @@ import { Box, Grid } from "@mui/material"; //Интерфейсные компо import { RichTreeView } from "@mui/x-tree-view/RichTreeView"; //Дерево 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"; //Вспомогательные хуки +import { useEqConfigTree, useEqConfigTechObjTable, useEqConfigTechObjCard, findTreeItem, needLoadLevel } from "./forecast_tab_hooks"; //Вспомогательные хуки +import { TechObjCard } from "./forecast_tab_layout"; //Вспомогательные компоненты и вёрстка //--------- //Константы @@ -25,22 +26,20 @@ const APP_BAR_HEIGHT = "64px"; const TABS_HEIGHT = "49px"; //Высота кнопки "Ещё" -const TABLE_MORE_HEIGHT = "47px"; +const TABLE_MORE_HEIGHT = "49px"; //Стили const STYLES = { - LEFT_SIDE_GRID: { backgroundColor: "red" }, - RIGHT_SIDE_GRID: { backgroundColor: "green" }, + LEFT_SIDE_GRID: {}, + RIGHT_SIDE_GRID: {}, TREE_BOX: { minHeight: `calc(100vh - ${APP_BAR_HEIGHT} - ${TABS_HEIGHT})`, maxHeight: `calc(100vh - ${APP_BAR_HEIGHT} - ${TABS_HEIGHT})`, - backgroundColor: "yellow", overflowX: "hidden", - overflowY: "auto", - scrollbarWidth: "thin", - scrollbarColor: "red blue" + overflowY: "scroll", + scrollbarWidth: "thin" }, - TECH_OBJ_TABLE: { height: `calc(100vh - ${APP_BAR_HEIGHT} - ${TABS_HEIGHT} - ${TABLE_MORE_HEIGHT})` } + TECH_OBJ_TABLE: morePages => ({ height: `calc(100vh - ${APP_BAR_HEIGHT} - ${TABS_HEIGHT} - ${morePages ? TABLE_MORE_HEIGHT : "0px"})` }) }; //Начальное состояние спецификации техничких объектов @@ -58,6 +57,9 @@ const ForecastTab = () => { //Собственное состояние - спецификация технических объектов const [techObjSpec, setTechObjSpec] = useState({ ...TECH_OBJ_SPEC_INIT }); + //Собственное состояния - карточка технического объекта + const [techObjCardId, setTechObjCardId] = useState(null); + //Загрузчик веток дерева const { tree } = useEqConfigTree(loadingTreeItem); @@ -69,12 +71,22 @@ const ForecastTab = () => { techObjSpec.pageNumber ); + //Загрузчик карточки выбоанного технического объекта + const { techObjCard, techObjCardIsLoading } = useEqConfigTechObjCard(techObjCardId); + //Обработка развёртывания/свёртывания уровня дерева const handleTreeItemExpansionToggle = (event, itemId, isExpanded) => isExpanded && needLoadLevel(tree, itemId) ? setLoadingTreeItem(parseInt(itemId)) : null; //Обработка фокусировки на элементе дерева - const handleTreeItemFocus = (event, itemId) => setTechObjSpec({ ...TECH_OBJ_SPEC_INIT, parent: parseInt(itemId) }); + const handleTreeItemFocus = (event, itemId) => { + const item = findTreeItem(tree, itemId); + if (item && item?.showCard) setTechObjCardId(parseInt(itemId)); + else { + setTechObjCardId(null); + setTechObjSpec({ ...TECH_OBJ_SPEC_INIT, parent: parseInt(itemId) }); + } + }; //При изменении состояния фильтров спецификации технических объектов const handleTechObjSpecFilterChanged = ({ filters }) => setTechObjSpec(pv => ({ ...pv, filters: [...filters], pageNumber: 1 })); @@ -95,7 +107,11 @@ const ForecastTab = () => { - {techObjsDataGrid.init ? ( + {techObjCardId ? ( + !techObjCardIsLoading ? ( + + ) : null + ) : techObjsDataGrid.init ? ( { ? "Минуточку..." : "Выбранный уровень структуры не содержит данных о технических объектах" }} - containerComponentProps={{ sx: STYLES.TECH_OBJ_TABLE, elevation: 0 }} + containerComponentProps={{ sx: STYLES.TECH_OBJ_TABLE(techObjsDataGrid.morePages), elevation: 0 }} columnsDef={techObjsDataGrid.columnsDef} rows={techObjsDataGrid.rows} size={P8P_DATA_GRID_SIZE.SMALL} diff --git a/panels/eqs_tech_cond_forecast/forecast_tab_hooks.js b/panels/eqs_tech_cond_forecast/forecast_tab_hooks.js index fabee55..632f52b 100644 --- a/panels/eqs_tech_cond_forecast/forecast_tab_hooks.js +++ b/panels/eqs_tech_cond_forecast/forecast_tab_hooks.js @@ -146,8 +146,44 @@ const useEqConfigTechObjTable = (parent, filters, orders, pageNumber) => { return { techObjsDataGrid: data, techObjsDataGridIsLoading: isLoading }; }; +//Загрузка карточки технического объекта +const useEqConfigTechObjCard = id => { + //Собственное состояние - флаг загрузки + const [isLoading, setLoading] = useState(false); + + //Собственное состояние - данные дерева + const [card, setCard] = useState({}); + + //Подключение к контексту взаимодействия с сервером + const { executeStored } = useContext(BackEndСtx); + + //Загрузка данных при изменении зависимостей + useEffect(() => { + const loadData = async () => { + try { + setLoading(true); + const data = await executeStored({ + stored: "UDO_PKG_EQUIPTCF.EQCONFIG_THOBJ_CARD", + args: { + NEQCONFIG: id + }, + respArg: "COUT", + loader: false + }); + setCard(data.techObj ? data.techObj : {}); + } finally { + setLoading(false); + } + }; + if (id) loadData(); + }, [id, executeStored]); + + //Вернём данные + return { techObjCard: card, techObjCardIsLoading: isLoading }; +}; + //---------------- //Интерфейс модуля //---------------- -export { useEqConfigTree, useEqConfigTechObjTable, needLoadLevel }; +export { useEqConfigTree, useEqConfigTechObjTable, useEqConfigTechObjCard, findTreeItem, needLoadLevel }; diff --git a/panels/eqs_tech_cond_forecast/forecast_tab_layout.js b/panels/eqs_tech_cond_forecast/forecast_tab_layout.js new file mode 100644 index 0000000..95014d0 --- /dev/null +++ b/panels/eqs_tech_cond_forecast/forecast_tab_layout.js @@ -0,0 +1,48 @@ +/* + Парус 8 - Панели мониторинга - ТОиР - Прогнозирование технического состояния + Дополнительная разметка и вёрстка клиентских элементов +*/ + +//--------------------- +//Подключение библиотек +//--------------------- + +import React from "react"; //Классы React +import { Box, Card, CardContent, Typography, CardActions, Button } from "@mui/material"; //Интерфейсные компоненты + +//----------- +//Тело модуля +//----------- + +const TechObjCard = ({ cardData }) => { + //Генерация содержимого + return ( + + + + + Технологический объект + + + {cardData.SCODE} + + + {cardData.DOPER_DATE} + + {cardData.SNAME} + + + + + + + + + ); +}; + +//---------------- +//Интерфейс модуля +//---------------- + +export { TechObjCard };