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
};
}
};