Исправлен алгоритм расчета вероятности выхода из строя, доработана карточка технического объекта (больше данных о прогнозе) и карточка интерапретации (даты выхода из строя относительного сегодняшнего дня, больше комментариев)

This commit is contained in:
Mikhail Chechnev 2025-04-11 15:58:40 +03:00
parent 07976cbe82
commit 55519e072e
5 changed files with 221 additions and 130 deletions

View File

@ -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,11 +1562,16 @@ 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);
@ -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,8 +1707,8 @@ 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,
/* Возвращаем полученные данные карточки - конвертируем 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_,
@ -1708,10 +1716,15 @@ create or replace package body UDO_PKG_EQUIPDS as
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 => '<b>Формат прогноза:</b> "XXД / YY%", где<br>' ||
'<b>XXД</b> - время (в днях, от текущей даты) до перехода в критическое состояние<br>' ||
'<b>YY%</b> - вероятность перехода в критическое состояние до следующего ТО и ремонта<br><br>' ||
'<b>Цвет прогноза:</b><br>' || 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 => '<b>Формат:</b> "XXД / YY%", где<br>' ||
'<b>XXД</b> - время (в днях, от текущей даты) до перехода в критическое состояние<br>' ||
'<b>YY%</b> - вероятность перехода в критическое состояние до следующего ТО и ремонта<br><br>' ||
'<b>Цвет:</b><br>' || 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);

View File

@ -1429,6 +1429,25 @@ create or replace package body UDO_PKG_EQUIPDS_BASE as
end CMMLH_FORECAST_DAYS_NOW;
/* Вычисление вероятности выхода из строя на дату по 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;

View File

@ -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,8 +1007,6 @@ 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
@ -1023,11 +1021,17 @@ text="Проверка прав доступа при формировании
NFORECAST_DAYS := C.NFORECAST_DAYS;
exit;
end loop;
/* Если есть и прогноз */
if (NFORECAST_DAYS is not null) then
/* Если есть прогноз */
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;
/* Вернём то, что собрали */

View File

@ -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,7 +224,9 @@ const ForecastTab = ({ onGoToAdmin }) => {
};
//Выполняем запрос
showLoader("Прогнозирование...");
const response = await fetch(forecastReqData.SURL, {
let response = null;
try {
response = await fetch(forecastReqData.SURL, {
method: "POST",
body: JSON.stringify(body),
headers: {
@ -233,8 +235,12 @@ const ForecastTab = ({ onGoToAdmin }) => {
"Content-Type": "application/json"
}
});
} catch (e) {
throw new Error("Сетевая ошибка или ошибка внешнего сервера.");
}
//Обработаем результаты
if (response.status === 200) {
if (response) {
if (response?.status === 200) {
let responseJson;
try {
responseJson = await response.json();
@ -255,7 +261,7 @@ const ForecastTab = ({ onGoToAdmin }) => {
NEQUIPDSCMML: model.NRN,
CFORECAST: {
VALUE: object2Base64XML(
{ XDATA: { XFORECAST: responseJson.forecast.map(f => ({ STIME: f.time, SVALUE: f.value })) } },
{ XDATA: { XFORECAST: responseJson.forecast.map(f => ({ STIME: f.time, VALUE: f.value })) } },
{ arrayNodeName: "XFORECAST" }
),
SDATA_TYPE: SERV_DATA_TYPE_CLOB
@ -268,6 +274,7 @@ const ForecastTab = ({ onGoToAdmin }) => {
} else throw new Error("Неожиданный ответ системы прогнозирования: ответ не содержит данных прогноза.");
} else throw new Error("Неожиданный ответ системы прогнозирования: ответ не содержит данных.");
} else throw new Error(`Ошибка (${response.status}) при взаимодейтсвии с системой прогнозирования.`);
} else throw new Error("Система прогнозирования не вернула ответ.");
} catch (e) {
hideLoader();
showMsgErr(e.message);

View File

@ -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 }) => {
<DialogTitle>{`Детали прогноза от ${date}`}</DialogTitle>
<DialogContent>
<Typography variant="subtitle1">
{datails.taskName}: <b>{`${datails.forecast} ${datails.meas}`}</b>
{details.taskName} на дату выборки ({`${details.forecastDate}`}):{" "}
<b>{`${details.forecastDays} д (до ${details.forecastDateCalc})*`}</b>
</Typography>
<Typography variant="caption" color={"text.secondary"} sx={STYLES.FORECAST_DETAIL_NOTE}>
*по данным фреймворка прогнозирования
</Typography>
<Typography variant="subtitle1">
{details.taskName} на сегодня ({`${details.forecastDateNow}`}): <b>{`${details.forecastDaysNow} д*`}</b>
</Typography>
<Typography variant="caption" color={"text.secondary"} sx={STYLES.FORECAST_DETAIL_NOTE}>
*по данным фреймворка прогнозирования
</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 variant="subtitle1" color={details.nextRepair ? "" : "error.main"}>
<b>{details.nextRepair ? `${formatDateRF(details.nextRepair)}*` : "Нет графиков ТО и ремонтов/ремонтых ведомостей"}</b>
</Typography>
</Stack>
{datails.nextRepair ? (
{details.nextRepair ? (
<Typography variant="caption" color={"text.secondary"} sx={STYLES.FORECAST_DETAIL_NOTE}>
*по графику/ремонтной ведомости
</Typography>
) : null}
<Stack direction={"row"}>
<Typography variant="subtitle1">Bероятность перехода в критическое состояние:&nbsp;</Typography>
<Typography variant="subtitle1" color={datails.breakDownColor}>
<b>{`${datails.breakDown}%*`}</b>
<Typography variant="subtitle1" color={details.breakDownColor}>
<b>{`${details.breakDown}%*`}</b>
</Typography>
</Stack>
<Typography variant="caption" color={"text.secondary"} sx={STYLES.FORECAST_DETAIL_NOTE}>
*до даты следующего ТО/ремонта по графику/ремонтной ведомости
</Typography>
{chart.loaded ? <P8PChart {...chart} style={STYLES.TECH_OBJ_FORECAST_DETAIL_CHART} /> : null}
{!chart.available ? (
{chart.loaded && (
<>
<P8PChart {...chart} style={STYLES.TECH_OBJ_FORECAST_DETAIL_CHART} />
<Typography variant="caption" color={"text.secondary"} sx={STYLES.FORECAST_DETAIL_NOTE} pt={2}>
При расчёте вероятности принято, что она имеет равномерную функцию распределения на интервале [a, b],
<br />
гда a = 0 (текущий момент времени), b = количество дней до выхода из строя от текущего момента времени,
<br />
полученное от фреймворка прогнозирования
</Typography>
</>
)}
{!chart.available && (
<Box p={5}>
<Paper elevation={6}>
<Box p={5}>
@ -213,7 +245,7 @@ const ForecastDetail = ({ date, forecast, onClose }) => {
</Box>
</Paper>
</Box>
) : null}
)}
</DialogContent>
<DialogActions>
<Button onClick={() => (onClose ? onClose() : null)}>{BUTTONS.CLOSE}</Button>
@ -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 }));
};
//При нажатии на закрытие деталей прогноза