WEB APP: Панель "Финансы проекта" - графики, % готовности, переход к РНОПотр

This commit is contained in:
Mikhail Chechnev 2023-10-21 03:51:10 +03:00
parent 6176387826
commit 13170ab591
3 changed files with 158 additions and 37 deletions

View File

@ -255,6 +255,7 @@ export const rowExpandRender = ({
showCostNotes,
showPaymentAccountsIn,
showIncomingInvoices,
showGoodsTransInvoicesToConsumers,
showStageArts,
showContracts
}) => {
@ -333,6 +334,8 @@ export const rowExpandRender = ({
? 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"

View File

@ -8,11 +8,12 @@
//---------------------
import React, { useState, useCallback, useEffect, useContext } from "react"; //Классы React
import { Box } from "@mui/material"; //Интерфейсные компоненты
import { Box, Grid, Paper, Fab, Icon } from "@mui/material"; //Интерфейсные компоненты
import { object2Base64XML } from "../../core/utils"; //Вспомогательные процедуры и функции
import { TEXTS } from "../../../app.text"; //Тектовые ресурсы и константы
import { P8PDataGrid, P8P_DATA_GRID_SIZE } from "../../components/p8p_data_grid"; //Таблица данных
import { P8PFullScreenDialog } from "../../components/p8p_fullscreen_dialog"; //Полноэкранный диалог
import { P8PChart } from "../../components/p8p_chart"; //График
import { BackEndСtx } from "../../context/backend"; //Контекст взаимодействия с сервером
import { ApplicationСtx } from "../../context/application"; //Контекст приложения
import { MessagingСtx } from "../../context/messaging"; //Контекст сообщений
@ -20,6 +21,17 @@ import { P8P_DATA_GRID_CONFIG_PROPS } from "../../config_wrapper"; //Подкл
import { PANEL_UNITS, headCellRender, dataCellRender, valueFormatter, rowExpandRender } from "./layouts"; //Дополнительная разметка и вёрстка клиентских элементов
import { Stages } from "./stages"; //Список этапов проекта
//---------
//Константы
//---------
//Стили
const STYLES = {
CHART: { maxHeight: "300px", display: "flex", justifyContent: "center" },
CHART_PAPER: { height: "100%" },
CHART_FAB: { position: "absolute", top: 80, left: 16 }
};
//-----------
//Тело модуля
//-----------
@ -40,6 +52,12 @@ const Projects = () => {
stagesFilters: []
});
//Состояния графиков
const [showCharts, setShowCharts] = useState(true);
const [problemsChart, setProblemsChart] = useState({ loaded: false, labels: [], datasets: [] });
const [customersChart, setCustomersChart] = useState({ loaded: false, labels: [], datasets: [] });
const [costNotesChart, setCostNotesChart] = useState({ loaded: false, labels: [], datasets: [] });
//Подключение к контексту взаимодействия с сервером
const { executeStored, SERV_DATA_TYPE_CLOB } = useContext(BackEndСtx);
@ -84,6 +102,37 @@ const Projects = () => {
SERV_DATA_TYPE_CLOB
]);
//Получение данных графиков
const loadChartData = async () => {
const problemsChart = await executeStored({
stored: "PKG_P8PANELS_PROJECTS.CHART_PROBLEMS",
respArg: "COUT"
});
setProblemsChart(pv => ({
...pv,
loaded: true,
...problemsChart.XCHART
}));
const customersChart = await executeStored({
stored: "PKG_P8PANELS_PROJECTS.CHART_CUSTOMERS",
respArg: "COUT"
});
setCustomersChart(pv => ({
...pv,
loaded: true,
...customersChart.XCHART
}));
const costNotesChart = await executeStored({
stored: "PKG_P8PANELS_PROJECTS.CHART_FCCOSTNOTES",
respArg: "COUT"
});
setCostNotesChart(pv => ({
...pv,
loaded: true,
...costNotesChart.XCHART
}));
};
//Отображение журнала платежей по этапу проекта
const showPayNotes = async ({ sender, direction }) => {
const data = await executeStored({
@ -94,6 +143,16 @@ const Projects = () => {
else showMsgErr(TEXTS.NO_DATA_FOUND);
};
//Отображение детализации точки графика затрат
const showCostNotesChartDetail = async ({ unitCode, year, month }) => {
const data = await executeStored({
stored: "PKG_P8PANELS_PROJECTS.CHART_FCCOSTNOTES_SELECT_COST",
args: { NYEAR: year, NMONTH: month }
});
if (data.NIDENT) pOnlineShowUnit({ unitCode, inputParameters: [{ name: "in_SelectList_Ident", value: data.NIDENT }] });
else showMsgErr(TEXTS.NO_DATA_FOUND);
};
//Отображение этапов проекта
const showStages = ({ sender, filters = [] } = {}) =>
setProjectsDataGrid(pv => ({ ...pv, selectedProject: { ...sender }, stagesFilters: [...filters] }));
@ -110,48 +169,95 @@ const Projects = () => {
//При закрытии списка этапов проекта
const handleStagesClose = () => setProjectsDataGrid(pv => ({ ...pv, selectedProject: null, stagesFilters: [] }));
//Отработка нажатия на график
const handleChartClick = ({ item }) => {
if (item.SFILTER && item.SFILTER_VALUE)
setProjectsDataGrid(pv => ({
...pv,
filters: [{ name: item.SFILTER, from: item.SFILTER_VALUE }],
pageNumber: 1,
reload: true
}));
if (item.SUNITCODE && item.NYEAR && item.NMONTH) showCostNotesChartDetail({ unitCode: item.SUNITCODE, year: item.NYEAR, month: item.NMONTH });
};
//При необходимости обновить данные
useEffect(() => {
loadProjects();
}, [projectsDataGrid.reload, loadProjects]);
//При подключении к странице
useEffect(() => {
loadChartData();
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
//Генерация содержимого
return (
<Box p={2}>
{projectsDataGrid.dataLoaded ? (
<P8PDataGrid
{...P8P_DATA_GRID_CONFIG_PROPS}
columnsDef={projectsDataGrid.columnsDef}
rows={projectsDataGrid.rows}
size={P8P_DATA_GRID_SIZE.SMALL}
morePages={projectsDataGrid.morePages}
reloading={projectsDataGrid.reload}
expandable={true}
headCellRender={headCellRender}
dataCellRender={prms => dataCellRender({ ...prms, panelUnit: PANEL_UNITS.PROJECTS, showStages })}
rowExpandRender={prms =>
rowExpandRender({
...prms,
panelUnit: PANEL_UNITS.PROJECTS,
pOnlineShowDocument,
showPayNotes,
showStages
})
}
valueFormatter={prms => valueFormatter({ ...prms, panelUnit: PANEL_UNITS.PROJECTS })}
onOrderChanged={handleOrderChanged}
onFilterChanged={handleFilterChanged}
onPagesCountChanged={handlePagesCountChanged}
/>
) : null}
{projectsDataGrid.selectedProject ? (
<P8PFullScreenDialog title={`Этапы проекта "${projectsDataGrid.selectedProject.SNAME_USL}"`} onClose={handleStagesClose}>
<Stages
project={projectsDataGrid.selectedProject.NRN}
projectName={projectsDataGrid.selectedProject.SNAME_USL}
filters={projectsDataGrid.stagesFilters}
/>
</P8PFullScreenDialog>
<Box p={1}>
<Grid container spacing={1}>
{showCharts ? (
<>
<Grid item xs={4}>
<Paper elevation={3} sx={STYLES.CHART_PAPER}>
{problemsChart.loaded ? <P8PChart {...problemsChart} onClick={handleChartClick} style={STYLES.CHART} /> : null}
</Paper>
</Grid>
<Grid item xs={4}>
<Paper elevation={3} sx={STYLES.CHART_PAPER}>
{customersChart.loaded ? <P8PChart {...customersChart} onClick={handleChartClick} style={STYLES.CHART} /> : null}
</Paper>
</Grid>
<Grid item xs={4}>
<Paper elevation={3} sx={STYLES.CHART_PAPER}>
{costNotesChart.loaded ? <P8PChart {...costNotesChart} onClick={handleChartClick} style={STYLES.CHART} /> : null}
</Paper>
</Grid>
</>
) : null}
<Grid item xs={12}>
{projectsDataGrid.dataLoaded ? (
<P8PDataGrid
{...P8P_DATA_GRID_CONFIG_PROPS}
columnsDef={projectsDataGrid.columnsDef}
rows={projectsDataGrid.rows}
size={P8P_DATA_GRID_SIZE.SMALL}
filtersInitial={projectsDataGrid.filters}
morePages={projectsDataGrid.morePages}
reloading={projectsDataGrid.reload}
expandable={true}
headCellRender={headCellRender}
dataCellRender={prms => dataCellRender({ ...prms, panelUnit: PANEL_UNITS.PROJECTS, showStages })}
rowExpandRender={prms =>
rowExpandRender({
...prms,
panelUnit: PANEL_UNITS.PROJECTS,
pOnlineShowDocument,
showPayNotes,
showStages
})
}
valueFormatter={prms => valueFormatter({ ...prms, panelUnit: PANEL_UNITS.PROJECTS })}
onOrderChanged={handleOrderChanged}
onFilterChanged={handleFilterChanged}
onPagesCountChanged={handlePagesCountChanged}
/>
) : null}
{projectsDataGrid.selectedProject ? (
<P8PFullScreenDialog title={`Этапы проекта "${projectsDataGrid.selectedProject.SNAME_USL}"`} onClose={handleStagesClose}>
<Stages
project={projectsDataGrid.selectedProject.NRN}
projectName={projectsDataGrid.selectedProject.SNAME_USL}
filters={projectsDataGrid.stagesFilters}
/>
</P8PFullScreenDialog>
) : null}
</Grid>
</Grid>
{problemsChart.loaded || customersChart.loaded || costNotesChart.loaded ? (
<Fab size="small" color="secondary" sx={STYLES.CHART_FAB} onClick={() => setShowCharts(!showCharts)}>
<Icon>{showCharts ? "expand_less" : "expand_more"}</Icon>
</Fab>
) : null}
</Box>
);

View File

@ -110,6 +110,17 @@ const Stages = ({ project, projectName, filters }) => {
else showMsgErr(TEXTS.NO_DATA_FOUND);
};
//Отображение расходных накладных на отпуск потребителям по этапу проекта
const showGoodsTransInvoicesToConsumers = async ({ sender }) => {
const data = await executeStored({
stored: "PKG_P8PANELS_PROJECTS.STAGES_SELECT_SUMM_REALIZ",
args: { NRN: sender.NRN }
});
if (data.NIDENT)
pOnlineShowUnit({ unitCode: "GoodsTransInvoicesToConsumers", inputParameters: [{ name: "in_SelectList_Ident", value: data.NIDENT }] });
else showMsgErr(TEXTS.NO_DATA_FOUND);
};
//Отображение статей калькуляции по этапу проекта
const showStageArts = ({ sender, filters = [] } = {}) =>
setStagesDataGrid(pv => ({ ...pv, showStageArts: sender.NRN, selectedStageNumb: sender.SNUMB, stageArtsFilters: [...filters] }));
@ -161,7 +172,8 @@ const Stages = ({ project, projectName, filters }) => {
showStageArts,
showContracts,
showPayNotes,
showCostNotes
showCostNotes,
showGoodsTransInvoicesToConsumers
})
}
valueFormatter={prms => valueFormatter({ ...prms, panelUnit: PANEL_UNITS.PROJECT_STAGES })}