ЦИТК-823 - Изменение панели "Редактор настройки регламентированного отчёта"
This commit is contained in:
parent
331fc33839
commit
1a01536b35
@ -10,8 +10,8 @@
|
|||||||
import React, { useState, useContext, useCallback, useEffect } from "react"; //Классы React
|
import React, { useState, useContext, useCallback, useEffect } from "react"; //Классы React
|
||||||
import PropTypes from "prop-types"; //Контроль свойств компонента
|
import PropTypes from "prop-types"; //Контроль свойств компонента
|
||||||
import { Dialog, DialogTitle, IconButton, Icon, DialogContent, Typography, DialogActions, Button } from "@mui/material"; //Интерфейсные компоненты
|
import { Dialog, DialogTitle, IconButton, Icon, DialogContent, Typography, DialogActions, Button } from "@mui/material"; //Интерфейсные компоненты
|
||||||
import { ApplicationСtx } from "../../context/application"; //Контекст приложения
|
import { ApplicationСtx } from "../../../context/application"; //Контекст приложения
|
||||||
import { BackEndСtx } from "../../context/backend"; //Контекст взаимодействия с сервером
|
import { BackEndСtx } from "../../../context/backend"; //Контекст взаимодействия с сервером
|
||||||
import { IUDFormTextField } from "./iud_form_text_field"; //Компонент поля ввода
|
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 () => {
|
const changeSections = useCallback(async () => {
|
||||||
@ -139,13 +141,11 @@ const IUDFormDialog = ({ initial, onClose, onReload }) => {
|
|||||||
NPRN: formData.prn,
|
NPRN: formData.prn,
|
||||||
SCODE: formData.code,
|
SCODE: formData.code,
|
||||||
SNAME: formData.name,
|
SNAME: formData.name,
|
||||||
SCOLCODE: formData.colCode,
|
NRRPROW: formData.rowRn,
|
||||||
SCOLVER: formData.colVCode,
|
NRRPCOLUMN: formData.colRn
|
||||||
SROWCODE: formData.rowCode,
|
|
||||||
SROWVER: formData.rowVCode
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}, [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 () => {
|
const editRRPCONFSCTNMRK = useCallback(async () => {
|
||||||
@ -210,14 +210,15 @@ const IUDFormDialog = ({ initial, onClose, onReload }) => {
|
|||||||
const selectRow = (showDictionary, callBack) => {
|
const selectRow = (showDictionary, callBack) => {
|
||||||
showDictionary({
|
showDictionary({
|
||||||
unitCode: "RRPRow",
|
unitCode: "RRPRow",
|
||||||
|
inputParameters: [{ name: "in_RN", value: formData.rowRn }],
|
||||||
callBack: res => {
|
callBack: res => {
|
||||||
if (res.success === true) {
|
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 => ({
|
setFormData(pv => ({
|
||||||
...pv,
|
...pv,
|
||||||
|
reload: true,
|
||||||
rowCode: res.outParameters.out_CODE,
|
rowCode: res.outParameters.out_CODE,
|
||||||
rowVCode: res.outParameters.out_RRPVERSION_CODE,
|
rowRn: res.outParameters.out_RN
|
||||||
rowVRn: res.outParameters.out_RRPVERSION
|
|
||||||
}));
|
}));
|
||||||
} else callBack(null);
|
} else callBack(null);
|
||||||
}
|
}
|
||||||
@ -228,14 +229,15 @@ const IUDFormDialog = ({ initial, onClose, onReload }) => {
|
|||||||
const selectColumn = (showDictionary, callBack) => {
|
const selectColumn = (showDictionary, callBack) => {
|
||||||
showDictionary({
|
showDictionary({
|
||||||
unitCode: "RRPColumn",
|
unitCode: "RRPColumn",
|
||||||
|
inputParameters: [{ name: "in_RN", value: formData.colRn }],
|
||||||
callBack: res => {
|
callBack: res => {
|
||||||
if (res.success === true) {
|
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 => ({
|
setFormData(pv => ({
|
||||||
...pv,
|
...pv,
|
||||||
|
reload: true,
|
||||||
colCode: res.outParameters.out_CODE,
|
colCode: res.outParameters.out_CODE,
|
||||||
colVCode: res.outParameters.out_RRPVERSION_CODE,
|
colRn: res.outParameters.out_RN
|
||||||
colVRn: res.outParameters.out_RRPVERSION
|
|
||||||
}));
|
}));
|
||||||
} else callBack(null);
|
} else callBack(null);
|
||||||
}
|
}
|
||||||
@ -247,26 +249,41 @@ const IUDFormDialog = ({ initial, onClose, onReload }) => {
|
|||||||
const data = await executeStored({
|
const data = await executeStored({
|
||||||
stored: "PKG_P8PANELS_RRPCONFED.RRPCONFSCTNMRK_GET_CODE_NAME",
|
stored: "PKG_P8PANELS_RRPCONFED.RRPCONFSCTNMRK_GET_CODE_NAME",
|
||||||
args: {
|
args: {
|
||||||
SSCTNCODE: formData.sctnCode,
|
NRRPCONFSCTN: formData.prn,
|
||||||
SROWCODE: formData.rowCode,
|
NRRPROW: formData.rowRn,
|
||||||
NROWVER: formData.rowVRn,
|
NRRPCOLUMN: formData.colRn
|
||||||
SCOLUMNCODE: formData.colCode,
|
|
||||||
NCOLUMNVER: formData.colVRn
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
setFormData(pv => ({
|
setFormData(pv => ({
|
||||||
...pv,
|
...pv,
|
||||||
|
reload: false,
|
||||||
code: data.SCODE,
|
code: data.SCODE,
|
||||||
name: data.SNAME
|
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(() => {
|
useEffect(() => {
|
||||||
formData.status == STATUSES.RRPCONFSCTNMRK_CREATE && formData.sctnName && formData.sctnCode && formData.colCode && formData.rowCode
|
//Если это добавление показателя и требуется сформировать мнемокод и наименование
|
||||||
? getSctnMrkCodeName()
|
formData.status == STATUSES.RRPCONFSCTNMRK_CREATE && formData.reload && formData.rowRn && formData.colRn ? getSctnMrkCodeName() : null;
|
||||||
: null;
|
//Если это исправление и требуется инициализировать наименование показателя
|
||||||
}, [formData.colCode, formData.rowCode, formData.sctnCode, formData.sctnName, formData.status, getSctnMrkCodeName]);
|
formData.status == STATUSES.RRPCONFSCTNMRK_EDIT && formData.reload ? getMarkName() : null;
|
||||||
|
}, [formData.status, formData.reload, formData.rowRn, formData.colRn, getSctnMrkCodeName, getMarkName]);
|
||||||
|
|
||||||
//Генерация содержимого
|
//Генерация содержимого
|
||||||
return (
|
return (
|
344
app/panels/rrp_conf_editor/components/layouts.js
Normal file
344
app/panels/rrp_conf_editor/components/layouts.js
Normal 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
|
||||||
|
};
|
||||||
|
};
|
243
app/panels/rrp_conf_editor/components/rrp_section.js
Normal file
243
app/panels/rrp_conf_editor/components/rrp_section.js
Normal 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 };
|
@ -9,7 +9,17 @@
|
|||||||
|
|
||||||
import React from "react"; //Классы React
|
import React from "react"; //Классы React
|
||||||
import PropTypes from "prop-types"; //Контроль свойств компонента
|
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 (
|
return (
|
||||||
<div role="tabpanel" hidden={value !== index} id={`tabpanel-${index}`} aria-labelledby={`tab-${index}`} {...other}>
|
<div role="tabpanel" hidden={value !== index} id={`tabpanel-${index}`} aria-labelledby={`tab-${index}`} {...other}>
|
||||||
{value === index && (
|
{value === index && <Box sx={STYLES.SECTION_INFO}>{children}</Box>}
|
||||||
<Box p={3}>
|
|
||||||
<Typography component="span">{children}</Typography>
|
|
||||||
</Box>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
@ -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;
|
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 };
|
||||||
|
@ -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 };
|
|
||||||
};
|
|
@ -7,21 +7,11 @@
|
|||||||
//Подключение библиотек
|
//Подключение библиотек
|
||||||
//---------------------
|
//---------------------
|
||||||
|
|
||||||
import React, { useCallback, useContext, useState, useEffect } from "react"; //Классы React
|
import React, { useState, useEffect } from "react"; //Классы React
|
||||||
import { Box, Tab, Tabs, IconButton, Icon, Stack, Button } from "@mui/material"; //Интерфейсные компоненты
|
import { Box, Tab, Tabs, IconButton, Icon, Stack } from "@mui/material"; //Интерфейсные компоненты
|
||||||
import { P8PDataGrid, P8P_DATA_GRID_SIZE } from "../../components/p8p_data_grid"; //Таблица данных
|
import { IUDFormDialog } from "./IUD/iud_form_dialog"; //Диалог добавления/исправления/удаления компонентов настройки регламентированного отчёта
|
||||||
import { P8P_DATA_GRID_CONFIG_PROPS } from "../../config_wrapper"; //Подключение компонентов к настройкам приложения
|
import { useWindowResize, useTab, useConf, useRecOpen, useFormDialog, a11yProps } from "./hooks"; //Пользовательские хуки
|
||||||
import { ApplicationСtx } from "../../context/application"; //Контекст приложения
|
import { SectionTab } from "./components/rrp_section"; //Компонент раздела настройки
|
||||||
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"; //Пользовательские хуки
|
|
||||||
|
|
||||||
//---------
|
//---------
|
||||||
//Константы
|
//Константы
|
||||||
@ -36,20 +26,13 @@ const pxSectionAddButtonW = 40;
|
|||||||
|
|
||||||
//Стили
|
//Стили
|
||||||
const STYLES = {
|
const STYLES = {
|
||||||
CONTAINER: { width: "100%" },
|
CONTAINER: { width: "100%", minHeight: `calc(100vh - ${pxPanelHeaderH})`, maxHeight: `calc(100vh - ${pxPanelHeaderH})` },
|
||||||
PANELS_MAIN_COLOR: { backgroundColor: "#1976d2" },
|
PANELS_MAIN_COLOR: { backgroundColor: "#1976d2" },
|
||||||
ICON_WHITE: { color: "white" },
|
ICON_WHITE: { color: "white" },
|
||||||
TABS_BOTTOM_LINE: { borderBottom: 1, borderColor: "divider" },
|
TABS_BOTTOM_LINE: { borderBottom: 1, borderColor: "divider" },
|
||||||
TABS_PADDING: { padding: "5px" },
|
TABS_PADDING: { padding: "5px" },
|
||||||
TABS_SIZES: (width, pxSectionAddButtonW) => ({ maxHeight: 150, maxWidth: width - pxSectionAddButtonW }),
|
TABS_SIZES: (width, pxSectionAddButtonW) => ({ maxHeight: 150, maxWidth: width - pxSectionAddButtonW }),
|
||||||
GRID_PADDING: { paddingTop: 1, paddingBottom: 1 },
|
SECTION_ACTIONS: { display: "flex", justifyContent: "center", alignItems: "center" }
|
||||||
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
|
|
||||||
})
|
|
||||||
};
|
};
|
||||||
|
|
||||||
//-----------
|
//-----------
|
||||||
@ -58,257 +41,27 @@ const STYLES = {
|
|||||||
|
|
||||||
//Редактор настройки регламентированного отчёта
|
//Редактор настройки регламентированного отчёта
|
||||||
const RrpConfEditor = () => {
|
const RrpConfEditor = () => {
|
||||||
const dataGrid = {
|
//Состояние вкладки
|
||||||
rn: 0,
|
const [tabValue, handleSectionChange] = useTab("");
|
||||||
code: "",
|
|
||||||
name: "",
|
|
||||||
dataLoaded: false,
|
|
||||||
columnsDef: [],
|
|
||||||
groups: [],
|
|
||||||
rows: [],
|
|
||||||
fixedHeader: false,
|
|
||||||
fixedColumns: 0,
|
|
||||||
reload: false
|
|
||||||
};
|
|
||||||
|
|
||||||
//Собственное состояние
|
//Состояние настройки
|
||||||
const [rrpDoc, setRrpDoc] = useState({
|
const [rrpConf, handleReload] = useConf(tabValue, handleSectionChange);
|
||||||
docLoaded: false,
|
|
||||||
sections: [],
|
|
||||||
reload: true
|
|
||||||
});
|
|
||||||
|
|
||||||
//Состояние массива данных разделов
|
//Функции открытия разделов
|
||||||
const [dataGrids] = useState([]);
|
const [handleMarkOpen, handleMarkCnOpen, handleMarkCnInsert] = useRecOpen(handleReload);
|
||||||
|
|
||||||
//Состояние раздела
|
//Состояние форм диалога
|
||||||
const [tabValue, setTabValue] = useState("");
|
const [
|
||||||
|
formOpen,
|
||||||
//Состояние открытия диалогового окна
|
formData,
|
||||||
const [formOpen, setForm] = useState(false);
|
handleSectionAdd,
|
||||||
|
handleSectionEdit,
|
||||||
//Состояние диалогового окна
|
handleSectionDelete,
|
||||||
const [formData, setFormData] = useState({
|
handleMarkAdd,
|
||||||
rn: "",
|
handleMarkEdit,
|
||||||
prn: "",
|
handleMarkDelete,
|
||||||
sctnName: "",
|
handleDialogClose
|
||||||
sctnCode: "",
|
] = useFormDialog();
|
||||||
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 [width, height] = useWindowResize();
|
const [width, height] = useWindowResize();
|
||||||
@ -318,39 +71,49 @@ const RrpConfEditor = () => {
|
|||||||
|
|
||||||
//При рендере данных
|
//При рендере данных
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
rrpDoc.docLoaded ? setPxTabsH(document.getElementById("sectionTabs").offsetHeight) : null;
|
rrpConf.docLoaded ? setPxTabsH(document.getElementById("sectionTabs").offsetHeight) : null;
|
||||||
}, [rrpDoc.docLoaded]);
|
}, [rrpConf.docLoaded]);
|
||||||
|
|
||||||
|
//Формируем меню показателей
|
||||||
|
const markMenuItems = [
|
||||||
|
{ method: "EDIT", name: "Исправить", icon: "edit", func: handleMarkEdit },
|
||||||
|
{ method: "DELETE", name: "Удалить", icon: "delete", func: handleMarkDelete }
|
||||||
|
];
|
||||||
|
|
||||||
//Генерация содержимого
|
//Генерация содержимого
|
||||||
return (
|
return (
|
||||||
<Box sx={STYLES.CONTAINER}>
|
<Box sx={STYLES.CONTAINER}>
|
||||||
{formOpen ? <IUDFormDialog initial={formData} onClose={handleDialogClose} onReload={handleDialogReload} /> : null}
|
{formOpen ? <IUDFormDialog initial={formData} onClose={handleDialogClose} onReload={handleReload} /> : null}
|
||||||
{rrpDoc.docLoaded ? (
|
{rrpConf.docLoaded ? (
|
||||||
<Box>
|
<Box>
|
||||||
<Stack direction="row" sx={STYLES.TABS_BOTTOM_LINE}>
|
<Stack direction="row" sx={STYLES.TABS_BOTTOM_LINE}>
|
||||||
<Tabs
|
<Tabs
|
||||||
id="sectionTabs"
|
id="sectionTabs"
|
||||||
value={tabValue}
|
value={tabValue}
|
||||||
onChange={handleSectionChange}
|
onChange={(event, newValue) => handleSectionChange(newValue)}
|
||||||
variant="scrollable"
|
variant="scrollable"
|
||||||
scrollButtons={false}
|
scrollButtons={false}
|
||||||
visibleScrollbar
|
visibleScrollbar
|
||||||
aria-label="section tab"
|
aria-label="section tab"
|
||||||
sx={STYLES.TABS_SIZES(width, pxSectionAddButtonW)}
|
sx={STYLES.TABS_SIZES(width, pxSectionAddButtonW)}
|
||||||
>
|
>
|
||||||
{rrpDoc.sections.map((s, i) => {
|
{rrpConf.sections.map((s, i) => {
|
||||||
return (
|
return (
|
||||||
<Tab
|
<Tab
|
||||||
key={s.rn}
|
key={s.rn}
|
||||||
{...a11yProps(i)}
|
{...a11yProps(i)}
|
||||||
sx={STYLES.TABS_PADDING}
|
sx={STYLES.TABS_PADDING}
|
||||||
label={
|
label={
|
||||||
<Box sx={COMMON_STYLES.BOX_ROW}>
|
<Box sx={STYLES.SECTION_ACTIONS}>
|
||||||
{s.name}
|
{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>
|
<Icon>edit</Icon>
|
||||||
</IconButton>
|
</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>
|
<Icon>delete</Icon>
|
||||||
</IconButton>
|
</IconButton>
|
||||||
</Box>
|
</Box>
|
||||||
@ -361,42 +124,26 @@ const RrpConfEditor = () => {
|
|||||||
})}
|
})}
|
||||||
</Tabs>
|
</Tabs>
|
||||||
<Box display="flex" justifyContent="center" alignItems="center" sx={STYLES.PANELS_MAIN_COLOR}>
|
<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>
|
<Icon sx={STYLES.ICON_WHITE}>add</Icon>
|
||||||
</IconButton>
|
</IconButton>
|
||||||
</Box>
|
</Box>
|
||||||
</Stack>
|
</Stack>
|
||||||
{rrpDoc.sections.map((s, i) => {
|
{rrpConf.sections.map((s, i) => {
|
||||||
return (
|
return (
|
||||||
<SectionTabPanel key={s.rn} value={tabValue} index={i}>
|
<SectionTab
|
||||||
<Button onClick={() => addSectionMarkClick(s.rn, s.code, s.name)}>Добавить</Button>
|
key={s.rn}
|
||||||
{s.dataLoaded && s.columnsDef.length > 1 ? (
|
section={s}
|
||||||
<Box sx={{ ...STYLES.GRID_PADDING, ...COMMON_STYLES.BOX_ROW }}>
|
tabValue={tabValue}
|
||||||
<P8PDataGrid
|
index={i}
|
||||||
{...P8P_DATA_GRID_CONFIG_PROPS}
|
containerProps={{ height, pxOuterMenuH, pxPanelHeaderH, pxTabsH }}
|
||||||
containerComponentProps={{
|
handleReload={handleReload}
|
||||||
elevation: 6,
|
handleMarkOpen={handleMarkOpen}
|
||||||
style: STYLES.GRID_SIZES(width, height, pxOuterMenuH, pxPanelHeaderH, pxTabsH)
|
handleMarkAdd={handleMarkAdd}
|
||||||
}}
|
handleMarkCnOpen={handleMarkCnOpen}
|
||||||
columnsDef={s.columnsDef}
|
handleMarkCnInsert={handleMarkCnInsert}
|
||||||
groups={s.groups}
|
menuItems={markMenuItems}
|
||||||
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>
|
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
</Box>
|
</Box>
|
||||||
|
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user