Графики ТО и ремонтов - расчёт вероятности сбоя, отображение в карточке, корректировка, вероятность сбоя в списке тех. объектов

This commit is contained in:
Mikhail Chechnev 2024-08-16 01:32:40 +03:00
parent 2201fa4004
commit 355a53261e
5 changed files with 713 additions and 112 deletions

View File

@ -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 -- Значение прогноза
);
/* Список "Выборки данных оборудования (классы оборудования, модели, история запросов)" по единице оборудования */
@ -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 => '<b style="color:red">Опасность</b> - вероятность сбоя более 60%.<br>' ||
'<b style="color:orange">Внимание</b> - вероятность сбоя от 30% до 60%<br>' ||
'<b style="color:green">В норме</b> - вероятность сбоев менее 30%');
SDATA_TYPE => PKG_P8PANELS_VISUAL.SDATA_TYPE_STR,
SHINT => '<b>Формат прогноза:</b> "XXЕИ / YY%", где<br>' ||
'<b>XXЕИ</b> - время до перехода в критическое состояние в ЕИ ресурса единицы оборудования (часы/дни/месяцы/рабочие циклы и т.п.)<br>' ||
'<b>YY%</b> - вероятность перехода в критическое состояние до следующего ТО и ремонта<br><br>' ||
'<b>Цвет прогноза:</b><br>' || 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;

View File

@ -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 '<b>TCF</b> - Оценка технического состояния (<b>T</b>echnical <b>C</b>ondition <b>F</b>orecast)<br>' || '<b>RUL</b> - Прогнозирование остаточного ресурса (<b>R</b>emaining <b>U</b>seful <b>L</b>ife)<br>' || '<b>FP</b> - Прогнозирование отказа (<b>F</b>ailure <b>P</b>redict)';
return '<b>TCF</b> - ' || CMML_TASK_NAME(STASK => 'TCF') || ' (<b>T</b>echnical <b>C</b>ondition <b>F</b>orecast)<br>' ||
'<b>RUL</b> - ' || CMML_TASK_NAME(STASK => 'RUL') || ' (<b>R</b>emaining <b>U</b>seful <b>L</b>ife)<br>' ||
'<b>FP</b> - ' || CMML_TASK_NAME(STASK => 'FP') || ' (<b>F</b>ailure <b>P</b>redict)';
end CMML_TASK_HINT;
/* Базовое добавление "Выборки данных оборудования (классы оборудования, модели, история запросов)" */

View File

@ -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
(
@ -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,7 +404,8 @@ 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,');
@ -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;
@ -393,6 +487,11 @@ text="Проверка прав доступа при формировании
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 '<b style="color:red">Опасность</b> - вероятность сбоя более 60%.<br>' || '<b style="color:orange">Внимание</b> - вероятность сбоя от 30% до 60%<br>' || '<b style="color:green">В норме</b> - вероятность сбоев менее 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;
/* Формирование ремонтной ведомости для технического объекта */
@ -636,7 +1070,6 @@ text="Проверка прав доступа при формировании
SPREF PKG_STD.TSTRING; -- Префикс ведосмости
SNUMB PKG_STD.TSTRING; -- Номер ведомости
NEQRPSHEET PKG_STD.TREF; -- Рег. номер сформированной ведомости
NSELECTLIST PKG_STD.TREF; -- Рег. номер позиции списк сформированных ведомостей
begin
/* Определяем юридическую принадлежность технического объекта */
begin
@ -688,11 +1121,7 @@ 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;

View File

@ -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();
};
//При нажитии "Отмена" в диалоге формирования выборки данных

View File

@ -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: (
<Button
variant="outlined"
color={row.NFORECAST < 30 ? "success" : row.NFORECAST >= 30 && row.NFORECAST < 60 ? "warning" : "error"}
onClick={() => onShowForecastDetail(row)}
>
{`${row.NFORECAST}%`}
cellProps: { align: "right" },
data: row.STO_FORECAST_DESC ? (
<Button variant="outlined" color={row.STO_FORECAST_DESC_COLOR} onClick={() => onShowForecastDetail(row)}>
{row.STO_FORECAST_DESC}
</Button>
)
) : 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 (
<Dialog open={true} onClose={() => (onClose ? onClose() : null)} {...STYLES.TECH_OBJ_FORECAST_DETAIL_DIALOG}>
<DialogTitle>{`Детали прогноза от ${date}`}</DialogTitle>
<DialogContent>{chart.loaded ? <P8PChart {...chart} style={STYLES.TECH_OBJ_FORECAST_DETAIL_CHART} /> : null}</DialogContent>
<DialogContent>
<Typography variant="subtitle1">
{datails.taskName}: <b>{`${datails.forecast} ${datails.meas}`}</b>
</Typography>
<Stack direction={"row"}>
<Typography variant="subtitle1">Дата следующего ТО/ремонта по графику:&nbsp;</Typography>
<Typography variant="subtitle1" color={datails.nextRepair ? "" : "error.main"}>
<b>{datails.nextRepair ? formatDateRF(datails.nextRepair) : "Нет графиков ТО и ремонтов"}</b>
</Typography>
</Stack>
<Stack direction={"row"}>
<Typography variant="subtitle1">Bероятность перехода в критическое состояние:&nbsp;</Typography>
<Typography variant="subtitle1" color={datails.breakDownColor}>
<b>{`${datails.breakDown}%*`}</b>
</Typography>
</Stack>
<Typography variant="caption" color={"text.secondary"}>
*до даты следующего ТО/ремонта по графику
</Typography>
{chart.loaded ? <P8PChart {...chart} style={STYLES.TECH_OBJ_FORECAST_DETAIL_CHART} /> : null}
{!chart.available ? (
<Box p={5}>
<Paper elevation={6}>
<Box p={5}>
<Typography variant="body" color={"text.secondary"}>
Зарегистрируйте графики ТО и ремонтов <br />
для отображения диаграммы прогнозирования.
</Typography>
</Box>
</Paper>
</Box>
) : null}
</DialogContent>
<DialogActions>
<Button onClick={() => (onClose ? onClose() : null)}>{BUTTONS.CLOSE}</Button>
</DialogActions>
@ -187,6 +240,14 @@ const eqConfigTechObjTableDataCellRender = ({ row, columnDef, onCMMLStatus }) =>
</Button>
)
};
case "NBREAKDOWN_PROB":
return {
data: row[columnDef.name] ? (
<Button variant="outlined" color={row.SBREAKDOWN_PROB_COLOR} onClick={event => (onCMMLStatus ? onCMMLStatus(event, row) : null)}>
{`${row[columnDef.name]}%`}
</Button>
) : 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 = ({
<Typography color="text.secondary" variant="caption">
{`${formatDateRF(cardData.DOPER_DATE)}, ${cardData.SEQOBJKIND}`}
</Typography>
{cardData.DNEXT_EQTCHSRV ? (
<Typography color="text.secondary" variant="caption" gutterBottom>
Следующее ТО:{" "}
<Typography color="text.secondary" variant="caption">
Следующее ТО/ремонт по графику (план):{" "}
{cardData.DNEXT_EQTCHSRV ? (
<Link component="button" variant="body2" align="left" underline="hover" onClick={handleNextRepairClick}>
{cardData.DNEXT_EQTCHSRV}
</Link>
</Typography>
) : null}
) : (
<Typography color="error" variant="caption">
Нет графиков ТО и ремонтов
</Typography>
)}
</Typography>
<Typography color="text.secondary" variant="caption" gutterBottom>
Включен в ремонты на (факт):{" "}
{cardData.DNEXT_EQRPSHEET ? (
<Link component="button" variant="body2" align="left" underline="hover" onClick={handleNextRepairSheetClick}>
{cardData.DNEXT_EQRPSHEET}
</Link>
) : (
<Typography color="error" variant="caption">
Нет ремонтных ведомостей
</Typography>
)}
</Typography>
</Stack>
{modelsList.init ? (
<Card elevation={6}>
@ -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"}
/>
<IUDFormTextField
elementCode={"showEqTchSrv"}
elementValue={values.showEqTchSrv}
labelText={"Показать изменённый график"}
onChange={handleValueChanged}
list={[
{ name: "Нет", value: 0 },
{ name: "Да", value: 1 }
]}
/>
</DialogContent>
<DialogActions>
<Button onClick={() => (onOk ? onOk(values) : null)}>{BUTTONS.OK}</Button>