diff --git a/db/UDO_PKG_EQUIPDS_BASE.pck b/db/UDO_PKG_EQUIPDS_BASE.pck index 568c4f4..4404815 100644 --- a/db/UDO_PKG_EQUIPDS_BASE.pck +++ b/db/UDO_PKG_EQUIPDS_BASE.pck @@ -1,5 +1,5 @@ create or replace package UDO_PKG_EQUIPDS_BASE as - + /* Считывание записи "Выборки данных оборудования" по регистрационному номеру */ function GET ( @@ -199,6 +199,14 @@ create or replace package UDO_PKG_EQUIPDS_BASE as function CMML_TASK_HINT return varchar2; -- Подсказка для задачи + /* Вычисление вероятности выхода из строя на дату по RUL-прогнозу */ + function CMML_RUL_BREAKDOWN_PROB + ( + NFORECAST in number, -- RUL-прогноз (интервалов до перехода в предельное состояние) + DFORECAST_DATE in date, -- Дата прогноза + DDATE in date -- Дата на + ) return number; -- Значение вероятности + /* Базовое добавление "Выборки данных оборудования (классы оборудования, модели, история запросов)" */ procedure CMMLH_INS ( @@ -722,6 +730,41 @@ create or replace package body UDO_PKG_EQUIPDS_BASE as 'FP - ' || CMML_TASK_NAME(STASK => 'FP') || ' (Failure Predict)'; end CMML_TASK_HINT; + /* Вычисление вероятности выхода из строя на дату по RUL-прогнозу */ + function CMML_RUL_BREAKDOWN_PROB + ( + NFORECAST in number, -- RUL-прогноз (интервалов до перехода в предельное состояние) + DFORECAST_DATE in date, -- Дата прогноза + DDATE in date -- Дата на + ) return number -- Значение вероятности + is + NRES PKG_STD.TNUMBER; -- Буфер для результата + begin + /* Проверим параметры */ + if ((NFORECAST is null) or (DFORECAST_DATE is null) or (DDATE is null) or (DDATE < DFORECAST_DATE) or + (DFORECAST_DATE > sysdate) or (DDATE < sysdate)) then + return null; + end if; + /* Проверяем пограничные значения */ + if (NFORECAST = 0) or ((DDATE - sysdate) = 0) then + return 100; + end if; + if (sysdate + NFORECAST > DDATE) then + return 0; + end if; + /* Вычисляем */ + NRES := 100 - ROUND((NFORECAST - (TRUNC(sysdate) - TRUNC(DFORECAST_DATE))) / (DDATE - sysdate) * 100); + /* Корректируем флуктуации */ + if (NRES > 100) then + NRES := 100; + end if; + if (NRES < 0) then + NRES := 0; + end if; + /* Возвращаем результат */ + return NRES; + end CMML_RUL_BREAKDOWN_PROB; + /* Базовое добавление "Выборки данных оборудования (классы оборудования, модели, история запросов)" */ procedure CMMLH_INS ( diff --git a/db/UDO_PKG_EQUIPTCF.pck b/db/UDO_PKG_EQUIPTCF.pck index 8d22dbf..57fef5b 100644 --- a/db/UDO_PKG_EQUIPTCF.pck +++ b/db/UDO_PKG_EQUIPTCF.pck @@ -608,6 +608,34 @@ text="Проверка прав доступа при формировании end loop; end EQCONFIG_THOBJ_SELECT_EQRPSHT; + /* Получение даты следующего ремонта по ремонтной ведомости или графику ТО и ремонтов (что раньше) технического объекта */ + function EQCONFIG_THOBJ_GEN_NXTRPR + ( + NEQCONFIG in number -- Рег. номер технического объекта + ) return date -- Дата ближайшего ремонта + is + DNXTEQTCHSRV PKG_STD.TLDATE; -- Дата ближайшего ТО или ремонта по графику + DNXTEQRPSHT PKG_STD.TLDATE; -- Дата ближайшего ТО или ремонта по ремонтным ведомостям + DRES PKG_STD.TLDATE; -- Буфер для результата + begin + /* Определим дату ближайшего ТО или ремонта */ + DNXTEQTCHSRV := EQCONFIG_THOBJ_GET_NXTEQTCHSRV(NEQCONFIG => NEQCONFIG); + /* Определим дату ближайшей ремонтной ведомости */ + DNXTEQRPSHT := EQCONFIG_THOBJ_GET_NXTEQRPSHT(NEQCONFIG => NEQCONFIG); + /* Берм меньшую */ + if ((DNXTEQRPSHT is not null) and (DNXTEQTCHSRV is not null)) then + if (DNXTEQRPSHT < DNXTEQTCHSRV) then + DRES := DNXTEQRPSHT; + else + DRES := DNXTEQTCHSRV; + end if; + else + DRES := COALESCE(DNXTEQTCHSRV, DNXTEQRPSHT); + end if; + /* Вернём результат */ + return DRES; + end EQCONFIG_THOBJ_GEN_NXTRPR; + /* Формирование карточки технического объекта */ procedure EQCONFIG_THOBJ_CARD ( @@ -768,11 +796,11 @@ text="Проверка прав доступа при формировании 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; -- Дата ближайшего ТО и ремонта + NBREAKDOWN_PROB_CUR PKG_STD.TNUMBER; -- Вероятность выхода из строя (для текущей позиции графика ТО и ремонтов/рем. ведомости) + DNEXT_REPAIR PKG_STD.TLDATE; -- Дата ближайшего ТО и ремонта по графику/рем. ведомости begin - /* Вычислим вероятность выхода из строя до даты ближайшего ТО с учётом прогноза */ - DNEXT_REPAIR := UDO_PKG_EQUIPTCF.EQCONFIG_THOBJ_GET_NXTEQTCHSRV(NEQCONFIG => NEQCONFIG); + /* Вычислим вероятность выхода из строя до даты ближайшего ТО/ремонта по графику или рем. ведомости с учётом прогноза */ + DNEXT_REPAIR := EQCONFIG_THOBJ_GEN_NXTRPR(NEQCONFIG => NEQCONFIG); if (DNEXT_REPAIR is null) then NBREAKDOWN_PROB := 100; else @@ -814,43 +842,41 @@ text="Проверка прав доступа при формировании 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 => 'Прогноз с учётом графика ТО и ремонтов', + STITLE => 'Прогноз с учётом графика ТО и ремонтов/ремонтных ведомостей', SLGND_POS => PKG_P8PANELS_VISUAL.SCHART_LGND_POS_TOP); /* Сформируем набор данных */ RCH_DS := PKG_P8PANELS_VISUAL.TCHART_DATASET_MAKE(SCAPTION => 'Вероятность перехода в критическое состояние (%)'); - /* Обходим ближайшие 5 позиций графика ТО и ремонтов */ + /* Обходим ближайшие 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 + from (select T.DDATEPRD_BEG + from (select P.DATEPRD_BEG DDATEPRD_BEG + from EQTCHSRV P + where P.EQCONFIG_TECH = NEQCONFIG + and P.DATEPRD_BEG >= sysdate + union + select R.DATEPLAN_BEG DDATEPRD_BEG + from EQRPSHEETS R + where R.EQCONFIG = NEQCONFIG + and R.DATEPLAN_BEG >= sysdate) T + order by T.DDATEPRD_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; + PKG_P8PANELS_VISUAL.TCHART_ADD_LABEL(RCHART => RCH, SLABEL => TO_CHAR(C.DDATEPRD_BEG, 'dd.mm.yyyy')); + /* Считаем вероятность выхода из строя в эту дату */ + NBREAKDOWN_PROB_CUR := UDO_PKG_EQUIPDS_BASE.CMML_RUL_BREAKDOWN_PROB(NFORECAST => NFORECAST, + DFORECAST_DATE => DFORECAST_DATE, + DDATE => C.DDATEPRD_BEG); + /* Если ещё не фиксировали вероятность для первой даты - сделаем это */ + if (NBREAKDOWN_PROB is null) then + NBREAKDOWN_PROB := NBREAKDOWN_PROB_CUR; end if; + /* Добавим элемент в набор данных */ PKG_P8PANELS_VISUAL.TCHART_DATASET_ADD_ITEM(RDATASET => RCH_DS, NVALUE => NBREAKDOWN_PROB_CUR); end loop; /* Добавим набор данных в график */ @@ -932,18 +958,18 @@ text="Проверка прав доступа при формировании /* Вероятность выхода единицы оборудования из строя с учётом графика ТО и ремонтов и RUL-прогноза */ function EQCONFIG_THOBJ_TCHSRV_BRKDPROB ( - NEQCONFIG in number -- Рег. номер технического объекта - ) return number -- Вероятность выхода из строя + NEQCONFIG in number -- Рег. номер технического объекта + ) return number -- Вероятность выхода из строя is - NRES PKG_STD.TNUMBER; -- Буфер для результата - DFORECAST_DATE PKG_STD.TLDATE; - NFORECAST PKG_STD.TNUMBER; -- Значение самго свежего прогноза модели - DNXTEQTCHSRV PKG_STD.TLDATE; -- Дата ближайшего ТО или ремонта + NRES PKG_STD.TNUMBER; -- Буфер для результата + DFORECAST_DATE PKG_STD.TLDATE; -- Дата прогноза + NFORECAST PKG_STD.TNUMBER; -- Значение самго свежего прогноза модели + DCALC_DATE PKG_STD.TLDATE; -- Дата расчета вероятности begin /* Определим дату ближайшего ТО или ремонта */ - DNXTEQTCHSRV := EQCONFIG_THOBJ_GET_NXTEQTCHSRV(NEQCONFIG => NEQCONFIG); + DCALC_DATE := EQCONFIG_THOBJ_GEN_NXTRPR(NEQCONFIG => NEQCONFIG); /* Если дата есть */ - if (DNXTEQTCHSRV is not null) then + if (DCALC_DATE is not null) then /* Вынем самый свежий прогноз */ for C in (select T.RQ_DATE DFORECAST_DATE, T.FORECAST @@ -960,7 +986,9 @@ text="Проверка прав доступа при формировании end loop; /* Если есть и прогноз */ if (NFORECAST is not null) then - NRES := 100 - ROUND((NFORECAST - (TRUNC(sysdate) - TRUNC(DFORECAST_DATE))) / (DNXTEQTCHSRV - sysdate) * 100); + NRES := UDO_PKG_EQUIPDS_BASE.CMML_RUL_BREAKDOWN_PROB(NFORECAST => NFORECAST, + DFORECAST_DATE => DFORECAST_DATE, + DDATE => DCALC_DATE); 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 7e341d1..cf410c0 100644 --- a/panels/eqs_tech_cond_forecast/forecast_tab.js +++ b/panels/eqs_tech_cond_forecast/forecast_tab.js @@ -189,7 +189,8 @@ const ForecastTab = ({ onGoToAdmin }) => { const handleTechObjeCardMakeEqRpSheet = () => setDialogs(pv => ({ ...pv, makeEqRpSheet: true })); //При необходимости обновления карточки технического объекта - const handleCardDataRefresh = () => setRefresh(pv => ({ ...pv, techObjCard: pv.techObjCard + 1 })); + const handleCardDataRefresh = () => + setRefresh(pv => ({ ...pv, techObjCard: pv.techObjCard + 1, techObjForecastHistList: pv.techObjForecastHistList + 1 })); //При нажатии "ОК" в диалоге формирования ремонтной ведомости const handleTechObjMakeEqRpSheetOk = async values => { @@ -202,6 +203,7 @@ const ForecastTab = ({ onGoToAdmin }) => { DPLANDATE_FROM: new Date(values.planDateFrom) } }); + setRefresh(pv => ({ ...pv, techObjForecastHistList: pv.techObjForecastHistList + 1, techObjCard: pv.techObjCard + 1 })); setDialogs(pv => ({ ...pv, makeEqRpSheet: false })); pOnlineShowDictionary({ unitCode: "EquipRepairSheets", diff --git a/panels/eqs_tech_cond_forecast/forecast_tab_layout.js b/panels/eqs_tech_cond_forecast/forecast_tab_layout.js index 02c06fa..9f77f4d 100644 --- a/panels/eqs_tech_cond_forecast/forecast_tab_layout.js +++ b/panels/eqs_tech_cond_forecast/forecast_tab_layout.js @@ -47,7 +47,8 @@ const STYLES = { }, TECH_OBJ_FORECAST_DETAIL_DIALOG: { maxWidth: "600px" }, TECH_OBJ_FORECAST_DETAIL_CHART: { width: "550px", display: "flex", justifyContent: "center", paddingTop: "20px" }, - TECH_OBJ_MAKE_DATASET_DIALOG_CONTENT: { ...SCROLL_STYLES } + TECH_OBJ_MAKE_DATASET_DIALOG_CONTENT: { ...SCROLL_STYLES }, + FORECAST_DETAIL_NOTE: { display: "block", marginTop: "-5px" } }; //------------------------------------ @@ -162,19 +163,24 @@ const ForecastDetail = ({ date, forecast, onClose }) => { {datails.taskName}: {`${datails.forecast} ${datails.meas}`} - Дата следующего ТО/ремонта по графику:  + Дата следующего ТО/ремонта:  - {datails.nextRepair ? formatDateRF(datails.nextRepair) : "Нет графиков ТО и ремонтов"} + {datails.nextRepair ? `${formatDateRF(datails.nextRepair)}*` : "Нет графиков ТО и ремонтов/ремонтых ведомостей"} + {datails.nextRepair ? ( + + *по графику/ремонтной ведомости + + ) : null} Bероятность перехода в критическое состояние:  {`${datails.breakDown}%*`} - - *до даты следующего ТО/ремонта по графику + + *до даты следующего ТО/ремонта по графику/ремонтной ведомости {chart.loaded ? : null} {!chart.available ? ( @@ -182,7 +188,7 @@ const ForecastDetail = ({ date, forecast, onClose }) => { - Зарегистрируйте графики ТО и ремонтов
+ Зарегистрируйте графики ТО и ремонтов/ремонтные ведомости
для отображения диаграммы прогнозирования.
@@ -242,11 +248,16 @@ const eqConfigTechObjTableDataCellRender = ({ row, columnDef, onCMMLStatus }) => }; case "NBREAKDOWN_PROB": return { - data: row[columnDef.name] ? ( - - ) : null + data: + row[columnDef.name] !== null && row[columnDef.name] !== "" ? ( + + ) : null }; } };