From 2d5d46eb78e409925c2338872c85527e234c1708 Mon Sep 17 00:00:00 2001 From: Mikhail Chechnev Date: Fri, 29 Sep 2023 23:24:25 +0300 Subject: [PATCH] =?UTF-8?q?WEB=20APP:=20=D0=9F=D0=B0=D0=BD=D0=B5=D0=BB?= =?UTF-8?q?=D1=8C=20"=D0=A4=D0=B8=D0=BD=D0=B0=D0=BD=D1=81=D1=8B=20=D0=BF?= =?UTF-8?q?=D1=80=D0=BE=D0=B5=D0=BA=D1=82=D0=B0"=20-=20=D0=B2=D1=81=D1=8F?= =?UTF-8?q?=20=D0=BD=D0=B5=D1=81=D1=82=D0=B0=D0=BD=D0=B4=D0=B0=D1=80=D1=82?= =?UTF-8?q?=D0=BD=D0=B0=D1=8F=20=D1=80=D0=B0=D0=B7=D0=BC=D0=B5=D1=82=D0=BA?= =?UTF-8?q?=D0=B0=20=D0=B2=D1=8B=D0=BD=D0=B5=D1=81=D0=B5=D0=BD=D0=B0=20?= =?UTF-8?q?=D0=B2=20=D0=BE=D1=82=D0=B4=D0=B5=D0=BB=D1=8C=D0=BD=D1=8B=D0=B9?= =?UTF-8?q?=20=D0=BC=D0=BE=D0=B4=D1=83=D0=BB=D1=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/panels/prj_fin/layouts.js | 359 ++++++++++++++++++++++++++ app/panels/prj_fin/prj_fin.js | 36 +-- app/panels/prj_fin/projects.js | 243 +++-------------- app/panels/prj_fin/stage_arts.js | 81 +----- app/panels/prj_fin/stage_contracts.js | 171 ++---------- app/panels/prj_fin/stages.js | 241 ++--------------- 6 files changed, 445 insertions(+), 686 deletions(-) create mode 100644 app/panels/prj_fin/layouts.js diff --git a/app/panels/prj_fin/layouts.js b/app/panels/prj_fin/layouts.js new file mode 100644 index 0000000..07fda51 --- /dev/null +++ b/app/panels/prj_fin/layouts.js @@ -0,0 +1,359 @@ +/* + Парус 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" +}; + +//----------- +//Тело модуля +//----------- + +//Формирование значения для колонки "Состояние" проекта +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 ( + + {icon} + {addText == true ? text : null} + + ); +}; + +//Формирование значения для колонки "Состояние" этапа +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 ( + + {icon} + {addText == true ? text : null} + + ); +}; + +//Подбор функции форматирования колонки "Состояние" по разделу панели +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 ( + + + {icon} + + {addText == true ? text : null} + + ); + } 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 ? (columnDef.name === "NCTRL_FIN" ? 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" ? ( + +
+ {row.NDAYS_LEFT} дн. +
+ {formatCtrlValue(row[columnDef.name], false)} +
+ ) : panelUnit == PANEL_UNITS.PROJECT_STAGE_CONTRACTS && columnDef.name == "NCTRL_FIN" ? ( + + {row[columnDef.name] === 1 ? ( +
+ {formatNumberRFCurrency(row["NPAY_IN_REST"])} +
+ ) : null} + {formatCtrlValue(row[columnDef.name], false)} +
+ ) : panelUnit == PANEL_UNITS.PROJECT_STAGES && ["NCTRL_COEXEC", "NCTRL_ACT"].includes(columnDef.name) ? ( + formatCtrlValue(row[columnDef.name], false) + ) : panelUnit == PANEL_UNITS.PROJECT_STAGE_ARTS && ["NCTRL_COST", "NCTRL_CONTR"].includes(columnDef.name) ? ( + +
+ {formatNumberRFCurrency(row[columnDef.name === "NCTRL_COST" ? "NCOST_DIFF" : "NCONTR_LEFT"])} +
+ {formatCtrlValue(row[columnDef.name], false)} +
+ ) : ( + getCrlOnClick()({ sender: row, filters: [{ name: columnDef.name, from: row[columnDef.name] }] })}> + {formatCtrlValue(row[columnDef.name], false)} + + ) + ) : null + }); + //Формирование представлений + switch (columnDef.name) { + case "SCODE": + case "SNAME_USL": + return { + data: ( + showStages({ sender: row })}> + {row[columnDef.name]} + + ) + }; + case "SDOC_PREF": + case "SDOC_NUMB": + return { + data: ( + + pOnlineShowDocument({ unitCode: row[`SLNK_UNIT_${columnDef.name}`], document: row[`NLNK_DOCUMENT_${columnDef.name}`] }) + } + > + {row[columnDef.name]} + + ) + }; + case "NCOST_FACT": + case "NCONTR": + return { + data: row[columnDef.name] ? ( + (columnDef.name === "NCOST_FACT" ? showCostNotes({ sender: row }) : showContracts({ sender: row }))} + > + {formatNumberRFCurrency(row[columnDef.name])} + + ) : 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, + showStages, + showPayNotes, + showCostNotes, + showPaymentAccountsIn, + 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 ? ( + <> + + + + ) : panelUnit === PANEL_UNITS.PROJECT_STAGES ? ( + <> + + + + + ) : panelUnit === PANEL_UNITS.PROJECT_STAGE_CONTRACTS ? ( + + ) : null; + //Сборка содержимого + return ( + + + + {linkButtons()} + + + + + + {cardColumns.map((cardColumn, i) => ( + + + + {cardColumn.caption}: + + + + {(hasValue(row[`SLNK_UNIT_${cardColumn.name}`]) && hasValue(row[`NLNK_DOCUMENT_${cardColumn.name}`])) || + ["NPAY_IN", "NFIN_OUT"].includes(cardColumn.name) ? ( + + ["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 == "NPAY_IN" + ? showPaymentAccountsIn({ sender: row }) + : pOnlineShowDocument({ + unitCode: row[`SLNK_UNIT_${cardColumn.name}`], + document: row[`NLNK_DOCUMENT_${cardColumn.name}`] + }) + } + > + + {formatColumnValue(cardColumn.name, row[cardColumn.name])} + + + ) : ( + + {["NDAYS_LEFT", "NINCOME_PRC"].includes(cardColumn.name) + ? row[cardColumn.name] + : formatColumnValue(cardColumn.name, row[cardColumn.name])} + + )} + + + ))} + +
+
+
+
+
+ ); +}; diff --git a/app/panels/prj_fin/prj_fin.js b/app/panels/prj_fin/prj_fin.js index f3f03da..d7c2e02 100644 --- a/app/panels/prj_fin/prj_fin.js +++ b/app/panels/prj_fin/prj_fin.js @@ -7,11 +7,8 @@ //Подключение библиотек //--------------------- -import React, { useState } from "react"; //Классы React -import { Box } from "@mui/material"; //Интерфейсные компоненты -import { P8PFullScreenDialog } from "../../components/p8p_fullscreen_dialog"; //Полноэкранный диалог +import React from "react"; //Классы React import { Projects } from "./projects"; //Список проектов -import { Stages } from "./stages"; //Список этапов проекта //----------- //Тело модуля @@ -19,37 +16,8 @@ import { Stages } from "./stages"; //Список этапов проекта //Корневая панель экономики проекта const PrjFin = () => { - //Собственное состояние - const [prjFinPanel, setPrjFinPanel] = useState({ - selectedProject: null, - stagesFilters: [] - }); - - //При открытии списка этапов проекта - const handleStagesOpen = ({ project = {}, filters = [] } = {}) => { - setPrjFinPanel(pv => ({ ...pv, selectedProject: { ...project }, stagesFilters: [...filters] })); - }; - - //При закрытии списка этапов проекта - const handleStagesClose = () => { - setPrjFinPanel(pv => ({ ...pv, selectedProject: null, stagesFilters: [] })); - }; - //Генерация содержимого - return ( - - - {prjFinPanel.selectedProject ? ( - - - - ) : null} - - ); + return ; }; //---------------- diff --git a/app/panels/prj_fin/projects.js b/app/panels/prj_fin/projects.js index 05b103e..663517c 100644 --- a/app/panels/prj_fin/projects.js +++ b/app/panels/prj_fin/projects.js @@ -8,207 +8,24 @@ //--------------------- import React, { useState, useCallback, useEffect, useContext } from "react"; //Классы React -import PropTypes from "prop-types"; //Контроль свойств компонента -import { Grid, Icon, Stack, Link, Button, Table, TableBody, TableRow, TableCell, Typography, Box, Paper, IconButton } from "@mui/material"; //Интерфейсные компоненты -import { hasValue, formatDateRF, formatNumberRFCurrency, object2Base64XML } from "../../core/utils"; //Вспомогательные процедуры и функции +import { Box } 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 { BackEndСtx } from "../../context/backend"; //Контекст взаимодействия с сервером import { ApplicationСtx } from "../../context/application"; //Контекст приложения import { MessagingСtx } from "../../context/messaging"; //Контекст сообщений import { P8P_DATA_GRID_CONFIG_PROPS } from "../../config_wrapper"; //Подключение компонентов к настройкам приложения - -//----------------------- -//Вспомогательные функции -//----------------------- - -//Формирование значения для колонки "Состояние проекта" -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 ( - - {icon} - {addText == true ? text : null} - - ); -}; - -//Формирование значения для контрольных колонок -const formatCtrlValue = (value, addText = false) => { - if (hasValue(value)) { - const [text, icon, color] = value == 0 ? ["В норме", "done", "green"] : ["Требует внимания", "error", "red"]; - return ( - - - {icon} - - {addText == true ? text : null} - - ); - } else return value; -}; - -//Форматирование значений колонок -const valueFormatter = ({ value, columnDef }) => { - switch (columnDef.name) { - case "NSTATE": - return formatPrjStateValue(value, true); - case "DBEGPLAN": - case "DENDPLAN": - return formatDateRF(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; -}; - -//Генерация представления ячейки заголовка -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 данными -const dataCellRender = ({ row, columnDef }, handleStagesOpen) => { - switch (columnDef.name) { - case "SCODE": - case "SNAME_USL": - return { - data: ( - handleStagesOpen({ project: row })}> - {row[columnDef.name]} - - ) - }; - case "NSTATE": - return { - cellProps: { align: "center" }, - data: formatPrjStateValue(row[columnDef.name], false) - }; - case "NCTRL_FIN": - case "NCTRL_CONTR": - case "NCTRL_COEXEC": - case "NCTRL_PERIOD": - case "NCTRL_COST": - case "NCTRL_ACT": - return { - cellProps: { align: "center" }, - data: hasValue(row[columnDef.name]) ? ( - handleStagesOpen({ project: row, filters: [{ name: columnDef.name, from: row[columnDef.name] }] })}> - {formatCtrlValue(row[columnDef.name], false)} - - ) : null - }; - } -}; - -//Генерация представления расширения строки -const rowExpandRender = ({ columnsDef, row }, pOnlineShowDocument, showProjectPayNotes, handleStagesOpen) => { - 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]) - ); - const formatColumnValue = (name, value) => - name.startsWith("N") ? formatNumberRFCurrency(value) : name.startsWith("D") ? formatDateRF(value) : value; - return ( - - - - - - - - - - - - - {cardColumns.map((cardColumn, i) => ( - - - - {cardColumn.caption}: - - - - {hasValue(row[`SLNK_UNIT_${cardColumn.name}`]) && hasValue(row[`NLNK_DOCUMENT_${cardColumn.name}`]) ? ( - { - if (["NFIN_IN", "NFIN_OUT"].includes(cardColumn.name)) - showProjectPayNotes(row.NRN, row[`NLNK_DOCUMENT_${cardColumn.name}`]); - else - pOnlineShowDocument({ - unitCode: row[`SLNK_UNIT_${cardColumn.name}`], - document: row[`NLNK_DOCUMENT_${cardColumn.name}`] - }); - }} - > - - {formatColumnValue(cardColumn.name, row[cardColumn.name])} - - - ) : ( - - {formatColumnValue(cardColumn.name, row[cardColumn.name])} - - )} - - - ))} - -
-
-
-
-
- ); -}; +import { PANEL_UNITS, headCellRender, dataCellRender, valueFormatter, rowExpandRender } from "./layouts"; //Дополнительная разметка и вёрстка клиентских элементов +import { Stages } from "./stages"; //Список этапов проекта //----------- //Тело модуля //----------- //Список проектов -const Projects = ({ onStagesOpen }) => { +const Projects = () => { //Собственное состояние const [projectsDataGrid, setProjectsDataGrid] = useState({ dataLoaded: false, @@ -218,7 +35,9 @@ const Projects = ({ onStagesOpen }) => { rows: [], reload: true, pageNumber: 1, - morePages: true + morePages: true, + selectedProject: null, + stagesFilters: [] }); //Подключение к контексту взаимодействия с сервером @@ -265,15 +84,19 @@ const Projects = ({ onStagesOpen }) => { ]); //Отображение журнала платежей по этапу проекта - const showProjectPayNotes = async (project, direction) => { + const showPayNotes = async ({ sender, direction }) => { const data = await executeStored({ stored: "PKG_P8PANELS_PROJECTS.SELECT_FIN", - args: { NRN: project, NDIRECTION: direction } + args: { NRN: sender.NRN, NDIRECTION: direction } }); if (data.NIDENT) pOnlineShowUnit({ unitCode: "PayNotes", 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] })); + //При изменении состояния фильтра const handleFilterChanged = ({ filters }) => setProjectsDataGrid(pv => ({ ...pv, filters: [...filters], pageNumber: 1, reload: true })); @@ -283,8 +106,8 @@ const Projects = ({ onStagesOpen }) => { //При изменении количества отображаемых страниц const handlePagesCountChanged = () => setProjectsDataGrid(pv => ({ ...pv, pageNumber: pv.pageNumber + 1, reload: true })); - //При открытии списка этапов - const handleStagesOpen = ({ project, filters }) => (onStagesOpen ? onStagesOpen({ project, filters }) : null); + //При закрытии списка этапов проекта + const handleStagesClose = () => setProjectsDataGrid(pv => ({ ...pv, selectedProject: null, stagesFilters: [] })); //При необходимости обновить данные useEffect(() => { @@ -293,7 +116,7 @@ const Projects = ({ onStagesOpen }) => { //Генерация содержимого return ( - <> + {projectsDataGrid.dataLoaded ? ( { reloading={projectsDataGrid.reload} expandable={true} headCellRender={headCellRender} - dataCellRender={prms => dataCellRender(prms, handleStagesOpen)} - rowExpandRender={prms => rowExpandRender(prms, pOnlineShowDocument, showProjectPayNotes, handleStagesOpen)} - valueFormatter={valueFormatter} + 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 ? ( + + + + ) : null} + ); }; -//Контроль свойств - Список проектов -Projects.propTypes = { - onStagesOpen: PropTypes.func -}; - //---------------- //Интерфейс модуля //---------------- diff --git a/app/panels/prj_fin/stage_arts.js b/app/panels/prj_fin/stage_arts.js index e18e045..37103c3 100644 --- a/app/panels/prj_fin/stage_arts.js +++ b/app/panels/prj_fin/stage_arts.js @@ -9,80 +9,15 @@ import React, { useState, useCallback, useEffect, useContext } from "react"; //Классы React import PropTypes from "prop-types"; //Контроль свойств компонента -import { Box, Icon, Stack, Link } from "@mui/material"; //Интерфейсные компоненты -import { hasValue, formatNumberRFCurrency, object2Base64XML } from "../../core/utils"; //Вспомогательные процедуры и функции +import { Box } from "@mui/material"; //Интерфейсные компоненты +import { object2Base64XML } from "../../core/utils"; //Вспомогательные процедуры и функции import { TEXTS } from "../../../app.text"; //Тектовые ресурсы и константы import { P8PDataGrid, P8P_DATA_GRID_SIZE, P8P_DATA_GRID_FILTER_SHAPE } from "../../components/p8p_data_grid"; //Таблица данных import { BackEndСtx } from "../../context/backend"; //Контекст взаимодействия с сервером import { ApplicationСtx } from "../../context/application"; //Контекст приложения import { MessagingСtx } from "../../context/messaging"; //Контекст сообщений import { P8P_DATA_GRID_CONFIG_PROPS } from "../../config_wrapper"; //Подключение компонентов к настройкам приложения - -//----------------------- -//Вспомогательные функции -//----------------------- - -//Формирование значения для контрольных колонок -const formatCtrlValue = (value, addText = false) => { - if (hasValue(value)) { - const [text, icon, color] = value == 0 ? ["В норме", "done", "green"] : ["Требует внимания", "error", "red"]; - return ( - - - {icon} - - {addText == true ? text : null} - - ); - } else return value; -}; - -//Форматирование значений колонок -const valueFormatter = ({ value, columnDef }) => { - switch (columnDef.name) { - case "NPLAN": - case "NCOST_FACT": - case "NCONTR": - return formatNumberRFCurrency(value); - case "NCTRL_COST": - case "NCTRL_CONTR": - return formatCtrlValue(value, true); - } - return value; -}; - -//Генерация представления ячейки c данными -const dataCellRender = ({ row, columnDef }, showStageArtCostNotes, showStageArtContracts) => { - switch (columnDef.name) { - case "NCOST_FACT": - case "NCONTR": - return { - data: row[columnDef.name] ? ( - (columnDef.name === "NCOST_FACT" ? showStageArtCostNotes(row.NRN) : showStageArtContracts(row.NRN))} - > - {formatNumberRFCurrency(row[columnDef.name])} - - ) : null - }; - case "NCTRL_COST": - case "NCTRL_CONTR": - return { - data: ( - -
- {formatNumberRFCurrency(row[columnDef.name === "NCTRL_COST" ? "NCOST_DIFF" : "NCONTR_LEFT"])} -
- {formatCtrlValue(row[columnDef.name], false)} -
- ) - }; - } -}; +import { PANEL_UNITS, dataCellRender, valueFormatter } from "./layouts"; //Дополнительная разметка и вёрстка клиентских элементов //----------- //Тело модуля @@ -131,20 +66,20 @@ const StageArts = ({ stage, filters }) => { }, [stage, stageArtsDataGrid.reload, stageArtsDataGrid.filters, stageArtsDataGrid.dataLoaded, executeStored, SERV_DATA_TYPE_CLOB]); //Отображение журнала затрат по статье калькуляции - const showStageArtCostNotes = async article => { + const showCostNotes = async ({ sender }) => { const data = await executeStored({ stored: "PKG_P8PANELS_PROJECTS.STAGE_ARTS_SELECT_COST_FACT", - args: { NSTAGE: stage, NFPDARTCL: article } + args: { NSTAGE: stage, NFPDARTCL: sender.NRN } }); if (data.NIDENT) pOnlineShowUnit({ unitCode: "CostNotes", inputParameters: [{ name: "in_SelectList_Ident", value: data.NIDENT }] }); else showMsgErr(TEXTS.NO_DATA_FOUND); }; //Отображение договоров по статье калькуляции - const showStageArtContracts = async article => { + const showContracts = async ({ sender }) => { const data = await executeStored({ stored: "PKG_P8PANELS_PROJECTS.STAGE_ARTS_SELECT_CONTR", - args: { NSTAGE: stage, NFPDARTCL: article } + args: { NSTAGE: stage, NFPDARTCL: sender.NRN } }); if (data.NIDENT) pOnlineShowUnit({ unitCode: "Contracts", inputParameters: [{ name: "in_Ident", value: data.NIDENT }] }); else showMsgErr(TEXTS.NO_DATA_FOUND); @@ -170,7 +105,7 @@ const StageArts = ({ stage, filters }) => { size={P8P_DATA_GRID_SIZE.SMALL} morePages={false} reloading={stageArtsDataGrid.reload} - dataCellRender={prms => dataCellRender(prms, showStageArtCostNotes, showStageArtContracts)} + dataCellRender={prms => dataCellRender({ ...prms, panelUnit: PANEL_UNITS.PROJECT_STAGE_ARTS, showCostNotes, showContracts })} valueFormatter={valueFormatter} onFilterChanged={handleFilterChanged} /> diff --git a/app/panels/prj_fin/stage_contracts.js b/app/panels/prj_fin/stage_contracts.js index 0af5207..84ef9c3 100644 --- a/app/panels/prj_fin/stage_contracts.js +++ b/app/panels/prj_fin/stage_contracts.js @@ -9,162 +9,15 @@ import React, { useState, useCallback, useEffect, useContext } from "react"; //Классы React import PropTypes from "prop-types"; //Контроль свойств компонента -import { Box, Stack, Grid, Paper, Table, TableBody, TableRow, TableCell, Typography, Button, Link, Icon } from "@mui/material"; //Интерфейсные компоненты -import { hasValue, formatDateRF, formatNumberRFCurrency, object2Base64XML } from "../../core/utils"; //Вспомогательные процедуры и функции +import { Box } from "@mui/material"; //Интерфейсные компоненты +import { object2Base64XML } from "../../core/utils"; //Вспомогательные процедуры и функции import { TEXTS } from "../../../app.text"; //Тектовые ресурсы и константы import { P8PDataGrid, P8P_DATA_GRID_SIZE, P8P_DATA_GRID_FILTER_SHAPE } from "../../components/p8p_data_grid"; //Таблица данных import { BackEndСtx } from "../../context/backend"; //Контекст взаимодействия с сервером import { ApplicationСtx } from "../../context/application"; //Контекст приложения import { MessagingСtx } from "../../context/messaging"; //Контекст сообщений import { P8P_DATA_GRID_CONFIG_PROPS } from "../../config_wrapper"; //Подключение компонентов к настройкам приложения - -//----------------------- -//Вспомогательные функции -//----------------------- - -//Формирование значения для контрольных колонок -const formatCtrlValue = (value, addText = false) => { - if (hasValue(value)) { - const [text, icon, color] = value == 0 ? ["В норме", "done", "green"] : ["Требует внимания", "error", "red"]; - return ( - - - {icon} - - {addText == true ? text : null} - - ); - } else return value; -}; - -//Форматирование значений колонок -const valueFormatter = ({ value, columnDef }) => { - switch (columnDef.name) { - case "DDOC_DATE": - case "DCSTAGE_BEGIN_DATE": - case "DCSTAGE_END_DATE": - return formatDateRF(value); - case "NCTRL_FIN": - return formatCtrlValue(value, true); - } - return value; -}; - -//Генерация представления ячейки c данными -const dataCellRender = ({ row, columnDef }, pOnlineShowDocument) => { - switch (columnDef.name) { - case "SDOC_PREF": - case "SDOC_NUMB": - return { - data: ( - - pOnlineShowDocument({ - unitCode: row[`SLNK_UNIT_${columnDef.name}`], - document: row[`NLNK_DOCUMENT_${columnDef.name}`] - }) - } - > - {row[columnDef.name]} - - ) - }; - case "NCTRL_FIN": - return { - data: ( - - {row[columnDef.name] === 1 ? ( -
- {formatNumberRFCurrency(row["NPAY_IN_REST"])} -
- ) : null} - {formatCtrlValue(row[columnDef.name], false)} -
- ) - }; - } -}; - -//Генерация представления расширения строки -const rowExpandRender = ({ columnsDef, row }, pOnlineShowDocument, showStageContractPaymentAccountsIn, showStageContractPayNotes) => { - 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]) - ); - const formatColumnValue = (name, value) => - name.startsWith("N") ? formatNumberRFCurrency(value) : name.startsWith("D") ? formatDateRF(value) : value; - return ( - - - - - - - - - - - - {cardColumns.map((cardColumn, i) => ( - - - - {cardColumn.caption}: - - - - {(hasValue(row[`SLNK_UNIT_${cardColumn.name}`]) && hasValue(row[`NLNK_DOCUMENT_${cardColumn.name}`])) || - ["NPAY_IN", "NFIN_OUT"].includes(cardColumn.name) ? ( - - cardColumn.name === "NPAY_IN" - ? showStageContractPaymentAccountsIn(row.NRN) - : cardColumn.name === "NFIN_OUT" - ? showStageContractPayNotes(row.NRN) - : pOnlineShowDocument({ - unitCode: row[`SLNK_UNIT_${cardColumn.name}`], - document: row[`NLNK_DOCUMENT_${cardColumn.name}`] - }) - } - > - - {formatColumnValue(cardColumn.name, row[cardColumn.name])} - - - ) : ( - - {formatColumnValue(cardColumn.name, row[cardColumn.name])} - - )} - - - ))} - -
-
-
-
-
- ); -}; +import { PANEL_UNITS, dataCellRender, valueFormatter, rowExpandRender } from "./layouts"; //Дополнительная разметка и вёрстка клиентских элементов //----------- //Тело модуля @@ -233,20 +86,20 @@ const StageContracts = ({ stage, filters }) => { ]); //Отображение выходящих счетов на оплату от соисполнителя этапа - const showStageContractPaymentAccountsIn = async contract => { + const showPaymentAccountsIn = async ({ sender }) => { const data = await executeStored({ stored: "PKG_P8PANELS_PROJECTS.STAGE_CONTRACTS_SELECT_PAY_IN", - args: { NPROJECTSTAGEPF: contract } + args: { NPROJECTSTAGEPF: sender.NRN } }); if (data.NIDENT) pOnlineShowUnit({ unitCode: "PaymentAccountsIn", inputParameters: [{ name: "in_SelectList_Ident", value: data.NIDENT }] }); else showMsgErr(TEXTS.NO_DATA_FOUND); }; //Отображение фактических платежей соисполнителю этапа - const showStageContractPayNotes = async contract => { + const showPayNotes = async ({ sender }) => { const data = await executeStored({ stored: "PKG_P8PANELS_PROJECTS.STAGE_CONTRACTS_SELECT_FIN_OUT", - args: { NPROJECTSTAGEPF: contract } + args: { NPROJECTSTAGEPF: sender.NRN } }); if (data.NIDENT) pOnlineShowUnit({ unitCode: "PayNotes", inputParameters: [{ name: "in_SelectList_Ident", value: data.NIDENT }] }); else showMsgErr(TEXTS.NO_DATA_FOUND); @@ -279,9 +132,15 @@ const StageContracts = ({ stage, filters }) => { morePages={stageContractsDataGrid.morePages} reloading={stageContractsDataGrid.reload} expandable={true} - dataCellRender={prms => dataCellRender(prms, pOnlineShowDocument)} + dataCellRender={prms => dataCellRender({ ...prms, panelUnit: PANEL_UNITS.PROJECT_STAGE_CONTRACTS, pOnlineShowDocument })} rowExpandRender={prms => - rowExpandRender(prms, pOnlineShowDocument, showStageContractPaymentAccountsIn, showStageContractPayNotes) + rowExpandRender({ + ...prms, + panelUnit: PANEL_UNITS.PROJECT_STAGE_CONTRACTS, + pOnlineShowDocument, + showPaymentAccountsIn, + showPayNotes + }) } valueFormatter={valueFormatter} onOrderChanged={handleOrderChanged} diff --git a/app/panels/prj_fin/stages.js b/app/panels/prj_fin/stages.js index d295599..aef5dad 100644 --- a/app/panels/prj_fin/stages.js +++ b/app/panels/prj_fin/stages.js @@ -9,8 +9,8 @@ import React, { useState, useCallback, useEffect, useContext } from "react"; //Классы React import PropTypes from "prop-types"; //Контроль свойств компонента -import { Box, Icon, Stack, Grid, Paper, Table, TableBody, TableRow, TableCell, Typography, Button, IconButton, Link } from "@mui/material"; //Интерфейсные компоненты -import { hasValue, formatDateRF, formatNumberRFCurrency, object2Base64XML } from "../../core/utils"; //Вспомогательные процедуры и функции +import { Box } from "@mui/material"; //Интерфейсные компоненты +import { object2Base64XML } from "../../core/utils"; //Вспомогательные процедуры и функции import { TEXTS } from "../../../app.text"; //Тектовые ресурсы и константы import { P8PDataGrid, P8P_DATA_GRID_SIZE, P8P_DATA_GRID_FILTER_SHAPE } from "../../components/p8p_data_grid"; //Таблица данных import { P8PFullScreenDialog } from "../../components/p8p_fullscreen_dialog"; //Полноэкранный диалог @@ -20,210 +20,7 @@ import { BackEndСtx } from "../../context/backend"; //Контекст взаи import { ApplicationСtx } from "../../context/application"; //Контекст приложения import { MessagingСtx } from "../../context/messaging"; //Контекст сообщений import { P8P_DATA_GRID_CONFIG_PROPS } from "../../config_wrapper"; //Подключение компонентов к настройкам приложения - -//----------------------- -//Вспомогательные функции -//----------------------- - -//Формирование значения для колонки "Состояние" -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 ( - - {icon} - {addText == true ? text : null} - - ); -}; - -//Формирование значения для контрольных колонок -const formatCtrlValue = (value, addText = false) => { - if (hasValue(value)) { - const [text, icon, color] = value == 0 ? ["В норме", "done", "green"] : ["Требует внимания", "error", "red"]; - return ( - - - {icon} - - {addText == true ? text : null} - - ); - } else return value; -}; - -//Форматирование значений колонок -const valueFormatter = ({ value, columnDef }) => { - switch (columnDef.name) { - case "NSTATE": - return formatStageStatusValue(value, true); - case "DBEGPLAN": - case "DENDPLAN": - return formatDateRF(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; -}; - -//Генерация представления ячейки заголовка -const headCellRender = ({ columnDef }) => { - switch (columnDef.name) { - case "NSTATE": - case "NCTRL_FIN": - case "NCTRL_CONTR": - case "NCTRL_COEXEC": - case "NCTRL_COST": - case "NCTRL_ACT": - return { - stackProps: { justifyContent: "center" }, - cellProps: { align: "center" } - }; - } -}; - -//Генерация представления ячейки c данными -const dataCellRender = ({ row, columnDef }, showStageArts, showStageContracts) => { - switch (columnDef.name) { - case "NSTATE": - return { - cellProps: { align: "center" }, - data: formatStageStatusValue(row[columnDef.name], false) - }; - case "NCTRL_COEXEC": - case "NCTRL_ACT": - return { - cellProps: { align: "center" }, - data: formatCtrlValue(row[columnDef.name], false) - }; - case "NCTRL_FIN": - case "NCTRL_CONTR": - case "NCTRL_COST": - return { - cellProps: { align: "center" }, - data: hasValue(row[columnDef.name]) ? ( - - (columnDef.name === "NCTRL_FIN" ? showStageContracts : showStageArts)({ - stage: row.NRN, - stageNumb: row.SNUMB, - filters: [{ name: columnDef.name, from: row[columnDef.name] }] - }) - } - > - {formatCtrlValue(row[columnDef.name], false)} - - ) : null - }; - case "NCTRL_PERIOD": - return { - cellProps: { align: "right" }, - data: hasValue(row[columnDef.name]) ? ( - -
- {row.NDAYS_LEFT} дн. -
- {formatCtrlValue(row[columnDef.name], false)} -
- ) : null - }; - } -}; - -//Генерация представления расширения строки -const rowExpandRender = ({ columnsDef, row }, pOnlineShowDocument, showStageArts, showStageContracts, showStagePayNotes, showStageCostNotes) => { - 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]) - ); - const formatColumnValue = (name, value) => - name.startsWith("N") ? formatNumberRFCurrency(value) : name.startsWith("D") ? formatDateRF(value) : value; - return ( - - - - - - - - - - - - - - {cardColumns.map((cardColumn, i) => ( - - - - {cardColumn.caption}: - - - - {hasValue(row[`SLNK_UNIT_${cardColumn.name}`]) && hasValue(row[`NLNK_DOCUMENT_${cardColumn.name}`]) ? ( - { - if (["NFIN_IN", "NFIN_OUT"].includes(cardColumn.name)) - showStagePayNotes(row.NRN, row[`NLNK_DOCUMENT_${cardColumn.name}`]); - else if (cardColumn.name == "NCOST_FACT") showStageCostNotes(row.NRN); - else - pOnlineShowDocument({ - unitCode: row[`SLNK_UNIT_${cardColumn.name}`], - document: row[`NLNK_DOCUMENT_${cardColumn.name}`] - }); - }} - > - - {formatColumnValue(cardColumn.name, row[cardColumn.name])} - - - ) : ( - - {["NDAYS_LEFT", "NINCOME_PRC"].includes(cardColumn.name) - ? row[cardColumn.name] - : formatColumnValue(cardColumn.name, row[cardColumn.name])} - - )} - - - ))} - -
-
-
-
-
- ); -}; +import { PANEL_UNITS, headCellRender, dataCellRender, valueFormatter, rowExpandRender } from "./layouts"; //Дополнительная разметка и вёрстка клиентских элементов //----------- //Тело модуля @@ -294,34 +91,32 @@ const Stages = ({ project, projectName, filters }) => { ]); //Отображение журнала платежей по этапу проекта - const showStagePayNotes = async (stage, direction) => { + const showPayNotes = async ({ sender, direction }) => { const data = await executeStored({ stored: "PKG_P8PANELS_PROJECTS.STAGES_SELECT_FIN", - args: { NRN: stage, NDIRECTION: direction } + args: { NRN: sender.NRN, NDIRECTION: direction } }); if (data.NIDENT) pOnlineShowUnit({ unitCode: "PayNotes", inputParameters: [{ name: "in_SelectList_Ident", value: data.NIDENT }] }); else showMsgErr(TEXTS.NO_DATA_FOUND); }; //Отображение журнала затрат по этапу проекта - const showStageCostNotes = async stage => { + const showCostNotes = async ({ sender }) => { const data = await executeStored({ stored: "PKG_P8PANELS_PROJECTS.STAGES_SELECT_COST_FACT", - args: { NRN: stage } + args: { NRN: sender.NRN } }); if (data.NIDENT) pOnlineShowUnit({ unitCode: "CostNotes", inputParameters: [{ name: "in_SelectList_Ident", value: data.NIDENT }] }); else showMsgErr(TEXTS.NO_DATA_FOUND); }; //Отображение статей калькуляции по этапу проекта - const showStageArts = ({ stage, stageNumb, filters = [] } = {}) => { - setStagesDataGrid(pv => ({ ...pv, showStageArts: stage, selectedStageNumb: stageNumb, stageArtsFilters: [...filters] })); - }; + const showStageArts = ({ sender, filters = [] } = {}) => + setStagesDataGrid(pv => ({ ...pv, showStageArts: sender.NRN, selectedStageNumb: sender.SNUMB, stageArtsFilters: [...filters] })); //Отображение договоров с соисполнителями по этапу проекта - const showStageContracts = ({ stage, stageNumb, filters = [] } = {}) => { - setStagesDataGrid(pv => ({ ...pv, showStageContracts: stage, selectedStageNumb: stageNumb, stageContractsFilters: [...filters] })); - }; + const showContracts = ({ sender, filters = [] } = {}) => + setStagesDataGrid(pv => ({ ...pv, showStageContracts: sender.NRN, selectedStageNumb: sender.SNUMB, stageContractsFilters: [...filters] })); //При изменении состояния фильтра const handleFilterChanged = ({ filters }) => setStagesDataGrid(pv => ({ ...pv, filters, pageNumber: 1, reload: true })); @@ -357,11 +152,19 @@ const Stages = ({ project, projectName, filters }) => { reloading={stagesDataGrid.reload} expandable={true} headCellRender={headCellRender} - dataCellRender={prms => dataCellRender(prms, showStageArts, showStageContracts)} + dataCellRender={prms => dataCellRender({ ...prms, panelUnit: PANEL_UNITS.PROJECT_STAGES, showStageArts, showContracts })} rowExpandRender={prms => - rowExpandRender(prms, pOnlineShowDocument, showStageArts, showStageContracts, showStagePayNotes, showStageCostNotes) + rowExpandRender({ + ...prms, + panelUnit: PANEL_UNITS.PROJECT_STAGES, + pOnlineShowDocument, + showStageArts, + showContracts, + showPayNotes, + showCostNotes + }) } - valueFormatter={valueFormatter} + valueFormatter={prms => valueFormatter({ ...prms, panelUnit: PANEL_UNITS.PROJECT_STAGES })} onOrderChanged={handleOrderChanged} onFilterChanged={handleFilterChanged} onPagesCountChanged={handlePagesCountChanged}