diff --git a/db/UDO_PKG_EQUIPDS.pck b/db/UDO_PKG_EQUIPDS.pck index 40c0707..d4a25f2 100644 --- a/db/UDO_PKG_EQUIPDS.pck +++ b/db/UDO_PKG_EQUIPDS.pck @@ -135,11 +135,17 @@ create or replace package UDO_PKG_EQUIPDS as COUT out clob -- Сериализованная таблица данных ); - /* Формирование демо-прогноза */ - procedure CMMLH_DEMO_BUILD + /* Формирование данных прогноза "Выборки данных оборудования (классы оборудования, модели, история запросов)" */ + procedure CMMLH_BUILD_FORECAST ( - STASK in varchar2, -- Задача - COUT out clob -- Данные демо-прогноза + COUT out clob -- Данные прогноза + ); + + /* Извлечение описания из данных прогноза "Выборки данных оборудования (классы оборудования, модели, история запросов)" */ + procedure CMMLH_PARSE_FORECAST + ( + CFORECAST in clob, -- Данные прогноза + NFORECAST out number -- Значение прогноза ); /* Список "Выборки данных оборудования (классы оборудования, модели, история запросов)" по единице оборудования */ @@ -757,7 +763,7 @@ text="Проверка прав доступа на работу с ""Выбор /* Возвращаем результат */ return NRES; end CMML_STATUS_BY_EQCONFIG; - + /* Список "Выборки данных оборудования (классы оборудования, модели)" по единице оборудования */ procedure CMML_LIST_BY_EQCONFIG ( @@ -853,45 +859,46 @@ text="Проверка прав доступа на работу с ""Выбор COUT := PKG_P8PANELS_VISUAL.TDATA_GRID_TO_XML(RDATA_GRID => RDG, NINCLUDE_DEF => 1); end CMML_LIST_BY_EQCONFIG; - /* Формирование демо-прогноза */ - procedure CMMLH_DEMO_BUILD + /* Формирование данных прогноза "Выборки данных оборудования (классы оборудования, модели, история запросов)" */ + procedure CMMLH_BUILD_FORECAST ( - STASK in varchar2, -- Задача - COUT out clob -- Данные демо-прогноза + COUT out clob -- Данные прогноза ) is - RCH PKG_P8PANELS_VISUAL.TCHART; -- График - RCH_DS PKG_P8PANELS_VISUAL.TCHART_DATASET; -- Набор данных - DMONTH date; -- Месяц прогноза + NCUR integer; -- Курсор документа для результата + XDOC PKG_XMAKE.TNODE; -- Документ для результата + XROOT PKG_XMAKE.TNODE; -- Содержимое корневого узла документа + NFORECAST PKG_STD.TNUMBER; -- Прогноз по заданной задаче begin - /* Сформируем заголовок графика */ - RCH := PKG_P8PANELS_VISUAL.TCHART_MAKE(STYPE => PKG_P8PANELS_VISUAL.SCHART_TYPE_LINE, - STITLE => 'Прогноз на 5 месяцев', - SLGND_POS => PKG_P8PANELS_VISUAL.SCHART_LGND_POS_RIGHT); - /* Сформируем набор данных */ - RCH_DS := PKG_P8PANELS_VISUAL.TCHART_DATASET_MAKE(SCAPTION => STASK); - /* Генерируем случайные данные */ - for I in 1 .. 5 - loop - /* Добавим метку для месяца */ - DMONTH := ADD_MONTHS(sysdate, I); - PKG_P8PANELS_VISUAL.TCHART_ADD_LABEL(RCHART => RCH, - SLABEL => F_GET_MONTH(NVALUE => EXTRACT(month from DMONTH)) || ' ' || - TO_CHAR(DMONTH, 'yyyy')); - /* Добавим месяц в набор данных */ - PKG_P8PANELS_VISUAL.TCHART_DATASET_ADD_ITEM(RDATASET => RCH_DS, NVALUE => ROUND(DBMS_RANDOM.VALUE(1, 100))); - end loop; - /* Добавим набор данных в график */ - PKG_P8PANELS_VISUAL.TCHART_ADD_DATASET(RCHART => RCH, RDATASET => RCH_DS); - /* Сериализуем описание */ - COUT := PKG_P8PANELS_VISUAL.TCHART_TO_XML(RCHART => RCH, NINCLUDE_DEF => 1); - end CMMLH_DEMO_BUILD; + /* Вычислим прогноз - количество периодов в указанных ЕИ до достижения предельного состояния */ + NFORECAST := ROUND(DBMS_RANDOM.VALUE(10, 60)); + /* Открываем документ */ + NCUR := PKG_XMAKE.OPEN_CURSOR(); + /* Заполним прогноз */ + XROOT := PKG_XMAKE.CONCAT(ICURSOR => NCUR, + RNODE00 => XROOT, + RNODE01 => PKG_XMAKE.ELEMENT(ICURSOR => NCUR, + SNAME => 'NFORECAST', + RVALUE00 => PKG_XMAKE.VALUE(ICURSOR => NCUR, NVALUE => NFORECAST))); + /* Формируем XML-представление ответа */ + XDOC := PKG_XMAKE.ELEMENT(ICURSOR => NCUR, SNAME => 'XDATA', RNODE00 => XROOT); + /* Конвертируем в 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 CMMLH_BUILD_FORECAST; - /* Извлечение прогноза из демо-данных */ - function CMMLH_DEMO_FORECAST_PARSE + /* Извлечение описания из данных прогноза "Выборки данных оборудования (классы оборудования, модели, история запросов)" */ + procedure CMMLH_PARSE_FORECAST ( - CFORECAST in clob -- Данные демо-прогноза - ) return number -- Прогнозное значение + CFORECAST in clob, -- Данные прогноза + NFORECAST out number -- Значение прогноза + ) is XDOC PKG_XPATH.TDOCUMENT; -- Десериализованный демо-прогноз XROOT PKG_XPATH.TNODE; -- Корневой элемент данных @@ -900,13 +907,12 @@ text="Проверка прав доступа на работу с ""Выбор XDOC := PKG_XPATH.PARSE_FROM_CLOB(LCXML => CFORECAST); /* Извлекаем корневой элемент */ XROOT := PKG_XPATH.ROOT_NODE(RDOCUMENT => XDOC); - /* Возвращаем значение за ближайший месяц */ - return PKG_XPATH.VALUE_NUM(RNODE => PKG_XPATH.SINGLE_NODE(RPARENT_NODE => XROOT, - SPATTERN => 'XDATA/XCHART/datasets/data')); + /* Читаем прогноз */ + NFORECAST := PKG_XPATH.VALUE_NUM(RNODE => PKG_XPATH.SINGLE_NODE(RPARENT_NODE => XROOT, SPATTERN => 'XDATA/NFORECAST')); exception when others then - return null; - end CMMLH_DEMO_FORECAST_PARSE; + null; + end CMMLH_PARSE_FORECAST; /* Список "Выборки данных оборудования (классы оборудования, модели, история запросов)" по единице оборудования */ procedure CMMLH_LIST_BY_EQCONFIG @@ -948,41 +954,62 @@ text="Проверка прав доступа на работу с ""Выбор SCAPTION => 'Точность (факт)', SDATA_TYPE => PKG_P8PANELS_VISUAL.SDATA_TYPE_NUMB); PKG_P8PANELS_VISUAL.TDATA_GRID_ADD_COL_DEF(RDATA_GRID => RDG, - SNAME => 'NFORECAST', + SNAME => 'STO_FORECAST_DESC', SCAPTION => 'Прогноз', - SDATA_TYPE => PKG_P8PANELS_VISUAL.SDATA_TYPE_NUMB, - SHINT => 'Опасность - вероятность сбоя более 60%.
' || - 'Внимание - вероятность сбоя от 30% до 60%
' || - 'В норме - вероятность сбоев менее 30%'); + SDATA_TYPE => PKG_P8PANELS_VISUAL.SDATA_TYPE_STR, + SHINT => 'Формат прогноза: "XXЕИ / YY%", где
' || + 'XXЕИ - время до перехода в критическое состояние в ЕИ ресурса единицы оборудования (часы/дни/месяцы/рабочие циклы и т.п.)
' || + 'YY% - вероятность перехода в критическое состояние до следующего ТО и ремонта

' || + 'Цвет прогноза:
' || UDO_PKG_EQUIPTCF.EQCONFIG_THOBJ_FORECAST_CLR(NMODE => 0)); PKG_P8PANELS_VISUAL.TDATA_GRID_ADD_COL_DEF(RDATA_GRID => RDG, - SNAME => 'SFORECAST', - SCAPTION => 'Данные прогноза', + SNAME => 'STO_FORECAST_DESC_COLOR', + SCAPTION => 'Цвет прогноза', + SDATA_TYPE => PKG_P8PANELS_VISUAL.SDATA_TYPE_STR, + BVISIBLE => false); + PKG_P8PANELS_VISUAL.TDATA_GRID_ADD_COL_DEF(RDATA_GRID => RDG, + SNAME => 'STO_FORECAST', + SCAPTION => 'Данные карточки прогноза для конкретного технического объекта', SDATA_TYPE => PKG_P8PANELS_VISUAL.SDATA_TYPE_STR, BVISIBLE => false); /* Обходим данные */ for C in (select T.RN NRN, T.RQ_AUTHID SRQ_AUTHID, + T.RQ_DATE DRQ_DATE, TO_CHAR(T.RQ_DATE, 'dd.mm.yyyy hh24:mi:ss') SRQ_DATE, DS.CODE SEQUIPDS_CODE, ML.TASK SEQUIPDSCMML_TASK, ML.PRECISION_F NEQUIPDSCMML_PRECISION_F, + DM.MEAS_MNEMO SDICMUNTS, + T.FORECAST BFORECAST, null NFORECAST, - null SFORECAST, - T.FORECAST BFORECAST + null STO_FORECAST_DESC, + null STO_FORECAST_DESC_COLOR, + null STO_FORECAST from UDO_T_EQUIPDSCMMLH T, UDO_T_EQUIPDSCMML ML, UDO_T_EQUIPDSCM CM, - UDO_T_EQUIPDS DS + UDO_T_EQUIPDS DS, + DICMUNTS DM where T.EQCONFIG = NEQCONFIG and T.PRN = ML.RN and ML.PRN = CM.RN and CM.PRN = DS.RN + and CM.DICMUNTS = DM.RN order by T.RN desc) loop - /* Конвертируем данные прогноза */ - C.SFORECAST := BLOB2CLOB(LBDATA => C.BFORECAST); - /* Извлекаем прогноз */ - C.NFORECAST := CMMLH_DEMO_FORECAST_PARSE(CFORECAST => C.SFORECAST); + /* Извлекаем данные из прогноза фреймворка */ + CMMLH_PARSE_FORECAST(CFORECAST => BLOB2CLOB(LBDATA => C.BFORECAST), NFORECAST => C.NFORECAST); + /* Формируем данные карточки прогноза для конкретного тех. объекта */ + UDO_PKG_EQUIPTCF.EQCONFIG_THOBJ_FORECAST_CRD(NEQCONFIG => NEQCONFIG, + DFORECAST_DATE => C.DRQ_DATE, + NFORECAST => C.NFORECAST, + SDICMUNTS => C.SDICMUNTS, + STASK => C.SEQUIPDSCMML_TASK, + COUT => C.STO_FORECAST); + /* Извлекаем прогноз и цвет для видимой колонки таблицы из карточки прогноза для конкретного тех. объекта */ + UDO_PKG_EQUIPTCF.EQCONFIG_THOBJ_FORECAST_CRDP(CFORECAST => C.STO_FORECAST, + SFORECAST_DESC => C.STO_FORECAST_DESC, + SFORECAST_DESC_COLOR => C.STO_FORECAST_DESC_COLOR); /* Добавляем колонки с данными */ 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 => 'SRQ_AUTHID', SVALUE => C.SRQ_AUTHID); @@ -992,8 +1019,11 @@ text="Проверка прав доступа на работу с ""Выбор PKG_P8PANELS_VISUAL.TROW_ADD_COL(RROW => RDG_ROW, SNAME => 'NEQUIPDSCMML_PRECISION_F', NVALUE => C.NEQUIPDSCMML_PRECISION_F); - PKG_P8PANELS_VISUAL.TROW_ADD_COL(RROW => RDG_ROW, SNAME => 'NFORECAST', NVALUE => C.NFORECAST); - PKG_P8PANELS_VISUAL.TROW_ADD_COL(RROW => RDG_ROW, SNAME => 'SFORECAST', SVALUE => C.SFORECAST); + PKG_P8PANELS_VISUAL.TROW_ADD_COL(RROW => RDG_ROW, SNAME => 'STO_FORECAST_DESC', SVALUE => C.STO_FORECAST_DESC); + PKG_P8PANELS_VISUAL.TROW_ADD_COL(RROW => RDG_ROW, + SNAME => 'STO_FORECAST_DESC_COLOR', + SVALUE => C.STO_FORECAST_DESC_COLOR); + PKG_P8PANELS_VISUAL.TROW_ADD_COL(RROW => RDG_ROW, SNAME => 'STO_FORECAST', SVALUE => C.STO_FORECAST); /* Добавляем строку в таблицу */ PKG_P8PANELS_VISUAL.TDATA_GRID_ADD_ROW(RDATA_GRID => RDG, RROW => RDG_ROW); end loop; diff --git a/db/UDO_PKG_EQUIPDS_BASE.pck b/db/UDO_PKG_EQUIPDS_BASE.pck index 1919b93..568c4f4 100644 --- a/db/UDO_PKG_EQUIPDS_BASE.pck +++ b/db/UDO_PKG_EQUIPDS_BASE.pck @@ -189,6 +189,12 @@ create or replace package UDO_PKG_EQUIPDS_BASE as SERR in varchar2 -- Сообщение об ошибке ); + /* Формирование наименования для задачи "Выборки данных оборудования (классы оборудования, модели)" */ + function CMML_TASK_NAME + ( + STASK in varchar2 -- Задача (TCF - оценка технического состояния (Technical Condition Forecast), RUL - прогнозирование остаточного ресурса (Remaining Useful Life), FP - Прогнозирование отказа (Failure Predict)) */ + ) return varchar2; -- Наименование задачи + /* Формирование подсказки для задачи "Выборки данных оборудования (классы оборудования, модели)" */ function CMML_TASK_HINT return varchar2; -- Подсказка для задачи @@ -687,12 +693,33 @@ create or replace package body UDO_PKG_EQUIPDS_BASE as where T.RN = NRN; end CMML_SET_STATUS; + /* Формирование наименования для задачи "Выборки данных оборудования (классы оборудования, модели)" */ + function CMML_TASK_NAME + ( + STASK in varchar2 -- Задача (TCF - оценка технического состояния (Technical Condition Forecast), RUL - прогнозирование остаточного ресурса (Remaining Useful Life), FP - Прогнозирование отказа (Failure Predict)) */ + ) return varchar2 -- Наименование задачи + is + begin + case STASK + when 'TCF' then + return 'Оценка технического состояния'; + when 'RUL' then + return 'Прогноз остаточного ресурса'; + when 'FP' then + return 'Прогноз отказа'; + else + return 'Вид задачи оценки не поддерживается'; + end case; + end CMML_TASK_NAME; + /* Формирование подсказки для задачи "Выборки данных оборудования (классы оборудования, модели)" */ function CMML_TASK_HINT return varchar2 -- Подсказка для задачи is begin - return 'TCF - Оценка технического состояния (Technical Condition Forecast)
' || 'RUL - Прогнозирование остаточного ресурса (Remaining Useful Life)
' || 'FP - Прогнозирование отказа (Failure Predict)'; + return 'TCF - ' || CMML_TASK_NAME(STASK => 'TCF') || ' (Technical Condition Forecast)
' || + 'RUL - ' || CMML_TASK_NAME(STASK => 'RUL') || ' (Remaining Useful Life)
' || + 'FP - ' || CMML_TASK_NAME(STASK => 'FP') || ' (Failure Predict)'; end CMML_TASK_HINT; /* Базовое добавление "Выборки данных оборудования (классы оборудования, модели, история запросов)" */ diff --git a/db/UDO_PKG_EQUIPTCF.pck b/db/UDO_PKG_EQUIPTCF.pck index 382df1c..8d22dbf 100644 --- a/db/UDO_PKG_EQUIPTCF.pck +++ b/db/UDO_PKG_EQUIPTCF.pck @@ -22,6 +22,13 @@ create or replace package UDO_PKG_EQUIPTCF as COUT out clob -- Сериализованная таблица данных ); + /* Получение даты следующего технического обслуживания технического объекта */ + function EQCONFIG_THOBJ_GET_NXTEQTCHSRV + ( + NEQCONFIG in number, -- Рег. номер технического объекта + NSTATE in number := null -- Состояние (null - любое) + ) return date; -- Дата следующего технического обслуживания + /* Выбор графиков технического обслуживания и ремонта технического объекта */ procedure EQCONFIG_THOBJ_SELECT_EQTCHSRV ( @@ -31,6 +38,22 @@ create or replace package UDO_PKG_EQUIPTCF as NIDENT out number -- Идентификатор списка ); + /* Получение даты следующего ремонта по ремонтной ведомости технического объекта */ + function EQCONFIG_THOBJ_GET_NXTEQRPSHT + ( + NEQCONFIG in number, -- Рег. номер технического объекта + NSTATE in number := null -- Состояние (null - любое) + ) return date; -- Дата следующего ремонта по ведомости + + /* Выбор ремонтных ведомостей технического объекта */ + procedure EQCONFIG_THOBJ_SELECT_EQRPSHT + ( + NEQRPSHEETS in number := null, -- Рег. номер ремонтной ведосочти (null - любой) + NEQCONFIG in number := null, -- Рег. номер технического объекта (null - любой) + NSTATE in number := null, -- Состояние (null - любое) + NIDENT out number -- Идентификатор списка + ); + /* Формирование карточки технического объекта */ procedure EQCONFIG_THOBJ_CARD ( @@ -45,6 +68,38 @@ create or replace package UDO_PKG_EQUIPTCF as NEQUIPDSCMML in number -- Рег. номер модели ); + /* Формирование цвета прогноза для технического объекта */ + function EQCONFIG_THOBJ_FORECAST_CLR + ( + NMODE in number := 0, -- Режим работы (0 - для подсказки в колонке таблицы, 1 - для колонки таблицы, 2 - для карточки детализации + NVALUE in number :=0 -- Значение для подсветки + ) return varchar2; -- Запрошенное значение в зависимости от режима + + /* Формирование детальной карточки прогноза для технического объекта */ + procedure EQCONFIG_THOBJ_FORECAST_CRD + ( + NEQCONFIG in number, -- Рег. номер позиции состава оборудования + DFORECAST_DATE in date, -- Дата получения прогноза + NFORECAST in number, -- Прогнозное значение, полученное от фреймворка + SDICMUNTS in varchar2, -- Единица измерения выборки + STASK in varchar2, -- Задача (TCF - оценка технического состояния (Technical Condition Forecast), RUL - прогнозирование остаточного ресурса (Remaining Useful Life), FP - Прогнозирование отказа (Failure Predict)) */ + COUT out clob -- Данные детальной карточки прогноза + ); + + /* Извлечение сведений из детальной карточки прогноза для технического объекта */ + procedure EQCONFIG_THOBJ_FORECAST_CRDP + ( + CFORECAST in clob, -- Данные детальной карточки прогноза + SFORECAST_DESC out varchar2, -- Описание прогноза + SFORECAST_DESC_COLOR out varchar2 -- Цвет заливки прогноза + ); + + /* Вероятность выхода единицы оборудования из строя с учётом графика ТО и ремонтов и RUL-прогноза */ + function EQCONFIG_THOBJ_TCHSRV_BRKDPROB + ( + NEQCONFIG in number -- Рег. номер технического объекта + ) return number; -- Вероятность выхода из строя + /* Модификация графика ТО и ремонтов для технического объекта */ procedure EQCONFIG_THOBJ_CHNG_EQTCHSRV ( @@ -62,7 +117,7 @@ create or replace package UDO_PKG_EQUIPTCF as DPLANDATE_FROM in date, -- Плановая дата начала ремонта NIDENT out number -- Идентификатор списка сформированных ведомостей ); - + end UDO_PKG_EQUIPTCF; / create or replace package body UDO_PKG_EQUIPTCF as @@ -197,6 +252,30 @@ text="Проверка прав доступа при формировании PKG_COND_BROKER.BIND_VARIABLE(SVARIABLE_NAME => 'NCMML_STATUS', SVALUE => PKG_COND_BROKER.GET_CONDITION_NUM(SCONDITION_NAME => 'NCMML_STATUSFrom')); end if; + /* Вероятность выхода из строя */ + if ((PKG_COND_BROKER.CONDITION_EXISTS(SCONDITION_NAME => 'NBREAKDOWN_PROBFrom') = 1) and + (PKG_COND_BROKER.CONDITION_EXISTS(SCONDITION_NAME => 'NBREAKDOWN_PROBTo') = 0)) then + PKG_COND_BROKER.ADD_CLAUSE(SCLAUSE => PKG_SQL_BUILD.PKG_NAME(SNAME => 'UDO_PKG_EQUIPTCF.EQCONFIG_THOBJ_TCHSRV_BRKDPROB') || + '(RN) >= :NBREAKDOWN_PROBFrom'); + PKG_COND_BROKER.BIND_VARIABLE(SVARIABLE_NAME => 'NBREAKDOWN_PROBFrom', + NVALUE => PKG_COND_BROKER.GET_CONDITION_NUM(SCONDITION_NAME => 'NBREAKDOWN_PROBFrom')); + end if; + if ((PKG_COND_BROKER.CONDITION_EXISTS(SCONDITION_NAME => 'NBREAKDOWN_PROBTo') = 1) and + (PKG_COND_BROKER.CONDITION_EXISTS(SCONDITION_NAME => 'NBREAKDOWN_PROBFrom') = 0)) then + PKG_COND_BROKER.ADD_CLAUSE(SCLAUSE => PKG_SQL_BUILD.PKG_NAME(SNAME => 'UDO_PKG_EQUIPTCF.EQCONFIG_THOBJ_TCHSRV_BRKDPROB') || + '(RN) <= :NBREAKDOWN_PROBTo'); + PKG_COND_BROKER.BIND_VARIABLE(SVARIABLE_NAME => 'NBREAKDOWN_PROBTo', + NVALUE => PKG_COND_BROKER.GET_CONDITION_NUM(SCONDITION_NAME => 'NBREAKDOWN_PROBTo')); + end if; + if ((PKG_COND_BROKER.CONDITION_EXISTS(SCONDITION_NAME => 'NBREAKDOWN_PROBFrom') = 1) and + (PKG_COND_BROKER.CONDITION_EXISTS(SCONDITION_NAME => 'NBREAKDOWN_PROBTo') = 1)) then + PKG_COND_BROKER.ADD_CLAUSE(SCLAUSE => PKG_SQL_BUILD.PKG_NAME(SNAME => 'UDO_PKG_EQUIPTCF.EQCONFIG_THOBJ_TCHSRV_BRKDPROB') || + '(RN) between :NBREAKDOWN_PROBFrom and :NBREAKDOWN_PROBTo'); + PKG_COND_BROKER.BIND_VARIABLE(SVARIABLE_NAME => 'NBREAKDOWN_PROBFrom', + NVALUE => PKG_COND_BROKER.GET_CONDITION_NUM(SCONDITION_NAME => 'NBREAKDOWN_PROBFrom')); + PKG_COND_BROKER.BIND_VARIABLE(SVARIABLE_NAME => 'NBREAKDOWN_PROBTo', + NVALUE => PKG_COND_BROKER.GET_CONDITION_NUM(SCONDITION_NAME => 'NBREAKDOWN_PROBTo')); + end if; end EQCONFIG_THOBJ_LIST_COND; /* Формирование списка технических объектов для выбранного узла состава оборудования */ @@ -222,6 +301,7 @@ text="Проверка прав доступа при формировании NROW_TO PKG_STD.TREF; -- Номер строки по CSQL clob; -- Буфер для запроса ICURSOR integer; -- Курсор для исполнения запроса + NBREAKDOWN_PROB PKG_STD.TNUMBER; -- Вероятность выхода единицы оборудования из строя begin /* Читаем фильтры */ RF := PKG_P8PANELS_VISUAL.TFILTERS_FROM_XML(CFILTERS => CFILTERS); @@ -295,6 +375,18 @@ text="Проверка прав доступа при формировании BORDER => true, BFILTER => true, RCOL_VALS => RCOL_VALS); + PKG_P8PANELS_VISUAL.TDATA_GRID_ADD_COL_DEF(RDATA_GRID => RDG, + SNAME => 'NBREAKDOWN_PROB', + SCAPTION => 'Вероятность выхода из строя', + SDATA_TYPE => PKG_P8PANELS_VISUAL.SDATA_TYPE_NUMB, + BORDER => true, + BFILTER => true, + SHINT => EQCONFIG_THOBJ_FORECAST_CLR(NMODE => 0)); + PKG_P8PANELS_VISUAL.TDATA_GRID_ADD_COL_DEF(RDATA_GRID => RDG, + SNAME => 'SBREAKDOWN_PROB_COLOR', + SCAPTION => 'Цвет вероятности выхода из строя', + SDATA_TYPE => PKG_P8PANELS_VISUAL.SDATA_TYPE_STR, + BVISIBLE => false); /* Обходим данные */ begin /* Добавляем подсказку совместимости */ @@ -312,10 +404,11 @@ text="Проверка прав доступа при формировании PKG_SQL_BUILD.APPEND(SSQL => CSQL, SELEMENT1 => ' OK.NAME SOBJ_KIND,'); PKG_SQL_BUILD.APPEND(SSQL => CSQL, SELEMENT1 => ' FORMAT_HIER_NAME(OK.COMPANY, null, OK.FULLCODE) SOBJ_KIND_FULL_CODE,'); PKG_SQL_BUILD.APPEND(SSQL => CSQL, SELEMENT1 => ' DM.MEAS_MNEMO SUMEAS_RES,'); - PKG_SQL_BUILD.APPEND(SSQL => CSQL, SELEMENT1 => PKG_SQL_BUILD.PKG_NAME(SNAME => 'UDO_PKG_EQUIPDS.CMML_STATUS_BY_EQCONFIG') || '(C.RN) NCMML_STATUS'); + PKG_SQL_BUILD.APPEND(SSQL => CSQL, SELEMENT1 => PKG_SQL_BUILD.PKG_NAME(SNAME => 'UDO_PKG_EQUIPDS.CMML_STATUS_BY_EQCONFIG') || '(C.RN) NCMML_STATUS,'); + PKG_SQL_BUILD.APPEND(SSQL => CSQL, SELEMENT1 => PKG_SQL_BUILD.PKG_NAME(SNAME => 'UDO_PKG_EQUIPTCF.EQCONFIG_THOBJ_TCHSRV_BRKDPROB') || '(C.RN) NBREAKDOWN_PROB'); PKG_SQL_BUILD.APPEND(SSQL => CSQL, SELEMENT1 => ' from EQCONFIG C'); 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 DICMUNTS DM on C.UMEAS_RES = DM.RN,'); + PKG_SQL_BUILD.APPEND(SSQL => CSQL, SELEMENT1 => ' left outer join DICMUNTS DM on C.UMEAS_RES = DM.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'); @@ -350,6 +443,7 @@ text="Проверка прав доступа при формировании PKG_SQL_DML.DEFINE_COLUMN_STR(ICURSOR => ICURSOR, IPOSITION => 9); PKG_SQL_DML.DEFINE_COLUMN_NUM(ICURSOR => ICURSOR, IPOSITION => 10); PKG_SQL_DML.DEFINE_COLUMN_NUM(ICURSOR => ICURSOR, IPOSITION => 11); + PKG_SQL_DML.DEFINE_COLUMN_NUM(ICURSOR => ICURSOR, IPOSITION => 12); /* Делаем выборку */ if (PKG_SQL_DML.EXECUTE(ICURSOR => ICURSOR) = 0) then null; @@ -388,11 +482,16 @@ text="Проверка прав доступа при формировании PKG_P8PANELS_VISUAL.TROW_ADD_CUR_COLS(RROW => RDG_ROW, SNAME => 'SUMEAS_RES', ICURSOR => ICURSOR, - NPOSITION => 9); + NPOSITION => 9); PKG_P8PANELS_VISUAL.TROW_ADD_CUR_COLN(RROW => RDG_ROW, SNAME => 'NCMML_STATUS', ICURSOR => ICURSOR, NPOSITION => 10); + PKG_SQL_DML.COLUMN_VALUE_NUM(ICURSOR => ICURSOR, IPOSITION => 11, NVALUE => NBREAKDOWN_PROB); + PKG_P8PANELS_VISUAL.TROW_ADD_COL(RROW => RDG_ROW, SNAME => 'NBREAKDOWN_PROB', NVALUE => NBREAKDOWN_PROB); + PKG_P8PANELS_VISUAL.TROW_ADD_COL(RROW => RDG_ROW, + SNAME => 'SBREAKDOWN_PROB_COLOR', + SVALUE => EQCONFIG_THOBJ_FORECAST_CLR(NMODE => 1, NVALUE => NBREAKDOWN_PROB)); /* Добавляем строку в таблицу */ PKG_P8PANELS_VISUAL.TDATA_GRID_ADD_ROW(RDATA_GRID => RDG, RROW => RDG_ROW); end loop; @@ -416,7 +515,7 @@ text="Проверка прав доступа при формировании is DRES PKG_STD.TLDATE; -- Буфер для результата begin - /* Найдем график ТО и ремонтов, утвержденный, с минимальной датой по данному тех. объекту */ + /* Найдем график ТО и ремонтов, в заданном состоянии, с минимальной датой по данному тех. объекту */ select min(T.DATEPRD_BEG) into DRES from EQTCHSRV T @@ -458,6 +557,57 @@ text="Проверка прав доступа при формировании end loop; end EQCONFIG_THOBJ_SELECT_EQTCHSRV; + /* Получение даты следующего ремонта по ремонтной ведомости технического объекта */ + function EQCONFIG_THOBJ_GET_NXTEQRPSHT + ( + NEQCONFIG in number, -- Рег. номер технического объекта + NSTATE in number := null -- Состояние (null - любое) + ) return date -- Дата следующего ремонта по ведомости + is + DRES PKG_STD.TLDATE; -- Буфер для результата + begin + /* Найдем график ТО и ремонтов, в заданном состоянии, с минимальной датой по данному тех. объекту */ + select min(T.DATEPLAN_BEG) + into DRES + from EQRPSHEETS T + where T.EQCONFIG = NEQCONFIG + and ((NSTATE is null) or ((NSTATE is not null) and (T.STATE = NSTATE))) + and T.DATEPLAN_BEG >= sysdate; + /* Вернём результат */ + return DRES; + exception + when others then + return null; + end EQCONFIG_THOBJ_GET_NXTEQRPSHT; + + /* Выбор ремонтных ведомостей технического объекта */ + procedure EQCONFIG_THOBJ_SELECT_EQRPSHT + ( + NEQRPSHEETS in number := null, -- Рег. номер ремонтной ведосочти (null - любой) + NEQCONFIG in number := null, -- Рег. номер технического объекта (null - любой) + NSTATE in number := null, -- Состояние (null - любое) + NIDENT out number -- Идентификатор списка + ) + is + NTMP PKG_STD.TREF; -- Рег. номер записи буфера отобранных + begin + /* Обходим графики по тех. объекту */ + for C in (select T.RN + from EQRPSHEETS T + where ((NEQRPSHEETS is null) or ((NEQRPSHEETS is not null) and (T.RN = NEQRPSHEETS))) + and ((NEQCONFIG is null) or ((NEQCONFIG is not null) and (T.EQCONFIG = NEQCONFIG))) + and ((NEQRPSHEETS is not null) or ((NEQRPSHEETS is null) and (T.DATEPLAN_BEG >= sysdate))) + and ((NSTATE is null) or ((NSTATE is not null) and (T.STATE = NSTATE)))) + loop + /* Формируем идентификатор списка если необходимо */ + if (NIDENT is null) then + NIDENT := GEN_IDENT(); + end if; + /* Добавляем отобранное в список */ + P_SELECTLIST_INSERT(NIDENT => NIDENT, NDOCUMENT => C.RN, SUNITCODE => 'EquipRepairSheets', NRN => NTMP); + end loop; + end EQCONFIG_THOBJ_SELECT_EQRPSHT; + /* Формирование карточки технического объекта */ procedure EQCONFIG_THOBJ_CARD ( @@ -503,6 +653,10 @@ text="Проверка прав доступа при формировании SVALUE => TO_CHAR(EQCONFIG_THOBJ_GET_NXTEQTCHSRV(NEQCONFIG => C.NRN), 'dd.mm.yyyy hh24:mi:ss')), RATTRIBUTE05 => PKG_XMAKE.ATTRIBUTE(ICURSOR => NCUR, + SNAME => 'DNEXT_EQRPSHEET', + SVALUE => TO_CHAR(EQCONFIG_THOBJ_GET_NXTEQRPSHT(NEQCONFIG => C.NRN), + 'dd.mm.yyyy hh24:mi:ss')), + RATTRIBUTE06 => PKG_XMAKE.ATTRIBUTE(ICURSOR => NCUR, SNAME => 'SEQOBJKIND', SVALUE => C.SEQOBJKIND))); end loop; @@ -537,13 +691,282 @@ text="Проверка прав доступа при формировании BRQ => null, NRN => NEQUIPDSCMMLH); /* Добавим демо-данные */ - for C in (select T.TASK from UDO_T_EQUIPDSCMML T where T.RN = NEQUIPDSCMML) + for C in (select T.TASK STASK, + DM.MEAS_MNEMO SDICMUNTS + from UDO_T_EQUIPDSCMML T, + UDO_T_EQUIPDSCM CM, + DICMUNTS DM + where T.RN = NEQUIPDSCMML + and T.PRN = CM.RN + and CM.DICMUNTS = DM.RN) loop - UDO_PKG_EQUIPDS.CMMLH_DEMO_BUILD(STASK => C.TASK, COUT => CDEMO); + UDO_PKG_EQUIPDS.CMMLH_BUILD_FORECAST(COUT => CDEMO); UDO_PKG_EQUIPDS_BASE.CMMLH_SET_FORECAST(NRN => NEQUIPDSCMMLH, BFORECAST => CLOB2BLOB(LCDATA => CDEMO)); end loop; end EQCONFIG_THOBJ_FORECAST; + /* Формирование цвета прогноза для технического объекта */ + function EQCONFIG_THOBJ_FORECAST_CLR + ( + NMODE in number := 0, -- Режим работы (0 - для подсказки в колонке таблицы, 1 - для колонки таблицы, 2 - для карточки детализации + NVALUE in number :=0 -- Значение для подсветки + ) return varchar2 -- Запрошенное значение в зависимости от режима + is + begin + /* Работаем от режима */ + case NMODE + /* Для подсказки в колонке таблицы */ + when 0 then + return 'Опасность - вероятность сбоя более 60%.
' || 'Внимание - вероятность сбоя от 30% до 60%
' || 'В норме - вероятность сбоев менее 30%'; + /* Для колонки таблицы */ + when 1 then + begin + if (NVALUE < 30) then + return 'success'; + else + if ((NVALUE >= 30) and (NVALUE < 60)) then + return 'warning'; + else + return 'error'; + end if; + end if; + end; + /* Для карточки детализации */ + when 2 then + begin + if (NVALUE < 30) then + return 'success.main'; + else + if ((NVALUE >= 30) and (NVALUE < 60)) then + return 'warning.main'; + else + return 'error.main'; + end if; + end if; + end; + /* Неверный режим */ + else + return null; + end case; + end EQCONFIG_THOBJ_FORECAST_CLR; + + /* Формирование детальной карточки прогноза для технического объекта */ + procedure EQCONFIG_THOBJ_FORECAST_CRD + ( + NEQCONFIG in number, -- Рег. номер позиции состава оборудования + DFORECAST_DATE in date, -- Дата получения прогноза + NFORECAST in number, -- Прогнозное значение, полученное от фреймворка + SDICMUNTS in varchar2, -- Единица измерения выборки + STASK in varchar2, -- Задача (TCF - оценка технического состояния (Technical Condition Forecast), RUL - прогнозирование остаточного ресурса (Remaining Useful Life), FP - Прогнозирование отказа (Failure Predict)) */ + COUT out clob -- Данные детальной карточки прогноза + ) + is + NCUR integer; -- Курсор документа для результата + XDOC PKG_XMAKE.TNODE; -- Документ для результата + XROOT PKG_XMAKE.TNODE; -- Содержимое корневого узла документа + RCH PKG_P8PANELS_VISUAL.TCHART; -- График + RCH_DS PKG_P8PANELS_VISUAL.TCHART_DATASET; -- Набор данных + CCHART clob; -- Сериализованный график + NBREAKDOWN_PROB PKG_STD.TNUMBER; -- Вероятность выхода из строя + NBREAKDOWN_PROB_CUR PKG_STD.TNUMBER; -- Вероятность выхода из строя (для текущей позиции графика ТО и ремонтов) + DNEXT_REPAIR PKG_STD.TLDATE; -- Дата ближайшего ТО и ремонта + begin + /* Вычислим вероятность выхода из строя до даты ближайшего ТО с учётом прогноза */ + DNEXT_REPAIR := UDO_PKG_EQUIPTCF.EQCONFIG_THOBJ_GET_NXTEQTCHSRV(NEQCONFIG => NEQCONFIG); + if (DNEXT_REPAIR is null) then + NBREAKDOWN_PROB := 100; + else + if (sysdate + NFORECAST > DNEXT_REPAIR) then + NBREAKDOWN_PROB := 0; + end if; + end if; + /* Открываем документ */ + NCUR := PKG_XMAKE.OPEN_CURSOR(); + /* Заполним единицу измерения */ + XROOT := PKG_XMAKE.CONCAT(ICURSOR => NCUR, + RNODE00 => XROOT, + RNODE01 => PKG_XMAKE.ELEMENT(ICURSOR => NCUR, + SNAME => 'SDICMUNTS', + RVALUE00 => PKG_XMAKE.VALUE(ICURSOR => NCUR, SVALUE => SDICMUNTS))); + /* Заполним прогноз */ + XROOT := PKG_XMAKE.CONCAT(ICURSOR => NCUR, + RNODE00 => XROOT, + RNODE01 => PKG_XMAKE.ELEMENT(ICURSOR => NCUR, + SNAME => 'NFORECAST', + RVALUE00 => PKG_XMAKE.VALUE(ICURSOR => NCUR, NVALUE => NFORECAST))); + /* Заполним код задачи прогнозирования */ + XROOT := PKG_XMAKE.CONCAT(ICURSOR => NCUR, + RNODE00 => XROOT, + RNODE01 => PKG_XMAKE.ELEMENT(ICURSOR => NCUR, + SNAME => 'STASK', + RVALUE00 => PKG_XMAKE.VALUE(ICURSOR => NCUR, SVALUE => STASK))); + /* Заполним наименование задачи прогнозирования */ + XROOT := PKG_XMAKE.CONCAT(ICURSOR => NCUR, + RNODE00 => XROOT, + RNODE01 => PKG_XMAKE.ELEMENT(ICURSOR => NCUR, + SNAME => 'STASK_NAME', + RVALUE00 => PKG_XMAKE.VALUE(ICURSOR => NCUR, + SVALUE => UDO_PKG_EQUIPDS_BASE.CMML_TASK_NAME(STASK => STASK)))); + /* Заполним дату следующего ТО и ремонта */ + XROOT := PKG_XMAKE.CONCAT(ICURSOR => NCUR, + RNODE00 => XROOT, + RNODE01 => PKG_XMAKE.ELEMENT(ICURSOR => NCUR, + SNAME => 'DNEXT_REPAIR', + RVALUE00 => PKG_XMAKE.VALUE(ICURSOR => NCUR, + DVALUE => DNEXT_REPAIR))); + /* Если есть запланированные графики ТО и ремонта */ + if (DNEXT_REPAIR is not null) then + /* Строим график вероятностей выхода из строя опираясь на них */ + RCH := PKG_P8PANELS_VISUAL.TCHART_MAKE(STYPE => PKG_P8PANELS_VISUAL.SCHART_TYPE_LINE, + STITLE => 'Прогноз с учётом графика ТО и ремонтов', + SLGND_POS => PKG_P8PANELS_VISUAL.SCHART_LGND_POS_TOP); + /* Сформируем набор данных */ + RCH_DS := PKG_P8PANELS_VISUAL.TCHART_DATASET_MAKE(SCAPTION => 'Вероятность перехода в критическое состояние (%)'); + /* Обходим ближайшие 5 позиций графика ТО и ремонтов */ + for C in (select ROWNUM, + D.SEQTCHSRV, + D.DDATEPRD_BEG + from (select trim(COALESCE(K.CODE, ' ') || ' ' || TO_CHAR(T.DATEPRD_BEG, 'dd.mm.yyyy')) SEQTCHSRV, + T.DATEPRD_BEG DDATEPRD_BEG + from EQTCHSRV T, + EQTECSRVKIND K + where T.EQCONFIG_TECH = NEQCONFIG + and T.DATEPRD_BEG >= sysdate + and T.EQTECSRVKIND = K.RN(+) + order by T.DATEPRD_BEG) D + where ROWNUM <= 5) + loop + /* Добавим метку для графика */ + PKG_P8PANELS_VISUAL.TCHART_ADD_LABEL(RCHART => RCH, SLABEL => C.SEQTCHSRV); + /* Добавим график в набор данных */ + if (sysdate + NFORECAST > C.DDATEPRD_BEG) then + NBREAKDOWN_PROB_CUR := 0; + else + NBREAKDOWN_PROB_CUR := 100 - ROUND((NFORECAST - (TRUNC(sysdate) - TRUNC(DFORECAST_DATE))) / + (C.DDATEPRD_BEG - sysdate) * 100); + if (NBREAKDOWN_PROB_CUR > 100) then + NBREAKDOWN_PROB_CUR := 100; + end if; + if (NBREAKDOWN_PROB is null) then + NBREAKDOWN_PROB := NBREAKDOWN_PROB_CUR; + end if; + end if; + PKG_P8PANELS_VISUAL.TCHART_DATASET_ADD_ITEM(RDATASET => RCH_DS, NVALUE => NBREAKDOWN_PROB_CUR); + end loop; + /* Добавим набор данных в график */ + PKG_P8PANELS_VISUAL.TCHART_ADD_DATASET(RCHART => RCH, RDATASET => RCH_DS); + /* Сериализуем график */ + CCHART := PKG_P8PANELS_VISUAL.TCHART_TO_XML(RCHART => RCH, NINCLUDE_DEF => 1); + end if; + /* Заполним вероятность выхода из стороя до ближайшего ТО с учётом прогноза */ + XROOT := PKG_XMAKE.CONCAT(ICURSOR => NCUR, + RNODE00 => XROOT, + RNODE01 => PKG_XMAKE.ELEMENT(ICURSOR => NCUR, + SNAME => 'NBREAKDOWN_PROB', + RVALUE00 => PKG_XMAKE.VALUE(ICURSOR => NCUR, + NVALUE => NBREAKDOWN_PROB))); + /* Заполним цвет вероятности выхода из стороя до ближайшего ТО с учётом прогноза */ + XROOT := PKG_XMAKE.CONCAT(ICURSOR => NCUR, + RNODE00 => XROOT, + RNODE01 => PKG_XMAKE.ELEMENT(ICURSOR => NCUR, + SNAME => 'SBREAKDOWN_PROB_COLOR', + RVALUE00 => PKG_XMAKE.VALUE(ICURSOR => NCUR, + SVALUE => EQCONFIG_THOBJ_FORECAST_CLR(NMODE => 2, + NVALUE => NBREAKDOWN_PROB)))); + /* Добавляем график в ответ */ + XROOT := PKG_XMAKE.CONCAT(ICURSOR => NCUR, + RNODE00 => XROOT, + RNODE01 => PKG_XMAKE.ELEMENT(ICURSOR => NCUR, + SNAME => 'XCHART', + RVALUE00 => PKG_XMAKE.VALUE(ICURSOR => NCUR, LCVALUE => CCHART))); + /* Формируем XML-представление ответа */ + XDOC := PKG_XMAKE.ELEMENT(ICURSOR => NCUR, SNAME => 'XDATA', RNODE00 => XROOT); + /* Конвертируем в 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 EQCONFIG_THOBJ_FORECAST_CRD; + + /* Извлечение сведений из детальной карточки прогноза для технического объекта */ + procedure EQCONFIG_THOBJ_FORECAST_CRDP + ( + CFORECAST in clob, -- Данные детальной карточки прогноза + SFORECAST_DESC out varchar2, -- Описание прогноза + SFORECAST_DESC_COLOR out varchar2 -- Цвет заливки прогноза + ) + is + XDOC PKG_XPATH.TDOCUMENT; -- Десериализованный демо-прогноз + XROOT PKG_XPATH.TNODE; -- Корневой элемент данных + SDICMUNTS PKG_STD.TSTRING; -- Единица измерения выборки + NFORECAST PKG_STD.TNUMBER; -- Прогноз по заданной задаче + NBREAKDOWN_PROB PKG_STD.TNUMBER; -- Вероятность выхода из строя + begin + /* Разбираем демо-даные */ + XDOC := PKG_XPATH.PARSE_FROM_CLOB(LCXML => CFORECAST); + /* Извлекаем корневой элемент */ + XROOT := PKG_XPATH.ROOT_NODE(RDOCUMENT => XDOC); + /* Читаем единицу измерения */ + SDICMUNTS := PKG_XPATH.VALUE(RNODE => PKG_XPATH.SINGLE_NODE(RPARENT_NODE => XROOT, SPATTERN => 'XDATA/SDICMUNTS')); + /* Читаем прогноз */ + NFORECAST := PKG_XPATH.VALUE_NUM(RNODE => PKG_XPATH.SINGLE_NODE(RPARENT_NODE => XROOT, SPATTERN => 'XDATA/NFORECAST')); + /* Читаем вероятность выхода из строя */ + NBREAKDOWN_PROB := PKG_XPATH.VALUE_NUM(RNODE => PKG_XPATH.SINGLE_NODE(RPARENT_NODE => XROOT, + SPATTERN => 'XDATA/NBREAKDOWN_PROB')); + /* Проноз есть */ + if (NFORECAST is not null) then + /* Возвращаем значение описания */ + SFORECAST_DESC := TO_CHAR(ROUND(NFORECAST)) || SDICMUNTS || ' / ' || TO_CHAR(ROUND(NBREAKDOWN_PROB)) || '%'; + /* Возвращаем значение цвета заливки описания прогноза */ + SFORECAST_DESC_COLOR := EQCONFIG_THOBJ_FORECAST_CLR(NMODE => 1, NVALUE => NBREAKDOWN_PROB); + end if; + exception + when others then + null; + end EQCONFIG_THOBJ_FORECAST_CRDP; + + /* Вероятность выхода единицы оборудования из строя с учётом графика ТО и ремонтов и RUL-прогноза */ + function EQCONFIG_THOBJ_TCHSRV_BRKDPROB + ( + NEQCONFIG in number -- Рег. номер технического объекта + ) return number -- Вероятность выхода из строя + is + NRES PKG_STD.TNUMBER; -- Буфер для результата + DFORECAST_DATE PKG_STD.TLDATE; + NFORECAST PKG_STD.TNUMBER; -- Значение самго свежего прогноза модели + DNXTEQTCHSRV PKG_STD.TLDATE; -- Дата ближайшего ТО или ремонта + begin + /* Определим дату ближайшего ТО или ремонта */ + DNXTEQTCHSRV := EQCONFIG_THOBJ_GET_NXTEQTCHSRV(NEQCONFIG => NEQCONFIG); + /* Если дата есть */ + if (DNXTEQTCHSRV is not null) then + /* Вынем самый свежий прогноз */ + for C in (select T.RQ_DATE DFORECAST_DATE, + T.FORECAST + from UDO_T_EQUIPDSCMMLH T, + UDO_T_EQUIPDSCMML CMML + where T.EQCONFIG = NEQCONFIG + and T.PRN = CMML.RN + and CMML.TASK = 'RUL' + order by T.RQ_DATE desc) + loop + DFORECAST_DATE := C.DFORECAST_DATE; + UDO_PKG_EQUIPDS.CMMLH_PARSE_FORECAST(CFORECAST => BLOB2CLOB(LBDATA => C.FORECAST), NFORECAST => NFORECAST); + exit; + end loop; + /* Если есть и прогноз */ + if (NFORECAST is not null) then + NRES := 100 - ROUND((NFORECAST - (TRUNC(sysdate) - TRUNC(DFORECAST_DATE))) / (DNXTEQTCHSRV - sysdate) * 100); + end if; + end if; + /* Вернём то, что собрали */ + return NRES; + end EQCONFIG_THOBJ_TCHSRV_BRKDPROB; + /* Модификация графика ТО и ремонтов для технического объекта */ procedure EQCONFIG_THOBJ_CHNG_EQTCHSRV ( @@ -591,6 +1014,10 @@ text="Проверка прав доступа при формировании 'Выбранный график ТО и ремонтов уже запланирован на %s', TO_CHAR(DPLANDATE_FROM, 'dd.mm.yyyy')); end if; + /* Сбросим состояние графика */ + if (REQTCHSRV.STATE <> 0) then + P_EQTCHSRV_SET_STATE(NCOMPANY => REQTCHSRV.COMPANY, NRN => REQTCHSRV.RN, NSTATE => 0, DDATE => sysdate); + end if; /* Определим отклонение и новые даты графика */ NDIFF := DPLANDATE_FROM - REQTCHSRV.DATEPRD_BEG; DDATEPRD_BEG := REQTCHSRV.DATEPRD_BEG + NDIFF; @@ -615,6 +1042,13 @@ text="Проверка прав доступа при формировании DDATEPRD_END => DDATEPRD_END, NPERIOD => null, NMODE => 1); + /* Восстановим состояние графика */ + if (REQTCHSRV.STATE <> 0) then + P_EQTCHSRV_SET_STATE(NCOMPANY => REQTCHSRV.COMPANY, + NRN => REQTCHSRV.RN, + NSTATE => REQTCHSRV.STATE, + DDATE => sysdate); + end if; end EQCONFIG_THOBJ_CHNG_EQTCHSRV; /* Формирование ремонтной ведомости для технического объекта */ @@ -635,8 +1069,7 @@ text="Проверка прав доступа при формировании SDOCTYPES PKG_STD.TSTRING; -- Тип документа ведомости SPREF PKG_STD.TSTRING; -- Префикс ведосмости SNUMB PKG_STD.TSTRING; -- Номер ведомости - NEQRPSHEET PKG_STD.TREF; -- Рег. номер сформированной ведомости - NSELECTLIST PKG_STD.TREF; -- Рег. номер позиции списк сформированных ведомостей + NEQRPSHEET PKG_STD.TREF; -- Рег. номер сформированной ведомости begin /* Определяем юридическую принадлежность технического объекта */ begin @@ -688,12 +1121,8 @@ text="Проверка прав доступа при формировании SEQOBJKIND => null, NRN => NEQRPSHEET); /* Добавим ведомость в список */ - NIDENT := GEN_IDENT(); - P_SELECTLIST_INSERT(NIDENT => NIDENT, - NDOCUMENT => NEQRPSHEET, - SUNITCODE => 'EquipRepairSheets', - NRN => NSELECTLIST); + EQCONFIG_THOBJ_SELECT_EQRPSHT(NEQRPSHEETS => NEQRPSHEET, NIDENT => NIDENT); end EQCONFIG_THOBJ_MAKE_EQRPSHEET; - + 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 6d08e6c..7e341d1 100644 --- a/panels/eqs_tech_cond_forecast/forecast_tab.js +++ b/panels/eqs_tech_cond_forecast/forecast_tab.js @@ -50,7 +50,7 @@ const DIALOGS_INITIAL = { makeEqRpSheet: false, makeEqDataSet: false, techObjCar //Начальное состояние спецификации технических объектов const TECH_OBJ_SPEC_INITIAL = { - parent: 8938140, + parent: null, filters: [], orders: [], pageNumber: 1 @@ -92,7 +92,7 @@ const ForecastTab = ({ onGoToAdmin }) => { const { InlineMsgInfo } = useContext(MessagingСtx); //Подключение к контексту приложения - const { pOnlineShowUnit } = useContext(ApplicationСtx); + const { pOnlineShowUnit, pOnlineShowDictionary } = useContext(ApplicationСtx); //Собственное состояние - текущая загружаемая ветка const [loadingTreeItem, setLoadingTreeItem] = useState(0); @@ -130,6 +130,12 @@ const ForecastTab = ({ onGoToAdmin }) => { //Загрузчик истории прогнозов выбранного технического объекта const { techObjForecastHistList } = useTechObjForecastHistList(techObj.id, refresh.techObjForecastHistList); + //Принудительное обновление текущей спецификации технических обхектов + const refreshTechObjSpec = () => { + if (techObjSpec.pageNumber == 1) setRefresh(pv => ({ ...pv, techObjSpec: pv.techObjSpec + 1 })); + else setTechObjSpec(pv => ({ ...pv, pageNumber: 1 })); + }; + //Обработка развёртывания/свёртывания уровня дерева const handleTreeItemExpansionToggle = (event, itemId, isExpanded) => isExpanded && needLoadLevel(eQconfigTree, itemId) ? setLoadingTreeItem(parseInt(itemId)) : null; @@ -171,6 +177,7 @@ const ForecastTab = ({ onGoToAdmin }) => { //При закрытии карточки технического объекта const handleTechObjeCardClose = () => { + refreshTechObjSpec(); setDialogs(pv => ({ ...pv, techObjCard: false })); setTechObj(TECH_OBJ_INITIAL); }; @@ -196,7 +203,12 @@ const ForecastTab = ({ onGoToAdmin }) => { } }); setDialogs(pv => ({ ...pv, makeEqRpSheet: false })); - pOnlineShowUnit({ unitCode: "EquipRepairSheets", showMethod: "main_selected", inputParameters: [{ name: "in_Ident", value: data.NIDENT }] }); + pOnlineShowDictionary({ + unitCode: "EquipRepairSheets", + showMethod: "main_selected", + inputParameters: [{ name: "in_Ident", value: data.NIDENT }], + callBack: handleCardDataRefresh + }); }; //При нажитии "Отмена" в диалоге формирования ремонтной ведомости @@ -212,14 +224,16 @@ const ForecastTab = ({ onGoToAdmin }) => { DPLANDATE_FROM: new Date(values.planDateFrom) } }); - handleCardDataRefresh(); + setRefresh(pv => ({ ...pv, techObjForecastHistList: pv.techObjForecastHistList + 1, techObjCard: pv.techObjCard + 1 })); setDialogs(pv => ({ ...pv, changeEqTchSrv: false })); - const data = await executeStored({ stored: "UDO_PKG_EQUIPTCF.EQCONFIG_THOBJ_SELECT_EQTCHSRV", args: { NEQTCHSRV: values.eQTchSrv } }); - if (data.NIDENT) - pOnlineShowUnit({ - unitCode: "EquipTechServices", - inputParameters: [{ name: "in_SelectList_Ident", value: data.NIDENT }] - }); + if (values?.showEqTchSrv == 1) { + const data = await executeStored({ stored: "UDO_PKG_EQUIPTCF.EQCONFIG_THOBJ_SELECT_EQTCHSRV", args: { NEQTCHSRV: values.eQTchSrv } }); + if (data.NIDENT) + pOnlineShowUnit({ + unitCode: "EquipTechServices", + inputParameters: [{ name: "in_SelectList_Ident", value: data.NIDENT }] + }); + } }; //При нажитии "Отмена" в диалоге корректировки графика ТО и ремонтов @@ -246,8 +260,7 @@ const ForecastTab = ({ onGoToAdmin }) => { }); setDialogs(pv => ({ ...pv, makeEqDataSet: false })); if (onGoToAdmin) onGoToAdmin(data.NEQUIPDS, data.NEQUIPDSCM); - if (techObjSpec.pageNumber == 1) setRefresh(pv => ({ ...pv, techObjSpec: pv.techObjSpec + 1 })); - else setTechObjSpec(pv => ({ ...pv, pageNumber: 1 })); + refreshTechObjSpec(); }; //При нажитии "Отмена" в диалоге формирования выборки данных diff --git a/panels/eqs_tech_cond_forecast/forecast_tab_layout.js b/panels/eqs_tech_cond_forecast/forecast_tab_layout.js index 710dd50..02c06fa 100644 --- a/panels/eqs_tech_cond_forecast/forecast_tab_layout.js +++ b/panels/eqs_tech_cond_forecast/forecast_tab_layout.js @@ -9,7 +9,7 @@ import React, { useState, useEffect, useContext } from "react"; //Классы React import PropTypes from "prop-types"; //Контроль свойств компонента -import { Stack, Card, CardContent, Typography, Button, Link, Dialog, DialogTitle, DialogContent, DialogActions } from "@mui/material"; //Интерфейсные компоненты +import { Stack, Card, CardContent, Typography, Button, Link, Dialog, DialogTitle, DialogContent, DialogActions, Paper, Box } from "@mui/material"; //Интерфейсные компоненты import { useTheme } from "@mui/material/styles"; //Темы оформления import { ApplicationСtx } from "../../context/application"; //Контекст приложения import { BackEndСtx } from "../../context/backend"; //Контекст взаимодействия с серверомs @@ -46,7 +46,7 @@ const STYLES = { ...SCROLL_STYLES }, TECH_OBJ_FORECAST_DETAIL_DIALOG: { maxWidth: "600px" }, - TECH_OBJ_FORECAST_DETAIL_CHART: { width: "550px", display: "flex", justifyContent: "center" }, + TECH_OBJ_FORECAST_DETAIL_CHART: { width: "550px", display: "flex", justifyContent: "center", paddingTop: "20px" }, TECH_OBJ_MAKE_DATASET_DIALOG_CONTENT: { ...SCROLL_STYLES } }; @@ -98,35 +98,56 @@ const techObjCardModelsTableDataCellRender = ({ row, columnDef, theme, onGoToMod } }; +//Форматирование заголовка таблицы истории прогнозов класса оборудования выборки данных +const techObjCardForecastListTableHeadCellRender = ({ columnDef }) => { + switch (columnDef.name) { + case "STO_FORECAST_DESC": + return { + stackProps: { justifyContent: "right" }, + cellProps: { align: "right" } + }; + } +}; + //Форматирование колонок таблицы истории прогнозов класса оборудования выборки данных const techObjCardForecastListTableDataCellRender = ({ row, columnDef, onShowForecastDetail }) => { switch (columnDef.name) { - case "NFORECAST": + case "STO_FORECAST_DESC": return { - data: ( - - ) + ) : null }; } }; //Детали прогноза const ForecastDetail = ({ date, forecast, onClose }) => { + //Собственное состояние - сведения о прогнозе + const [datails, setDetails] = useState({ taskName: null, forecast: null, meas: null, nextRepair: null, breakDown: null, breakDownColor: null }); + //Собственное состояние - график - const [chart, setChart] = useState({ loaded: false, labels: [], datasets: [] }); + const [chart, setChart] = useState({ loaded: false, available: true, labels: [], datasets: [] }); //При подключении к странице useEffect(() => { const loadChart = async () => { - const chart = await xml2JSON({ xmlDoc: forecast }); - console.log(chart); - setChart(pv => ({ ...pv, loaded: true, ...chart.XDATA.XCHART })); + const data = await xml2JSON({ xmlDoc: forecast }); + setDetails({ + taskName: data.XDATA.STASK_NAME, + forecast: data.XDATA.NFORECAST, + meas: data.XDATA.SDICMUNTS, + nextRepair: data.XDATA.DNEXT_REPAIR, + breakDown: data.XDATA.NBREAKDOWN_PROB, + breakDownColor: data.XDATA.SBREAKDOWN_PROB_COLOR + }); + if (data.XDATA.XCHART) { + const chart = await xml2JSON({ xmlDoc: data.XDATA.XCHART }); + setChart(pv => ({ ...pv, loaded: true, ...chart.XDATA.XCHART })); + } else setChart(pv => ({ ...pv, available: false })); }; loadChart(); // eslint-disable-next-line react-hooks/exhaustive-deps @@ -136,7 +157,39 @@ const ForecastDetail = ({ date, forecast, onClose }) => { return ( (onClose ? onClose() : null)} {...STYLES.TECH_OBJ_FORECAST_DETAIL_DIALOG}> {`Детали прогноза от ${date}`} - {chart.loaded ? : null} + + + {datails.taskName}: {`${datails.forecast} ${datails.meas}`} + + + Дата следующего ТО/ремонта по графику:  + + {datails.nextRepair ? formatDateRF(datails.nextRepair) : "Нет графиков ТО и ремонтов"} + + + + Bероятность перехода в критическое состояние:  + + {`${datails.breakDown}%*`} + + + + *до даты следующего ТО/ремонта по графику + + {chart.loaded ? : null} + {!chart.available ? ( + + + + + Зарегистрируйте графики ТО и ремонтов
+ для отображения диаграммы прогнозирования. +
+
+
+
+ ) : null} +
@@ -187,6 +240,14 @@ const eqConfigTechObjTableDataCellRender = ({ row, columnDef, onCMMLStatus }) => ) }; + case "NBREAKDOWN_PROB": + return { + data: row[columnDef.name] ? ( + + ) : null + }; } }; @@ -234,20 +295,33 @@ const TechObjCard = ({ //При нажатии на отображение деталей прогноза const handleShowForecastDetailClick = modelHist => { - setState(pv => ({ ...pv, forecastDetail: modelHist.SFORECAST, forecastDate: modelHist.SRQ_DATE })); + setState(pv => ({ ...pv, forecastDetail: modelHist.STO_FORECAST, forecastDate: modelHist.SRQ_DATE })); }; //При нажатии на закрытие деталей прогноза const handleCloseForecastDetailClick = () => setState(pv => ({ ...pv, forecastDetail: null, forecastDate: null })); - //При нажатии на дату следующего обслуживания + //При нажатии на дату следующего обслуживания согласно графику ТО и ремонтов const handleNextRepairClick = async () => { const data = await executeStored({ stored: "UDO_PKG_EQUIPTCF.EQCONFIG_THOBJ_SELECT_EQTCHSRV", args: { NEQCONFIG: cardData.NRN } }); if (data.NIDENT) pOnlineShowDictionary({ unitCode: "EquipTechServices", inputParameters: [{ name: "in_SelectList_Ident", value: data.NIDENT }], - callBack: res => (res.success && onCardDataRefresh ? onCardDataRefresh() : null) + callBack: () => (onCardDataRefresh ? onCardDataRefresh() : null) + }); + else showMsgErr(TEXTS.NO_DATA_FOUND); + }; + + //При нажатии надату следующего ремонта согласно ремнтной ведомости + const handleNextRepairSheetClick = async () => { + const data = await executeStored({ stored: "UDO_PKG_EQUIPTCF.EQCONFIG_THOBJ_SELECT_EQRPSHT", args: { NEQCONFIG: cardData.NRN } }); + if (data.NIDENT) + pOnlineShowDictionary({ + unitCode: "EquipRepairSheets", + showMethod: "main_selected", + inputParameters: [{ name: "in_Ident", value: data.NIDENT }], + callBack: () => (onCardDataRefresh ? onCardDataRefresh() : null) }); else showMsgErr(TEXTS.NO_DATA_FOUND); }; @@ -267,14 +341,30 @@ const TechObjCard = ({ {`${formatDateRF(cardData.DOPER_DATE)}, ${cardData.SEQOBJKIND}`} - {cardData.DNEXT_EQTCHSRV ? ( - - Следующее ТО:{" "} + + Следующее ТО/ремонт по графику (план):{" "} + {cardData.DNEXT_EQTCHSRV ? ( {cardData.DNEXT_EQTCHSRV} - - ) : null} + ) : ( + + Нет графиков ТО и ремонтов + + )} + + + Включен в ремонты на (факт):{" "} + {cardData.DNEXT_EQRPSHEET ? ( + + {cardData.DNEXT_EQRPSHEET} + + ) : ( + + Нет ремонтных ведомостей + + )} + {modelsList.init ? ( @@ -319,6 +409,7 @@ const TechObjCard = ({ morePages={false} fixedHeader={true} reloading={false} + headCellRender={techObjCardForecastListTableHeadCellRender} dataCellRender={prms => techObjCardForecastListTableDataCellRender({ ...prms, @@ -376,7 +467,8 @@ const TechObjChangeEqTchSrv = ({ eQConfig, onOk, onCancel }) => { const [values, setValues] = useState({ eQTchSrv: "", eQTchSrvDesc: "", - planDateFrom: "" + planDateFrom: "", + showEqTchSrv: 0 }); //Отработка воода значения в форму @@ -433,6 +525,16 @@ const TechObjChangeEqTchSrv = ({ eQConfig, onOk, onCancel }) => { onChange={handleValueChanged} type={"date"} /> +