diff --git a/db/UDO_PKG_EQUIPDS.pck b/db/UDO_PKG_EQUIPDS.pck
index ecb4dee..ff636a9 100644
--- a/db/UDO_PKG_EQUIPDS.pck
+++ b/db/UDO_PKG_EQUIPDS.pck
@@ -205,9 +205,10 @@ create or replace package UDO_PKG_EQUIPDS as
DFORECAST_DATE in date, -- Дата получения прогноза
NFORECAST_DAYS in number, -- Прогнозное количество дней до выхода из строя (на дату прогноза)
STASK in varchar2, -- Задача (см. константы UDO_PKG_EQUIPDS_BASE.CMML_TASK_*)
- SFORECAST_DESC out varchar2, -- Краткое описание прогноза
- SFORECAST_DESC_COLOR out varchar2, -- Цвет заливки прогноза
- CFORECAST out clob -- Данные детальной карточки прогноза
+ SFORECAST out varchar2, -- Прогноз
+ SFORECAST_DESC out varchar2, -- Интерпретация прогноза
+ SFORECAST_DESC_COLOR out varchar2, -- Цвет заливки интерпретации прогноза
+ CFORECAST_CARD out clob -- Данные детальной карточки прогноза
);
/* Список "Выборки данных оборудования (классы оборудования, модели, история запросов)" по единице оборудования */
@@ -1544,9 +1545,10 @@ create or replace package body UDO_PKG_EQUIPDS as
DFORECAST_DATE in date, -- Дата получения прогноза
NFORECAST_DAYS in number, -- Прогнозное количество дней до выхода из строя (на дату прогноза)
STASK in varchar2, -- Задача (см. константы UDO_PKG_EQUIPDS_BASE.CMML_TASK_*)
- SFORECAST_DESC out varchar2, -- Краткое описание прогноза
- SFORECAST_DESC_COLOR out varchar2, -- Цвет заливки прогноза
- CFORECAST out clob -- Данные детальной карточки прогноза
+ SFORECAST out varchar2, -- Прогноз
+ SFORECAST_DESC out varchar2, -- Интерпретация прогноза
+ SFORECAST_DESC_COLOR out varchar2, -- Цвет заливки интерпретации прогноза
+ CFORECAST_CARD out clob -- Данные детальной карточки прогноза
)
is
RCMMLH UDO_T_EQUIPDSCMMLH%rowtype; -- Запись истории запросов модели
@@ -1560,16 +1562,21 @@ create or replace package body UDO_PKG_EQUIPDS as
NBREAKDOWN_PROB_CUR PKG_STD.TNUMBER; -- Вероятность выхода из строя (для текущей позиции графика ТО и ремонтов/рем. ведомости)
DNEXT_REPAIR PKG_STD.TLDATE; -- Дата ближайшего ТО и ремонта по графику/рем. ведомости
NFORECAST_DAYS_NOW PKG_STD.TNUMBER; -- Количество дней до выхода из строя согласно прогнозу, но от текущей даты
+ STASK_NAME PKG_STD.TSTRING; -- Текстовая расшифровка задачи
+ SFORECAST_DATE_CALC PKG_STD.TSTRING; -- Текстовое представление плановой даты перехода в предельное состояние
begin
/* Считаем запись истории запросов к модели */
RCMMLH := UDO_PKG_EQUIPDS_BASE.CMMLH_GET(NFLAG_SMART => 0, NRN => NEQUIPDSCMMLH);
/* Проноз есть */
if ((DFORECAST_DATE is not null) and (NFORECAST_DAYS is not null)) then
+ /* Получим текстовую расшифровку задачи */
+ STASK_NAME := UDO_PKG_EQUIPDS_BASE.CMML_TASK_NAME(STASK => STASK);
+ SFORECAST_DATE_CALC := TO_CHAR(DFORECAST_DATE + NFORECAST_DAYS, 'dd.mm.yyyy');
/* Вычислим сколько осталось до выхода из строя от текущей даты */
NFORECAST_DAYS_NOW := UDO_PKG_EQUIPDS_BASE.CMMLH_FORECAST_DAYS_NOW(DFORECAST_DATE => DFORECAST_DATE,
NFORECAST_DAYS => NFORECAST_DAYS);
/* Вычислим вероятность выхода из строя до даты ближайшего ТО/ремонта по графику или рем. ведомости с учётом прогноза */
- DNEXT_REPAIR := UDO_PKG_EQUIPTCF.EQCONFIG_THOBJ_GEN_NXTRPR(NEQCONFIG => RCMMLH.EQCONFIG);
+ DNEXT_REPAIR := UDO_PKG_EQUIPTCF.EQCONFIG_THOBJ_GEN_NXTRPR(NEQCONFIG => RCMMLH.EQCONFIG);
NBREAKDOWN_PROB := UDO_PKG_EQUIPDS_BASE.CMMLH_RUL_BREAKDOWN_PROB(DFORECAST_DATE => DFORECAST_DATE,
NFORECAST_DAYS => NFORECAST_DAYS,
DDATE => DNEXT_REPAIR);
@@ -1596,9 +1603,7 @@ create or replace package body UDO_PKG_EQUIPDS as
RNODE01 => PKG_XMAKE.ELEMENT(ICURSOR => NCUR,
SNAME => 'SFORECAST_DATE_CALC',
RVALUE00 => PKG_XMAKE.VALUE(ICURSOR => NCUR,
- SVALUE => TO_CHAR(DFORECAST_DATE +
- NFORECAST_DAYS,
- 'dd.mm.yyyy'))));
+ SVALUE => SFORECAST_DATE_CALC)));
/* Заполним текущую дату */
XROOT := PKG_XMAKE.CONCAT(ICURSOR => NCUR,
RNODE00 => XROOT,
@@ -1626,7 +1631,7 @@ create or replace package body UDO_PKG_EQUIPDS as
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))));
+ SVALUE => STASK_NAME)));
/* Заполним дату следующего ТО и ремонта */
XROOT := PKG_XMAKE.CONCAT(ICURSOR => NCUR,
RNODE00 => XROOT,
@@ -1675,6 +1680,9 @@ create or replace package body UDO_PKG_EQUIPDS as
PKG_P8PANELS_VISUAL.TCHART_ADD_DATASET(RCHART => RCH, RDATASET => RCH_DS);
/* Сериализуем график */
CCHART := PKG_P8PANELS_VISUAL.TCHART_TO_XML(RCHART => RCH, NINCLUDE_DEF => 1);
+ else
+ /* Запланированных ремонтов или ТО нет, но прогноз есть - значит точно выйдет из строя */
+ NBREAKDOWN_PROB := 100;
end if;
/* Заполним вероятность выхода из стороя до ближайшего ТО с учётом прогноза */
XROOT := PKG_XMAKE.CONCAT(ICURSOR => NCUR,
@@ -1699,19 +1707,24 @@ create or replace package body UDO_PKG_EQUIPDS as
RVALUE00 => PKG_XMAKE.VALUE(ICURSOR => NCUR, LCVALUE => CCHART)));
/* Формируем XML-представление ответа */
XDOC := PKG_XMAKE.ELEMENT(ICURSOR => NCUR, SNAME => 'XDATA', RNODE00 => XROOT);
- /* Конвертируем в CLOB */
- CFORECAST := 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_));
+ /* Возвращаем полученные данные карточки - конвертируем XML-представление ответа в CLOB */
+ CFORECAST_CARD := 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);
- /* Возвращаем значение краткого описания прогноза */
+ /* Возвращаем текстовое описание прогноза */
+ SFORECAST := STASK_NAME || ' на дату выборки (' || TO_CHAR(DFORECAST_DATE, 'dd.mm.yyyy') || '): ' ||
+ TO_CHAR(NFORECAST_DAYS) || 'д (до ' || SFORECAST_DATE_CALC || ')';
+ /* Возвращаем интерпретацию прогноза */
SFORECAST_DESC := TO_CHAR(NFORECAST_DAYS_NOW) || 'Д / ' || TO_CHAR(ROUND(NBREAKDOWN_PROB)) || '%';
- /* Возвращаем значение цвета заливки описания прогноза */
+ /* Возвращаем цвета заливки интерпретации прогноза */
SFORECAST_DESC_COLOR := CMMLH_FORECAST_COLOR(NMODE => 1, NVALUE => NBREAKDOWN_PROB);
+ else
+ SFORECAST := 'Не удалось разобрать ответ модели';
end if;
end CMMLH_FORECAST_CARD;
@@ -1744,7 +1757,8 @@ create or replace package body UDO_PKG_EQUIPDS as
PKG_P8PANELS_VISUAL.TDG_ADD_COL_DEF(RDATA_GRID => RDG,
SNAME => 'SEQUIPDS_CODE',
SCAPTION => 'Выборка',
- SDATA_TYPE => PKG_P8PANELS_VISUAL.SDATA_TYPE_STR);
+ SDATA_TYPE => PKG_P8PANELS_VISUAL.SDATA_TYPE_STR,
+ BVISIBLE => false);
PKG_P8PANELS_VISUAL.TDG_ADD_COL_DEF(RDATA_GRID => RDG,
SNAME => 'SEQUIPDSCMML_TASK',
SCAPTION => 'Задача',
@@ -1753,22 +1767,27 @@ create or replace package body UDO_PKG_EQUIPDS as
PKG_P8PANELS_VISUAL.TDG_ADD_COL_DEF(RDATA_GRID => RDG,
SNAME => 'NEQUIPDSCMML_PRECISION',
SCAPTION => 'Точность',
- SDATA_TYPE => PKG_P8PANELS_VISUAL.SDATA_TYPE_NUMB);
- PKG_P8PANELS_VISUAL.TDG_ADD_COL_DEF(RDATA_GRID => RDG,
- SNAME => 'STO_FORECAST_DESC',
- SCAPTION => 'Прогноз',
- SDATA_TYPE => PKG_P8PANELS_VISUAL.SDATA_TYPE_STR,
- SHINT => 'Формат прогноза: "XXД / YY%", где
' ||
- 'XXД - время (в днях, от текущей даты) до перехода в критическое состояние
' ||
- 'YY% - вероятность перехода в критическое состояние до следующего ТО и ремонта
' ||
- 'Цвет прогноза:
' || CMMLH_FORECAST_COLOR(NMODE => 0));
- PKG_P8PANELS_VISUAL.TDG_ADD_COL_DEF(RDATA_GRID => RDG,
- SNAME => 'STO_FORECAST_DESC_COLOR',
- SCAPTION => 'Цвет прогноза',
- SDATA_TYPE => PKG_P8PANELS_VISUAL.SDATA_TYPE_STR,
+ SDATA_TYPE => PKG_P8PANELS_VISUAL.SDATA_TYPE_NUMB,
BVISIBLE => false);
PKG_P8PANELS_VISUAL.TDG_ADD_COL_DEF(RDATA_GRID => RDG,
SNAME => 'STO_FORECAST',
+ SCAPTION => 'Ответ модели',
+ SDATA_TYPE => PKG_P8PANELS_VISUAL.SDATA_TYPE_STR);
+ PKG_P8PANELS_VISUAL.TDG_ADD_COL_DEF(RDATA_GRID => RDG,
+ SNAME => 'STO_FORECAST_DESC',
+ SCAPTION => 'Интерпретация',
+ SDATA_TYPE => PKG_P8PANELS_VISUAL.SDATA_TYPE_STR,
+ SHINT => 'Формат: "XXД / YY%", где
' ||
+ 'XXД - время (в днях, от текущей даты) до перехода в критическое состояние
' ||
+ 'YY% - вероятность перехода в критическое состояние до следующего ТО и ремонта
' ||
+ 'Цвет:
' || CMMLH_FORECAST_COLOR(NMODE => 0));
+ PKG_P8PANELS_VISUAL.TDG_ADD_COL_DEF(RDATA_GRID => RDG,
+ SNAME => 'STO_FORECAST_DESC_COLOR',
+ SCAPTION => 'Цвет интерпретации',
+ SDATA_TYPE => PKG_P8PANELS_VISUAL.SDATA_TYPE_STR,
+ BVISIBLE => false);
+ PKG_P8PANELS_VISUAL.TDG_ADD_COL_DEF(RDATA_GRID => RDG,
+ SNAME => 'STO_FORECAST_CARD',
SCAPTION => 'Данные карточки прогноза для конкретного технического объекта',
SDATA_TYPE => PKG_P8PANELS_VISUAL.SDATA_TYPE_STR,
BVISIBLE => false);
@@ -1789,9 +1808,10 @@ create or replace package body UDO_PKG_EQUIPDS as
T.FORECAST BFORECAST,
T.FORECAST_DATE DFORECAST_DATE,
T.FORECAST_DAYS NFORECAST_DAYS,
+ null STO_FORECAST,
null STO_FORECAST_DESC,
null STO_FORECAST_DESC_COLOR,
- null STO_FORECAST
+ null STO_FORECAST_CARD
from UDO_T_EQUIPDSCMMLH T,
UDO_T_EQUIPDSCMML ML,
UDO_T_EQUIPDSCM CM,
@@ -1809,9 +1829,10 @@ create or replace package body UDO_PKG_EQUIPDS as
DFORECAST_DATE => C.DFORECAST_DATE,
NFORECAST_DAYS => C.NFORECAST_DAYS,
STASK => C.SEQUIPDSCMML_TASK,
+ SFORECAST => C.STO_FORECAST,
SFORECAST_DESC => C.STO_FORECAST_DESC,
SFORECAST_DESC_COLOR => C.STO_FORECAST_DESC_COLOR,
- CFORECAST => C.STO_FORECAST);
+ CFORECAST_CARD => C.STO_FORECAST_CARD);
/* Добавляем колонки с данными */
PKG_P8PANELS_VISUAL.TDG_ROW_ADD_COL(RROW => RDG_ROW, SNAME => 'NRN', NVALUE => C.NRN, BCLEAR => true);
PKG_P8PANELS_VISUAL.TDG_ROW_ADD_COL(RROW => RDG_ROW, SNAME => 'SRQ_AUTHID', SVALUE => C.SRQ_AUTHID);
@@ -1821,11 +1842,12 @@ create or replace package body UDO_PKG_EQUIPDS as
PKG_P8PANELS_VISUAL.TDG_ROW_ADD_COL(RROW => RDG_ROW,
SNAME => 'NEQUIPDSCMML_PRECISION',
NVALUE => C.NEQUIPDSCMML_PRECISION);
+ PKG_P8PANELS_VISUAL.TDG_ROW_ADD_COL(RROW => RDG_ROW, SNAME => 'STO_FORECAST', SVALUE => C.STO_FORECAST);
PKG_P8PANELS_VISUAL.TDG_ROW_ADD_COL(RROW => RDG_ROW, SNAME => 'STO_FORECAST_DESC', SVALUE => C.STO_FORECAST_DESC);
PKG_P8PANELS_VISUAL.TDG_ROW_ADD_COL(RROW => RDG_ROW,
SNAME => 'STO_FORECAST_DESC_COLOR',
SVALUE => C.STO_FORECAST_DESC_COLOR);
- PKG_P8PANELS_VISUAL.TDG_ROW_ADD_COL(RROW => RDG_ROW, SNAME => 'STO_FORECAST', SVALUE => C.STO_FORECAST);
+ PKG_P8PANELS_VISUAL.TDG_ROW_ADD_COL(RROW => RDG_ROW, SNAME => 'STO_FORECAST_CARD', SVALUE => C.STO_FORECAST_CARD);
PKG_P8PANELS_VISUAL.TDG_ROW_ADD_COL(RROW => RDG_ROW, SNAME => 'SDICMUNTS', SVALUE => C.SDICMUNTS);
/* Добавляем строку в таблицу */
PKG_P8PANELS_VISUAL.TDG_ADD_ROW(RDATA_GRID => RDG, RROW => RDG_ROW);
diff --git a/db/UDO_PKG_EQUIPDS_BASE.pck b/db/UDO_PKG_EQUIPDS_BASE.pck
index d650bdf..c539ad7 100644
--- a/db/UDO_PKG_EQUIPDS_BASE.pck
+++ b/db/UDO_PKG_EQUIPDS_BASE.pck
@@ -1428,7 +1428,26 @@ create or replace package body UDO_PKG_EQUIPDS_BASE as
return NRES;
end CMMLH_FORECAST_DAYS_NOW;
- /* Вычисление вероятности выхода из строя на дату по RUL-прогнозу */
+ /* Вычисление вероятности выхода из строя на дату по RUL-прогнозу */
+ /*
+ Описание алгоритма:
+
+ Считаем, что остаточный ресурс "k" - случайная величина, имеющая равномерную функцию распределения на интервале [a, b]
+ Необходимо определить вероятность того, что остаточный ресурс составит не менее "m" дней (P(k>=m)).
+
+ Здесь:
+ "k" - остаточный ресурс
+ "m" - количество дней, от текущего, до проверяемой даты (DDATE)
+ "a" - текущий день, 0
+ "b" - количество дней от текущего, до даты выхода из строя (DFORECAST_DATE + NFORECAST_DAYS), спрогнозированной фреймворком
+
+ Таким образом:
+ - вычисления невозможны, если хоть один из входных параметров неопределён, будем возвращать null
+ - если дата выхода из строя (DFORECAST_DATE + NFORECAST_DAYS) меньше текущей (т.е. b < a и интервал распределения неопределён), то считаем, что ресурс гарантировано меньше (P(k>=m) = 1)
+ - если проверяемая дата (DDATE) меньше текущей (т.е. не левее [a, b]) - вероятность 0, ресурс гарантировано больше (P(k>=m) = 0)
+ - если проверяемая дата (DDATE) больше даты выхода из строя (т.е. правее [a, b]) - вероятность 1, ресурс гарантировано меньше (P(k>=m) = 1)
+ - если проверяемая дата (DDATE) в диапазоне от текущей, до предсказанной даты выхода из строя (в [a, b]), то P(k>=m) = 1 - ((b - m)/(b - a))
+ */
function CMMLH_RUL_BREAKDOWN_PROB
(
DFORECAST_DATE in date, -- Дата прогноза
@@ -1436,26 +1455,33 @@ create or replace package body UDO_PKG_EQUIPDS_BASE as
DDATE in date -- Дата на
) return number -- Значение вероятности
is
+ DFORECAST_BREAKDOWN PKG_STD.TLDATE; -- Прогнозная дата выхода из строя
+ NB PKG_STD.TNUMBER; -- Правая граница диапазона распределения вероятности (количество дней от текущего до прогнозной даты выхода из строя)
+ NM PKG_STD.TNUMBER; -- Проверяемый аргумент (количество дней от текущего до проверяемой даты)
NRES PKG_STD.TNUMBER; -- Буфер для результата
begin
- /* Проверим параметры */
- if ((NFORECAST_DAYS is null) or (DFORECAST_DATE is null) or (DDATE is null) or (DDATE < DFORECAST_DATE) or
- (DFORECAST_DATE > sysdate) or (DDATE < sysdate)) then
+ /* Проверим параметры - должны быть заданы все параметры */
+ if ((NFORECAST_DAYS is null) or (DFORECAST_DATE is null) or (DDATE is null)) then
return null;
end if;
- /* Проверяем пограничные значения */
- if ((NFORECAST_DAYS = 0) or ((DDATE - sysdate) = 0)) then
+ /* Вычислим дату выхода из строя */
+ DFORECAST_BREAKDOWN := DFORECAST_DATE + NFORECAST_DAYS;
+ /* Если прогнозируемая дата выхода из строя меньше текущей - ресурс гарантировано ниже */
+ if (DFORECAST_BREAKDOWN < sysdate) then
+ return 100;
+ end if;
+ /* Если проверяемя дата меньше текущей - ресурс гарантировано выше */
+ if (DDATE < sysdate) then
+ return 0;
+ end if;
+ /* Если проверяемя дата больше прогнозной дты выхода из строя - ресурс гарантировано ниже */
+ if (DDATE > DFORECAST_BREAKDOWN) then
return 100;
end if;
/* Вычисляем */
- NRES := 100 - ROUND((NFORECAST_DAYS - (TRUNC(sysdate) - TRUNC(DFORECAST_DATE))) / (DDATE - sysdate) * 100);
- /* Корректируем флуктуации */
- if (NRES > 100) then
- NRES := 100;
- end if;
- if (NRES < 0) then
- NRES := 0;
- end if;
+ NB := DFORECAST_BREAKDOWN - sysdate;
+ NM := DDATE - sysdate;
+ NRES := 100 - ROUND(((NB - NM) / NB) * 100);
/* Возвращаем результат */
return NRES;
end CMMLH_RUL_BREAKDOWN_PROB;
diff --git a/db/UDO_PKG_EQUIPTCF.pck b/db/UDO_PKG_EQUIPTCF.pck
index 81685db..ec47029 100644
--- a/db/UDO_PKG_EQUIPTCF.pck
+++ b/db/UDO_PKG_EQUIPTCF.pck
@@ -962,7 +962,7 @@ text="Проверка прав доступа при формировании
/* Читаем последнее значение из массива предсказаний (оно соответствует дате окончания из параметров прогноза) */
NLAST := PKG_XPATH.COUNT_NODES(RNODES => XFCTS);
XLAST_FCT := PKG_XPATH.ITEM_NODE(RNODES => XFCTS, INUMBER => NLAST);
- NLAST_INTERVALS := TO_CHAR(PKG_XPATH.VALUE(RNODE => XLAST_FCT, SPATTERN => 'SVALUE'));
+ NLAST_INTERVALS := PKG_XPATH.VALUE_NUM(RNODE => XLAST_FCT, SPATTERN => 'VALUE');
if (NLAST_INTERVALS < 0) then
NLAST_INTERVALS := 0;
end if;
@@ -1007,27 +1007,31 @@ text="Проверка прав доступа при формировании
begin
/* Определим дату ближайшего ТО или ремонта */
DCALC_DATE := EQCONFIG_THOBJ_GEN_NXTRPR(NEQCONFIG => NEQCONFIG);
- /* Если дата есть */
- if (DCALC_DATE is not null) then
- /* Вынем самый свежий прогноз */
- for C in (select T.FORECAST_DATE DFORECAST_DATE,
- T.FORECAST_DAYS NFORECAST_DAYS
- from UDO_T_EQUIPDSCMMLH T,
- UDO_T_EQUIPDSCMML CMML
- where T.EQCONFIG = NEQCONFIG
- and T.PRN = CMML.RN
- and CMML.TASK = UDO_PKG_EQUIPDS_BASE.SCMML_TASK_RUL
- order by T.RQ_DATE desc)
- loop
- DFORECAST_DATE := C.DFORECAST_DATE;
- NFORECAST_DAYS := C.NFORECAST_DAYS;
- exit;
- end loop;
- /* Если есть и прогноз */
- if (NFORECAST_DAYS is not null) then
+ /* Вынем самый свежий прогноз */
+ for C in (select T.FORECAST_DATE DFORECAST_DATE,
+ T.FORECAST_DAYS NFORECAST_DAYS
+ from UDO_T_EQUIPDSCMMLH T,
+ UDO_T_EQUIPDSCMML CMML
+ where T.EQCONFIG = NEQCONFIG
+ and T.PRN = CMML.RN
+ and CMML.TASK = UDO_PKG_EQUIPDS_BASE.SCMML_TASK_RUL
+ order by T.RQ_DATE desc)
+ loop
+ DFORECAST_DATE := C.DFORECAST_DATE;
+ NFORECAST_DAYS := C.NFORECAST_DAYS;
+ exit;
+ end loop;
+ /* Если есть прогноз */
+ if ((DFORECAST_DATE is not null) and (NFORECAST_DAYS is not null)) then
+ /* Если и дата ТО есть */
+ if (DCALC_DATE is not null) then
+ /* Вычислим вероятность */
NRES := UDO_PKG_EQUIPDS_BASE.CMMLH_RUL_BREAKDOWN_PROB(DFORECAST_DATE => DFORECAST_DATE,
NFORECAST_DAYS => NFORECAST_DAYS,
DDATE => DCALC_DATE);
+ else
+ /* Запланированных ремонтов или ТО нет, но прогноз есть - значит точно выйдет из строя */
+ NRES := 100;
end if;
end if;
/* Вернём то, что собрали */
diff --git a/panels/eqs_tech_cond_forecast/forecast_tab.js b/panels/eqs_tech_cond_forecast/forecast_tab.js
index cd52878..b02da01 100644
--- a/panels/eqs_tech_cond_forecast/forecast_tab.js
+++ b/panels/eqs_tech_cond_forecast/forecast_tab.js
@@ -58,7 +58,7 @@ const TECH_OBJ_SPEC_INITIAL = {
};
//Начальное состояние выбранного технического объекта
-const TECH_OBJ_INITIAL = { id: 20005565, objKind: null, measureUnit: null };
+const TECH_OBJ_INITIAL = { id: null, objKind: null, measureUnit: null };
//Стили
const STYLES = {
@@ -224,50 +224,57 @@ const ForecastTab = ({ onGoToAdmin }) => {
};
//Выполняем запрос
showLoader("Прогнозирование...");
- const response = await fetch(forecastReqData.SURL, {
- method: "POST",
- body: JSON.stringify(body),
- headers: {
- Authorization: `Basic ${forecastReqData.SAUTH_TOKEN}`,
- Accept: "*/*",
- "Content-Type": "application/json"
- }
- });
+ let response = null;
+ try {
+ response = await fetch(forecastReqData.SURL, {
+ method: "POST",
+ body: JSON.stringify(body),
+ headers: {
+ Authorization: `Basic ${forecastReqData.SAUTH_TOKEN}`,
+ Accept: "*/*",
+ "Content-Type": "application/json"
+ }
+ });
+ } catch (e) {
+ throw new Error("Сетевая ошибка или ошибка внешнего сервера.");
+ }
//Обработаем результаты
- if (response.status === 200) {
- let responseJson;
- try {
- responseJson = await response.json();
- } catch (e) {
- throw new Error("Неожиданный ответ системы прогнозирования: ответ неверного формата.");
- }
- if (responseJson) {
- if (responseJson?.status && responseJson.status == "ERR")
- throw new Error(`Ошибка формирования прогноза: ${responseJson.message}`);
- if (responseJson?.forecast && Array.isArray(responseJson?.forecast)) {
- await executeStored({
- stored: "UDO_PKG_EQUIPTCF.EQCONFIG_THOBJ_FORECAST_EPLG",
- args: {
- NDATASET_IDENT: res.outParameters.NDATASET_IDENT,
- NDATASET_CONFIG_IDENT: res.outParameters.NDATASET_CONFIG_IDENT,
- NREQUEST_CONFIG_IDENT: res.outParameters.NREQUEST_CONFIG_IDENT,
- NEQCONFIG: techObj.id,
- NEQUIPDSCMML: model.NRN,
- CFORECAST: {
- VALUE: object2Base64XML(
- { XDATA: { XFORECAST: responseJson.forecast.map(f => ({ STIME: f.time, SVALUE: f.value })) } },
- { arrayNodeName: "XFORECAST" }
- ),
- SDATA_TYPE: SERV_DATA_TYPE_CLOB
- }
- },
- loader: false
- });
- hideLoader();
- setRefresh(pv => ({ ...pv, techObjForecastHistList: pv.techObjForecastHistList + 1 }));
- } else throw new Error("Неожиданный ответ системы прогнозирования: ответ не содержит данных прогноза.");
- } else throw new Error("Неожиданный ответ системы прогнозирования: ответ не содержит данных.");
- } else throw new Error(`Ошибка (${response.status}) при взаимодейтсвии с системой прогнозирования.`);
+ if (response) {
+ if (response?.status === 200) {
+ let responseJson;
+ try {
+ responseJson = await response.json();
+ } catch (e) {
+ throw new Error("Неожиданный ответ системы прогнозирования: ответ неверного формата.");
+ }
+ if (responseJson) {
+ if (responseJson?.status && responseJson.status == "ERR")
+ throw new Error(`Ошибка формирования прогноза: ${responseJson.message}`);
+ if (responseJson?.forecast && Array.isArray(responseJson?.forecast)) {
+ await executeStored({
+ stored: "UDO_PKG_EQUIPTCF.EQCONFIG_THOBJ_FORECAST_EPLG",
+ args: {
+ NDATASET_IDENT: res.outParameters.NDATASET_IDENT,
+ NDATASET_CONFIG_IDENT: res.outParameters.NDATASET_CONFIG_IDENT,
+ NREQUEST_CONFIG_IDENT: res.outParameters.NREQUEST_CONFIG_IDENT,
+ NEQCONFIG: techObj.id,
+ NEQUIPDSCMML: model.NRN,
+ CFORECAST: {
+ VALUE: object2Base64XML(
+ { XDATA: { XFORECAST: responseJson.forecast.map(f => ({ STIME: f.time, VALUE: f.value })) } },
+ { arrayNodeName: "XFORECAST" }
+ ),
+ SDATA_TYPE: SERV_DATA_TYPE_CLOB
+ }
+ },
+ loader: false
+ });
+ hideLoader();
+ setRefresh(pv => ({ ...pv, techObjForecastHistList: pv.techObjForecastHistList + 1 }));
+ } else throw new Error("Неожиданный ответ системы прогнозирования: ответ не содержит данных прогноза.");
+ } else throw new Error("Неожиданный ответ системы прогнозирования: ответ не содержит данных.");
+ } else throw new Error(`Ошибка (${response.status}) при взаимодейтсвии с системой прогнозирования.`);
+ } else throw new Error("Система прогнозирования не вернула ответ.");
} catch (e) {
hideLoader();
showMsgErr(e.message);
diff --git a/panels/eqs_tech_cond_forecast/forecast_tab_layout.js b/panels/eqs_tech_cond_forecast/forecast_tab_layout.js
index e167ce4..6717e13 100644
--- a/panels/eqs_tech_cond_forecast/forecast_tab_layout.js
+++ b/panels/eqs_tech_cond_forecast/forecast_tab_layout.js
@@ -63,7 +63,7 @@ const STYLES = {
...SCROLL_STYLES
},
TECH_OBJ_FORECAST_DETAIL_DIALOG: { maxWidth: "600px" },
- TECH_OBJ_FORECAST_DETAIL_CHART: { width: "550px", display: "flex", justifyContent: "center", paddingTop: "20px" },
+ TECH_OBJ_FORECAST_DETAIL_CHART: { display: "flex", alignItems: "center", justifyContent: "center", paddingTop: "20px" },
TECH_OBJ_MAKE_DATASET_DIALOG_CONTENT: { minHeight: "40vh", maxHeight: "40vh", ...SCROLL_STYLES },
TECH_OBJ_MAKE_DATASET_DIALOG_TABS_CONTAINER: { borderBottom: 1, borderColor: "divider" },
FORECAST_DETAIL_NOTE: { display: "block", marginTop: "-5px" }
@@ -130,8 +130,6 @@ const techObjCardForecastListTableHeadCellRender = ({ columnDef }) => {
//Форматирование колонок таблицы истории прогнозов класса оборудования выборки данных
const techObjCardForecastListTableDataCellRender = ({ row, columnDef, onShowForecastDetail }) => {
switch (columnDef.name) {
- case "NEQUIPDSCMML_PRECISION":
- return { data: `${row.NEQUIPDSCMML_PRECISION} ${row.SDICMUNTS}` };
case "STO_FORECAST_DESC":
return {
cellProps: { align: "right" },
@@ -147,7 +145,17 @@ const techObjCardForecastListTableDataCellRender = ({ row, columnDef, onShowFore
//Детали прогноза
const ForecastDetail = ({ date, forecast, onClose }) => {
//Собственное состояние - сведения о прогнозе
- const [datails, setDetails] = useState({ taskName: null, forecast: null, meas: null, nextRepair: null, breakDown: null, breakDownColor: null });
+ const [details, setDetails] = useState({
+ taskName: null,
+ forecastDate: null,
+ forecastDays: null,
+ forecastDateCalc: null,
+ forecastDateNow: null,
+ forecastDaysNow: null,
+ nextRepair: null,
+ breakDown: null,
+ breakDownColor: null
+ });
//Собственное состояние - график
const [chart, setChart] = useState({ loaded: false, available: true, labels: [], datasets: [] });
@@ -158,8 +166,11 @@ const ForecastDetail = ({ date, forecast, onClose }) => {
const data = await xml2JSON({ xmlDoc: forecast });
setDetails({
taskName: data.XDATA.STASK_NAME,
- forecast: data.XDATA.NFORECAST,
- meas: data.XDATA.SDICMUNTS,
+ forecastDate: data.XDATA.SFORECAST_DATE,
+ forecastDays: data.XDATA.NFORECAST_DAYS,
+ forecastDateCalc: data.XDATA.SFORECAST_DATE_CALC,
+ forecastDateNow: data.XDATA.SFORECAST_DATE_NOW,
+ forecastDaysNow: data.XDATA.NFORECAST_DAYS_NOW,
nextRepair: data.XDATA.DNEXT_REPAIR,
breakDown: data.XDATA.NBREAKDOWN_PROB,
breakDownColor: data.XDATA.SBREAKDOWN_PROB_COLOR
@@ -179,30 +190,51 @@ const ForecastDetail = ({ date, forecast, onClose }) => {
{`Детали прогноза от ${date}`}
- {datails.taskName}: {`${datails.forecast} ${datails.meas}`}
+ {details.taskName} на дату выборки ({`${details.forecastDate}`}):{" "}
+ {`${details.forecastDays} д (до ${details.forecastDateCalc})*`}
+
+
+ *по данным фреймворка прогнозирования
+
+
+ {details.taskName} на сегодня ({`${details.forecastDateNow}`}): {`${details.forecastDaysNow} д*`}
+
+
+ *по данным фреймворка прогнозирования
Дата следующего ТО/ремонта:
-
- {datails.nextRepair ? `${formatDateRF(datails.nextRepair)}*` : "Нет графиков ТО и ремонтов/ремонтых ведомостей"}
+
+ {details.nextRepair ? `${formatDateRF(details.nextRepair)}*` : "Нет графиков ТО и ремонтов/ремонтых ведомостей"}
- {datails.nextRepair ? (
+ {details.nextRepair ? (
*по графику/ремонтной ведомости
) : null}
Bероятность перехода в критическое состояние:
-
- {`${datails.breakDown}%*`}
+
+ {`${details.breakDown}%*`}
*до даты следующего ТО/ремонта по графику/ремонтной ведомости
- {chart.loaded ? : null}
- {!chart.available ? (
+ {chart.loaded && (
+ <>
+
+
+ При расчёте вероятности принято, что она имеет равномерную функцию распределения на интервале [a, b],
+
+ гда a = 0 (текущий момент времени), b = количество дней до выхода из строя от текущего момента времени,
+
+ полученное от фреймворка прогнозирования
+
+ >
+ )}
+ {!chart.available && (
@@ -213,7 +245,7 @@ const ForecastDetail = ({ date, forecast, onClose }) => {
- ) : null}
+ )}
@@ -325,7 +357,7 @@ const TechObjCard = ({
//При нажатии на отображение деталей прогноза
const handleShowForecastDetailClick = modelHist => {
- setState(pv => ({ ...pv, forecastDetail: modelHist.STO_FORECAST, forecastDate: modelHist.SRQ_DATE }));
+ setState(pv => ({ ...pv, forecastDetail: modelHist.STO_FORECAST_CARD, forecastDate: modelHist.SRQ_DATE }));
};
//При нажатии на закрытие деталей прогноза