392 lines
18 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
Парус 8 - Панели мониторинга - ПУП - Экономика проектов
Дополнительная разметка и вёрстка клиентских элементов
*/
//---------------------
//Подключение библиотек
//---------------------
import React from "react"; //Классы React
import { Grid, Icon, Stack, Link, Button, Table, TableBody, TableRow, TableCell, Typography, Box, Paper, IconButton } from "@mui/material"; //Интерфейсные компоненты
import { hasValue, formatDateRF, formatNumberRFCurrency } from "../../core/utils"; //Вспомогательные процедуры и функции
//---------
//Константы
//---------
//Разделы панелей экономики проектов
export const PANEL_UNITS = {
PROJECTS: "PROJECTS",
PROJECT_STAGES: "PROJECT_STAGES",
PROJECT_STAGE_CONTRACTS: "PROJECT_STAGE_CONTRACTS",
PROJECT_STAGE_ARTS: "PROJECT_STAGE_ARTS"
};
//Общие стили
export const COMMON_PROJECTS_STYLES = {
FULL_SCREEN_DIALOG_CONTENT: {
padding: 0
}
};
//-----------
//Тело модуля
//-----------
//Формирование значения для колонки "Состояние" проекта
const formatPrjStateValue = (value, addText = false) => {
const [text, icon] =
value == 0
? ["Зарегистрирован", "app_registration"]
: value == 1
? ["Открыт", "lock_open"]
: value == 2
? ["Остановлен", "do_not_disturb_on"]
: value == 3
? ["Закрыт", "lock_outline"]
: value == 4
? ["Согласован", "thumb_up_alt"]
: ["Исполнение прекращено", "block"];
return (
<Stack direction="row" gap={0.5} alignItems="center" justifyContent="center">
<Icon title={text}>{icon}</Icon>
{addText == true ? text : null}
</Stack>
);
};
//Формирование значения для колонки "Состояние" этапа
const formatStageStatusValue = (value, addText = false) => {
const [text, icon] =
value == 0
? ["Зарегистрирован", "app_registration"]
: value == 1
? ["Открыт", "lock_open"]
: value == 2
? ["Закрыт", "lock_outline"]
: value == 3
? ["Согласован", "thumb_up_alt"]
: value == 4
? ["Исполнение прекращено", "block"]
: ["Остановлен", "do_not_disturb_on"];
return (
<Stack direction="row" gap={0.5} alignItems="center" justifyContent="center">
<Icon title={text}>{icon}</Icon>
{addText == true ? text : null}
</Stack>
);
};
//Подбор функции форматирования колонки "Состояние" по разделу панели
const getStatusFormatter = panelUnit => (panelUnit === PANEL_UNITS.PROJECTS ? formatPrjStateValue : formatStageStatusValue);
//Формирование значения для контрольных колонок
const formatCtrlValue = (value, addText = false) => {
if (hasValue(value)) {
const [text, icon, color] = value == 0 ? ["В норме", "done", "green"] : ["Требует внимания", "error", "red"];
return (
<Stack direction="row" gap={0.5} alignItems="center" justifyContent="center">
<Icon title={text} sx={{ color }}>
{icon}
</Icon>
{addText == true ? text : null}
</Stack>
);
} else return value;
};
//Форматирование значений колонок
export const valueFormatter = ({ panelUnit, value, columnDef }) => {
switch (columnDef.name) {
case "NSTATE":
return getStatusFormatter(panelUnit)(value, true);
case "DBEGPLAN":
case "DENDPLAN":
case "DDOC_DATE":
case "DCSTAGE_BEGIN_DATE":
case "DCSTAGE_END_DATE":
return formatDateRF(value);
case "NPLAN":
case "NCOST_FACT":
case "NCONTR":
return formatNumberRFCurrency(value);
case "NCTRL_FIN":
case "NCTRL_CONTR":
case "NCTRL_COEXEC":
case "NCTRL_PERIOD":
case "NCTRL_COST":
case "NCTRL_ACT":
return formatCtrlValue(value, true);
}
return value;
};
//Генерация представления ячейки заголовка
export const headCellRender = ({ columnDef }) => {
switch (columnDef.name) {
case "NSTATE":
case "NCTRL_FIN":
case "NCTRL_CONTR":
case "NCTRL_COEXEC":
case "NCTRL_PERIOD":
case "NCTRL_COST":
case "NCTRL_ACT":
return {
stackProps: { justifyContent: "center" },
cellProps: { align: "center" }
};
}
};
//Генерация представления ячейки c данными
export const dataCellRender = ({ panelUnit, row, columnDef, pOnlineShowDocument, showStages, showStageArts, showCostNotes, showContracts }) => {
//Подбор функции на нажатие в ячейки контрольной колонки в зависимости от контекста
const getCrlOnClick = () =>
panelUnit == PANEL_UNITS.PROJECT_STAGES
? ["NCTRL_FIN", "NCTRL_COEXEC"].includes(columnDef.name)
? showContracts
: showStageArts
: showStages;
//Подбор представления ячейки контрольной колонки в зависимости от контекста
const renderCtl = () => ({
cellProps: {
align:
(panelUnit == PANEL_UNITS.PROJECT_STAGES && columnDef.name == "NCTRL_PERIOD") ||
(panelUnit == PANEL_UNITS.PROJECT_STAGE_CONTRACTS && columnDef.name == "NCTRL_FIN") ||
(panelUnit == PANEL_UNITS.PROJECT_STAGE_ARTS && ["NCTRL_COST", "NCTRL_CONTR"].includes(columnDef.name))
? "right"
: "center"
},
data: hasValue(row[columnDef.name]) ? (
panelUnit == PANEL_UNITS.PROJECT_STAGES && columnDef.name == "NCTRL_PERIOD" ? (
<Stack sx={{ justifyContent: "right" }} direction="row" spacing={1}>
<div style={{ color: row[columnDef.name] === 1 ? "red" : "green", display: "flex", alignItems: "center" }}>
{row.NDAYS_LEFT} дн.
</div>
{formatCtrlValue(row[columnDef.name], false)}
</Stack>
) : panelUnit == PANEL_UNITS.PROJECT_STAGE_CONTRACTS && columnDef.name == "NCTRL_FIN" ? (
<Stack sx={{ justifyContent: "right" }} direction="row" spacing={1}>
{row[columnDef.name] === 1 ? (
<div style={{ color: "red", display: "flex", alignItems: "center" }} title="Счетов к оплате">
{formatNumberRFCurrency(row["NPAY_IN_REST"])}
</div>
) : null}
{formatCtrlValue(row[columnDef.name], false)}
</Stack>
) : (panelUnit == PANEL_UNITS.PROJECT_STAGES && columnDef.name == "NCTRL_ACT") ||
(panelUnit == PANEL_UNITS.PROJECT_STAGE_CONTRACTS && columnDef.name == "NCTRL_COEXEC") ? (
formatCtrlValue(row[columnDef.name], false)
) : panelUnit == PANEL_UNITS.PROJECT_STAGE_ARTS && ["NCTRL_COST", "NCTRL_CONTR"].includes(columnDef.name) ? (
<Stack sx={{ justifyContent: "right" }} direction="row" spacing={1}>
<div style={{ color: row[columnDef.name] === 1 ? "red" : "green", display: "flex", alignItems: "center" }}>
{formatNumberRFCurrency(row[columnDef.name === "NCTRL_COST" ? "NCOST_DIFF" : "NCONTR_LEFT"])}
</div>
{formatCtrlValue(row[columnDef.name], false)}
</Stack>
) : (
<IconButton onClick={() => getCrlOnClick()({ sender: row, filters: [{ name: columnDef.name, from: row[columnDef.name] }] })}>
{formatCtrlValue(row[columnDef.name], false)}
</IconButton>
)
) : null
});
//Формирование представлений
switch (columnDef.name) {
case "SCODE":
case "SNAME_USL":
return {
data: (
<Link component="button" variant="body2" align="left" underline="hover" onClick={() => showStages({ sender: row })}>
{row[columnDef.name]}
</Link>
)
};
case "SDOC_PREF":
case "SDOC_NUMB":
return {
data: (
<Link
component="button"
variant="body2"
align="left"
underline="hover"
onClick={() =>
pOnlineShowDocument({ unitCode: row[`SLNK_UNIT_${columnDef.name}`], document: row[`NLNK_DOCUMENT_${columnDef.name}`] })
}
>
{row[columnDef.name]}
</Link>
)
};
case "NCOST_FACT":
case "NCONTR":
return {
data: row[columnDef.name] ? (
<Link
component="button"
variant="body2"
align="left"
underline="hover"
onClick={() => (columnDef.name === "NCOST_FACT" ? showCostNotes({ sender: row }) : showContracts({ sender: row }))}
>
{formatNumberRFCurrency(row[columnDef.name])}
</Link>
) : null
};
case "NSTATE":
return {
cellProps: { align: "center" },
data: getStatusFormatter(panelUnit)(row[columnDef.name], false)
};
case "NCTRL_FIN":
case "NCTRL_CONTR":
case "NCTRL_COEXEC":
case "NCTRL_PERIOD":
case "NCTRL_COST":
case "NCTRL_ACT":
return renderCtl();
}
};
//Генерация представления расширения строки
export const rowExpandRender = ({
panelUnit,
columnsDef,
row,
pOnlineShowDocument,
pOnlineShowUnit,
showStages,
showPayNotes,
showCostNotes,
showPaymentAccountsIn,
showIncomingInvoices,
showGoodsTransInvoicesToConsumers,
showStageArts,
showContracts
}) => {
//Фильтруем системные атрибуты и атрибуты без значений
const cardColumns = columnsDef.filter(
columnDef =>
columnDef.visible == false &&
columnDef.name != "NRN" &&
!columnDef.name.startsWith("SLNK_UNIT_") &&
!columnDef.name.startsWith("NLNK_DOCUMENT_") &&
hasValue(row[columnDef.name])
);
//Автоформатирование значения (N* - число, D* - дата, всё остальное - строка)
const formatColumnValue = (name, value) =>
name.startsWith("N") ? formatNumberRFCurrency(value) : name.startsWith("D") ? formatDateRF(value) : value;
//Формирование кнопок переходов
const linkButtons = () =>
panelUnit === PANEL_UNITS.PROJECTS ? (
<>
<Button variant="outlined" onClick={() => showStages({ sender: row })}>
Этапы
</Button>
<Button variant="outlined" onClick={() => pOnlineShowDocument({ unitCode: "Projects", document: row.NRN, modal: false })}>
К проекту
</Button>
</>
) : panelUnit === PANEL_UNITS.PROJECT_STAGES ? (
<>
<Button variant="outlined" onClick={() => showStageArts({ sender: row })}>
Статьи
</Button>
<Button variant="outlined" onClick={() => showContracts({ sender: row })}>
Сисполнители
</Button>
<Button
variant="outlined"
onClick={() =>
pOnlineShowUnit({
unitCode: "Projects",
inputParameters: [
{ name: "in_RN", value: row.NPROJECT },
{ name: "in_STAGE_RN", value: row.NRN }
],
modal: false
})
}
>
К этапу
</Button>
</>
) : panelUnit === PANEL_UNITS.PROJECT_STAGE_CONTRACTS ? (
<Button
variant="outlined"
onClick={() => pOnlineShowDocument({ unitCode: row.SLNK_UNIT_SDOC_PREF, document: row.NLNK_DOCUMENT_SDOC_PREF, modal: false })}
>
К договору
</Button>
) : null;
//Сборка содержимого
return (
<Box p={2}>
<Grid container spacing={2}>
<Grid item xs={12} md={12}>
<Stack spacing={2} direction="row">
{linkButtons()}
</Stack>
</Grid>
<Grid item xs={12} md={12}>
<Paper elevation={5}>
<Table sx={{ width: "100%" }} size="small">
<TableBody>
{cardColumns.map((cardColumn, i) => (
<TableRow key={i}>
<TableCell sx={{ width: "1px", whiteSpace: "nowrap" }}>
<Typography variant="h6" color="primary" noWrap>
{cardColumn.caption}:
</Typography>
</TableCell>
<TableCell sx={{ paddingLeft: 0 }}>
{(hasValue(row[`SLNK_UNIT_${cardColumn.name}`]) && hasValue(row[`NLNK_DOCUMENT_${cardColumn.name}`])) ||
["NPAY_IN", "NFIN_OUT", "NCOEXEC_IN"].includes(cardColumn.name) ? (
<Link
component="button"
variant="body2"
align="left"
underline="always"
onClick={() =>
["NFIN_IN", "NFIN_OUT"].includes(cardColumn.name)
? showPayNotes({ sender: row, direction: row[`NLNK_DOCUMENT_${cardColumn.name}`] })
: cardColumn.name == "NCOST_FACT"
? showCostNotes({ sender: row })
: cardColumn.name == "NSUMM_REALIZ"
? showGoodsTransInvoicesToConsumers({ sender: row })
: cardColumn.name == "NPAY_IN"
? showPaymentAccountsIn({ sender: row })
: cardColumn.name == "NCOEXEC_IN"
? showIncomingInvoices({ sender: row })
: pOnlineShowDocument({
unitCode: row[`SLNK_UNIT_${cardColumn.name}`],
document: row[`NLNK_DOCUMENT_${cardColumn.name}`]
})
}
>
<Typography variant="h6" color="text.secondary">
{formatColumnValue(cardColumn.name, row[cardColumn.name])}
</Typography>
</Link>
) : (
<Typography variant="h6" color="text.secondary">
{["NDAYS_LEFT", "NINCOME_PRC"].includes(cardColumn.name)
? row[cardColumn.name]
: formatColumnValue(cardColumn.name, row[cardColumn.name])}
</Typography>
)}
</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</Paper>
</Grid>
</Grid>
</Box>
);
};