344 lines
12 KiB
JavaScript
344 lines
12 KiB
JavaScript
/*
|
||
Парус 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"
|
||
},
|
||
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
|
||
};
|
||
};
|