ЦИТК-823 - доработки "Редактор настройки регламентированного отчёта" по примечанию от 23.07.2024 19:46

This commit is contained in:
Mim 2024-08-23 17:49:05 +03:00
commit e9cba113f7
9 changed files with 2113 additions and 596 deletions

View File

@ -10,8 +10,8 @@
import React, { useState, useContext, useCallback, useEffect } from "react"; //Классы React
import PropTypes from "prop-types"; //Контроль свойств компонента
import { Dialog, DialogTitle, IconButton, Icon, DialogContent, Typography, DialogActions, Button } from "@mui/material"; //Интерфейсные компоненты
import { ApplicationСtx } from "../../context/application"; //Контекст приложения
import { BackEndСtx } from "../../context/backend"; //Контекст взаимодействия с сервером
import { ApplicationСtx } from "../../../context/application"; //Контекст приложения
import { BackEndСtx } from "../../../context/backend"; //Контекст взаимодействия с сервером
import { IUDFormTextField } from "./iud_form_text_field"; //Компонент поля ввода
//---------
@ -65,7 +65,9 @@ const IUDFormDialog = ({ initial, onClose, onReload }) => {
};
//При изменении значения элемента
const handleDialogItemChange = (item, value) => setFormData(pv => ({ ...pv, [item]: value }));
const handleDialogItemChange = (item, value) => {
setFormData(pv => ({ ...pv, [item]: value }));
};
//Отработка изменений в разделе или показателе раздела
const changeSections = useCallback(async () => {
@ -139,13 +141,11 @@ const IUDFormDialog = ({ initial, onClose, onReload }) => {
NPRN: formData.prn,
SCODE: formData.code,
SNAME: formData.name,
SCOLCODE: formData.colCode,
SCOLVER: formData.colVCode,
SROWCODE: formData.rowCode,
SROWVER: formData.rowVCode
NRRPROW: formData.rowRn,
NRRPCOLUMN: formData.colRn
}
});
}, [executeStored, formData.code, formData.colVCode, formData.colCode, formData.name, formData.prn, formData.rowCode, formData.rowVCode]);
}, [executeStored, formData.code, formData.colRn, formData.name, formData.prn, formData.rowRn]);
//Исправление показателя раздела
const editRRPCONFSCTNMRK = useCallback(async () => {
@ -210,14 +210,15 @@ const IUDFormDialog = ({ initial, onClose, onReload }) => {
const selectRow = (showDictionary, callBack) => {
showDictionary({
unitCode: "RRPRow",
inputParameters: [{ name: "in_RN", value: formData.rowRn }],
callBack: res => {
if (res.success === true) {
callBack(res.outParameters.out_CODE, res.outParameters.out_RRPVERSION_CODE, res.outParameters.out_RRPVERSION);
callBack(res.outParameters.out_CODE, res.outParameters.out_RN);
setFormData(pv => ({
...pv,
reload: true,
rowCode: res.outParameters.out_CODE,
rowVCode: res.outParameters.out_RRPVERSION_CODE,
rowVRn: res.outParameters.out_RRPVERSION
rowRn: res.outParameters.out_RN
}));
} else callBack(null);
}
@ -228,14 +229,15 @@ const IUDFormDialog = ({ initial, onClose, onReload }) => {
const selectColumn = (showDictionary, callBack) => {
showDictionary({
unitCode: "RRPColumn",
inputParameters: [{ name: "in_RN", value: formData.colRn }],
callBack: res => {
if (res.success === true) {
callBack(res.outParameters.out_CODE, res.outParameters.out_RRPVERSION_CODE, res.outParameters.out_RRPVERSION);
callBack(res.outParameters.out_CODE, res.outParameters.out_RN);
setFormData(pv => ({
...pv,
reload: true,
colCode: res.outParameters.out_CODE,
colVCode: res.outParameters.out_RRPVERSION_CODE,
colVRn: res.outParameters.out_RRPVERSION
colRn: res.outParameters.out_RN
}));
} else callBack(null);
}
@ -247,26 +249,41 @@ const IUDFormDialog = ({ initial, onClose, onReload }) => {
const data = await executeStored({
stored: "PKG_P8PANELS_RRPCONFED.RRPCONFSCTNMRK_GET_CODE_NAME",
args: {
SSCTNCODE: formData.sctnCode,
SROWCODE: formData.rowCode,
NROWVER: formData.rowVRn,
SCOLUMNCODE: formData.colCode,
NCOLUMNVER: formData.colVRn
NRRPCONFSCTN: formData.prn,
NRRPROW: formData.rowRn,
NRRPCOLUMN: formData.colRn
}
});
setFormData(pv => ({
...pv,
reload: false,
code: data.SCODE,
name: data.SNAME
}));
}, [executeStored, formData.colCode, formData.colVRn, formData.rowCode, formData.rowVRn, formData.sctnCode]);
}, [executeStored, formData.colRn, formData.prn, formData.rowRn]);
//Считывание наименования показателя
const getMarkName = useCallback(async () => {
const data = await executeStored({
stored: "PKG_P8PANELS_RRPCONFED.RRPCONFSCTNMRK_GET_NAME",
args: {
NRRPCONFSCTNMRK: formData.rn
}
});
setFormData(pv => ({
...pv,
reload: false,
name: data.SNAME
}));
}, [executeStored, formData.rn]);
//Получение наименования и мнемокода показателя раздела при заполнении необходимых полей
useEffect(() => {
formData.status == STATUSES.RRPCONFSCTNMRK_CREATE && formData.sctnName && formData.sctnCode && formData.colCode && formData.rowCode
? getSctnMrkCodeName()
: null;
}, [formData.colCode, formData.rowCode, formData.sctnCode, formData.sctnName, formData.status, getSctnMrkCodeName]);
//Если это добавление показателя и требуется сформировать мнемокод и наименование
formData.status == STATUSES.RRPCONFSCTNMRK_CREATE && formData.reload && formData.rowRn && formData.colRn ? getSctnMrkCodeName() : null;
//Если это исправление и требуется инициализировать наименование показателя
formData.status == STATUSES.RRPCONFSCTNMRK_EDIT && formData.reload ? getMarkName() : null;
}, [formData.status, formData.reload, formData.rowRn, formData.colRn, getSctnMrkCodeName, getMarkName]);
//Генерация содержимого
return (

View File

@ -0,0 +1,344 @@
/*
Парус 8 - Панели мониторинга - РО - Редактор настройки регламентированного отчёта
Дополнительная разметка и вёрстка клиентских элементов
*/
//---------------------
//Подключение библиотек
//---------------------
import React, { useState } from "react"; //Классы React
import PropTypes from "prop-types"; //Контроль свойств компонента
import {
IconButton,
Icon,
Link,
Card,
CardContent,
CardHeader,
Menu,
MenuItem,
Table,
TableRow,
TableCell,
TableBody,
Box,
Typography
} from "@mui/material"; //Интерфейсные компоненты
//---------
//Константы
//---------
//Стили
export const STYLES = {
BOX_ROW: { display: "flex", justifyContent: "center", alignItems: "center" },
LINK_STYLE: { component: "button", cursor: "pointer", width: "-webkit-fill-available" },
DATA_CELL: columnDef => ({
padding: "5px 5px",
fontSize: "0.775rem",
letterSpacing: "0.005em",
textAlign: "center",
wordBreak: "break-all",
backgroundColor: columnDef.name === "SROW_NAME" ? "#b4b4b4" : "trasparent"
}),
DATA_CELL_CARD: {
padding: "0px 3px 3px 0px",
border: "1px solid lightgrey",
borderRadius: "5%"
},
DATA_CELL_CARD_HEADER: {
padding: "0px"
},
DATA_CELL_CARD_SUBHEADER: {
textAlign: "left",
paddingLeft: "10px",
fontSize: "1rem",
fontWeight: "450"
},
DATA_CELL_CARD_CONTENT: listLength => {
return {
fontSize: "0.75rem",
padding: "5px 0px",
minHeight: "105px",
maxHeight: "105px",
overflowY: "auto",
"&::-webkit-scrollbar": {
width: "8px"
},
"&::-webkit-scrollbar-track": {
borderRadius: "8px",
backgroundColor: "#EBEBEB"
},
"&::-webkit-scrollbar-thumb": {
borderRadius: "8px",
backgroundColor: "#b4b4b4"
},
"&::-webkit-scrollbar-thumb:hover": {
backgroundColor: "#808080"
},
"&:last-child": {
paddingBottom: "0px"
},
...(listLength === 0 ? { display: "flex", justifyContent: "center", alignItems: "center" } : null)
};
},
DATA_CELL_CARD_CONTEXT_FONT: {
fontSize: "0.75rem"
},
DATA_CELL_CARD_CONTEXT_MARK: {
padding: "0px 0px 0px 10px",
borderBottom: "1px solid #EBEBEB"
},
DATA_CELL_CN: {
textOverflow: "ellipsis",
overflow: "hidden",
whiteSpace: "pre",
padding: "0px 5px",
maxWidth: "100px",
border: "none"
},
GRID_PANEL_CARD: { maxWidth: 400, flexDirection: "column", display: "flex" },
MARK_INFO: {
fontSize: "0.8rem",
textAlign: "left",
textOverflow: "ellipsis",
overflow: "hidden",
whiteSpace: "pre",
maxWidth: "max-content",
width: "-webkit-fill-available"
},
BUTTON_CN_INSERT: {
padding: "0px 8px",
marginBottom: "2px",
"& .MuiIcon-root": {
fontWeight: "bold",
fontSize: "1rem"
}
},
HEAD_CELL: {
backgroundColor: "#b4b4b4",
textAlign: "center"
},
HEAD_CELL_STACK: {
justifyContent: "space-around"
}
};
//------------------------------------
//Вспомогательные функции и компоненты
//------------------------------------
//Действия карты показателя
const DataCellCardActions = ({ columnDef, menuItems, cellData, markRn }) => {
//Собственное состояние
const [cardActions, setCardActions] = useState({ anchorMenuMethods: null, openMethods: false });
//По нажатию на открытие меню действий
const handleMethodsMenuButtonClick = event => {
setCardActions(pv => ({ ...pv, anchorMenuMethods: event.currentTarget, openMethods: true }));
};
//При закрытии меню
const handleMethodsMenuClose = () => {
setCardActions(pv => ({ ...pv, anchorMenuMethods: null, openMethods: false }));
};
return (
<Box sx={STYLES.BOX_ROW}>
<IconButton id={`${columnDef.name}_menu_button`} aria-haspopup="true" onClick={handleMethodsMenuButtonClick}>
<Icon>more_vert</Icon>
</IconButton>
<Menu
id={`${columnDef.name}_menu`}
anchorEl={cardActions.anchorMenuMethods}
open={cardActions.openMethods}
onClose={handleMethodsMenuClose}
>
{menuItems.map(el => {
return (
<MenuItem
key={`${cellData}_${el.method}`}
onClick={() => {
el.func(markRn);
handleMethodsMenuClose();
}}
>
<Icon>{el.icon}</Icon>
{el.name}
</MenuItem>
);
})}
</Menu>
</Box>
);
};
//Контроль свойств - Действия карты показателя
DataCellCardActions.propTypes = {
columnDef: PropTypes.object.isRequired,
menuItems: PropTypes.array,
cellData: PropTypes.any,
markRn: PropTypes.number
};
//Таблица составов показателя
const MarkCnList = ({ markRn, list, handleMarkCnOpen }) => {
return (
<Table>
<TableBody>
{list.map((el, index) => {
return (
<TableRow key={index}>
<TableCell
sx={{ ...STYLES.DATA_CELL_CN, ...STYLES.DATA_CELL_CARD_CONTEXT_FONT }}
title={el.SDESC}
align="left"
size="small"
>
<Link sx={STYLES.LINK_STYLE} onClick={() => handleMarkCnOpen(markRn, el.NRN)}>
{el.SDESC}
</Link>
</TableCell>
</TableRow>
);
})}
</TableBody>
</Table>
);
};
//Контроль свойств - Таблица составов показателя
MarkCnList.propTypes = {
markRn: PropTypes.number.isRequired,
list: PropTypes.array.isRequired,
handleMarkCnOpen: PropTypes.func.isRequired
};
//Ячейка таблицы строки
const DataCellContent = ({ row, columnDef, menuItems, sectionRn, handleMarkAdd, handleMarkOpen, handleMarkCnOpen, handleMarkCnInsert }) => {
//Считываем информацию о показателе
let mark = {
sectionRn: sectionRn,
data: row[columnDef.name],
nRn: row["NMARK_RN_" + columnDef.name.substring(5)],
sCode: row["SMARK_CODE_" + columnDef.name.substring(5)],
sRowCode: row["SROW_CODE"],
nRowRn: row["NROW_RN"],
sColCode: columnDef.name.substring(5),
nColRn: row["NCOL_RN_" + columnDef.name.substring(5)],
rCnList: row["MARK_CNS_" + columnDef.name.substring(5)] ? [...row["MARK_CNS_" + columnDef.name.substring(5)]] : []
};
return (
<>
{mark.nRn ? (
<Card variant={"plain"} sx={STYLES.DATA_CELL_CARD}>
<CardHeader
sx={STYLES.DATA_CELL_CARD_HEADER}
subheader={
<Box>
<Link sx={STYLES.LINK_STYLE} onClick={() => (handleMarkOpen ? handleMarkOpen(mark.nRn) : null)}>
Состав
</Link>
{mark.rCnList.length !== 0 ? (
<IconButton sx={STYLES.BUTTON_CN_INSERT} aria-haspopup="true" onClick={() => handleMarkCnInsert(mark.nRn)}>
<Icon>add</Icon>
</IconButton>
) : null}
</Box>
}
subheaderTypographyProps={STYLES.DATA_CELL_CARD_SUBHEADER}
action={<DataCellCardActions columnDef={columnDef} menuItems={menuItems} cellData={mark.data} markRn={mark.nRn} />}
></CardHeader>
<CardContent sx={STYLES.DATA_CELL_CARD_CONTEXT_MARK}>
<Typography sx={STYLES.MARK_INFO} title={mark.sCode}>
{mark.sCode}
</Typography>
</CardContent>
<CardContent sx={STYLES.DATA_CELL_CARD_CONTENT(mark.rCnList.length)}>
{mark.rCnList.length !== 0 ? (
<MarkCnList markRn={mark.nRn} list={mark.rCnList} handleMarkCnOpen={handleMarkCnOpen} />
) : (
<Box>
<Typography sx={STYLES.DATA_CELL_CARD_CONTEXT_FONT}>Показатель не имеет состава</Typography>
<Link sx={STYLES.LINK_STYLE} onClick={() => (handleMarkCnInsert ? handleMarkCnInsert(mark.nRn) : null)}>
Добавить
</Link>
</Box>
)}
</CardContent>
</Card>
) : (
<Box>
<Typography sx={STYLES.DATA_CELL_CARD_CONTEXT_FONT}>Показатель отсутствует</Typography>
<Link
sx={STYLES.LINK_STYLE}
onClick={() =>
handleMarkOpen ? handleMarkAdd(mark.sectionRn, mark.nRowRn, mark.sRowCode, mark.nColRn, mark.sColCode) : null
}
>
Добавить
</Link>
</Box>
)}
</>
);
};
//Контроль свойств - Ячейка таблицы строки
DataCellContent.propTypes = {
row: PropTypes.object.isRequired,
columnDef: PropTypes.object.isRequired,
menuItems: PropTypes.array,
sectionRn: PropTypes.number.isRequired,
handleMarkAdd: PropTypes.func,
handleMarkOpen: PropTypes.func,
handleMarkCnOpen: PropTypes.func,
handleMarkCnInsert: PropTypes.func
};
//-----------
//Тело модуля
//-----------
//Генерация представления ячейки c данными показателя раздела регламентированного отчета
export const confSctnMrkCellRender = ({
row,
columnDef,
sectionRn,
handleMarkAdd,
handleMarkOpen,
handleMarkCnOpen,
handleMarkCnInsert,
menuItems
}) => {
//Иницализируем стили
let cellStyle = STYLES.DATA_CELL(columnDef);
//Считываем значение
let data = row[columnDef.name];
//Если это не наименование строки и есть значение
columnDef.name != "SROW_NAME" && data != undefined && columnDef.visible == true
? (data = (
<DataCellContent
row={row}
columnDef={columnDef}
menuItems={menuItems}
sectionRn={sectionRn}
handleMarkAdd={handleMarkAdd}
handleMarkOpen={handleMarkOpen}
handleMarkCnOpen={handleMarkCnOpen}
handleMarkCnInsert={handleMarkCnInsert}
/>
))
: null;
return { cellStyle: { ...cellStyle }, data: data };
};
//Генерация представления ячейки заголовка группы c данными показателя раздела регламентированного отчета
export const confSctnMrkHeadCellRender = ({ columnDef }) => {
return {
cellStyle: STYLES.HEAD_CELL,
stackStyle: STYLES.HEAD_CELL_STACK,
data: columnDef.caption
};
};

View File

@ -0,0 +1,243 @@
/*
Парус 8 - Панели мониторинга - РО - Редактор настройки регламентированного отчёта
Компонент панели: Раздел настройки
*/
//---------------------
//Подключение библиотек
//---------------------
import React, { useState } from "react"; //Классы React
import PropTypes from "prop-types"; //Контроль свойств компонента
import { Box, IconButton, Icon, Dialog, DialogTitle, DialogContent, Typography, List, ListItem } from "@mui/material"; //Интерфейсные элементы
import { P8PDataGrid, P8P_DATA_GRID_SIZE } from "../../../components/p8p_data_grid"; //Таблица данных
import { P8P_DATA_GRID_CONFIG_PROPS } from "../../../config_wrapper"; //Подключение компонентов к настройкам приложения
import { SectionTabPanel } from "./section_tab_panel"; //Компонент вкладки раздела
import { confSctnMrkCellRender, confSctnMrkHeadCellRender } from "./layouts"; //Дополнительная разметка и вёрстка клиентских элементов
//---------
//Константы
//---------
//Стили
const STYLES = {
GRID_SIZES: (height, pxOuterMenuH, pxPanelHeaderH, pxTabsH) => ({
padding: 0,
minWidth: "98vw",
minHeight: (height - pxOuterMenuH - pxPanelHeaderH - pxTabsH) * 0.93,
maxWidth: "98vw",
maxHeight: (height - pxOuterMenuH - pxPanelHeaderH - pxTabsH) * 0.93
}),
TABLE_CONTAINER: {
display: "flex",
justifyContent: "center",
alignItems: "center",
paddingTop: 1,
paddingBottom: 1
},
SECTION_ACTIONS: { display: "flex", justifyContent: "space-between", padding: "0px 5px" },
TABLE_SCROLL: {
"&::-webkit-scrollbar": {
width: "12px",
height: "12px"
},
"&::-webkit-scrollbar-track": {
borderRadius: "88px",
backgroundColor: "#EBEBEB"
},
"&::-webkit-scrollbar-thumb": {
borderRadius: "88px",
backgroundColor: "#b4b4b4",
backgroundClip: "padding-box",
border: "3px solid #EBEBEB"
},
"&::-webkit-scrollbar-thumb:hover": {
backgroundColor: "#808080"
}
},
HELP_LIST_ITEM: {
padding: "0px 0px 0px 5px",
whiteSpace: "pre",
fontSize: "0.95rem"
},
HELP_LIST_ITEM_NAME: {
fontWeight: "bold",
fontSize: "inherit",
minWidth: "45px"
},
HELP_LIST_ITEM_DESC: {
fontSize: "inherit"
}
};
//---------------------------------------------
//Вспомогательные функции и компоненты
//---------------------------------------------
//Элемент списка расшифровки состава
const HelpListItem = ({ name, desc }) => {
return (
<ListItem sx={STYLES.HELP_LIST_ITEM}>
<Typography sx={STYLES.HELP_LIST_ITEM_NAME}>{name}</Typography>
<Typography sx={STYLES.HELP_LIST_ITEM_DESC}>{` - ${desc}`}</Typography>
</ListItem>
);
};
//Контроль свойств - Элемент списка расшифровки состава
HelpListItem.propTypes = {
name: PropTypes.string.isRequired,
desc: PropTypes.string.isRequired
};
//Диалог дополнительной информации
const HelpDialog = ({ handleOpenHelpChange }) => {
//Генерация содержимого
return (
<Dialog open onClose={handleOpenHelpChange}>
<DialogTitle>
<Box display="flex" alignItems="center">
<Box flexGrow={1} textAlign="center">
Информация
</Box>
<Box>
<IconButton aria-label="close" onClick={handleOpenHelpChange}>
<Icon>close</Icon>
</IconButton>
</Box>
</Box>
</DialogTitle>
<DialogContent>
<Typography>Карточки показателей содержат сокращенную информацию о типе состава показателя.</Typography>
<Typography>Список сокращений:</Typography>
<List disablePadding={true}>
<HelpListItem name="fx" desc="формула" />
<HelpListItem name="СЗ" desc="статическое значение" />
<HelpListItem name="ХП" desc="хранимая процедура" />
<HelpListItem name="РП" desc="расчетный показатель" />
<HelpListItem name="ХО" desc="хозяйственные операции" />
<HelpListItem name="РСДК" desc="расчёты с дебиторами/кредиторами" />
<HelpListItem name="ОС" desc="остатки средств по счетам" />
<HelpListItem name="ТМЦ" desc="остатки товарно-материальных ценностей" />
<HelpListItem name="ДКЗ" desc="дебиторская/кредиторская задолженность" />
<HelpListItem name="ИК" desc="инвентарная картотека" />
<HelpListItem name="МБП" desc="картотека МБП" />
<HelpListItem name="КОБП" desc="картотека операций будущих периодов" />
<HelpListItem name="ДПНП" desc="декларация по налогу на прибыль" />
<HelpListItem name="РО" desc="регламентированный отчет" />
</List>
</DialogContent>
</Dialog>
);
};
//Контроль свойств - Диалог дополнительной информации
HelpDialog.propTypes = {
handleOpenHelpChange: PropTypes.func.isRequired
};
//-----------
//Тело модуля
//-----------
//Раздел настройки
const SectionTab = ({
section,
tabValue,
index,
containerProps,
handleMarkAdd,
handleReload,
handleMarkOpen,
handleMarkCnOpen,
handleMarkCnInsert,
menuItems
}) => {
//Состояние - диалог информации
const [openHelp, setOpenHelp] = useState(false);
//Изменение состояния диалога информации
const handleOpenHelpChange = () => {
setOpenHelp(!openHelp);
};
//Генерация содержимого
return (
<>
<SectionTabPanel key={section.rn} value={tabValue} index={index}>
<Box sx={STYLES.SECTION_ACTIONS}>
<Box>
<IconButton onClick={() => handleMarkAdd(section.rn)}>
<Icon>add</Icon>
</IconButton>
<IconButton onClick={() => handleReload()}>
<Icon>refresh</Icon>
</IconButton>
</Box>
<Box>
<IconButton onClick={() => handleOpenHelpChange()}>
<Icon>help</Icon>
</IconButton>
</Box>
</Box>
{section.dataLoaded && section.columnsDef.length > 3 ? (
<Box sx={STYLES.TABLE_CONTAINER}>
<P8PDataGrid
{...P8P_DATA_GRID_CONFIG_PROPS}
containerComponentProps={{
elevation: 6,
sx: { ...STYLES.TABLE_SCROLL },
style: STYLES.GRID_SIZES(
containerProps.height,
containerProps.pxOuterMenuH,
containerProps.pxPanelHeaderH,
containerProps.pxTabsH
)
}}
columnsDef={section.columnsDef}
groups={section.groups}
rows={section.rows}
fixedHeader={section.fixedHeader}
fixedColumns={section.fixedColumns}
size={P8P_DATA_GRID_SIZE.LARGE}
reloading={section.reload}
dataCellRender={prms =>
confSctnMrkCellRender({
...prms,
sectionRn: section.rn,
handleMarkAdd: handleMarkAdd,
handleMarkOpen: handleMarkOpen,
handleMarkCnOpen: handleMarkCnOpen,
handleMarkCnInsert: handleMarkCnInsert,
menuItems: menuItems
})
}
headCellRender={confSctnMrkHeadCellRender}
/>
</Box>
) : null}
</SectionTabPanel>
{openHelp ? <HelpDialog handleOpenHelpChange={handleOpenHelpChange} /> : null}
</>
);
};
//Контроль свойств - Раздел настройки
SectionTab.propTypes = {
section: PropTypes.object.isRequired,
tabValue: PropTypes.number,
index: PropTypes.number,
containerProps: PropTypes.object,
handleMarkAdd: PropTypes.func,
handleReload: PropTypes.func,
handleMarkOpen: PropTypes.func,
handleMarkCnOpen: PropTypes.func,
handleMarkCnInsert: PropTypes.func,
menuItems: PropTypes.array
};
//----------------
//Интерфейс модуля
//----------------
export { SectionTab };

View File

@ -9,7 +9,17 @@
import React from "react"; //Классы React
import PropTypes from "prop-types"; //Контроль свойств компонента
import { Box, Typography } from "@mui/material"; //Интерфейсные компоненты
import { Box } from "@mui/material"; //Интерфейсные компоненты
//---------
//Константы
//---------
const STYLES = {
SECTION_INFO: {
padding: "24px 5px 0px 5px"
}
};
//---------------
//Тело компонента
@ -21,11 +31,7 @@ const SectionTabPanel = props => {
//Генерация содержимого
return (
<div role="tabpanel" hidden={value !== index} id={`tabpanel-${index}`} aria-labelledby={`tab-${index}`} {...other}>
{value === index && (
<Box p={3}>
<Typography component="span">{children}</Typography>
</Box>
)}
{value === index && <Box sx={STYLES.SECTION_INFO}>{children}</Box>}
</div>
);
};

View File

@ -7,7 +7,17 @@
//Подключение библиотек
//---------------------
import { useState, useLayoutEffect } from "react"; //Классы React
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"; //Тексты для ошибок
//---------------------------------------------
//Вспомогательные функции форматирования данных
//---------------------------------------------
//-----------
//Тело модуля
@ -32,8 +42,359 @@ const useWindowResize = () => {
return size;
};
//Хук для настройки регламентированного отчета
const useConf = (currentTab, handleSectionChange) => {
//Собственное состояние - таблица данных
const dataGrid = {
rn: 0,
code: "",
name: "",
dataLoaded: false,
columnsDef: [],
groups: [],
rows: [],
fixedHeader: false,
fixedColumns: 0,
reload: false
};
//Собственное состояние
const [rrpConf, setRrpConf] = useState({
docLoaded: false,
sections: [],
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)
},
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.map(s => {
let dg = {};
Object.assign(dg, dataGrid, {
rn: s.NRN,
code: s.SCODE,
name: s.SNAME,
delete_allow: s.NDELETE_ALLOW,
dataLoaded: true,
columnsDef: [...(s.XDATA.XCOLUMNS_DEF || [])],
groups: [...(s.XDATA.XGROUPS || [])],
rows: [...(s.XDATA.XROWS || [])],
fixedHeader: s.XDATA.XDATA_GRID.fixedHeader,
fixedColumns: s.XDATA.XDATA_GRID.fixedColumns,
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 = 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,
reload: false,
sections: dataGrids
}));
handleSectionChange(tabFocus);
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [rrpConf.reload, rrpConf.docLoaded, dataGrid.reload, dataGrid.docLoaded, executeStored]);
//При необходимости обновить данные таблицы
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 };
export { useWindowResize, useConf, useTab, useRecOpen, useFormDialog, a11yProps };

View File

@ -1,46 +0,0 @@
/*
Парус 8 - Панели мониторинга - РО - Редактор настройки регламентированного отчёта
Дополнительная разметка и вёрстка клиентских элементов
*/
//---------------------
//Подключение библиотек
//---------------------
import React from "react"; //Классы React
import { Box, IconButton, Icon, Link } from "@mui/material"; //Интерфейсные компоненты
//---------
//Константы
//---------
//Стили
export const STYLES = {
BOX_ROW: { display: "flex", justifyContent: "center", alignItems: "center" },
LINK_STYLE: { component: "button", cursor: "pointer", width: "-webkit-fill-available" }
};
//-----------
//Тело модуля
//-----------
//Генерация представления ячейки c данными показателя раздела регламентированного отчета
export const confSctnMrkCellRender = ({ row, columnDef, onLinkClick, onEditClick, onDeleteClick }) => {
let data = row[columnDef.name];
columnDef.name != "SROW_NAME" && data != undefined && columnDef.visible == true
? (data = (
<Box sx={STYLES.BOX_ROW}>
<Link sx={STYLES.LINK_STYLE} onClick={() => (onLinkClick ? onLinkClick(row["NRN_" + columnDef.name.substring(5)]) : null)}>
{row[columnDef.name]}
</Link>
<IconButton onClick={() => (onEditClick ? onEditClick(row["NRN_" + columnDef.name.substring(5)], row[columnDef.name]) : null)}>
<Icon>edit</Icon>
</IconButton>
<IconButton onClick={() => (onDeleteClick ? onDeleteClick(row["NRN_" + columnDef.name.substring(5)], row[columnDef.name]) : null)}>
<Icon>delete</Icon>
</IconButton>
</Box>
))
: null;
return { data };
};

View File

@ -7,21 +7,11 @@
//Подключение библиотек
//---------------------
import React, { useCallback, useContext, useState, useEffect } from "react"; //Классы React
import { Box, Tab, Tabs, IconButton, Icon, Stack, Button } from "@mui/material"; //Интерфейсные компоненты
import { P8PDataGrid, P8P_DATA_GRID_SIZE } from "../../components/p8p_data_grid"; //Таблица данных
import { P8P_DATA_GRID_CONFIG_PROPS } from "../../config_wrapper"; //Подключение компонентов к настройкам приложения
import { ApplicationСtx } from "../../context/application"; //Контекст приложения
import { BackEndСtx } from "../../context/backend"; //Контекст взаимодействия с сервером
import { NavigationCtx } from "../../context/navigation"; //Контекст навигации
import { MessagingСtx } from "../../context/messaging"; //Контекст сообщений
import { SectionTabPanel } from "./section_tab_panel"; //Компонент вкладки раздела
import { IUDFormDialog } from "./iud_form_dialog"; //Диалог добавления/исправления/удаления компонентов настройки регламентированного отчёта
import { confSctnMrkCellRender } from "./layouts"; //Дополнительная разметка и вёрстка клиентских элементов
import { STATUSES } from "./iud_form_dialog"; //Статусы диалогового окна
import { TEXTS } from "../../../app.text"; //Текстовые константы
import { STYLES as COMMON_STYLES } from "./layouts"; //Общие стили
import { useWindowResize } from "./hooks"; //Пользовательские хуки
import React, { useState, useEffect } from "react"; //Классы React
import { Box, Tab, Tabs, IconButton, Icon, Stack } from "@mui/material"; //Интерфейсные компоненты
import { IUDFormDialog } from "./IUD/iud_form_dialog"; //Диалог добавления/исправления/удаления компонентов настройки регламентированного отчёта
import { useWindowResize, useTab, useConf, useRecOpen, useFormDialog, a11yProps } from "./hooks"; //Пользовательские хуки
import { SectionTab } from "./components/rrp_section"; //Компонент раздела настройки
//---------
//Константы
@ -36,20 +26,13 @@ const pxSectionAddButtonW = 40;
//Стили
const STYLES = {
CONTAINER: { width: "100%" },
CONTAINER: { width: "100%", minHeight: `calc(100vh - ${pxPanelHeaderH})`, maxHeight: `calc(100vh - ${pxPanelHeaderH})` },
PANELS_MAIN_COLOR: { backgroundColor: "#1976d2" },
ICON_WHITE: { color: "white" },
TABS_BOTTOM_LINE: { borderBottom: 1, borderColor: "divider" },
TABS_PADDING: { padding: "5px" },
TABS_SIZES: (width, pxSectionAddButtonW) => ({ maxHeight: 150, maxWidth: width - pxSectionAddButtonW }),
GRID_PADDING: { paddingTop: 1, paddingBottom: 1 },
GRID_SIZES: (width, height, pxOuterMenuH, pxPanelHeaderH, pxTabsH) => ({
padding: 0,
minWidth: width * 0.95,
minHeight: (height - pxOuterMenuH - pxPanelHeaderH - pxTabsH) * 0.88,
maxWidth: width * 0.95,
maxHeight: (height - pxOuterMenuH - pxPanelHeaderH - pxTabsH) * 0.88
})
SECTION_ACTIONS: { display: "flex", justifyContent: "center", alignItems: "center" }
};
//-----------
@ -58,257 +41,27 @@ const STYLES = {
//Редактор настройки регламентированного отчёта
const RrpConfEditor = () => {
const dataGrid = {
rn: 0,
code: "",
name: "",
dataLoaded: false,
columnsDef: [],
groups: [],
rows: [],
fixedHeader: false,
fixedColumns: 0,
reload: false
};
//Состояние вкладки
const [tabValue, handleSectionChange] = useTab("");
//Собственное состояние
const [rrpDoc, setRrpDoc] = useState({
docLoaded: false,
sections: [],
reload: true
});
//Состояние настройки
const [rrpConf, handleReload] = useConf(tabValue, handleSectionChange);
//Состояние массива данных разделов
const [dataGrids] = useState([]);
//Функции открытия разделов
const [handleMarkOpen, handleMarkCnOpen, handleMarkCnInsert] = useRecOpen(handleReload);
//Состояние раздела
const [tabValue, setTabValue] = useState("");
//Состояние открытия диалогового окна
const [formOpen, setForm] = useState(false);
//Состояние диалогового окна
const [formData, setFormData] = useState({
rn: "",
prn: "",
sctnName: "",
sctnCode: "",
status: "",
code: "",
name: "",
colName: "",
colCode: "",
colVCode: "",
colVRn: 0,
rowName: "",
rowCode: "",
rowVCode: "",
rowVRn: 0
});
//Открытие диалогового окна
const openForm = () => {
setForm(true);
};
//Очистка диалогового окна
const clearFormData = () => {
setFormData({
rn: "",
prn: "",
sctnName: "",
sctnCode: "",
status: "",
code: "",
name: "",
colName: "",
colCode: "",
colVCode: "",
colVRn: 0,
rowName: "",
rowCode: "",
rowVCode: "",
rowVRn: 0
});
};
//Подключение к контексту взаимодействия с сервером
const { executeStored } = useContext(BackEndСtx);
//Подключение к контексту приложения
const { pOnlineShowUnit } = useContext(ApplicationСtx);
//Подключение к контексту навигации
const { getNavigationSearch } = useContext(NavigationCtx);
//Подключение к контексту сообщений
const { showMsgErr } = useContext(MessagingСtx);
//Переключение раздела
const handleSectionChange = (event, newValue) => {
setTabValue(newValue);
};
//Отработка нажатия на кнопку добавления секции
const addSectionClick = () => {
setFormData({ status: STATUSES.CREATE, prn: Number(getNavigationSearch().NRN) });
openForm();
};
//Отработка нажатия на кнопку исправления секции
const editSectionClick = (rn, code, name) => {
setFormData({ rn: rn, code: code, name: name, status: STATUSES.EDIT });
openForm();
};
//Отработка нажатия на кнопку удаления секции
const deleteSectionClick = (rn, code, name) => {
setFormData({ rn: rn, code: code, name: name, status: STATUSES.DELETE });
openForm();
};
//Отработка нажатия на кнопку добавления показателя раздела
const addSectionMarkClick = (prn, sctnCode, sctnName) => {
setFormData({ status: STATUSES.RRPCONFSCTNMRK_CREATE, prn: prn, sctnCode: sctnCode, sctnName: sctnName });
openForm();
};
//Отработка нажатия на кнопку исправления показателя раздела
const editSectionMarkClick = (rn, name) => {
setFormData({ status: STATUSES.RRPCONFSCTNMRK_EDIT, rn: rn, name: name });
openForm();
};
//Отработка нажатия на кнопку удаления показателя раздела
const deleteSectionMarkClick = (rn, name) => {
setFormData({ status: STATUSES.RRPCONFSCTNMRK_DELETE, rn: rn, name: name });
openForm();
};
//Отображение показателя раздела
const showSectionMark = async rn => {
const data = await executeStored({
stored: "PKG_P8PANELS_RRPCONFED.RRPCONFSCTNMRK_GET_CODES",
args: {
NRN: rn
},
tagValueProcessor: () => undefined
});
if (data) {
pOnlineShowUnit({
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 }
]
});
} else showMsgErr(TEXTS.NO_DATA_FOUND);
};
//Формирование разделов
const a11yProps = index => {
return {
id: `simple-tab-${index}`,
"aria-controls": `simple-tabpanel-${index}`
};
};
//Загрузка данных разделов регламентированного отчёта
const loadData = useCallback(async () => {
if (rrpDoc.reload) {
//Переменная номера раздела с фокусом
let tabFocus = 0;
const data = await executeStored({
stored: "PKG_P8PANELS_RRPCONFED.RRPCONF_GET_SECTIONS",
args: {
NRN_RRPCONF: Number(getNavigationSearch().NRN)
},
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.map(s => {
let dg = {};
Object.assign(dg, dataGrid, {
rn: s.NRN,
code: s.SCODE,
name: s.SNAME,
dataLoaded: true,
columnsDef: [...(s.XDATA.XCOLUMNS_DEF || [])],
groups: [...(s.XDATA.XGROUPS || [])],
rows: [...(s.XDATA.XROWS || [])],
fixedHeader: s.XDATA.XDATA_GRID.fixedHeader,
fixedColumns: s.XDATA.XDATA_GRID.fixedColumns,
reload: false
});
//Ищем загружен ли уже раздел с таким же ид.
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 = 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;
});
setRrpDoc(pv => ({
...pv,
docLoaded: true,
reload: false,
sections: dataGrids
}));
setTabValue(tabFocus);
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [rrpDoc.reload, rrpDoc.docLoaded, dataGrid.reload, dataGrid.docLoaded, executeStored]);
//При необходимости обновить данные таблицы
useEffect(() => {
loadData();
}, [rrpDoc.reload, dataGrid.reload, loadData]);
//При изменениях элемента
const handleDialogReload = () => {
setRrpDoc(pv => ({ ...pv, reload: true }));
};
//При закрытии диалога
const handleDialogClose = () => {
setForm(false);
clearFormData();
};
//Состояние форм диалога
const [
formOpen,
formData,
handleSectionAdd,
handleSectionEdit,
handleSectionDelete,
handleMarkAdd,
handleMarkEdit,
handleMarkDelete,
handleDialogClose
] = useFormDialog();
//Состояние ширины и высоты рабочей области окна
const [width, height] = useWindowResize();
@ -318,39 +71,49 @@ const RrpConfEditor = () => {
//При рендере данных
useEffect(() => {
rrpDoc.docLoaded ? setPxTabsH(document.getElementById("sectionTabs").offsetHeight) : null;
}, [rrpDoc.docLoaded]);
rrpConf.docLoaded ? setPxTabsH(document.getElementById("sectionTabs").offsetHeight) : null;
}, [rrpConf.docLoaded]);
//Формируем меню показателей
const markMenuItems = [
{ method: "EDIT", name: "Исправить", icon: "edit", func: handleMarkEdit },
{ method: "DELETE", name: "Удалить", icon: "delete", func: handleMarkDelete }
];
//Генерация содержимого
return (
<Box sx={STYLES.CONTAINER}>
{formOpen ? <IUDFormDialog initial={formData} onClose={handleDialogClose} onReload={handleDialogReload} /> : null}
{rrpDoc.docLoaded ? (
{formOpen ? <IUDFormDialog initial={formData} onClose={handleDialogClose} onReload={handleReload} /> : null}
{rrpConf.docLoaded ? (
<Box>
<Stack direction="row" sx={STYLES.TABS_BOTTOM_LINE}>
<Tabs
id="sectionTabs"
value={tabValue}
onChange={handleSectionChange}
onChange={(event, newValue) => handleSectionChange(newValue)}
variant="scrollable"
scrollButtons={false}
visibleScrollbar
aria-label="section tab"
sx={STYLES.TABS_SIZES(width, pxSectionAddButtonW)}
>
{rrpDoc.sections.map((s, i) => {
{rrpConf.sections.map((s, i) => {
return (
<Tab
key={s.rn}
{...a11yProps(i)}
sx={STYLES.TABS_PADDING}
label={
<Box sx={COMMON_STYLES.BOX_ROW}>
<Box sx={STYLES.SECTION_ACTIONS}>
{s.name}
<IconButton component="span" onClick={() => editSectionClick(s.rn, s.code, s.name)}>
<IconButton component="span" onClick={() => handleSectionEdit(s.rn, s.code, s.name)}>
<Icon>edit</Icon>
</IconButton>
<IconButton component="span" onClick={() => deleteSectionClick(s.rn, s.code, s.name)}>
<IconButton
disabled={s.delete_allow === 0}
component="span"
onClick={() => handleSectionDelete(s.rn, s.code, s.name)}
>
<Icon>delete</Icon>
</IconButton>
</Box>
@ -361,42 +124,26 @@ const RrpConfEditor = () => {
})}
</Tabs>
<Box display="flex" justifyContent="center" alignItems="center" sx={STYLES.PANELS_MAIN_COLOR}>
<IconButton onClick={addSectionClick}>
<IconButton onClick={handleSectionAdd}>
<Icon sx={STYLES.ICON_WHITE}>add</Icon>
</IconButton>
</Box>
</Stack>
{rrpDoc.sections.map((s, i) => {
{rrpConf.sections.map((s, i) => {
return (
<SectionTabPanel key={s.rn} value={tabValue} index={i}>
<Button onClick={() => addSectionMarkClick(s.rn, s.code, s.name)}>Добавить</Button>
{s.dataLoaded && s.columnsDef.length > 1 ? (
<Box sx={{ ...STYLES.GRID_PADDING, ...COMMON_STYLES.BOX_ROW }}>
<P8PDataGrid
{...P8P_DATA_GRID_CONFIG_PROPS}
containerComponentProps={{
elevation: 6,
style: STYLES.GRID_SIZES(width, height, pxOuterMenuH, pxPanelHeaderH, pxTabsH)
}}
columnsDef={s.columnsDef}
groups={s.groups}
rows={s.rows}
fixedHeader={s.fixedHeader}
fixedColumns={s.fixedColumns}
size={P8P_DATA_GRID_SIZE.LARGE}
reloading={s.reload}
dataCellRender={prms =>
confSctnMrkCellRender({
...prms,
onLinkClick: showSectionMark,
onEditClick: editSectionMarkClick,
onDeleteClick: deleteSectionMarkClick
})
}
/>
</Box>
) : null}
</SectionTabPanel>
<SectionTab
key={s.rn}
section={s}
tabValue={tabValue}
index={i}
containerProps={{ height, pxOuterMenuH, pxPanelHeaderH, pxTabsH }}
handleReload={handleReload}
handleMarkOpen={handleMarkOpen}
handleMarkAdd={handleMarkAdd}
handleMarkCnOpen={handleMarkCnOpen}
handleMarkCnInsert={handleMarkCnInsert}
menuItems={markMenuItems}
/>
);
})}
</Box>

File diff suppressed because it is too large Load Diff