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

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, -- Признак включения описания колонок таблицы в ответ
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;
/

View File

@ -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 = () => {
</Box>
</Grid>
<Grid item xs={8} sx={STYLES.RIGHT_SIDE_GRID}>
{techObjsDataGrid.init ? (
{techObjCardId ? (
!techObjCardIsLoading ? (
<TechObjCard cardData={techObjCard} />
) : null
) : techObjsDataGrid.init ? (
<P8PDataGrid
{...{
...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}
rows={techObjsDataGrid.rows}
size={P8P_DATA_GRID_SIZE.SMALL}

View File

@ -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 };

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 };