Закладка "Прогнозирование" - карточка технического объекта

This commit is contained in:
Mikhail Chechnev 2024-08-02 19:42:30 +03:00
parent 57d7dd2e68
commit a9ffc6cc09
4 changed files with 190 additions and 17 deletions

View File

@ -21,11 +21,23 @@ create or replace package UDO_PKG_EQUIPTCF as
NINCLUDE_DEF in number, -- Признак включения описания колонок таблицы в ответ NINCLUDE_DEF in number, -- Признак включения описания колонок таблицы в ответ
COUT out clob -- Сериализованная таблица данных COUT out clob -- Сериализованная таблица данных
); );
/* Формирование карточки технического объекта */
procedure EQCONFIG_THOBJ_CARD
(
NEQCONFIG in number, -- Рег. номер технического объекта
COUT out clob -- Сериализованная карточка
);
end UDO_PKG_EQUIPTCF; end UDO_PKG_EQUIPTCF;
/ /
create or replace package body UDO_PKG_EQUIPTCF as create or replace package body UDO_PKG_EQUIPTCF as
/*
TODO: owner="root" created="02.08.2024"
text="Проверка прав доступа при формировании таблицы и карточки ТО"
*/
/* Формирование ветки дерева состава оборудования */ /* Формирование ветки дерева состава оборудования */
function EQCONFIG_HIER_NODE function EQCONFIG_HIER_NODE
( (
@ -51,7 +63,9 @@ create or replace package body UDO_PKG_EQUIPTCF as
1 1
else else
0 0
end NHASCHILDREN end NHASCHILDREN,
M.OBJ_KIND NOBJ_KIND,
0 NSHOW_CARD
from EQCONFIG M, from EQCONFIG M,
EQOBJLEVEL OL EQOBJLEVEL OL
where M.PR_OBJ_LEVEL = OL.RN(+) where M.PR_OBJ_LEVEL = OL.RN(+)
@ -77,6 +91,10 @@ create or replace package body UDO_PKG_EQUIPTCF as
else else
XCHILD := null; XCHILD := null;
end if; 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, XLEAF := PKG_XMAKE.ELEMENT(ICURSOR => NCUR,
SNAME => 'children', SNAME => 'children',
@ -86,7 +104,10 @@ create or replace package body UDO_PKG_EQUIPTCF as
SVALUE => C.NRN), SVALUE => C.NRN),
RATTRIBUTE01 => PKG_XMAKE.ATTRIBUTE(ICURSOR => NCUR, RATTRIBUTE01 => PKG_XMAKE.ATTRIBUTE(ICURSOR => NCUR,
SNAME => 'label', SNAME => 'label',
SVALUE => C.SNAME)), SVALUE => C.SNAME),
RATTRIBUTE02 => PKG_XMAKE.ATTRIBUTE(ICURSOR => NCUR,
SNAME => 'showCard',
NVALUE => C.NSHOW_CARD)),
RNODE00 => XCHILD); RNODE00 => XCHILD);
/* Соберём листы в ветку */ /* Соберём листы в ветку */
XRES := PKG_XMAKE.CONCAT(ICURSOR => NCUR, RNODE00 => XRES, RNODE01 => XLEAF); 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_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 => 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 => ' 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 => ' 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 => ' 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_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); COUT := PKG_P8PANELS_VISUAL.TDATA_GRID_TO_XML(RDATA_GRID => RDG, NINCLUDE_DEF => NINCLUDE_DEF);
end EQCONFIG_THOBJ_LIST; 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; end UDO_PKG_EQUIPTCF;
/ /

View File

@ -12,7 +12,8 @@ import { Box, Grid } from "@mui/material"; //Интерфейсные компо
import { RichTreeView } from "@mui/x-tree-view/RichTreeView"; //Дерево import { RichTreeView } from "@mui/x-tree-view/RichTreeView"; //Дерево
import { P8PDataGrid, P8P_DATA_GRID_SIZE } from "../../components/p8p_data_grid"; //Таблица данных import { P8PDataGrid, P8P_DATA_GRID_SIZE } from "../../components/p8p_data_grid"; //Таблица данных
import { P8P_DATA_GRID_CONFIG_PROPS } from "../../config_wrapper"; //Подключение компонентов к настройкам приложения 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 TABS_HEIGHT = "49px";
//Высота кнопки "Ещё" //Высота кнопки "Ещё"
const TABLE_MORE_HEIGHT = "47px"; const TABLE_MORE_HEIGHT = "49px";
//Стили //Стили
const STYLES = { const STYLES = {
LEFT_SIDE_GRID: { backgroundColor: "red" }, LEFT_SIDE_GRID: {},
RIGHT_SIDE_GRID: { backgroundColor: "green" }, RIGHT_SIDE_GRID: {},
TREE_BOX: { TREE_BOX: {
minHeight: `calc(100vh - ${APP_BAR_HEIGHT} - ${TABS_HEIGHT})`, minHeight: `calc(100vh - ${APP_BAR_HEIGHT} - ${TABS_HEIGHT})`,
maxHeight: `calc(100vh - ${APP_BAR_HEIGHT} - ${TABS_HEIGHT})`, maxHeight: `calc(100vh - ${APP_BAR_HEIGHT} - ${TABS_HEIGHT})`,
backgroundColor: "yellow",
overflowX: "hidden", overflowX: "hidden",
overflowY: "auto", overflowY: "scroll",
scrollbarWidth: "thin", scrollbarWidth: "thin"
scrollbarColor: "red blue"
}, },
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 [techObjSpec, setTechObjSpec] = useState({ ...TECH_OBJ_SPEC_INIT });
//Собственное состояния - карточка технического объекта
const [techObjCardId, setTechObjCardId] = useState(null);
//Загрузчик веток дерева //Загрузчик веток дерева
const { tree } = useEqConfigTree(loadingTreeItem); const { tree } = useEqConfigTree(loadingTreeItem);
@ -69,12 +71,22 @@ const ForecastTab = () => {
techObjSpec.pageNumber techObjSpec.pageNumber
); );
//Загрузчик карточки выбоанного технического объекта
const { techObjCard, techObjCardIsLoading } = useEqConfigTechObjCard(techObjCardId);
//Обработка развёртывания/свёртывания уровня дерева //Обработка развёртывания/свёртывания уровня дерева
const handleTreeItemExpansionToggle = (event, itemId, isExpanded) => const handleTreeItemExpansionToggle = (event, itemId, isExpanded) =>
isExpanded && needLoadLevel(tree, itemId) ? setLoadingTreeItem(parseInt(itemId)) : null; 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 })); const handleTechObjSpecFilterChanged = ({ filters }) => setTechObjSpec(pv => ({ ...pv, filters: [...filters], pageNumber: 1 }));
@ -95,7 +107,11 @@ const ForecastTab = () => {
</Box> </Box>
</Grid> </Grid>
<Grid item xs={8} sx={STYLES.RIGHT_SIDE_GRID}> <Grid item xs={8} sx={STYLES.RIGHT_SIDE_GRID}>
{techObjsDataGrid.init ? ( {techObjCardId ? (
!techObjCardIsLoading ? (
<TechObjCard cardData={techObjCard} />
) : null
) : techObjsDataGrid.init ? (
<P8PDataGrid <P8PDataGrid
{...{ {...{
...P8P_DATA_GRID_CONFIG_PROPS, ...P8P_DATA_GRID_CONFIG_PROPS,
@ -104,7 +120,7 @@ const ForecastTab = () => {
? "Минуточку..." ? "Минуточку..."
: "Выбранный уровень структуры не содержит данных о технических объектах" : "Выбранный уровень структуры не содержит данных о технических объектах"
}} }}
containerComponentProps={{ sx: STYLES.TECH_OBJ_TABLE, elevation: 0 }} containerComponentProps={{ sx: STYLES.TECH_OBJ_TABLE(techObjsDataGrid.morePages), elevation: 0 }}
columnsDef={techObjsDataGrid.columnsDef} columnsDef={techObjsDataGrid.columnsDef}
rows={techObjsDataGrid.rows} rows={techObjsDataGrid.rows}
size={P8P_DATA_GRID_SIZE.SMALL} size={P8P_DATA_GRID_SIZE.SMALL}

View File

@ -146,8 +146,44 @@ const useEqConfigTechObjTable = (parent, filters, orders, pageNumber) => {
return { techObjsDataGrid: data, techObjsDataGridIsLoading: isLoading }; 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 };

View File

@ -0,0 +1,48 @@
/*
Парус 8 - Панели мониторинга - ТОиР - Прогнозирование технического состояния
Дополнительная разметка и вёрстка клиентских элементов
*/
//---------------------
//Подключение библиотек
//---------------------
import React from "react"; //Классы React
import { Box, Card, CardContent, Typography, CardActions, Button } from "@mui/material"; //Интерфейсные компоненты
//-----------
//Тело модуля
//-----------
const TechObjCard = ({ cardData }) => {
//Генерация содержимого
return (
<Box p={3}>
<Card>
<CardContent>
<Typography sx={{ fontSize: 14 }} color="text.secondary" gutterBottom>
Технологический объект
</Typography>
<Typography variant="h5" component="div">
{cardData.SCODE}
</Typography>
<Typography sx={{ mb: 1.5 }} color="text.secondary">
{cardData.DOPER_DATE}
</Typography>
<Typography variant="body2">{cardData.SNAME}</Typography>
</CardContent>
<CardActions>
<Button size="large">Прогнозировать</Button>
<Button size="large">Ремонтировать</Button>
<Button size="large">Обучать</Button>
</CardActions>
</Card>
</Box>
);
};
//----------------
//Интерфейс модуля
//----------------
export { TechObjCard };