From 2da177248909dcffebfe15a393b35838d219063f Mon Sep 17 00:00:00 2001 From: Mikhail Chechnev Date: Tue, 6 Aug 2024 01:15:48 +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=9E=D0=B1=D1=83=D1=87=D0=B5=D0=BD=D0=B8=D0=B5"=20-?= =?UTF-8?q?=20=D1=81=D0=BF=D0=B8=D1=81=D0=BA=D0=B8=20=D0=B2=D1=8B=D0=B1?= =?UTF-8?q?=D0=BE=D1=80=D0=BE=D0=BA=20=D0=B8=20=D0=BA=D0=BB=D0=B0=D1=81?= =?UTF-8?q?=D1=81=D0=BE=D0=B2,=20=D0=BA=D0=B0=D1=80=D1=82=D0=BE=D1=87?= =?UTF-8?q?=D0=BA=D0=B0=20=D0=BA=D0=BB=D0=B0=D1=81=D1=81=D0=B0=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 | 245 +++++++++++++++++- panels/eqs_tech_cond_forecast/admin_tab.js | 85 +++++- .../eqs_tech_cond_forecast/admin_tab_hooks.js | 196 ++++++++++++++ .../admin_tab_layout.js | 206 +++++++++++++++ .../eqs_tech_cond_forecast.js | 33 +-- .../eqs_tech_cond_forecast_lyaout.js | 73 ++++++ panels/eqs_tech_cond_forecast/forecast_tab.js | 31 +-- .../forecast_tab_hooks.js | 6 +- .../forecast_tab_layout.js | 18 +- 9 files changed, 838 insertions(+), 55 deletions(-) create mode 100644 panels/eqs_tech_cond_forecast/admin_tab_hooks.js create mode 100644 panels/eqs_tech_cond_forecast/admin_tab_layout.js create mode 100644 panels/eqs_tech_cond_forecast/eqs_tech_cond_forecast_lyaout.js diff --git a/db/UDO_PKG_EQUIPDS.pck b/db/UDO_PKG_EQUIPDS.pck index 6b0568a..216a832 100644 --- a/db/UDO_PKG_EQUIPDS.pck +++ b/db/UDO_PKG_EQUIPDS.pck @@ -1,5 +1,32 @@ create or replace package UDO_PKG_EQUIPDS as + /* Список выборок данных */ + procedure LIST + ( + COUT out clob -- Сериализованная таблица данных + ); + + /* Список классов оборудования выборки данных */ + procedure CM_LIST + ( + NEQUIPDS in number, -- Рег. номер выборки данных + COUT out clob -- Сериализованная таблица данных + ); + + /* Список файлов данных класса оборудования */ + procedure CMFL_LIST + ( + NEQUIPDSCM in number, -- Рег. номер класса оборудования выборки данных + COUT out clob -- Сериализованная таблица данных + ); + + /* Список моделей класса оборудования */ + procedure CMML_LIST + ( + NEQUIPDSCM in number, -- Рег. номер класса оборудования выборки данных + COUT out clob -- Сериализованная таблица данных + ); + /* Код доступного действия с моделью по единице оборудования */ function CMML_ACT_BY_EQCONFIG ( @@ -16,6 +43,222 @@ end UDO_PKG_EQUIPDS; / create or replace package body UDO_PKG_EQUIPDS as + /* Список выборок данных */ + procedure LIST + ( + COUT out clob -- Сериализованная таблица данных + ) + is + NCOMPANY PKG_STD.TREF := GET_SESSION_COMPANY(); -- Организация сеанса + NCUR integer; -- Курсор документа для результата + XDOC PKG_XMAKE.TNODE; -- Документ для результата + XDS PKG_XMAKE.TNODE; -- Элемент для выборки данных + begin + /* Открываем документ */ + NCUR := PKG_XMAKE.OPEN_CURSOR(); + /* Обходим выборки данных */ + for C in (select T.RN NRN, + T.NAME SNAME + from UDO_T_EQUIPDS T + where T.COMPANY = NCOMPANY + order by T.NAME) + loop + XDS := PKG_XMAKE.CONCAT(ICURSOR => NCUR, + RNODE00 => XDS, + RNODE01 => PKG_XMAKE.ELEMENT(ICURSOR => NCUR, + SNAME => 'XDS', + RATTRIBUTES => PKG_XMAKE.ATTRIBUTES(ICURSOR => NCUR, + RATTRIBUTE00 => PKG_XMAKE.ATTRIBUTE(ICURSOR => NCUR, + SNAME => 'NRN', + SVALUE => C.NRN), + RATTRIBUTE01 => PKG_XMAKE.ATTRIBUTE(ICURSOR => NCUR, + SNAME => 'SNAME', + SVALUE => C.SNAME)))); + end loop; + /* Формируем XML-представление ответа */ + XDOC := PKG_XMAKE.ELEMENT(ICURSOR => NCUR, SNAME => 'XDATA', RNODE00 => XDS); + /* Конвертируем в CLOB */ + 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 LIST; + + /* Список классов оборудования выборки данных */ + procedure CM_LIST + ( + NEQUIPDS in number, -- Рег. номер выборки данных + COUT out clob -- Сериализованная таблица данных + ) + is + NCUR integer; -- Курсор документа для результата + XDOC PKG_XMAKE.TNODE; -- Документ для результата + XDSCM PKG_XMAKE.TNODE; -- Элемент для выборки данных + begin + /* Открываем документ */ + NCUR := PKG_XMAKE.OPEN_CURSOR(); + /* Обходим классы оборудования заданной выборки данных */ + for C in (select T.RN NRN, + OK.CODE SCODE, + OK.NAME SNAME + from UDO_T_EQUIPDSCM T, + EQOBJKIND OK + where T.PRN = NEQUIPDS + and T.EQOBJKIND = OK.RN + order by OK.CODE) + loop + XDSCM := PKG_XMAKE.CONCAT(ICURSOR => NCUR, + RNODE00 => XDSCM, + RNODE01 => PKG_XMAKE.ELEMENT(ICURSOR => NCUR, + SNAME => 'XDSCM', + RATTRIBUTES => PKG_XMAKE.ATTRIBUTES(ICURSOR => NCUR, + RATTRIBUTE00 => PKG_XMAKE.ATTRIBUTE(ICURSOR => NCUR, + SNAME => 'NRN', + SVALUE => C.NRN), + RATTRIBUTE01 => PKG_XMAKE.ATTRIBUTE(ICURSOR => NCUR, + SNAME => 'SCODE', + SVALUE => C.SCODE), + RATTRIBUTE02 => PKG_XMAKE.ATTRIBUTE(ICURSOR => NCUR, + SNAME => 'SNAME', + SVALUE => C.SNAME)))); + end loop; + /* Формируем XML-представление ответа */ + XDOC := PKG_XMAKE.ELEMENT(ICURSOR => NCUR, SNAME => 'XDATA', RNODE00 => XDSCM); + /* Конвертируем в CLOB */ + 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 CM_LIST; + + /* Список файлов данных класса оборудования */ + procedure CMFL_LIST + ( + NEQUIPDSCM in number, -- Рег. номер класса оборудования выборки данных + COUT out clob -- Сериализованная таблица данных + ) + is + RDG PKG_P8PANELS_VISUAL.TDATA_GRID; -- Описание таблицы + RDG_ROW PKG_P8PANELS_VISUAL.TROW; -- Строка таблицы + begin + /* Инициализируем таблицу данных */ + 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 => 'SFILE_NAME', + SCAPTION => 'Имя', + SDATA_TYPE => PKG_P8PANELS_VISUAL.SDATA_TYPE_STR); + PKG_P8PANELS_VISUAL.TDATA_GRID_ADD_COL_DEF(RDATA_GRID => RDG, + SNAME => 'SDESCR', + SCAPTION => 'Описание', + SDATA_TYPE => PKG_P8PANELS_VISUAL.SDATA_TYPE_STR); + PKG_P8PANELS_VISUAL.TDATA_GRID_ADD_COL_DEF(RDATA_GRID => RDG, + SNAME => 'NSTATUS', + SCAPTION => 'Состояние', + SDATA_TYPE => PKG_P8PANELS_VISUAL.SDATA_TYPE_NUMB); + PKG_P8PANELS_VISUAL.TDATA_GRID_ADD_COL_DEF(RDATA_GRID => RDG, + SNAME => 'SERR', + SCAPTION => 'Сообщение об ошибке', + SDATA_TYPE => PKG_P8PANELS_VISUAL.SDATA_TYPE_STR); + /* Обходим данные */ + for C in (select T.RN NRN, + T.FILE_NAME SFILE_NAME, + T.DESCR SDESCR, + T.STATUS NSTATUS, + T.ERR SERR + from UDO_T_EQUIPDSCMFL T + where T.PRN = NEQUIPDSCM + order by T.RN) + loop + /* Добавляем колонки с данными */ + PKG_P8PANELS_VISUAL.TROW_ADD_COL(RROW => RDG_ROW, SNAME => 'NRN', NVALUE => C.NRN, BCLEAR => true); + PKG_P8PANELS_VISUAL.TROW_ADD_COL(RROW => RDG_ROW, SNAME => 'SFILE_NAME', SVALUE => C.SFILE_NAME); + PKG_P8PANELS_VISUAL.TROW_ADD_COL(RROW => RDG_ROW, SNAME => 'SDESCR', SVALUE => C.SDESCR); + PKG_P8PANELS_VISUAL.TROW_ADD_COL(RROW => RDG_ROW, SNAME => 'NSTATUS', NVALUE => C.NSTATUS); + PKG_P8PANELS_VISUAL.TROW_ADD_COL(RROW => RDG_ROW, SNAME => 'SERR', SVALUE => C.SERR); + /* Добавляем строку в таблицу */ + PKG_P8PANELS_VISUAL.TDATA_GRID_ADD_ROW(RDATA_GRID => RDG, RROW => RDG_ROW); + end loop; + /* Сериализуем описание */ + COUT := PKG_P8PANELS_VISUAL.TDATA_GRID_TO_XML(RDATA_GRID => RDG, NINCLUDE_DEF => 1); + end CMFL_LIST; + + /* Список моделей класса оборудования */ + procedure CMML_LIST + ( + NEQUIPDSCM in number, -- Рег. номер класса оборудования выборки данных + COUT out clob -- Сериализованная таблица данных + ) + is + RDG PKG_P8PANELS_VISUAL.TDATA_GRID; -- Описание таблицы + RDG_ROW PKG_P8PANELS_VISUAL.TROW; -- Строка таблицы + begin + /* Инициализируем таблицу данных */ + 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 => 'STASK', + SCAPTION => 'Задача', + SDATA_TYPE => PKG_P8PANELS_VISUAL.SDATA_TYPE_STR); + PKG_P8PANELS_VISUAL.TDATA_GRID_ADD_COL_DEF(RDATA_GRID => RDG, + SNAME => 'NPRECISION_P', + SCAPTION => 'Точность (план)', + SDATA_TYPE => PKG_P8PANELS_VISUAL.SDATA_TYPE_NUMB); + PKG_P8PANELS_VISUAL.TDATA_GRID_ADD_COL_DEF(RDATA_GRID => RDG, + SNAME => 'NPRECISION_F', + SCAPTION => 'Точность (факт)', + SDATA_TYPE => PKG_P8PANELS_VISUAL.SDATA_TYPE_NUMB); + PKG_P8PANELS_VISUAL.TDATA_GRID_ADD_COL_DEF(RDATA_GRID => RDG, + SNAME => 'NSTATUS', + SCAPTION => 'Состояние', + SDATA_TYPE => PKG_P8PANELS_VISUAL.SDATA_TYPE_NUMB); + PKG_P8PANELS_VISUAL.TDATA_GRID_ADD_COL_DEF(RDATA_GRID => RDG, + SNAME => 'SERR', + SCAPTION => 'Сообщение об ошибке', + SDATA_TYPE => PKG_P8PANELS_VISUAL.SDATA_TYPE_STR); + /* Обходим данные */ + for C in (select T.RN NRN, + T.TASK STASK, + T.PRECISION_P NPRECISION_P, + T.PRECISION_F NPRECISION_F, + T.STATUS NSTATUS, + T.ERR SERR + from UDO_T_EQUIPDSCMML T + where T.PRN = NEQUIPDSCM + order by T.RN) + loop + /* Добавляем колонки с данными */ + PKG_P8PANELS_VISUAL.TROW_ADD_COL(RROW => RDG_ROW, SNAME => 'NRN', NVALUE => C.NRN, BCLEAR => true); + PKG_P8PANELS_VISUAL.TROW_ADD_COL(RROW => RDG_ROW, SNAME => 'STASK', SVALUE => C.STASK); + PKG_P8PANELS_VISUAL.TROW_ADD_COL(RROW => RDG_ROW, SNAME => 'NPRECISION_P', NVALUE => C.NPRECISION_P); + PKG_P8PANELS_VISUAL.TROW_ADD_COL(RROW => RDG_ROW, SNAME => 'NPRECISION_F', NVALUE => C.NPRECISION_F); + PKG_P8PANELS_VISUAL.TROW_ADD_COL(RROW => RDG_ROW, SNAME => 'NSTATUS', NVALUE => C.NSTATUS); + PKG_P8PANELS_VISUAL.TROW_ADD_COL(RROW => RDG_ROW, SNAME => 'SERR', SVALUE => C.SERR); + /* Добавляем строку в таблицу */ + PKG_P8PANELS_VISUAL.TDATA_GRID_ADD_ROW(RDATA_GRID => RDG, RROW => RDG_ROW); + end loop; + /* Сериализуем описание */ + COUT := PKG_P8PANELS_VISUAL.TDATA_GRID_TO_XML(RDATA_GRID => RDG, NINCLUDE_DEF => 1); + end CMML_LIST; + /* Код доступного действия с моделью по единице оборудования */ function CMML_ACT_BY_EQCONFIG ( @@ -34,7 +277,7 @@ create or replace package body UDO_PKG_EQUIPDS as is begin return 'TCF;RUL;FP'; - end CMML_LIST_BY_EQCONFIG; + end CMML_LIST_BY_EQCONFIG; end UDO_PKG_EQUIPDS; / diff --git a/panels/eqs_tech_cond_forecast/admin_tab.js b/panels/eqs_tech_cond_forecast/admin_tab.js index 454bb7e..e85929d 100644 --- a/panels/eqs_tech_cond_forecast/admin_tab.js +++ b/panels/eqs_tech_cond_forecast/admin_tab.js @@ -7,8 +7,26 @@ //Подключение библиотек //--------------------- -import React from "react"; //Классы React -import { Grid } from "@mui/material"; //Интерфейсные компоненты +import React, { useState, useEffect } from "react"; //Классы React +import { Box, Grid, Stack, Icon, Button } from "@mui/material"; //Интерфейсные компоненты +import { EquipDataSelectionList, EquipDataSelectionClassMachineList, EquipDataSelectionClassMachineCard } from "./admin_tab_layout"; //Вспомогательные компоненты и вёрстка +import { + DS_RN_DEFAULT, + useEquipDataSelectionList, + useEquipDataSelectionClassMachineList, + useEquipDataSelectionClassMachineFilesList, + useEquipDataSelectionClassMachineModelsList +} from "./admin_tab_hooks"; //Вспомогательные хуки + +//--------- +//Константы +//--------- + +//Стили +const STYLES = { + DATA_SELECTION_STACK: { alignItems: "center" }, + CLASS_MACHINE_ADD_BUTTON: { margin: "5px" } +}; //----------- //Тело модуля @@ -16,15 +34,70 @@ import { Grid } from "@mui/material"; //Интерфейсные компоне //Закладка администрирования const AdminTab = () => { + //Собственное состояние - выбранная выборка данных + const [equipDataSelection, setDataSelection] = useState(DS_RN_DEFAULT); + + //Собственное состояние - выбранный класс оборудования + const [equipDataSelectionClassMachine, setDataSelectionClassMachine] = useState(null); + + //Загрузка списка выборок данных + const { equipDataSelectionList } = useEquipDataSelectionList(); + + //Загрузка классов оборудования выбранной выборки данных + const { equipDataSelectionClassMachineList } = useEquipDataSelectionClassMachineList(equipDataSelection); + + //Загрузка файлов класса оборудования + const { equipDataSelectionClassMachineFilesList } = useEquipDataSelectionClassMachineFilesList(equipDataSelectionClassMachine); + + //Загрузка файлов класса оборудования + const { equipDataSelectionClassMachineModelsList } = useEquipDataSelectionClassMachineModelsList(equipDataSelectionClassMachine); + + //При подключении компонента к странице + useEffect(() => {}, []); + + //При смене выборки данных + const handleDataSelectionChange = value => { + setDataSelectionClassMachine(null); + setDataSelection(value); + }; + + //При нажатии на класс оборудования + const handleDataSelectionClassMachineClick = value => setDataSelectionClassMachine(value); + //Генерация содержимого return ( -
+ - - Здесь только администраторы могут работать + + + + + + + + + + + -
+ ); }; diff --git a/panels/eqs_tech_cond_forecast/admin_tab_hooks.js b/panels/eqs_tech_cond_forecast/admin_tab_hooks.js new file mode 100644 index 0000000..2ec3e41 --- /dev/null +++ b/panels/eqs_tech_cond_forecast/admin_tab_hooks.js @@ -0,0 +1,196 @@ +/* + Парус 8 - Панели мониторинга - ТОиР - Прогнозирование технического состояния + Закладка администрирования: кастомные хуки +*/ + +//--------------------- +//Подключение библиотек +//--------------------- + +import { useState, useEffect, useContext } from "react"; //Классы React +import { BackEndСtx } from "../../context/backend"; //Контекст взаимодействия с сервером + +//--------- +//Константы +//--------- + +//Рег. номер выборки данных по умолчанию +const DS_RN_DEFAULT = -1; + +//Наименование выборки данных по умолчанию +const DS_NAME_DEFAULT = "Не указана"; + +//Выборка данных по умолчанию +const DS_DEFAULT = { NRN: DS_RN_DEFAULT, SNAME: DS_NAME_DEFAULT }; + +//----------- +//Тело модуля +//----------- + +//Загрузка списка выборок данных +const useEquipDataSelectionList = () => { + //Собственное состояние - флаг загрузки + const [isLoading, setLoading] = useState(false); + + //Собственное состояние - данные + const [data, setData] = useState([DS_DEFAULT]); + + //Подключение к контексту взаимодействия с сервером + const { executeStored } = useContext(BackEndСtx); + + //Загрузка данных при изменении зависимостей + useEffect(() => { + const loadData = async () => { + try { + setLoading(true); + const data = await executeStored({ + stored: "UDO_PKG_EQUIPDS.LIST", + respArg: "COUT", + isArray: name => ["XDS"].includes(name), + loader: false + }); + setData([DS_DEFAULT, ...(data?.XDS ? data.XDS : [])]); + } finally { + setLoading(false); + } + }; + loadData(); + }, [executeStored]); + + //Вернём данные + return { equipDataSelectionList: data, equipDataSelectionListIsLoading: isLoading }; +}; + +//Загрузка классов оборудования выбороки данных +const useEquipDataSelectionClassMachineList = dataSelection => { + //Собственное состояние - флаг загрузки + const [isLoading, setLoading] = useState(false); + + //Собственное состояние - данные + const [data, setData] = useState([]); + + //Подключение к контексту взаимодействия с сервером + const { executeStored } = useContext(BackEndСtx); + + //Загрузка данных при изменении зависимостейuse + useEffect(() => { + const loadData = async () => { + try { + setLoading(true); + const data = await executeStored({ + stored: "UDO_PKG_EQUIPDS.CM_LIST", + args: { NEQUIPDS: dataSelection }, + respArg: "COUT", + isArray: name => ["XDSCM"].includes(name), + attributeValueProcessor: (name, val) => (["SCODE"].includes(name) ? undefined : val), + loader: false + }); + setData(data?.XDSCM || []); + } finally { + setLoading(false); + } + }; + if (dataSelection && dataSelection != DS_RN_DEFAULT) loadData(); + }, [dataSelection, executeStored]); + + //Вернём данные + return { equipDataSelectionClassMachineList: data, equipDataSelectionClassMachineListIsLoading: isLoading }; +}; + +//Загрузка списка файлов класса оборудования +const useEquipDataSelectionClassMachineFilesList = classMachine => { + //Собственное состояние - флаг загрузки + const [isLoading, setLoading] = useState(false); + + //Собственное состояние - таблица данных + const [data, setData] = useState({ + init: false, + columnsDef: [], + rows: [] + }); + + //Подключение к контексту взаимодействия с сервером + const { executeStored } = useContext(BackEndСtx); + + //Загрузка данных при изменении зависимостей + useEffect(() => { + const loadData = async () => { + try { + setLoading(true); + const data = await executeStored({ + stored: "UDO_PKG_EQUIPDS.CMFL_LIST", + args: { NEQUIPDSCM: classMachine }, + respArg: "COUT", + loader: false + }); + setData(pv => ({ + ...pv, + columnsDef: [...data.XCOLUMNS_DEF], + rows: [...(data.XROWS || [])], + init: true + })); + } finally { + setLoading(false); + } + }; + if (classMachine) loadData(); + }, [classMachine, executeStored]); + + //Вернём данные + return { equipDataSelectionClassMachineFilesList: data, equipDataSelectionClassMachineFilesListIsLoading: isLoading }; +}; + +//Загрузка списка моделей класса оборудования +const useEquipDataSelectionClassMachineModelsList = classMachine => { + //Собственное состояние - флаг загрузки + const [isLoading, setLoading] = useState(false); + + //Собственное состояние - таблица данных + const [data, setData] = useState({ + init: false, + columnsDef: [], + rows: [] + }); + + //Подключение к контексту взаимодействия с сервером + const { executeStored } = useContext(BackEndСtx); + + //Загрузка данных при изменении зависимостей + useEffect(() => { + const loadData = async () => { + try { + setLoading(true); + const data = await executeStored({ + stored: "UDO_PKG_EQUIPDS.CMML_LIST", + args: { NEQUIPDSCM: classMachine }, + respArg: "COUT", + loader: false + }); + setData(pv => ({ + ...pv, + columnsDef: [...data.XCOLUMNS_DEF], + rows: [...(data.XROWS || [])], + init: true + })); + } finally { + setLoading(false); + } + }; + if (classMachine) loadData(); + }, [classMachine, executeStored]); + + //Вернём данные + return { equipDataSelectionClassMachineModelsList: data, equipDataSelectionClassMachineModelsListIsLoading: isLoading }; +}; + +//---------------- +//Интерфейс модуля +//---------------- + +export { + DS_RN_DEFAULT, + useEquipDataSelectionList, + useEquipDataSelectionClassMachineList, + useEquipDataSelectionClassMachineFilesList, + useEquipDataSelectionClassMachineModelsList +}; diff --git a/panels/eqs_tech_cond_forecast/admin_tab_layout.js b/panels/eqs_tech_cond_forecast/admin_tab_layout.js new file mode 100644 index 0000000..7224caf --- /dev/null +++ b/panels/eqs_tech_cond_forecast/admin_tab_layout.js @@ -0,0 +1,206 @@ +/* + Парус 8 - Панели мониторинга - ТОиР - Прогнозирование технического состояния + Закладка администрирования: дополнительная разметка и вёрстка клиентских элементов +*/ + +//--------------------- +//Подключение библиотек +//--------------------- + +import React from "react"; //Классы React +import PropTypes from "prop-types"; //Контроль свойств компонента +import { + Box, + Stack, + FormControl, + InputLabel, + Select, + MenuItem, + List, + ListItem, + ListItemButton, + ListItemText, + Card, + CardContent, + CardActions, + Typography, + Button +} from "@mui/material"; //Интерфейсные компоненты +import { APP_BAR_HEIGHT, TABS_HEIGHT, SCROLL_STYLES } from "./eqs_tech_cond_forecast_lyaout"; //Общие вспомогательные компоненты и вёрстка +import { P8PDataGrid, P8P_DATA_GRID_SIZE } from "../../components/p8p_data_grid"; //Таблица данных +import { P8P_DATA_GRID_CONFIG_PROPS } from "../../config_wrapper"; //Подключение компонентов к настройкам приложения + +//--------- +//Константы +//--------- + +//Высота списка выборок данных +const DS_SELECTOR_HEIGHT = "80px"; + +//Высота кнопки добавления технического объекта +const CM_ADD_BTN_HEIGHT = "46.5px"; + +//Структура элемента списка выборок данных оборудования +const EQUIP_DATA_SELECTION_LIST = PropTypes.shape({ + NRN: PropTypes.number.isRequired, + SNAME: PropTypes.string.isRequired +}); + +//Структура элемента списка классов оборудования выборки данных +const EQUIP_DATA_SELECTION_CLASS_MACHINE_LIST = PropTypes.shape({ + NRN: PropTypes.number.isRequired, + SCODE: PropTypes.string.isRequired, + SNAME: PropTypes.string.isRequired +}); + +//Стили +const STYLES = { + EQUIP_DS_LIST_FORM_CONTROL: { minWidth: "300px" }, + EQUIP_DSCM_LIST: { + minHeight: `calc(100vh - ${APP_BAR_HEIGHT} - ${TABS_HEIGHT} - ${DS_SELECTOR_HEIGHT} - ${CM_ADD_BTN_HEIGHT})`, + maxHeight: `calc(100vh - ${APP_BAR_HEIGHT} - ${TABS_HEIGHT} - ${DS_SELECTOR_HEIGHT} - ${CM_ADD_BTN_HEIGHT})`, + overflowX: "hidden", + overflowY: "auto", + ...SCROLL_STYLES + }, + EQUIP_DSCM_CARD: { + minHeight: `calc(100vh - ${APP_BAR_HEIGHT} - ${TABS_HEIGHT} - ${DS_SELECTOR_HEIGHT})`, + maxHeight: `calc(100vh - ${APP_BAR_HEIGHT} - ${TABS_HEIGHT} - ${DS_SELECTOR_HEIGHT})`, + overflowY: "auto", + ...SCROLL_STYLES + }, + FL_ML_TABLE: { + height: `200px`, + ...SCROLL_STYLES + } +}; + +//----------- +//Тело модуля +//----------- + +//Список выборок данных оборудования +const EquipDataSelectionList = ({ list, value, onChange }) => { + //При выборе элемента + const handleChange = e => (onChange ? onChange(e.target.value) : null); + + //Генерация содержимого + return ( + + Выборка данных оборудования + + + ); +}; + +//Контроль свойств - Список выборок данных оборудования +EquipDataSelectionList.propTypes = { + list: PropTypes.arrayOf(EQUIP_DATA_SELECTION_LIST).isRequired, + value: PropTypes.number.isRequired, + onChange: PropTypes.func +}; + +//Список классов оборудования выборки данных +const EquipDataSelectionClassMachineList = ({ list, value, onClick }) => { + //При щелчке на элементе + const handleClick = id => (onClick ? onClick(id) : null); + + //Генерация содержимого + return ( + + {list.map((item, i) => ( + + handleClick(item.NRN)}> + + + + ))} + + ); +}; + +//Контроль свойств - Список классов оборудования выборки данных +EquipDataSelectionClassMachineList.propTypes = { + list: PropTypes.arrayOf(EQUIP_DATA_SELECTION_CLASS_MACHINE_LIST).isRequired, + value: PropTypes.number, + onClick: PropTypes.func +}; + +//Карточка класса оборудования выборки данных +const EquipDataSelectionClassMachineCard = ({ filesList, modelsList }) => { + //Генерация содержимого + return ( + + + + + + Наименование технического объекта + + + Состояние: готов к ... + + фывафывафва + + + + + + + + + + + Файлы данных + + + + + + + + Модели + + + + + + + ); +}; + +//---------------- +//Интерфейс модуля +//---------------- + +export { EquipDataSelectionList, EquipDataSelectionClassMachineList, EquipDataSelectionClassMachineCard }; diff --git a/panels/eqs_tech_cond_forecast/eqs_tech_cond_forecast.js b/panels/eqs_tech_cond_forecast/eqs_tech_cond_forecast.js index e086ac0..899446c 100644 --- a/panels/eqs_tech_cond_forecast/eqs_tech_cond_forecast.js +++ b/panels/eqs_tech_cond_forecast/eqs_tech_cond_forecast.js @@ -7,8 +7,9 @@ //Подключение библиотек //--------------------- -import React, { useState, useEffect } from "react"; //Классы React +import React, { useState } from "react"; //Классы React import { Box, Tabs, Tab } from "@mui/material"; //Интерфейсные компоненты +import { MODES, TabPanel } from "./eqs_tech_cond_forecast_lyaout"; //Вспомогательные компоненты и вёрстка import { AdminTab } from "./admin_tab"; //Интерфейс администрирования import { ForecastTab } from "./forecast_tab"; //Интерфейс прогнозирования @@ -16,23 +17,19 @@ import { ForecastTab } from "./forecast_tab"; //Интерфейс прогно //Константы //--------- -//Режимы работы панели -const MODES = { - FORECAST: 1, - ADMIN: 2 +//Стили +const STYLES = { + TABS_CONTAINER_BOX: { borderBottom: 1, borderColor: "divider" } }; //----------- //Тело модуля //----------- -//Закладка -const TapPanel = ({ children }) => {children}; - //Корневая панель прогнозирования технического состояния const EqsTechCondForecast = () => { //Собственное состояние - const [mode, setMode] = useState(MODES.FORECAST); + const [mode, setMode] = useState(MODES.ADMIN); //При переключении закладки const handleTabChange = (e, newValue) => setMode(newValue); @@ -40,22 +37,18 @@ const EqsTechCondForecast = () => { //Генерация содержимого return ( <> - + - {mode == MODES.ADMIN ? ( - - {" "} - - ) : null} - {mode == MODES.FORECAST ? ( - - - - ) : null} + + + + + + ); }; diff --git a/panels/eqs_tech_cond_forecast/eqs_tech_cond_forecast_lyaout.js b/panels/eqs_tech_cond_forecast/eqs_tech_cond_forecast_lyaout.js new file mode 100644 index 0000000..ead138e --- /dev/null +++ b/panels/eqs_tech_cond_forecast/eqs_tech_cond_forecast_lyaout.js @@ -0,0 +1,73 @@ +/* + Парус 8 - Панели мониторинга - ТОиР - Прогнозирование технического состояния + Корневая панель прогнозирования технического состояния: дополнительная разметка и вёрстка клиентских элементов +*/ + +//--------------------- +//Подключение библиотек +//--------------------- + +import React from "react"; //Классы React +import PropTypes from "prop-types"; //Контроль свойств компонента +import { Box } from "@mui/material"; //Интерфейсные компоненты + +//--------- +//Константы +//--------- + +//Режимы работы панели +const MODES = { + FORECAST: 1, + ADMIN: 2 +}; + +//Высота главного меню +const APP_BAR_HEIGHT = "64px"; + +//Высота закладок +const TABS_HEIGHT = "49px"; + +//Высота кнопки "Ещё" +const TABLE_MORE_HEIGHT = "49px"; + +//Высота фильтров таблицы +const TABLE_FILTERS_HEIGHT = "48px"; + +//Стиль скролов +const SCROLL_STYLES = { + "&::-webkit-scrollbar": { + height: "8px", + width: "8px" + }, + "&::-webkit-scrollbar-track": { + borderRadius: "8px", + backgroundColor: "#EBEBEB" + }, + "&::-webkit-scrollbar-thumb": { + borderRadius: "8px", + backgroundColor: "#b4b4b4" + }, + "&::-webkit-scrollbar-thumb:hover": { + backgroundColor: "#808080" + } +}; + +//----------- +//Тело модуля +//----------- + +//Закладка +const TabPanel = ({ mode, value, children }) => ; + +//Контроль свойств - Закладка +TabPanel.propTypes = { + mode: PropTypes.number.isRequired, + value: PropTypes.number.isRequired, + children: PropTypes.element +}; + +//---------------- +//Интерфейс модуля +//---------------- + +export { MODES, APP_BAR_HEIGHT, TABS_HEIGHT, TABLE_MORE_HEIGHT, TABLE_FILTERS_HEIGHT, SCROLL_STYLES, TabPanel }; diff --git a/panels/eqs_tech_cond_forecast/forecast_tab.js b/panels/eqs_tech_cond_forecast/forecast_tab.js index 672d6f2..b1e5711 100644 --- a/panels/eqs_tech_cond_forecast/forecast_tab.js +++ b/panels/eqs_tech_cond_forecast/forecast_tab.js @@ -13,25 +13,14 @@ import { RichTreeView } from "@mui/x-tree-view/RichTreeView"; //Дерево import { MessagingСtx } from "../../context/messaging"; //Контекст сообщений import { P8PDataGrid, P8P_DATA_GRID_SIZE } from "../../components/p8p_data_grid"; //Таблица данных import { P8P_DATA_GRID_CONFIG_PROPS } from "../../config_wrapper"; //Подключение компонентов к настройкам приложения -import { useEqConfigTree, useEqConfigTechObjTable, useEqConfigTechObjCard, findTreeItem, needLoadLevel } from "./forecast_tab_hooks"; //Вспомогательные хуки +import { APP_BAR_HEIGHT, TABS_HEIGHT, TABLE_FILTERS_HEIGHT, TABLE_MORE_HEIGHT, SCROLL_STYLES } from "./eqs_tech_cond_forecast_lyaout"; //Общие Вспомогательные компоненты и вёрстка import { TechObjCard, eqConfigTechObjTableValueFormatter } from "./forecast_tab_layout"; //Вспомогательные компоненты и вёрстка +import { useEqConfigTree, useEqConfigTechObjTable, useEqConfigTechObjCard, findTreeItem, needLoadLevel } from "./forecast_tab_hooks"; //Вспомогательные хуки //--------- //Константы //--------- -//Высота главного меню -const APP_BAR_HEIGHT = "64px"; - -//Высота закладок -const TABS_HEIGHT = "49px"; - -//Высота кнопки "Ещё" -const TABLE_MORE_HEIGHT = "49px"; - -//Высота фильтров таблицы -const TABLE_FILTERS_HEIGHT = "48px"; - //Стили const STYLES = { LEFT_SIDE_GRID: {}, @@ -40,15 +29,15 @@ const STYLES = { minHeight: `calc(100vh - ${APP_BAR_HEIGHT} - ${TABS_HEIGHT})`, maxHeight: `calc(100vh - ${APP_BAR_HEIGHT} - ${TABS_HEIGHT})`, overflowX: "hidden", - overflowY: "scroll", - scrollbarWidth: "thin", - padding: "3px" + overflowY: "auto", + padding: "3px", + ...SCROLL_STYLES }, TECH_OBJ_TABLE: (morePages, filters) => ({ height: `calc(100vh - ${APP_BAR_HEIGHT} - ${TABS_HEIGHT} - ${morePages ? TABLE_MORE_HEIGHT : "0px"} - ${ filters ? TABLE_FILTERS_HEIGHT : "0px" })`, - scrollbarWidth: "thin" + ...SCROLL_STYLES }) }; @@ -74,7 +63,7 @@ const ForecastTab = () => { const [techObjCardId, setTechObjCardId] = useState(null); //Загрузчик веток дерева - const { tree } = useEqConfigTree(loadingTreeItem); + const { eQconfigTree } = useEqConfigTree(loadingTreeItem); //Загрузчик технических объектов для выбранной ветки const { techObjsDataGrid, techObjsDataGridIsLoading } = useEqConfigTechObjTable( @@ -89,11 +78,11 @@ const ForecastTab = () => { //Обработка развёртывания/свёртывания уровня дерева const handleTreeItemExpansionToggle = (event, itemId, isExpanded) => - isExpanded && needLoadLevel(tree, itemId) ? setLoadingTreeItem(parseInt(itemId)) : null; + isExpanded && needLoadLevel(eQconfigTree, itemId) ? setLoadingTreeItem(parseInt(itemId)) : null; //Обработка фокусировки на элементе дерева const handleTreeItemFocus = (event, itemId) => { - const item = findTreeItem(tree, itemId); + const item = findTreeItem(eQconfigTree, itemId); if (item && item?.showCard) setTechObjCardId(parseInt(itemId)); else { setTechObjCardId(null); @@ -124,7 +113,7 @@ const ForecastTab = () => { - + diff --git a/panels/eqs_tech_cond_forecast/forecast_tab_hooks.js b/panels/eqs_tech_cond_forecast/forecast_tab_hooks.js index fe5ba33..c4d43fa 100644 --- a/panels/eqs_tech_cond_forecast/forecast_tab_hooks.js +++ b/panels/eqs_tech_cond_forecast/forecast_tab_hooks.js @@ -1,6 +1,6 @@ /* Парус 8 - Панели мониторинга - ТОиР - Прогнозирование технического состояния - Кастомные хуки закладки Прогнозирования + Закладка прогнозирования: кастомные хуки */ //--------------------- @@ -91,7 +91,7 @@ const useEqConfigTree = parent => { }, [parent, executeStored]); //Вернём данные - return { tree, isLoading }; + return { eQconfigTree: tree, eQconfigTreeIsLoading: isLoading }; }; //Загрузка списка технических объектов @@ -151,7 +151,7 @@ const useEqConfigTechObjCard = id => { //Собственное состояние - флаг загрузки const [isLoading, setLoading] = useState(false); - //Собственное состояние - данные дерева + //Собственное состояние - данные карточки const [card, setCard] = useState({}); //Подключение к контексту взаимодействия с сервером diff --git a/panels/eqs_tech_cond_forecast/forecast_tab_layout.js b/panels/eqs_tech_cond_forecast/forecast_tab_layout.js index f80149d..ef3fca8 100644 --- a/panels/eqs_tech_cond_forecast/forecast_tab_layout.js +++ b/panels/eqs_tech_cond_forecast/forecast_tab_layout.js @@ -1,6 +1,6 @@ /* Парус 8 - Панели мониторинга - ТОиР - Прогнозирование технического состояния - Дополнительная разметка и вёрстка клиентских элементов + Закладка прогнозирования: дополнительная разметка и вёрстка клиентских элементов */ //--------------------- @@ -12,6 +12,16 @@ import PropTypes from "prop-types"; //Контроль свойств компо import { Box, Card, CardContent, Typography, CardActions, Button } from "@mui/material"; //Интерфейсные компоненты import { formatDateRF } from "../../core/utils"; //Вспомогательные функции +//--------- +//Константы +//--------- + +//Стили +const STYLES = { + TECH_OBJ_CARD_TITLE: { fontSize: 14 }, + TECH_OBJ_CARD_SUB_TITLE: { mb: 1.5 } +}; + //----------- //Тело модуля //----------- @@ -20,16 +30,16 @@ import { formatDateRF } from "../../core/utils"; //Вспомогательны const TechObjCard = ({ cardData }) => { //Генерация содержимого return ( - + - + Технический объект {cardData.SCODE} - + {cardData.DOPER_DATE} {cardData.SNAME}