История прогнозов, карточка технического объекта, работа с прогнозом, формирование ремонтной ведомости
This commit is contained in:
parent
f7c0dd0e10
commit
b31fea736a
@ -102,19 +102,33 @@ create or replace package UDO_PKG_EQUIPDS as
|
||||
NEQUIPDSCMML in number -- Рег. номер модели класса оборудования выборки данных
|
||||
);
|
||||
|
||||
/* Состояние моделей по единице оборудования */
|
||||
/* Состояние "Выборки данных оборудования (классы оборудования, модели)" по единице оборудования */
|
||||
function CMML_STATUS_BY_EQCONFIG
|
||||
(
|
||||
NEQCONFIG in number -- Рег. номер позиции состава оборудования
|
||||
) return number; -- Код действия с моделью (0 - нет моделей, 1 - есть модели в процессе обучения, 2 - есть обученные модели)
|
||||
|
||||
/* Список моделей по единице оборудования */
|
||||
/* Список "Выборки данных оборудования (классы оборудования, модели)" по единице оборудования */
|
||||
procedure CMML_LIST_BY_EQCONFIG
|
||||
(
|
||||
NEQCONFIG in number, -- Рег. номер позиции состава оборудования
|
||||
COUT out clob -- Сериализованная таблица данных
|
||||
);
|
||||
|
||||
/* Формирование демо-прогноза */
|
||||
procedure CMMLH_DEMO_BUILD
|
||||
(
|
||||
STASK in varchar2, -- Задача
|
||||
COUT out clob -- Данные демо-прогноза
|
||||
);
|
||||
|
||||
/* Список "Выборки данных оборудования (классы оборудования, модели, история запросов)" по единице оборудования */
|
||||
procedure CMMLH_LIST_BY_EQCONFIG
|
||||
(
|
||||
NEQCONFIG in number, -- Рег. номер позиции состава оборудования
|
||||
COUT out clob -- Сериализованная таблица данных
|
||||
);
|
||||
|
||||
end UDO_PKG_EQUIPDS;
|
||||
/
|
||||
create or replace package body UDO_PKG_EQUIPDS as
|
||||
@ -592,7 +606,7 @@ text="Проверка прав доступа на работу с ""Выбор
|
||||
end loop;
|
||||
end CMML_SEND_RQ;
|
||||
|
||||
/* Состояние моделей по единице оборудования */
|
||||
/* Состояние "Выборки данных оборудования (классы оборудования, модели)" по единице оборудования */
|
||||
function CMML_STATUS_BY_EQCONFIG
|
||||
(
|
||||
NEQCONFIG in number -- Рег. номер позиции состава оборудования
|
||||
@ -620,7 +634,7 @@ text="Проверка прав доступа на работу с ""Выбор
|
||||
return NRES;
|
||||
end CMML_STATUS_BY_EQCONFIG;
|
||||
|
||||
/* Список моделей по единице оборудования */
|
||||
/* Список "Выборки данных оборудования (классы оборудования, модели)" по единице оборудования */
|
||||
procedure CMML_LIST_BY_EQCONFIG
|
||||
(
|
||||
NEQCONFIG in number, -- Рег. номер позиции состава оборудования
|
||||
@ -715,5 +729,153 @@ text="Проверка прав доступа на работу с ""Выбор
|
||||
COUT := PKG_P8PANELS_VISUAL.TDATA_GRID_TO_XML(RDATA_GRID => RDG, NINCLUDE_DEF => 1);
|
||||
end CMML_LIST_BY_EQCONFIG;
|
||||
|
||||
/* Формирование демо-прогноза */
|
||||
procedure CMMLH_DEMO_BUILD
|
||||
(
|
||||
STASK in varchar2, -- Задача
|
||||
COUT out clob -- Данные демо-прогноза
|
||||
)
|
||||
is
|
||||
RCH PKG_P8PANELS_VISUAL.TCHART; -- График
|
||||
RCH_DS PKG_P8PANELS_VISUAL.TCHART_DATASET; -- Набор данных
|
||||
DMONTH date; -- Месяц прогноза
|
||||
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;
|
||||
|
||||
/* Извлечение прогноза из демо-данных */
|
||||
function CMMLH_DEMO_FORECAST_PARSE
|
||||
(
|
||||
CFORECAST in clob -- Данные демо-прогноза
|
||||
) return number -- Прогнозное значение
|
||||
is
|
||||
XDOC PKG_XPATH.TDOCUMENT; -- Десериализованный демо-прогноз
|
||||
XROOT PKG_XPATH.TNODE; -- Корневой элемент данных
|
||||
begin
|
||||
/* Разбираем демо-даные */
|
||||
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'));
|
||||
exception
|
||||
when others then
|
||||
return null;
|
||||
end CMMLH_DEMO_FORECAST_PARSE;
|
||||
|
||||
/* Список "Выборки данных оборудования (классы оборудования, модели, история запросов)" по единице оборудования */
|
||||
procedure CMMLH_LIST_BY_EQCONFIG
|
||||
(
|
||||
NEQCONFIG in number, -- Рег. номер позиции состава оборудования
|
||||
COUT out clob -- Сериализованная таблица данных
|
||||
)
|
||||
is
|
||||
RDG PKG_P8PANELS_VISUAL.TDATA_GRID; -- Описание таблицы
|
||||
RDG_ROW PKG_P8PANELS_VISUAL.TROW; -- Строка таблицы
|
||||
begin
|
||||
/* Инициализируем таблицу данных */
|
||||
RDG := PKG_P8PANELS_VISUAL.TDATA_GRID_MAKE();
|
||||
/* Добавляем в таблицу описание колонок */
|
||||
PKG_P8PANELS_VISUAL.TDATA_GRID_ADD_COL_DEF(RDATA_GRID => RDG,
|
||||
SNAME => 'NRN',
|
||||
SCAPTION => 'Рег. номер',
|
||||
SDATA_TYPE => PKG_P8PANELS_VISUAL.SDATA_TYPE_NUMB,
|
||||
BVISIBLE => false);
|
||||
PKG_P8PANELS_VISUAL.TDATA_GRID_ADD_COL_DEF(RDATA_GRID => RDG,
|
||||
SNAME => 'SRQ_AUTHID',
|
||||
SCAPTION => 'Пользователь',
|
||||
SDATA_TYPE => PKG_P8PANELS_VISUAL.SDATA_TYPE_STR);
|
||||
PKG_P8PANELS_VISUAL.TDATA_GRID_ADD_COL_DEF(RDATA_GRID => RDG,
|
||||
SNAME => 'SRQ_DATE',
|
||||
SCAPTION => 'Дата/время запроса',
|
||||
SDATA_TYPE => PKG_P8PANELS_VISUAL.SDATA_TYPE_STR);
|
||||
PKG_P8PANELS_VISUAL.TDATA_GRID_ADD_COL_DEF(RDATA_GRID => RDG,
|
||||
SNAME => 'SEQUIPDS_CODE',
|
||||
SCAPTION => 'Выборка',
|
||||
SDATA_TYPE => PKG_P8PANELS_VISUAL.SDATA_TYPE_STR);
|
||||
PKG_P8PANELS_VISUAL.TDATA_GRID_ADD_COL_DEF(RDATA_GRID => RDG,
|
||||
SNAME => 'SEQUIPDSCMML_TASK',
|
||||
SCAPTION => 'Задача',
|
||||
SDATA_TYPE => PKG_P8PANELS_VISUAL.SDATA_TYPE_STR,
|
||||
SHINT => UDO_PKG_EQUIPDS_BASE.CMML_TASK_HINT());
|
||||
PKG_P8PANELS_VISUAL.TDATA_GRID_ADD_COL_DEF(RDATA_GRID => RDG,
|
||||
SNAME => 'NEQUIPDSCMML_PRECISION_F',
|
||||
SCAPTION => 'Точность (факт)',
|
||||
SDATA_TYPE => PKG_P8PANELS_VISUAL.SDATA_TYPE_NUMB);
|
||||
PKG_P8PANELS_VISUAL.TDATA_GRID_ADD_COL_DEF(RDATA_GRID => RDG,
|
||||
SNAME => 'NFORECAST',
|
||||
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%');
|
||||
PKG_P8PANELS_VISUAL.TDATA_GRID_ADD_COL_DEF(RDATA_GRID => RDG,
|
||||
SNAME => 'SFORECAST',
|
||||
SCAPTION => 'Данные прогноза',
|
||||
SDATA_TYPE => PKG_P8PANELS_VISUAL.SDATA_TYPE_STR,
|
||||
BVISIBLE => false);
|
||||
/* Обходим данные */
|
||||
for C in (select T.RN NRN,
|
||||
T.RQ_AUTHID SRQ_AUTHID,
|
||||
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,
|
||||
null NFORECAST,
|
||||
null SFORECAST,
|
||||
T.FORECAST BFORECAST
|
||||
from UDO_T_EQUIPDSCMMLH T,
|
||||
UDO_T_EQUIPDSCMML ML,
|
||||
UDO_T_EQUIPDSCM CM,
|
||||
UDO_T_EQUIPDS DS
|
||||
where T.EQCONFIG = NEQCONFIG
|
||||
and T.PRN = ML.RN
|
||||
and ML.PRN = CM.RN
|
||||
and CM.PRN = DS.RN
|
||||
order by T.RN desc)
|
||||
loop
|
||||
/* Конвертируем данные прогноза */
|
||||
C.SFORECAST := BLOB2CLOB(LBDATA => C.BFORECAST);
|
||||
/* Извлекаем прогноз */
|
||||
C.NFORECAST := CMMLH_DEMO_FORECAST_PARSE(CFORECAST => C.SFORECAST);
|
||||
/* Добавляем колонки с данными */
|
||||
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);
|
||||
PKG_P8PANELS_VISUAL.TROW_ADD_COL(RROW => RDG_ROW, SNAME => 'SRQ_DATE', SVALUE => C.SRQ_DATE);
|
||||
PKG_P8PANELS_VISUAL.TROW_ADD_COL(RROW => RDG_ROW, SNAME => 'SEQUIPDS_CODE', SVALUE => C.SEQUIPDS_CODE);
|
||||
PKG_P8PANELS_VISUAL.TROW_ADD_COL(RROW => RDG_ROW, SNAME => 'SEQUIPDSCMML_TASK', SVALUE => C.SEQUIPDSCMML_TASK);
|
||||
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.TDATA_GRID_ADD_ROW(RDATA_GRID => RDG, RROW => RDG_ROW);
|
||||
end loop;
|
||||
/* Сериализуем описание */
|
||||
COUT := PKG_P8PANELS_VISUAL.TDATA_GRID_TO_XML(RDATA_GRID => RDG, NINCLUDE_DEF => 1);
|
||||
end CMMLH_LIST_BY_EQCONFIG;
|
||||
|
||||
end UDO_PKG_EQUIPDS;
|
||||
/
|
||||
|
@ -147,6 +147,37 @@ create or replace package UDO_PKG_EQUIPDS_BASE as
|
||||
function CMML_TASK_HINT
|
||||
return varchar2; -- Подсказка для задачи
|
||||
|
||||
/* Базовое добавление "Выборки данных оборудования (классы оборудования, модели, история запросов)" */
|
||||
procedure CMMLH_INS
|
||||
(
|
||||
NPRN in number, -- Родитель
|
||||
NEQCONFIG in number, -- Рег. номер технического объекта
|
||||
SRQ_AUTHID in varchar2, -- Пользователь, выполнивший запрос
|
||||
DRQ_DATE in date, -- Дата/время запроса
|
||||
BRQ in blob, -- Параметры запроса
|
||||
NRN out number -- Регистрационный номер
|
||||
);
|
||||
|
||||
/* Базовое удаление "Выборки данных оборудования (классы оборудования, модели, история запросов)" */
|
||||
procedure CMMLH_DEL
|
||||
(
|
||||
NRN in number -- Регистрационный номер
|
||||
);
|
||||
|
||||
/* Базовая установка данных прогноза "Выборки данных оборудования (классы оборудования, файлы данных, история запросов)" */
|
||||
procedure CMMLH_SET_FORECAST
|
||||
(
|
||||
NRN in number, -- Регистрационный номер
|
||||
BFORECAST in blob -- Данные прогноза
|
||||
);
|
||||
|
||||
/* Базовая установка идентификатора очереди обмена "Выборки данных оборудования (классы оборудования, файлы данных, история запросов)" */
|
||||
procedure CMMLH_SET_EXSQUEUE
|
||||
(
|
||||
NRN in number, -- Регистрационный номер
|
||||
NEXSQUEUE in number -- Идентификатор очереди обмена
|
||||
);
|
||||
|
||||
end UDO_PKG_EQUIPDS_BASE;
|
||||
/
|
||||
create or replace package body UDO_PKG_EQUIPDS_BASE as
|
||||
@ -468,5 +499,61 @@ create or replace package body UDO_PKG_EQUIPDS_BASE as
|
||||
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)';
|
||||
end CMML_TASK_HINT;
|
||||
|
||||
/* Базовое добавление "Выборки данных оборудования (классы оборудования, модели, история запросов)" */
|
||||
procedure CMMLH_INS
|
||||
(
|
||||
NPRN in number, -- Родитель
|
||||
NEQCONFIG in number, -- Рег. номер технического объекта
|
||||
SRQ_AUTHID in varchar2, -- Пользователь, выполнивший запрос
|
||||
DRQ_DATE in date, -- Дата/время запроса
|
||||
BRQ in blob, -- Параметры запроса
|
||||
NRN out number -- Регистрационный номер
|
||||
)
|
||||
is
|
||||
begin
|
||||
/* Формируем рег. номер */
|
||||
NRN := GEN_ID();
|
||||
/* Добавляем запись */
|
||||
insert into UDO_T_EQUIPDSCMMLH
|
||||
(RN, PRN, EQCONFIG, RQ_AUTHID, RQ_DATE, RQ, FORECAST, EXSQUEUE)
|
||||
values
|
||||
(NRN, NPRN, NEQCONFIG, SRQ_AUTHID, DRQ_DATE, BRQ, null, null);
|
||||
end CMMLH_INS;
|
||||
|
||||
/* Базовое удаление "Выборки данных оборудования (классы оборудования, модели, история запросов)" */
|
||||
procedure CMMLH_DEL
|
||||
(
|
||||
NRN in number -- Регистрационный номер
|
||||
)
|
||||
is
|
||||
begin
|
||||
/* Удалим запись */
|
||||
delete from UDO_T_EQUIPDSCMMLH T where T.RN = NRN;
|
||||
end CMMLH_DEL;
|
||||
|
||||
/* Базовая установка данных прогноза "Выборки данных оборудования (классы оборудования, файлы данных, история запросов)" */
|
||||
procedure CMMLH_SET_FORECAST
|
||||
(
|
||||
NRN in number, -- Регистрационный номер
|
||||
BFORECAST in blob -- Данные прогноза
|
||||
)
|
||||
is
|
||||
begin
|
||||
/* Установим данные ответа */
|
||||
update UDO_T_EQUIPDSCMMLH T set T.FORECAST = BFORECAST where T.RN = NRN;
|
||||
end CMMLH_SET_FORECAST;
|
||||
|
||||
/* Базовая установка идентификатора очереди обмена "Выборки данных оборудования (классы оборудования, файлы данных, история запросов)" */
|
||||
procedure CMMLH_SET_EXSQUEUE
|
||||
(
|
||||
NRN in number, -- Регистрационный номер
|
||||
NEXSQUEUE in number -- Идентификатор очереди обмена
|
||||
)
|
||||
is
|
||||
begin
|
||||
/* Установим идентификатор очереди обмена */
|
||||
update UDO_T_EQUIPDSCMMLH T set T.EXSQUEUE = NEXSQUEUE where T.RN = NRN;
|
||||
end CMMLH_SET_EXSQUEUE;
|
||||
|
||||
end UDO_PKG_EQUIPDS_BASE;
|
||||
/
|
||||
|
@ -29,6 +29,23 @@ create or replace package UDO_PKG_EQUIPTCF as
|
||||
COUT out clob -- Сериализованная карточка
|
||||
);
|
||||
|
||||
/* Отправка запроса на формирование прогноза технического объекта */
|
||||
procedure EQCONFIG_THOBJ_FORECAST
|
||||
(
|
||||
NEQCONFIG in number, -- Рег. номер технического объекта
|
||||
NEQUIPDSCMML in number -- Рег. номер модели
|
||||
);
|
||||
|
||||
/* Формирование ремонтной ведомости для технического объекта */
|
||||
procedure EQCONFIG_THOBJ_MAKE_EQRPSHEET
|
||||
(
|
||||
NEQCONFIG in number, -- Рег. номер технического объекта
|
||||
SACATALOG in varchar2, -- Каталог размещения ведомости
|
||||
SEQTECSRVKIND in varchar2, -- Вид ремонта
|
||||
DPLANDATE_FROM in date, -- Плановая дата начала ремонта
|
||||
NIDENT out number -- Идентификатор списка сформированных ведомостей
|
||||
);
|
||||
|
||||
end UDO_PKG_EQUIPTCF;
|
||||
/
|
||||
create or replace package body UDO_PKG_EQUIPTCF as
|
||||
@ -417,5 +434,108 @@ text="Проверка прав доступа при формировании
|
||||
PKG_XMAKE.CLOSE_CURSOR(ICURSOR => NCUR);
|
||||
end EQCONFIG_THOBJ_CARD;
|
||||
|
||||
/* Отправка запроса на формирование прогноза технического объекта */
|
||||
procedure EQCONFIG_THOBJ_FORECAST
|
||||
(
|
||||
NEQCONFIG in number, -- Рег. номер технического объекта
|
||||
NEQUIPDSCMML in number -- Рег. номер модели
|
||||
)
|
||||
is
|
||||
NEQUIPDSCMMLH PKG_STD.TREF; -- Рег. номер истории запросов модели
|
||||
CDEMO clob; -- Демо-данные прогноза
|
||||
begin
|
||||
/* Добавляем запись истории запросов */
|
||||
UDO_PKG_EQUIPDS_BASE.CMMLH_INS(NPRN => NEQUIPDSCMML,
|
||||
NEQCONFIG => NEQCONFIG,
|
||||
SRQ_AUTHID => UTILIZER(),
|
||||
DRQ_DATE => sysdate,
|
||||
BRQ => null,
|
||||
NRN => NEQUIPDSCMMLH);
|
||||
/* Добавим демо-данные */
|
||||
for C in (select T.TASK from UDO_T_EQUIPDSCMML T where T.RN = NEQUIPDSCMML)
|
||||
loop
|
||||
UDO_PKG_EQUIPDS.CMMLH_DEMO_BUILD(STASK => C.TASK, COUT => CDEMO);
|
||||
UDO_PKG_EQUIPDS_BASE.CMMLH_SET_FORECAST(NRN => NEQUIPDSCMMLH, BFORECAST => CLOB2BLOB(LCDATA => CDEMO));
|
||||
end loop;
|
||||
end EQCONFIG_THOBJ_FORECAST;
|
||||
|
||||
/* Формирование ремонтной ведомости для технического объекта */
|
||||
procedure EQCONFIG_THOBJ_MAKE_EQRPSHEET
|
||||
(
|
||||
NEQCONFIG in number, -- Рег. номер технического объекта
|
||||
SACATALOG in varchar2, -- Каталог размещения ведомости
|
||||
SEQTECSRVKIND in varchar2, -- Вид ремонта
|
||||
DPLANDATE_FROM in date, -- Плановая дата начала ремонта
|
||||
NIDENT out number -- Идентификатор списка сформированных ведомостей
|
||||
|
||||
)
|
||||
is
|
||||
NCOMPANY PKG_STD.TREF := GET_SESSION_COMPANY(); -- Рег. номер организации
|
||||
NCRN PKG_STD.TREF; -- Рег. номер каталога размещения ведомости
|
||||
SJURPERSONS PKG_STD.TSTRING; -- Юридическая принадлежность технического объекта
|
||||
SCURRENCY PKG_STD.TSTRING; -- Валюта ведомости
|
||||
SDOCTYPES PKG_STD.TSTRING; -- Тип документа ведомости
|
||||
SPREF PKG_STD.TSTRING; -- Префикс ведосмости
|
||||
SNUMB PKG_STD.TSTRING; -- Номер ведомости
|
||||
NEQRPSHEET PKG_STD.TREF; -- Рег. номер сформированной ведомости
|
||||
NSELECTLIST PKG_STD.TREF; -- Рег. номер позиции списк сформированных ведомостей
|
||||
begin
|
||||
/* Определяем юридическую принадлежность технического объекта */
|
||||
begin
|
||||
select JP.CODE
|
||||
into SJURPERSONS
|
||||
from EQCONFIG T,
|
||||
JURPERSONS JP
|
||||
where T.RN = NEQCONFIG
|
||||
and T.JUR_PERS = JP.RN;
|
||||
exception
|
||||
when NO_DATA_FOUND then
|
||||
PKG_MSG.RECORD_NOT_FOUND(NFLAG_SMART => 0, NDOCUMENT => NEQCONFIG, SUNIT_TABLE => 'EquipConfiguration');
|
||||
end;
|
||||
/* Читаем валюту документа по-умолчанию из параметров */
|
||||
SCURRENCY := GET_OPTIONS_STR(SCODE => 'Equip_RepairSheets_Currency');
|
||||
/* Читаем тип документа по-умолчанию из параметров */
|
||||
SDOCTYPES := GET_OPTIONS_STR(SCODE => 'Equip_RepairSheets_DocType');
|
||||
/* Читаем префикс документа по-умолчанию из параметров */
|
||||
SPREF := GET_OPTIONS_STR(SCODE => 'Equip_RepairSheets_DocPref');
|
||||
/* Формируем очередной номер документа */
|
||||
P_EQRPSHEETS_GETNEXTNUMB(NCOMPANY => NCOMPANY, SPREF => SPREF, SDOCTYPES => SDOCTYPES, SNUMB => SNUMB);
|
||||
/* Определяем каталог размещения */
|
||||
FIND_ACATALOG_NAME(NFLAG_SMART => 0,
|
||||
NCOMPANY => NCOMPANY,
|
||||
NVERSION => null,
|
||||
SUNITCODE => 'EquipRepairSheets',
|
||||
SNAME => SACATALOG,
|
||||
NRN => NCRN);
|
||||
/* Формируем ведомость */
|
||||
P_EQRPSHEETS_MAKE_EQRPSHEET(NCOMPANY => NCOMPANY,
|
||||
NCRN => NCRN,
|
||||
SDOCTYPES => SDOCTYPES,
|
||||
SPREF => SPREF,
|
||||
SNUMB => SNUMB,
|
||||
DDOCDATE => sysdate,
|
||||
SJURPERSONS => SJURPERSONS,
|
||||
DPLANDATE_FROM => DPLANDATE_FROM,
|
||||
DPLANDATE_TO => DPLANDATE_FROM,
|
||||
SCURRENCY => SCURRENCY,
|
||||
NCOURSE => 1,
|
||||
SEQTECSRVKIND => SEQTECSRVKIND,
|
||||
NPR_OBJ => null,
|
||||
NTECH_OBJ => NEQCONFIG,
|
||||
STECH_SRV_DIV => null,
|
||||
SRESP_DIV => null,
|
||||
SPERF_DIV => null,
|
||||
SPERFORM_AGN => null,
|
||||
SLEVEL => null,
|
||||
SEQOBJKIND => null,
|
||||
NRN => NEQRPSHEET);
|
||||
/* Добавим ведомость в список */
|
||||
NIDENT := GEN_IDENT();
|
||||
P_SELECTLIST_INSERT(NIDENT => NIDENT,
|
||||
NDOCUMENT => NEQRPSHEET,
|
||||
SUNITCODE => 'EquipRepairSheets',
|
||||
NRN => NSELECTLIST);
|
||||
end EQCONFIG_THOBJ_MAKE_EQRPSHEET;
|
||||
|
||||
end UDO_PKG_EQUIPTCF;
|
||||
/
|
||||
|
27
db/UDO_T_EQUIPDSCMMLH.sql
Normal file
27
db/UDO_T_EQUIPDSCMMLH.sql
Normal file
@ -0,0 +1,27 @@
|
||||
/* Выборки данных оборудования (классы оборудования, модели, история запросов) */
|
||||
create table UDO_T_EQUIPDSCMMLH
|
||||
(
|
||||
/* Регистрационный номер */
|
||||
RN number(17) not null,
|
||||
/* Родитель */
|
||||
PRN number(17) not null,
|
||||
/* Рег. номер технического объекта */
|
||||
EQCONFIG number(17) not null,
|
||||
/* Пользователь, выполнивший запрос */
|
||||
RQ_AUTHID varchar2(30) not null,
|
||||
/* Дата/время запроса */
|
||||
RQ_DATE date not null,
|
||||
/* Параметры запроса */
|
||||
RQ blob,
|
||||
/* Данные прогноза */
|
||||
FORECAST blob,
|
||||
/* Идентификатор очереди обмена */
|
||||
EXSQUEUE number(17) default null,
|
||||
/* Ключи */
|
||||
constraint UDO_C_EQUIPDSCMMLH_RN_PK primary key (RN),
|
||||
constraint UDO_C_EQUIPDSCMMLH_PRN_FK foreign key (PRN) references UDO_T_EQUIPDSCMML(RN),
|
||||
constraint UDO_C_EQUIPDSCMMLH_EQCONFIG_FK foreign key (EQCONFIG) references EQCONFIG(RN),
|
||||
constraint UDO_C_EQUIPDSCMMLH_RQAUTHID_NB check (rtrim(RQ_AUTHID) is not null),
|
||||
constraint UDO_C_EQUIPDSCMMLH_EXSQUEUE_FK foreign key (EXSQUEUE) references EXSQUEUE(RN),
|
||||
constraint UDO_C_EQUIPDSCMMLH_UN unique (PRN, RQ_AUTHID, RQ_DATE)
|
||||
);
|
@ -43,6 +43,9 @@ const REFRESH_INITIAL = {
|
||||
dataSelectionClassMachineModelsList: 0
|
||||
};
|
||||
|
||||
//Начальное состояние диалогов
|
||||
const DIALOGS_INITIAL = { dataSelectionIU: false, dataSelectionClassMachineIU: false, dataSelectionClassMachineModelIU: false };
|
||||
|
||||
//Стили
|
||||
const STYLES = {
|
||||
DATA_SELECTION_STACK: { alignItems: "center" },
|
||||
@ -62,7 +65,7 @@ const AdminTab = ({ dataSelection = DS_RN_DEFAULT, dataSelectionClassMachine = n
|
||||
const { pOnlineUserProcedure } = useContext(ApplicationСtx);
|
||||
|
||||
//Собственное состояние - отображаемые диалоги
|
||||
const [dialogs, setDialogs] = useState({ dataSelectionIU: false, dataSelectionClassMachineIU: false, dataSelectionClassMachineModelIU: false });
|
||||
const [dialogs, setDialogs] = useState(DIALOGS_INITIAL);
|
||||
|
||||
//Собственное состояние - флаги обновления данных
|
||||
const [refresh, setRefresh] = useState(REFRESH_INITIAL);
|
||||
|
@ -7,7 +7,7 @@
|
||||
//Подключение библиотек
|
||||
//---------------------
|
||||
|
||||
import React, { useState, useContext, useEffect } from "react"; //Классы React
|
||||
import React, { useState, useContext } from "react"; //Классы React
|
||||
import PropTypes from "prop-types"; //Контроль свойств компонента
|
||||
import {
|
||||
Box,
|
||||
@ -28,15 +28,13 @@ import {
|
||||
DialogTitle,
|
||||
DialogContent,
|
||||
DialogActions,
|
||||
Input,
|
||||
InputAdornment,
|
||||
IconButton,
|
||||
Icon
|
||||
} from "@mui/material"; //Интерфейсные компоненты
|
||||
import { useTheme } from "@mui/material/styles"; //Темы оформления
|
||||
import { ApplicationСtx } from "../../context/application"; //Контекст приложения
|
||||
import { BUTTONS } from "../../../app.text"; //Текстовые ресурсы и константы
|
||||
import { APP_BAR_HEIGHT, TABS_HEIGHT, SCROLL_STYLES, formatModelStateValue } from "./eqs_tech_cond_forecast_lyaout"; //Общие вспомогательные компоненты и вёрстка
|
||||
import { APP_BAR_HEIGHT, TABS_HEIGHT, SCROLL_STYLES, formatModelStateValue, IUDFormTextField } from "./eqs_tech_cond_forecast_lyaout"; //Общие вспомогательные компоненты и вёрстка
|
||||
import { P8PDataGrid, P8P_DATA_GRID_SIZE } from "../../components/p8p_data_grid"; //Таблица данных
|
||||
import { P8P_DATA_GRID_CONFIG_PROPS } from "../../config_wrapper"; //Подключение компонентов к настройкам приложения
|
||||
import { DS_RN_DEFAULT } from "./admin_tab_hooks"; //Вспомогательные хуки
|
||||
@ -104,85 +102,6 @@ const STYLES = {
|
||||
//Вспомогательные функции и компоненты
|
||||
//------------------------------------
|
||||
|
||||
//Поле ввода из словаря
|
||||
const IUDFormTextField = ({ elementCode, elementValue, labelText, onChange, dictionary, list, ...other }) => {
|
||||
//Значение элемента
|
||||
const [value, setValue] = useState(elementValue);
|
||||
|
||||
//При получении нового значения из вне
|
||||
useEffect(() => {
|
||||
setValue(elementValue);
|
||||
}, [elementValue]);
|
||||
|
||||
//Выбор значения из словаря
|
||||
const handleDictionaryClick = () =>
|
||||
dictionary ? dictionary(res => (res ? res.map(i => handleChange({ target: { name: i.name, value: i.value } })) : null)) : null;
|
||||
|
||||
//Изменение значения элемента
|
||||
const handleChange = e => {
|
||||
console.log(e.target.name, e.target.value);
|
||||
setValue(e.target.value);
|
||||
if (onChange) onChange(e.target.name, e.target.value);
|
||||
};
|
||||
|
||||
//Генерация содержимого
|
||||
return (
|
||||
<Box p={1}>
|
||||
<FormControl variant="standard" fullWidth {...other}>
|
||||
{list ? (
|
||||
<>
|
||||
<InputLabel id={`${elementCode}Lable`}>{labelText}</InputLabel>
|
||||
<Select
|
||||
labelId={`${elementCode}Lable`}
|
||||
id={elementCode}
|
||||
name={elementCode}
|
||||
label={labelText}
|
||||
value={value ? value : ""}
|
||||
onChange={handleChange}
|
||||
displayEmpty
|
||||
>
|
||||
{list.map((item, i) => (
|
||||
<MenuItem key={i} value={item.value ? item.value : ""}>
|
||||
{item.name}
|
||||
</MenuItem>
|
||||
))}
|
||||
</Select>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<InputLabel htmlFor={elementCode}>{labelText}</InputLabel>
|
||||
<Input
|
||||
id={elementCode}
|
||||
name={elementCode}
|
||||
value={value ? value : ""}
|
||||
endAdornment={
|
||||
dictionary ? (
|
||||
<InputAdornment position="end">
|
||||
<IconButton aria-label={`${elementCode} select`} onClick={handleDictionaryClick} edge="end">
|
||||
<Icon>list</Icon>
|
||||
</IconButton>
|
||||
</InputAdornment>
|
||||
) : null
|
||||
}
|
||||
onChange={handleChange}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
</FormControl>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
//Контроль свойств - Поле ввода из словаря
|
||||
IUDFormTextField.propTypes = {
|
||||
elementCode: PropTypes.string.isRequired,
|
||||
elementValue: PropTypes.string,
|
||||
labelText: PropTypes.string.isRequired,
|
||||
onChange: PropTypes.func,
|
||||
dictionary: PropTypes.func,
|
||||
list: PropTypes.array
|
||||
};
|
||||
|
||||
//Кнопка с дополнительной подписью
|
||||
const ExtraCaptionButton = ({ caption, title, subtitle, maxWidth, onClick, theme }) => {
|
||||
//При нажатии на кнопку
|
||||
|
@ -7,9 +7,9 @@
|
||||
//Подключение библиотек
|
||||
//---------------------
|
||||
|
||||
import React from "react"; //Классы React
|
||||
import React, { useState, useEffect } from "react"; //Классы React
|
||||
import PropTypes from "prop-types"; //Контроль свойств компонента
|
||||
import { Box, Stack, Icon } from "@mui/material"; //Интерфейсные компоненты
|
||||
import { Box, Stack, Icon, Input, InputAdornment, FormControl, Select, InputLabel, MenuItem, IconButton } from "@mui/material"; //Интерфейсные компоненты
|
||||
|
||||
//---------
|
||||
//Константы
|
||||
@ -62,10 +62,10 @@ const formatModelStateValue = (theme, value, err) => {
|
||||
value == 0
|
||||
? ["Зарегистрирована", "app_registration", null]
|
||||
: value == 1
|
||||
? ["Обрабатывается внешней системой", "manage_history", theme.palette.warning.main]
|
||||
? ["Обучается", "manage_history", theme.palette.warning.main]
|
||||
: value == 2
|
||||
? ["Успешно обработана внешней системой", "check_circle", theme.palette.primary.main]
|
||||
: [`Ошибка обработки внешней системой: ${err}`, "error", theme.palette.error.main];
|
||||
? ["Обучена", "check_circle", theme.palette.primary.main]
|
||||
: [`Ошибка обучения: ${err}`, "error", theme.palette.error.main];
|
||||
return (
|
||||
<Stack direction="row" gap={0.5} alignItems="center" justifyContent="left" color={color}>
|
||||
<Icon title={text}>{icon}</Icon>
|
||||
@ -84,8 +84,98 @@ TabPanel.propTypes = {
|
||||
children: PropTypes.element
|
||||
};
|
||||
|
||||
//Поле ввода формы
|
||||
const IUDFormTextField = ({ elementCode, elementValue, labelText, onChange, dictionary, list, type, ...other }) => {
|
||||
//Значение элемента
|
||||
const [value, setValue] = useState(elementValue);
|
||||
|
||||
//При получении нового значения из вне
|
||||
useEffect(() => {
|
||||
setValue(elementValue);
|
||||
}, [elementValue]);
|
||||
|
||||
//Выбор значения из словаря
|
||||
const handleDictionaryClick = () =>
|
||||
dictionary ? dictionary(res => (res ? res.map(i => handleChange({ target: { name: i.name, value: i.value } })) : null)) : null;
|
||||
|
||||
//Изменение значения элемента
|
||||
const handleChange = e => {
|
||||
setValue(e.target.value);
|
||||
if (onChange) onChange(e.target.name, e.target.value);
|
||||
};
|
||||
|
||||
//Генерация содержимого
|
||||
return (
|
||||
<Box p={1}>
|
||||
<FormControl variant="standard" fullWidth {...other}>
|
||||
{list ? (
|
||||
<>
|
||||
<InputLabel id={`${elementCode}Lable`}>{labelText}</InputLabel>
|
||||
<Select
|
||||
labelId={`${elementCode}Lable`}
|
||||
id={elementCode}
|
||||
name={elementCode}
|
||||
label={labelText}
|
||||
value={value ? value : ""}
|
||||
onChange={handleChange}
|
||||
displayEmpty
|
||||
>
|
||||
{list.map((item, i) => (
|
||||
<MenuItem key={i} value={item.value ? item.value : ""}>
|
||||
{item.name}
|
||||
</MenuItem>
|
||||
))}
|
||||
</Select>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<InputLabel htmlFor={elementCode}>{labelText}</InputLabel>
|
||||
<Input
|
||||
id={elementCode}
|
||||
name={elementCode}
|
||||
value={value ? value : ""}
|
||||
endAdornment={
|
||||
dictionary ? (
|
||||
<InputAdornment position="end">
|
||||
<IconButton aria-label={`${elementCode} select`} onClick={handleDictionaryClick} edge="end">
|
||||
<Icon>list</Icon>
|
||||
</IconButton>
|
||||
</InputAdornment>
|
||||
) : null
|
||||
}
|
||||
{...(type ? { type } : {})}
|
||||
onChange={handleChange}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
</FormControl>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
//Контроль свойств - Поле ввода формы
|
||||
IUDFormTextField.propTypes = {
|
||||
elementCode: PropTypes.string.isRequired,
|
||||
elementValue: PropTypes.string,
|
||||
labelText: PropTypes.string.isRequired,
|
||||
onChange: PropTypes.func,
|
||||
dictionary: PropTypes.func,
|
||||
list: PropTypes.array,
|
||||
type: PropTypes.string
|
||||
};
|
||||
|
||||
//----------------
|
||||
//Интерфейс модуля
|
||||
//----------------
|
||||
|
||||
export { MODES, APP_BAR_HEIGHT, TABS_HEIGHT, TABLE_MORE_HEIGHT, TABLE_FILTERS_HEIGHT, SCROLL_STYLES, formatModelStateValue, TabPanel };
|
||||
export {
|
||||
MODES,
|
||||
APP_BAR_HEIGHT,
|
||||
TABS_HEIGHT,
|
||||
TABLE_MORE_HEIGHT,
|
||||
TABLE_FILTERS_HEIGHT,
|
||||
SCROLL_STYLES,
|
||||
formatModelStateValue,
|
||||
TabPanel,
|
||||
IUDFormTextField
|
||||
};
|
||||
|
@ -13,15 +13,18 @@ import { Box, Grid } from "@mui/material"; //Интерфейсные компо
|
||||
import { RichTreeView } from "@mui/x-tree-view/RichTreeView"; //Дерево
|
||||
import { useTreeViewApiRef } from "@mui/x-tree-view/hooks/useTreeViewApiRef"; //API дерева
|
||||
import { MessagingСtx } from "../../context/messaging"; //Контекст сообщений
|
||||
import { BackEndСtx } from "../../context/backend"; //Контекст взаимодействия с серверомs
|
||||
import { ApplicationСtx } from "../../context/application"; //Контекст приложения
|
||||
import { P8PDataGrid, P8P_DATA_GRID_SIZE } from "../../components/p8p_data_grid"; //Таблица данных
|
||||
import { P8P_DATA_GRID_CONFIG_PROPS } from "../../config_wrapper"; //Подключение компонентов к настройкам приложения
|
||||
import { APP_BAR_HEIGHT, TABS_HEIGHT, TABLE_FILTERS_HEIGHT, TABLE_MORE_HEIGHT, SCROLL_STYLES } from "./eqs_tech_cond_forecast_lyaout"; //Общие Вспомогательные компоненты и вёрстка
|
||||
import { TechObjCard, eqConfigTechObjTableValueFormatter, eqConfigTechObjTableDataCellRender } from "./forecast_tab_layout"; //Вспомогательные компоненты и вёрстка
|
||||
import { TechObjCard, eqConfigTechObjTableValueFormatter, eqConfigTechObjTableDataCellRender, TechObjMakeEqRpSheet } from "./forecast_tab_layout"; //Вспомогательные компоненты и вёрстка
|
||||
import {
|
||||
useEqConfigTree,
|
||||
useEqConfigTechObjTable,
|
||||
useEqConfigTechObjCard,
|
||||
useTechObjModelsList,
|
||||
useTechObjForecastHistList,
|
||||
findTreeItem,
|
||||
needLoadLevel
|
||||
} from "./forecast_tab_hooks"; //Вспомогательные хуки
|
||||
@ -30,6 +33,14 @@ import {
|
||||
//Константы
|
||||
//---------
|
||||
|
||||
//Начальное состояние флагов обновления
|
||||
const REFRESH_INITIAL = {
|
||||
techObjForecastHistList: 0
|
||||
};
|
||||
|
||||
//Начальное состояние диалогов
|
||||
const DIALOGS_INITIAL = { makeEqRpSheet: false };
|
||||
|
||||
//Стили
|
||||
const STYLES = {
|
||||
LEFT_SIDE_GRID: {},
|
||||
@ -59,9 +70,15 @@ const TECH_OBJ_SPEC_INIT = { parent: null, filters: [], orders: [], pageNumber:
|
||||
|
||||
//Закладка прогнозирования
|
||||
const ForecastTab = ({ onGoToAdmin }) => {
|
||||
//Подключение к контексту взаимодействия с сервером
|
||||
const { executeStored } = useContext(BackEndСtx);
|
||||
|
||||
//Подключение к контексту сообщений
|
||||
const { InlineMsgInfo } = useContext(MessagingСtx);
|
||||
|
||||
//Подключение к контексту приложения
|
||||
const { pOnlineShowUnit } = useContext(ApplicationСtx);
|
||||
|
||||
//Подключение к API дерева
|
||||
const apiRef = useTreeViewApiRef();
|
||||
|
||||
@ -71,9 +88,15 @@ const ForecastTab = ({ onGoToAdmin }) => {
|
||||
//Собственное состояние - спецификация технических объектов
|
||||
const [techObjSpec, setTechObjSpec] = useState({ ...TECH_OBJ_SPEC_INIT });
|
||||
|
||||
//Собственное состояния - карточка технического объекта
|
||||
//Собственное состояния - карточка технического объекта - 11984229
|
||||
const [techObjCardId, setTechObjCardId] = useState(null);
|
||||
|
||||
//Собственное состояние - отображаемые диалоги
|
||||
const [dialogs, setDialogs] = useState(DIALOGS_INITIAL);
|
||||
|
||||
//Собственное состояния - флаги перезагрузки
|
||||
const [refresh, setRefresh] = useState(REFRESH_INITIAL);
|
||||
|
||||
//Загрузчик веток дерева
|
||||
const { eQconfigTree } = useEqConfigTree(loadingTreeItem);
|
||||
|
||||
@ -89,7 +112,10 @@ const ForecastTab = ({ onGoToAdmin }) => {
|
||||
const { techObjCard, techObjCardIsLoading } = useEqConfigTechObjCard(techObjCardId);
|
||||
|
||||
//Загрузчик моделей выбранного технического объекта
|
||||
const { techObjModelsList, techObjModelsListIsLoading } = useTechObjModelsList(techObjCardId);
|
||||
const { techObjModelsList } = useTechObjModelsList(techObjCardId);
|
||||
|
||||
//
|
||||
const { techObjForecastHistList } = useTechObjForecastHistList(techObjCardId, refresh.techObjForecastHistList);
|
||||
|
||||
//Обработка развёртывания/свёртывания уровня дерева
|
||||
const handleTreeItemExpansionToggle = (event, itemId, isExpanded) =>
|
||||
@ -128,9 +154,36 @@ const ForecastTab = ({ onGoToAdmin }) => {
|
||||
//При переходе к закладке администрирования из карточки технического объекта
|
||||
const handleTechObjeCardGoToModel = model => (onGoToAdmin ? onGoToAdmin(model.NEQUIPDS, model.NEQUIPDSCM) : null);
|
||||
|
||||
//При запросе прогноза по модели из карточки технического объекта
|
||||
const handleTechObjeCardGetPrediction = async model => {
|
||||
await executeStored({ stored: "UDO_PKG_EQUIPTCF.EQCONFIG_THOBJ_FORECAST", args: { NEQCONFIG: techObjCardId, NEQUIPDSCMML: model.NRN } });
|
||||
setRefresh(pv => ({ ...pv, techObjForecastHistList: pv.techObjForecastHistList + 1 }));
|
||||
};
|
||||
|
||||
//При закрытии карточки технического объекта
|
||||
const handleTechObjeCardClose = () => setTechObjCardId(null);
|
||||
|
||||
//При нажатии на "Ремонтировать" в карточке технического объекта
|
||||
const handleTechObjeCardMakeEqRpSheet = () => setDialogs(pv => ({ ...pv, makeEqRpSheet: true }));
|
||||
|
||||
//При нажатии "ОК" в диалоге формирования ремонтной ведомости
|
||||
const handleTechObjMakeEqRpSheetOk = async values => {
|
||||
const data = await executeStored({
|
||||
stored: "UDO_PKG_EQUIPTCF.EQCONFIG_THOBJ_MAKE_EQRPSHEET",
|
||||
args: {
|
||||
NEQCONFIG: techObjCardId,
|
||||
SACATALOG: values.acatalog,
|
||||
SEQTECSRVKIND: values.eQTecSrvKind,
|
||||
DPLANDATE_FROM: new Date(values.planDateFrom)
|
||||
}
|
||||
});
|
||||
setDialogs(pv => ({ ...pv, makeEqRpSheet: false }));
|
||||
pOnlineShowUnit({ unitCode: "EquipRepairSheets", showMethod: "main_selected", inputParameters: [{ name: "in_Ident", value: data.NIDENT }] });
|
||||
};
|
||||
|
||||
//При нажитии "Отмена" в диалоге формирования ремонтной ведомости
|
||||
const handleTechObjMakeEqRpSheetCancel = () => setDialogs(pv => ({ ...pv, makeEqRpSheet: false }));
|
||||
|
||||
//Текст при отсутствии данных в списке технических объектов
|
||||
const noDataFoundText =
|
||||
techObjsDataGridIsLoading || !techObjsDataGrid.init
|
||||
@ -142,6 +195,7 @@ const ForecastTab = ({ onGoToAdmin }) => {
|
||||
//Генерация содержимого
|
||||
return (
|
||||
<div>
|
||||
{dialogs.makeEqRpSheet ? <TechObjMakeEqRpSheet onCancel={handleTechObjMakeEqRpSheetCancel} onOk={handleTechObjMakeEqRpSheetOk} /> : null}
|
||||
<Grid container>
|
||||
<Grid item xs={3} sx={STYLES.LEFT_SIDE_GRID}>
|
||||
<Box sx={STYLES.TREE_BOX}>
|
||||
@ -155,12 +209,15 @@ const ForecastTab = ({ onGoToAdmin }) => {
|
||||
</Grid>
|
||||
<Grid item xs={9} sx={STYLES.RIGHT_SIDE_GRID}>
|
||||
{techObjCardId ? (
|
||||
!techObjCardIsLoading && !techObjModelsListIsLoading ? (
|
||||
!techObjCardIsLoading ? (
|
||||
<TechObjCard
|
||||
cardData={techObjCard}
|
||||
modelsList={techObjModelsList}
|
||||
forecastHistList={techObjForecastHistList}
|
||||
onClose={handleTechObjeCardClose}
|
||||
onGoToModel={handleTechObjeCardGoToModel}
|
||||
onGetPrediction={handleTechObjeCardGetPrediction}
|
||||
onMakeEqRpSheet={handleTechObjeCardMakeEqRpSheet}
|
||||
/>
|
||||
) : null
|
||||
) : techObjsDataGrid.init ? (
|
||||
|
@ -225,8 +225,59 @@ const useTechObjModelsList = (id, refresh) => {
|
||||
return { techObjModelsList: data, techObjModelsListIsLoading: isLoading };
|
||||
};
|
||||
|
||||
//Загрузка истории запросов к модели единицы оборудования
|
||||
const useTechObjForecastHistList = (id, refresh) => {
|
||||
//Собственное состояние - флаг загрузки
|
||||
const [isLoading, setLoading] = useState(false);
|
||||
|
||||
//Собственное состояние - таблица данных
|
||||
const [data, setData] = useState({
|
||||
init: false,
|
||||
columnsDef: [],
|
||||
rows: []
|
||||
});
|
||||
|
||||
//Подключение к контексту взаимодействия с сервером
|
||||
const { executeStored } = useContext(BackEndСtx);
|
||||
|
||||
//Загрузка данных при изменении зависимостей
|
||||
useEffect(() => {
|
||||
const loadData = async () => {
|
||||
try {
|
||||
setLoading(true);
|
||||
const data = await executeStored({
|
||||
stored: "UDO_PKG_EQUIPDS.CMMLH_LIST_BY_EQCONFIG",
|
||||
args: { NEQCONFIG: id },
|
||||
respArg: "COUT",
|
||||
loader: false
|
||||
});
|
||||
setData(pv => ({
|
||||
...pv,
|
||||
columnsDef: [...data.XCOLUMNS_DEF],
|
||||
rows: [...(data.XROWS || [])],
|
||||
init: true
|
||||
}));
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
if (id) loadData();
|
||||
}, [id, refresh, executeStored]);
|
||||
|
||||
//Вернём данные
|
||||
return { techObjForecastHistList: data, techObjForecastHistListIsLoading: isLoading };
|
||||
};
|
||||
|
||||
//----------------
|
||||
//Интерфейс модуля
|
||||
//----------------
|
||||
|
||||
export { useEqConfigTree, useEqConfigTechObjTable, useEqConfigTechObjCard, findTreeItem, needLoadLevel, useTechObjModelsList };
|
||||
export {
|
||||
useEqConfigTree,
|
||||
useEqConfigTechObjTable,
|
||||
useEqConfigTechObjCard,
|
||||
findTreeItem,
|
||||
needLoadLevel,
|
||||
useTechObjModelsList,
|
||||
useTechObjForecastHistList
|
||||
};
|
||||
|
@ -7,15 +7,33 @@
|
||||
//Подключение библиотек
|
||||
//---------------------
|
||||
|
||||
import React from "react"; //Классы React
|
||||
import React, { useState, useEffect, useContext } from "react"; //Классы React
|
||||
import PropTypes from "prop-types"; //Контроль свойств компонента
|
||||
import { Stack, Icon, Box, Card, CardContent, Typography, CardActions, Button, IconButton, Divider } from "@mui/material"; //Интерфейсные компоненты
|
||||
import {
|
||||
Stack,
|
||||
Icon,
|
||||
Box,
|
||||
Card,
|
||||
CardContent,
|
||||
Typography,
|
||||
CardActions,
|
||||
Button,
|
||||
IconButton,
|
||||
Divider,
|
||||
Link,
|
||||
Dialog,
|
||||
DialogTitle,
|
||||
DialogContent,
|
||||
DialogActions
|
||||
} from "@mui/material"; //Интерфейсные компоненты
|
||||
import { useTheme } from "@mui/material/styles"; //Темы оформления
|
||||
import { ApplicationСtx } from "../../context/application"; //Контекст приложения
|
||||
import { BUTTONS } from "../../../app.text"; //Текстовые ресурсы и константы
|
||||
import { P8PDataGrid, P8P_DATA_GRID_SIZE } from "../../components/p8p_data_grid"; //Таблица данных
|
||||
import { P8P_DATA_GRID_CONFIG_PROPS } from "../../config_wrapper"; //Подключение компонентов к настройкам приложения
|
||||
import { formatDateRF } from "../../core/utils"; //Вспомогательные функции
|
||||
import { SCROLL_STYLES, formatModelStateValue } from "./eqs_tech_cond_forecast_lyaout"; //Общие вспомогательные компоненты и вёрстка
|
||||
import { Link } from "react-router-dom";
|
||||
import { formatDateRF, xml2JSON } from "../../core/utils"; //Вспомогательные функции
|
||||
import { SCROLL_STYLES, formatModelStateValue, IUDFormTextField } from "./eqs_tech_cond_forecast_lyaout"; //Общие вспомогательные компоненты и вёрстка
|
||||
import { P8PChart } from "../../components/p8p_chart"; //График
|
||||
|
||||
//---------
|
||||
//Константы
|
||||
@ -28,7 +46,13 @@ const STYLES = {
|
||||
EQ_ML_TABLE: {
|
||||
maxHeight: "200px",
|
||||
...SCROLL_STYLES
|
||||
}
|
||||
},
|
||||
EQ_FORECAST_TABLE: {
|
||||
maxHeight: "200px",
|
||||
...SCROLL_STYLES
|
||||
},
|
||||
EQ_FORECAST_DETAIL_DIALOG: { maxWidth: "600px" },
|
||||
EQ_FORECAST_DETAIL_CHART: { width: "550px", display: "flex", justifyContent: "center" }
|
||||
};
|
||||
|
||||
//------------------------------------
|
||||
@ -48,7 +72,7 @@ const techObjCardModelsTableHeadCellRender = ({ columnDef }) => {
|
||||
}
|
||||
};
|
||||
|
||||
//Форматирование колонок таблицы моделей класса оборудования выборки данных
|
||||
//Форматирование колонок таблицы моделей единицы оборудования
|
||||
const techObjCardModelsTableDataCellRender = ({ row, columnDef, theme, onGoToModel, onGetPrediction }) => {
|
||||
switch (columnDef.name) {
|
||||
case "SNEQUIPDS":
|
||||
@ -79,15 +103,71 @@ const techObjCardModelsTableDataCellRender = ({ row, columnDef, theme, onGoToMod
|
||||
}
|
||||
};
|
||||
|
||||
//Форматирование колонок таблицы истории прогнозов класса оборудования выборки данных
|
||||
const techObjCardForecastListTableDataCellRender = ({ row, columnDef, onShowForecastDetail }) => {
|
||||
switch (columnDef.name) {
|
||||
case "NFORECAST":
|
||||
return {
|
||||
data: (
|
||||
<Button
|
||||
variant="outlined"
|
||||
color={row.NFORECAST < 30 ? "success" : row.NFORECAST >= 30 && row.NFORECAST < 60 ? "warning" : "error"}
|
||||
onClick={() => onShowForecastDetail(row)}
|
||||
>
|
||||
{`${row.NFORECAST}%`}
|
||||
</Button>
|
||||
)
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
//Детали прогноза
|
||||
const ForecastDetail = ({ date, forecast, onClose }) => {
|
||||
//Собственное состояние - график
|
||||
const [chart, setChart] = useState({ loaded: false, labels: [], datasets: [] });
|
||||
|
||||
//При подключении к странице
|
||||
useEffect(() => {
|
||||
const loadChart = async () => {
|
||||
const chart = await xml2JSON({ xmlDoc: forecast });
|
||||
console.log(chart);
|
||||
setChart(pv => ({ ...pv, loaded: true, ...chart.XDATA.XCHART }));
|
||||
};
|
||||
loadChart();
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, []);
|
||||
|
||||
//Генерация содержимого
|
||||
return (
|
||||
<Dialog open={true} onClose={() => (onClose ? onClose() : null)} {...STYLES.EQ_FORECAST_DETAIL_DIALOG}>
|
||||
<DialogTitle>{`Детали прогноза от ${date}`}</DialogTitle>
|
||||
<DialogContent>{chart.loaded ? <P8PChart {...chart} style={STYLES.EQ_FORECAST_DETAIL_CHART} /> : null}</DialogContent>
|
||||
<DialogActions>
|
||||
<Button onClick={() => (onClose ? onClose() : null)}>{BUTTONS.CLOSE}</Button>
|
||||
</DialogActions>
|
||||
</Dialog>
|
||||
);
|
||||
};
|
||||
|
||||
//Контроль свойств - Детали прогноза
|
||||
ForecastDetail.propTypes = {
|
||||
date: PropTypes.string.isRequired,
|
||||
forecast: PropTypes.string.isRequired,
|
||||
onClose: PropTypes.func
|
||||
};
|
||||
|
||||
//-----------
|
||||
//Тело модуля
|
||||
//-----------
|
||||
|
||||
//Карточка технического объекта
|
||||
const TechObjCard = ({ cardData, modelsList, onClose, onGoToModel }) => {
|
||||
const TechObjCard = ({ cardData, modelsList, forecastHistList, onClose, onGoToModel, onGetPrediction, onMakeEqRpSheet }) => {
|
||||
//Подключаемся к теме
|
||||
const theme = useTheme();
|
||||
|
||||
//Собственное состояние
|
||||
const [state, setState] = useState({ forecastDetail: null, forecastDate: null });
|
||||
|
||||
//При нажатии на кнопку закрытия карточки
|
||||
const handleClose = () => (onClose ? onClose() : null);
|
||||
|
||||
@ -95,13 +175,25 @@ const TechObjCard = ({ cardData, modelsList, onClose, onGoToModel }) => {
|
||||
const handleGoToModelClick = model => (onGoToModel ? onGoToModel(model) : null);
|
||||
|
||||
//При нажатии на запрос предсказания
|
||||
const handleGetPredictionClick = model => {
|
||||
console.log(model);
|
||||
const handleGetPredictionClick = model => (onGetPrediction ? onGetPrediction(model) : null);
|
||||
|
||||
//При нажатии на формирование ремонтной ведомости
|
||||
const handleMakeEqRpSheetClick = () => (onMakeEqRpSheet ? onMakeEqRpSheet() : null);
|
||||
|
||||
//При нажатии на отображение деталей прогноза
|
||||
const handleShowForecastDetailClick = modelHist => {
|
||||
setState(pv => ({ ...pv, forecastDetail: modelHist.SFORECAST, forecastDate: modelHist.SRQ_DATE }));
|
||||
};
|
||||
|
||||
//При нажатии на закрытие деталей прогноза
|
||||
const handleCloseForecastDetailClick = () => setState(pv => ({ ...pv, forecastDetail: null, forecastDate: null }));
|
||||
|
||||
//Генерация содержимого
|
||||
return (
|
||||
<Box p={2}>
|
||||
{state.forecastDetail ? (
|
||||
<ForecastDetail date={state.forecastDate} forecast={state.forecastDetail} onClose={handleCloseForecastDetailClick} />
|
||||
) : null}
|
||||
<Card>
|
||||
<CardContent>
|
||||
<Stack spacing={2} direction={"row"} alignItems={"center"}>
|
||||
@ -122,6 +214,8 @@ const TechObjCard = ({ cardData, modelsList, onClose, onGoToModel }) => {
|
||||
</Typography>
|
||||
<Typography variant="h6">{cardData.SNAME}</Typography>
|
||||
<br />
|
||||
{modelsList.init ? (
|
||||
<>
|
||||
<Divider />
|
||||
<Typography variant="h6" component="div">
|
||||
Модели
|
||||
@ -145,10 +239,36 @@ const TechObjCard = ({ cardData, modelsList, onClose, onGoToModel }) => {
|
||||
})
|
||||
}
|
||||
/>
|
||||
</>
|
||||
) : null}
|
||||
{forecastHistList.init ? (
|
||||
<>
|
||||
<Divider />
|
||||
<Typography variant="h6" component="div">
|
||||
Прогнозы
|
||||
</Typography>
|
||||
<P8PDataGrid
|
||||
{...{ ...P8P_DATA_GRID_CONFIG_PROPS }}
|
||||
containerComponentProps={{ sx: STYLES.EQ_FORECAST_TABLE, elevation: 0 }}
|
||||
columnsDef={forecastHistList.columnsDef}
|
||||
rows={forecastHistList.rows}
|
||||
size={P8P_DATA_GRID_SIZE.SMALL}
|
||||
morePages={false}
|
||||
fixedHeader={true}
|
||||
reloading={false}
|
||||
dataCellRender={prms =>
|
||||
techObjCardForecastListTableDataCellRender({
|
||||
...prms,
|
||||
theme,
|
||||
onShowForecastDetail: handleShowForecastDetailClick
|
||||
})
|
||||
}
|
||||
/>
|
||||
</>
|
||||
) : null}
|
||||
</CardContent>
|
||||
<CardActions>
|
||||
<Button>Ремонтировать</Button>
|
||||
<Button onClick={handleMakeEqRpSheetClick}>Ремонтировать</Button>
|
||||
</CardActions>
|
||||
</Card>
|
||||
</Box>
|
||||
@ -159,8 +279,11 @@ const TechObjCard = ({ cardData, modelsList, onClose, onGoToModel }) => {
|
||||
TechObjCard.propTypes = {
|
||||
cardData: PropTypes.object.isRequired,
|
||||
modelsList: PropTypes.object.isRequired,
|
||||
forecastHistList: PropTypes.object.isRequired,
|
||||
onClose: PropTypes.func,
|
||||
onGoToModel: PropTypes.func
|
||||
onGoToModel: PropTypes.func,
|
||||
onGetPrediction: PropTypes.func,
|
||||
onMakeEqRpSheet: PropTypes.func
|
||||
};
|
||||
|
||||
//Формирование значения для колонки "Медель" таблицы технических объектов
|
||||
@ -198,8 +321,81 @@ const eqConfigTechObjTableDataCellRender = ({ row, columnDef, onCMMLStatus }) =>
|
||||
}
|
||||
};
|
||||
|
||||
//Диалог формирование ремонтной ведомости
|
||||
const TechObjMakeEqRpSheet = ({ onOk, onCancel }) => {
|
||||
//Подключение к контексту приложения
|
||||
const { pOnlineShowDictionary } = useContext(ApplicationСtx);
|
||||
|
||||
//Собственное состояние - значения формы
|
||||
const [values, setValues] = useState({
|
||||
acatalog: "",
|
||||
eQTecSrvKind: "",
|
||||
planDateFrom: ""
|
||||
});
|
||||
|
||||
//Отработка воода значения в форму
|
||||
const handleValueChanged = (name, value) => setValues(pv => ({ ...pv, [name]: value }));
|
||||
|
||||
//Выбор каталога размещения ремонтной ведомости
|
||||
const selectEquipRepairSheetsCatalog = (name, callBack) => {
|
||||
pOnlineShowDictionary({
|
||||
unitCode: "EquipRepairSheets",
|
||||
showMethod: "catalog",
|
||||
callBack: res => callBack(res.success ? [{ name, value: res.outParameters.ctlgname }] : null)
|
||||
});
|
||||
};
|
||||
|
||||
//Выбор вида технического обслуживания
|
||||
const selectEquipTechServiceKinds = (name, callBack) => {
|
||||
pOnlineShowDictionary({
|
||||
unitCode: "EquipTechServiceKinds",
|
||||
callBack: res => callBack(res.success ? [{ name, value: res.outParameters.out_CODE }] : null)
|
||||
});
|
||||
};
|
||||
|
||||
//Генерация содержимого
|
||||
return (
|
||||
<Dialog open={true} onClose={() => (onOk ? onCancel() : null)}>
|
||||
<DialogTitle>Формирование ремонтной ведомости</DialogTitle>
|
||||
<DialogContent>
|
||||
<IUDFormTextField
|
||||
elementCode={"acatalog"}
|
||||
elementValue={values.acatalog}
|
||||
labelText={"Каталог размещения"}
|
||||
onChange={handleValueChanged}
|
||||
dictionary={callBack => selectEquipRepairSheetsCatalog("acatalog", callBack)}
|
||||
/>
|
||||
<IUDFormTextField
|
||||
elementCode={"eQTecSrvKind"}
|
||||
elementValue={values.eQTecSrvKind}
|
||||
labelText={"Вид технического обслуживания"}
|
||||
onChange={handleValueChanged}
|
||||
dictionary={callBack => selectEquipTechServiceKinds("eQTecSrvKind", callBack)}
|
||||
/>
|
||||
<IUDFormTextField
|
||||
elementCode={"planDateFrom"}
|
||||
elementValue={values.planDateFrom}
|
||||
labelText={"Плановая дата ремонта"}
|
||||
onChange={handleValueChanged}
|
||||
type={"date"}
|
||||
/>
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
<Button onClick={() => (onOk ? onOk(values) : null)}>{BUTTONS.OK}</Button>
|
||||
<Button onClick={() => (onOk ? onCancel() : null)}>{BUTTONS.CANCEL}</Button>
|
||||
</DialogActions>
|
||||
</Dialog>
|
||||
);
|
||||
};
|
||||
|
||||
//Контроль свойств - Диалог формирование ремонтной ведомости
|
||||
TechObjMakeEqRpSheet.propTypes = {
|
||||
onOk: PropTypes.func,
|
||||
onCancel: PropTypes.func
|
||||
};
|
||||
|
||||
//----------------
|
||||
//Интерфейс модуля
|
||||
//----------------
|
||||
|
||||
export { TechObjCard, eqConfigTechObjTableValueFormatter, eqConfigTechObjTableDataCellRender };
|
||||
export { TechObjCard, eqConfigTechObjTableValueFormatter, eqConfigTechObjTableDataCellRender, TechObjMakeEqRpSheet };
|
||||
|
Loading…
x
Reference in New Issue
Block a user