208 lines
8.8 KiB
JavaScript
208 lines
8.8 KiB
JavaScript
/*
|
||
Парус 8 - Панели мониторинга - РО - Редактор настройки регламентированного отчёта
|
||
Компонент панели: Разделы настройки
|
||
*/
|
||
|
||
//---------------------
|
||
//Подключение библиотек
|
||
//---------------------
|
||
|
||
import React, { useState, useEffect, useContext, useCallback } from "react"; //Классы React
|
||
import PropTypes from "prop-types"; //Контроль свойств компонента
|
||
import { Box, Tabs, IconButton, Icon, Stack, Button } from "@mui/material"; //Интерфейсные компоненты
|
||
import { tabsClasses } from "@mui/material/Tabs"; //Классы закладок
|
||
import { ApplicationСtx } from "../../../context/application"; //Контекст взаимодействия с приложением
|
||
import { BackEndСtx } from "../../../context/backend"; //Контекст взаимодействия с сервером
|
||
import { MessagingСtx } from "../../../context/messaging"; //Контекст сообщений
|
||
import { useConfSections } from "../hooks"; //Кастомные хуки
|
||
import { ActionMessage } from "./action_message"; //Сообщение с действиями
|
||
import { SectionTab } from "./section_tab"; //Закладка раздела
|
||
import { DialogSectionIU } from "./dialog_section_iu"; //Диалог добавления/исправления раздела
|
||
|
||
//---------
|
||
//Константы
|
||
//---------
|
||
|
||
//Стили
|
||
const STYLES = {
|
||
CONTAINER: { borderBottom: 1, borderColor: "divider", width: "100%", height: "100%" },
|
||
TABS_SECTIONS: { width: "100%", [`& .${tabsClasses.scrollButtons}`]: { "&.Mui-disabled": { opacity: 0.3 } } }
|
||
};
|
||
|
||
//-----------------------
|
||
//Вспомогательные функции
|
||
//-----------------------
|
||
|
||
//Поиск активного раздела после удаления текущего
|
||
const getNextSectionAfterDelete = (sections, deletedSection) => {
|
||
//Находим индекс удаляемого раздела
|
||
const delInd = sections.findIndex(s => s.NRN === deletedSection);
|
||
//Возвращаем рег. номер либо предыдущего раздела, либо следующего, либо ничего
|
||
return delInd === -1 ? null : sections[delInd - 1]?.NRN || sections[delInd + 1]?.NRN || null;
|
||
};
|
||
|
||
//-----------
|
||
//Тело модуля
|
||
//-----------
|
||
|
||
//Разделы настройки
|
||
const Sections = ({ conf, onSectionChange, onSectionCountChange }) => {
|
||
//Текущий раздел настройки
|
||
const [section, setSection] = useState(-1);
|
||
|
||
//Редактируемый раздел настройки
|
||
const [modSection, setModSection] = useState(null);
|
||
|
||
//Список разделов и просто описание настройки
|
||
const [confDesc, sections, refreshSections, sectionsLoading, sectionsInit] = useConfSections(conf);
|
||
|
||
//Подключение к контексту приложения
|
||
const { setAppBarTitle } = useContext(ApplicationСtx);
|
||
|
||
//Подключение к контексту взаимодействия с сервером
|
||
const { executeStored } = useContext(BackEndСtx);
|
||
|
||
//Подключение к контексту сообщений
|
||
const { showMsgWarn } = useContext(MessagingСtx);
|
||
|
||
//Выбор раздела
|
||
const selectSection = useCallback(
|
||
section => {
|
||
if (onSectionChange) onSectionChange(section);
|
||
setSection(section);
|
||
},
|
||
[onSectionChange]
|
||
);
|
||
|
||
//Добавление раздела
|
||
const insertSection = async ({ conf, code, name }) => {
|
||
const data = await executeStored({
|
||
stored: "PKG_P8PANELS_RRPCONFED.RRPCONFSCTN_INSERT",
|
||
args: { NPRN: conf, SCODE: code, SNAME: name },
|
||
loader: false
|
||
});
|
||
selectSection(data.NRN);
|
||
refreshSections();
|
||
};
|
||
|
||
//Исправление раздела
|
||
const updateSection = async ({ rn, code, name }) => {
|
||
await executeStored({
|
||
stored: "PKG_P8PANELS_RRPCONFED.RRPCONFSCTN_UPDATE",
|
||
args: { NRN: rn, SCODE: code, SNAME: name },
|
||
loader: false
|
||
});
|
||
refreshSections();
|
||
};
|
||
|
||
//Удаление раздела
|
||
const deleteSection = async section => {
|
||
await executeStored({
|
||
stored: "PKG_P8PANELS_RRPCONFED.RRPCONFSCTN_DELETE",
|
||
args: { NRN: section },
|
||
loader: false
|
||
});
|
||
selectSection(getNextSectionAfterDelete(sections, section));
|
||
refreshSections();
|
||
};
|
||
|
||
//При измении закладки текущего раздела
|
||
const handleSectionTabChange = (event, section) => selectSection(section);
|
||
|
||
//При добавлении раздела настройки
|
||
const handleSectionAdd = () => setModSection(true);
|
||
|
||
//При редактировании раздела настройки
|
||
const handleSectionEdit = section => setModSection(sections.find(s => s.NRN === section) || null);
|
||
|
||
//При удалении раздела настройки
|
||
const handleSectionDelete = section => showMsgWarn("Удалить раздел?", () => deleteSection(section));
|
||
|
||
//При закрытии формы добавления/исправления по "ОК"
|
||
const handleIUFormOk = async values => {
|
||
if (modSection === true) await insertSection({ conf, ...values });
|
||
else await updateSection({ rn: modSection.NRN, ...values });
|
||
setModSection(null);
|
||
};
|
||
|
||
//При закрытии формы добавления/исправления по "Отмена"
|
||
const handleIUFormCancel = () => setModSection(null);
|
||
|
||
//При изменении состава разделов
|
||
useEffect(() => {
|
||
//Если ещё не инициализировали выбранный раздел и есть чем
|
||
if (section === -1 && sections.length > 0) selectSection(sections[0].NRN);
|
||
}, [section, sections, selectSection]);
|
||
|
||
//При изменении количества разделов
|
||
useEffect(() => {
|
||
onSectionCountChange && onSectionCountChange(sections.length);
|
||
}, [sections.length, onSectionCountChange]);
|
||
|
||
//При изменении описания раздела
|
||
useEffect(() => {
|
||
if (confDesc?.SNAME) setAppBarTitle(confDesc.SNAME);
|
||
}, [confDesc, setAppBarTitle]);
|
||
|
||
//Вычисление подсвеченной закладки раздела
|
||
const hlSection = sections.find(s => s.NRN === section)?.NRN || false;
|
||
|
||
//Формирование представления
|
||
return (
|
||
<Stack direction={"row"} sx={STYLES.CONTAINER}>
|
||
{modSection && (
|
||
<DialogSectionIU
|
||
code={modSection?.SCODE}
|
||
name={modSection?.SNAME}
|
||
insert={modSection === true}
|
||
onOk={handleIUFormOk}
|
||
onCancel={handleIUFormCancel}
|
||
/>
|
||
)}
|
||
{sections.length > 0 ? (
|
||
<>
|
||
<Box display={"flex"} justifyContent={"center"} alignItems={"center"} sx={STYLES.PANELS_MAIN_COLOR} title={"Добавить раздел"}>
|
||
<IconButton onClick={handleSectionAdd}>
|
||
<Icon>add</Icon>
|
||
</IconButton>
|
||
</Box>
|
||
<Tabs value={hlSection} onChange={handleSectionTabChange} variant={"scrollable"} scrollButtons sx={STYLES.TABS_SECTIONS}>
|
||
{sections.map((s, i) => (
|
||
<SectionTab
|
||
key={i}
|
||
value={s.NRN}
|
||
section={section}
|
||
sectionDesc={s}
|
||
onSectionEdit={handleSectionEdit}
|
||
onSectionDelete={handleSectionDelete}
|
||
/>
|
||
))}
|
||
</Tabs>
|
||
</>
|
||
) : (
|
||
sectionsInit &&
|
||
!sectionsLoading && (
|
||
<ActionMessage icon={"info"} title={"В настройке нет разделов"} desc={"Добавьте первый..."}>
|
||
<Button startIcon={<Icon>add</Icon>} onClick={handleSectionAdd}>
|
||
Раздел
|
||
</Button>
|
||
</ActionMessage>
|
||
)
|
||
)}
|
||
</Stack>
|
||
);
|
||
};
|
||
|
||
//Контроль свойств - Разделы настройки
|
||
Sections.propTypes = {
|
||
conf: PropTypes.number,
|
||
onSectionChange: PropTypes.func,
|
||
onSectionCountChange: PropTypes.func
|
||
};
|
||
|
||
//----------------
|
||
//Интерфейс модуля
|
||
//----------------
|
||
|
||
export { Sections };
|