410 lines
17 KiB
JavaScript
410 lines
17 KiB
JavaScript
/*
|
||
Парус 8 - Панели мониторинга - Редактор настройки регламентированного отчёта
|
||
Пользовательские хуки
|
||
*/
|
||
|
||
//---------------------
|
||
//Подключение библиотек
|
||
//---------------------
|
||
|
||
import { useState, useContext, useEffect, useCallback, useLayoutEffect } from "react"; //Классы React
|
||
import { ApplicationСtx } from "../../context/application"; //Контекст приложения
|
||
import { BackEndСtx } from "../../context/backend"; //Контекст взаимодействия с сервером
|
||
import { NavigationCtx } from "../../context/navigation"; //Контекст навигации
|
||
import { MessagingСtx } from "../../context/messaging"; //Контекст сообщений
|
||
import { STATUSES } from "./IUD/iud_form_dialog"; //Статусы диалогов
|
||
import { TEXTS } from "../../../app.text"; //Тексты для ошибок
|
||
|
||
//-----------
|
||
//Тело модуля
|
||
//-----------
|
||
|
||
//Хук для отработки изменений ширины и высоты рабочей области окна
|
||
const useWindowResize = () => {
|
||
//Состояние размера рабочей области
|
||
const [size, setSize] = useState([0, 0]);
|
||
|
||
//При изменении размера
|
||
useLayoutEffect(() => {
|
||
const updateSize = () => {
|
||
setSize([document.documentElement.clientWidth, document.documentElement.clientHeight]);
|
||
};
|
||
window.addEventListener("resize", updateSize);
|
||
updateSize();
|
||
return () => window.removeEventListener("resize", updateSize);
|
||
}, []);
|
||
|
||
//Вернём размеры
|
||
return size;
|
||
};
|
||
|
||
//Хук для настройки регламентированного отчета
|
||
const useConf = (currentTab, handleSectionChange, order) => {
|
||
//Собственное состояние - таблица данных
|
||
const dataGrid = {
|
||
rn: 0,
|
||
code: "",
|
||
name: "",
|
||
dataLoaded: false,
|
||
columnsDef: [],
|
||
groups: [],
|
||
rows: [],
|
||
fixedHeader: false,
|
||
fixedColumns: 0,
|
||
reload: false
|
||
};
|
||
|
||
//Собственное состояние
|
||
const [rrpConf, setRrpConf] = useState({
|
||
docLoaded: false,
|
||
sections: [],
|
||
orderChanged: false,
|
||
reload: true
|
||
});
|
||
|
||
//Состояние массива данных разделов
|
||
const [dataGrids] = useState([]);
|
||
|
||
//Подключение к контексту взаимодействия с сервером
|
||
const { executeStored } = useContext(BackEndСtx);
|
||
|
||
//Подключение к контексту навигации
|
||
const { getNavigationSearch } = useContext(NavigationCtx);
|
||
|
||
//При необходимости обновить
|
||
const handleReload = useCallback(async () => {
|
||
setRrpConf(pv => ({ ...pv, reload: true }));
|
||
}, []);
|
||
|
||
//Загрузка данных разделов регламентированного отчёта
|
||
const loadData = useCallback(
|
||
async () => {
|
||
if (rrpConf.reload) {
|
||
//Переменная номера раздела с фокусом
|
||
let tabFocus = currentTab ? currentTab : 0;
|
||
const data = await executeStored({
|
||
stored: "PKG_P8PANELS_RRPCONFED.RRPCONF_GET_SECTIONS",
|
||
args: {
|
||
NRN_RRPCONF: Number(getNavigationSearch().NRN),
|
||
NROW_ORDER: Number(order.rowOrder),
|
||
NCOL_ORDER: Number(order.columnOrder)
|
||
},
|
||
respArg: "COUT"
|
||
});
|
||
//Флаг первой загрузки данных
|
||
let firstLoad = dataGrids.length == 0 ? true : false;
|
||
//Копирование массива уже загруженных разделов
|
||
let cloneDGs = dataGrids.slice();
|
||
//Массив из нескольких разделов и из одного
|
||
const sections = data.SECTIONS ? (data.SECTIONS.length ? data.SECTIONS : [data.SECTIONS]) : [];
|
||
//Заполнение очередного раздела по шаблону
|
||
sections
|
||
.sort((a, b) => a.SCODE - b.SCODE)
|
||
.map(s => {
|
||
let dg = {};
|
||
Object.assign(dg, dataGrid, {
|
||
...s.XDATA.XDATA_GRID,
|
||
rn: s.NRN,
|
||
code: s.SCODE,
|
||
name: s.SNAME,
|
||
delete_allow: s.NDELETE_ALLOW,
|
||
dataLoaded: true,
|
||
columnsDef: [...(s.XDATA.XDATA_GRID.columnsDef || [])],
|
||
groups: [...(s.XDATA.XDATA_GRID.groups || [])],
|
||
rows: [...(s.XDATA.XDATA_GRID.rows || [])],
|
||
reload: false
|
||
});
|
||
//Если раздел имеет составы показателей
|
||
if (s.MARK_CNS.MARK_CN) {
|
||
//Обходим строки раздела
|
||
dg.rows.map(row => {
|
||
//Цикл по ключам строки
|
||
for (let key in row) {
|
||
//Если это ключ для группы составов показателей
|
||
if (key.match(/MARK_CNS_.*/)) {
|
||
//Считываем рег. номер показателя
|
||
let markRn = key.substring(9);
|
||
//Переносим из раздела
|
||
row[key] = Array.isArray(s.MARK_CNS.MARK_CN)
|
||
? [...s.MARK_CNS.MARK_CN].filter(el => el.NPRN === row[`NMARK_RN_${markRn}`])
|
||
: s.MARK_CNS.MARK_CN.NPRN === row[`NMARK_RN_${markRn}`]
|
||
? [s.MARK_CNS.MARK_CN]
|
||
: null;
|
||
}
|
||
}
|
||
});
|
||
}
|
||
//Ищем загружен ли уже раздел с таким же ид.
|
||
const dgItem = dataGrids.find(x => x.rn === dg.rn);
|
||
//Его индекс, если нет соответствия, то -1
|
||
let index = dataGrids.indexOf(dgItem);
|
||
//Если было соответствие
|
||
if (dgItem) {
|
||
//Если в нём не найдено изменений
|
||
if (JSON.stringify(dgItem, null, 4) === JSON.stringify(dg, null, 4)) {
|
||
//То из копированного массива его удаляем
|
||
cloneDGs.splice(cloneDGs.indexOf(cloneDGs.find(x => x.rn === dgItem.rn)), 1);
|
||
} else {
|
||
//Иначе обновляем раздел в массиве
|
||
dataGrids[index] = dg;
|
||
//Удаляем из копированного массива
|
||
cloneDGs.splice(cloneDGs.indexOf(cloneDGs.find(x => x.rn === dg.rn)), 1);
|
||
//Устанавливаем фокус на обновлённый раздел, если был добавлен
|
||
tabFocus = rrpConf.orderChanged ? 0 : index;
|
||
}
|
||
} else {
|
||
//Если раздел новый, то добавляем его в массив данных
|
||
dataGrids.push(dg);
|
||
//И устанавливаем на него фокус, если флаг первой загрузки = false
|
||
tabFocus = !firstLoad ? dataGrids.length - 1 : 0;
|
||
}
|
||
});
|
||
//Обходим разделы, что остались в копированном массиве (на удаление)
|
||
cloneDGs.map(s => {
|
||
let curIndex = dataGrids.indexOf(dataGrids.find(x => x.rn === s.rn));
|
||
//Устаревший раздел удаляем из массива данных
|
||
dataGrids.splice(curIndex, 1);
|
||
//Фокус на предшествующий раздел
|
||
if (curIndex > 0) tabFocus = curIndex - 1;
|
||
//Иначе фокус на следующий, если был удалён первый раздел
|
||
else tabFocus = curIndex;
|
||
});
|
||
setRrpConf(pv => ({
|
||
...pv,
|
||
docLoaded: true,
|
||
orderChanged: false,
|
||
reload: false,
|
||
sections: dataGrids
|
||
}));
|
||
handleSectionChange(tabFocus);
|
||
}
|
||
},
|
||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||
[rrpConf.reload, rrpConf.docLoaded, dataGrid.reload, dataGrid.docLoaded, executeStored]
|
||
);
|
||
|
||
//При изменении сортировок
|
||
useEffect(() => {
|
||
setRrpConf(pv => ({ ...pv, orderChanged: true, reload: true }));
|
||
}, [order]);
|
||
|
||
//При необходимости обновить данные таблицы
|
||
useEffect(() => {
|
||
loadData();
|
||
}, [rrpConf.reload, dataGrid.reload, loadData]);
|
||
|
||
return [rrpConf, handleReload];
|
||
};
|
||
|
||
//Хук для вкладки
|
||
const useTab = () => {
|
||
//Состояние раздела
|
||
const [tabValue, setTabValue] = useState("");
|
||
|
||
//Переключение раздела
|
||
const handleSectionChange = useCallback(newValue => {
|
||
setTabValue(newValue);
|
||
}, []);
|
||
|
||
return [tabValue, handleSectionChange];
|
||
};
|
||
|
||
//Хук для функций открытия записей
|
||
const useRecOpen = handleReload => {
|
||
//Подключение к контексту взаимодействия с сервером
|
||
const { executeStored } = useContext(BackEndСtx);
|
||
|
||
//Подключение к контексту приложения
|
||
const { pOnlineShowDictionary } = useContext(ApplicationСtx);
|
||
|
||
//Подключение к контексту сообщений
|
||
const { showMsgErr } = useContext(MessagingСtx);
|
||
|
||
//Отображение показателя раздела
|
||
const handleMarkOpen = useCallback(
|
||
async nRrpConfSctnMrk => {
|
||
const data = await executeStored({
|
||
stored: "PKG_P8PANELS_RRPCONFED.RRPCONFSCTNMRK_GET_CODES",
|
||
args: {
|
||
NRN: nRrpConfSctnMrk
|
||
},
|
||
tagValueProcessor: () => undefined
|
||
});
|
||
if (data) {
|
||
pOnlineShowDictionary({
|
||
unitCode: "RRPConfig",
|
||
showMethod: "main_mrk_settings",
|
||
inputParameters: [
|
||
{ name: "in_CODE", value: data.SRRPCONF },
|
||
{ name: "in_SCTN_CODE", value: data.SRRPCONFSCTN },
|
||
{ name: "in_MRK_CODE", value: data.SRRPCONFSCTNMRK }
|
||
],
|
||
callBack: res => {
|
||
res.success ? handleReload() : null;
|
||
}
|
||
});
|
||
} else showMsgErr(TEXTS.NO_DATA_FOUND);
|
||
},
|
||
[executeStored, handleReload, pOnlineShowDictionary, showMsgErr]
|
||
);
|
||
|
||
//Отображение показателя раздела
|
||
const handleMarkCnOpen = useCallback(
|
||
async (nRrpConfSctnMrk, nRrpConfSctnMrkCn) => {
|
||
pOnlineShowDictionary({
|
||
unitCode: "RRPConfigSectionMark",
|
||
showMethod: "link_cn",
|
||
inputParameters: [
|
||
{ name: "in_RN", value: nRrpConfSctnMrk },
|
||
{ name: "in_RRPCONFSCTNMRKCN", value: nRrpConfSctnMrkCn }
|
||
],
|
||
callBack: res => {
|
||
res.success ? handleReload() : null;
|
||
}
|
||
});
|
||
},
|
||
[handleReload, pOnlineShowDictionary]
|
||
);
|
||
|
||
//Отображение показателя раздела
|
||
const handleMarkCnInsert = useCallback(
|
||
async nRrpConfSctnMrk => {
|
||
pOnlineShowDictionary({
|
||
unitCode: "RRPConfigSectionMarkConstitution",
|
||
showMethod: "link_add",
|
||
inputParameters: [{ name: "in_PRN", value: nRrpConfSctnMrk }],
|
||
callBack: res => {
|
||
res.success ? handleReload() : null;
|
||
}
|
||
});
|
||
},
|
||
[handleReload, pOnlineShowDictionary]
|
||
);
|
||
|
||
return [handleMarkOpen, handleMarkCnOpen, handleMarkCnInsert];
|
||
};
|
||
|
||
//Хук для форм диалогового окна
|
||
const useFormDialog = () => {
|
||
//Состояние открытия диалогового окна
|
||
const [formOpen, setForm] = useState(false);
|
||
|
||
//Состояние диалогового окна
|
||
const [formData, setFormData] = useState({
|
||
reload: false,
|
||
rn: "",
|
||
prn: "",
|
||
sctnName: "",
|
||
sctnCode: "",
|
||
status: "",
|
||
code: "",
|
||
name: "",
|
||
colCode: "",
|
||
colRn: null,
|
||
rowCode: "",
|
||
rowRn: null
|
||
});
|
||
|
||
//Подключение к контексту навигации
|
||
const { getNavigationSearch } = useContext(NavigationCtx);
|
||
|
||
//Открытие диалогового окна
|
||
const openForm = () => {
|
||
setForm(true);
|
||
};
|
||
|
||
//Очистка диалогового окна
|
||
const clearFormData = () => {
|
||
setFormData({
|
||
reload: false,
|
||
rn: "",
|
||
prn: "",
|
||
sctnName: "",
|
||
sctnCode: "",
|
||
status: "",
|
||
code: "",
|
||
name: "",
|
||
colCode: "",
|
||
colRn: null,
|
||
rowCode: "",
|
||
rowRn: null
|
||
});
|
||
};
|
||
|
||
//Отработка нажатия на кнопку добавления секции
|
||
const handleSectionAdd = () => {
|
||
setFormData({ status: STATUSES.CREATE, prn: Number(getNavigationSearch().NRN) });
|
||
openForm();
|
||
};
|
||
|
||
//Отработка нажатия на кнопку исправления секции
|
||
const handleSectionEdit = (rn, code, name) => {
|
||
setFormData({ rn: rn, code: code, name: name, status: STATUSES.EDIT });
|
||
openForm();
|
||
};
|
||
|
||
//Отработка нажатия на кнопку удаления секции
|
||
const handleSectionDelete = (rn, code, name) => {
|
||
setFormData({ rn: rn, code: code, name: name, status: STATUSES.DELETE });
|
||
openForm();
|
||
};
|
||
|
||
//Отработка нажатия на кнопку добавления показателя раздела
|
||
const handleMarkAdd = (prn, rowRn = null, rowCode = "", colRn = null, colCode = "") => {
|
||
setFormData({
|
||
reload: rowRn && colRn ? true : false,
|
||
prn: prn,
|
||
rowRn: rowRn,
|
||
rowCode: rowCode,
|
||
colRn: colRn,
|
||
colCode: colCode,
|
||
status: STATUSES.RRPCONFSCTNMRK_CREATE
|
||
});
|
||
openForm();
|
||
};
|
||
|
||
//Отработка нажатия на кнопку исправления показателя раздела
|
||
const handleMarkEdit = rn => {
|
||
setFormData({ reload: true, rn: rn, status: STATUSES.RRPCONFSCTNMRK_EDIT });
|
||
openForm();
|
||
};
|
||
|
||
//Отработка нажатия на кнопку удаления показателя раздела
|
||
const handleMarkDelete = rn => {
|
||
setFormData({ rn: rn, status: STATUSES.RRPCONFSCTNMRK_DELETE });
|
||
openForm();
|
||
};
|
||
|
||
//При закрытии диалога
|
||
const handleDialogClose = () => {
|
||
setForm(false);
|
||
clearFormData();
|
||
};
|
||
|
||
return [
|
||
formOpen,
|
||
formData,
|
||
handleSectionAdd,
|
||
handleSectionEdit,
|
||
handleSectionDelete,
|
||
handleMarkAdd,
|
||
handleMarkEdit,
|
||
handleMarkDelete,
|
||
handleDialogClose
|
||
];
|
||
};
|
||
|
||
//Формирование разделов
|
||
const a11yProps = index => {
|
||
return {
|
||
id: `simple-tab-${index}`,
|
||
"aria-controls": `simple-tabpanel-${index}`
|
||
};
|
||
};
|
||
|
||
//----------------
|
||
//Интерфейс модуля
|
||
//----------------
|
||
|
||
export { useWindowResize, useConf, useTab, useRecOpen, useFormDialog, a11yProps };
|