From 320521a05427ce9de597d6f7e3e4f24a9ef9f7e3 Mon Sep 17 00:00:00 2001 From: Mikhail Chechnev Date: Thu, 9 May 2024 17:48:24 +0300 Subject: [PATCH] =?UTF-8?q?WEB=20APP:=20=D0=9F=D0=B0=D0=BD=D0=B5=D0=BB?= =?UTF-8?q?=D0=B8=20=D0=9F=D0=A3=D0=94=D0=9F=20"=D0=9F=D1=80=D0=BE=D0=B8?= =?UTF-8?q?=D0=B7=D0=B2=D0=BE=D0=B4=D1=81=D1=82=D0=B2=D0=B5=D0=BD=D0=BD?= =?UTF-8?q?=D1=8B=D0=B9=20=D0=BF=D0=BB=D0=B0=D0=BD=20=D1=86=D0=B5=D1=85?= =?UTF-8?q?=D0=B0"=20=D0=B8=20"=D0=97=D0=B0=D0=B3=D1=80=D1=83=D0=B7=D0=BA?= =?UTF-8?q?=D0=B0=20=D1=86=D0=B5=D1=85=D0=B0"=20-=20=D1=84=D0=B8=D0=BA?= =?UTF-8?q?=D1=81=D0=B8=D1=80=D0=BE=D0=B2=D0=B0=D0=BD=D0=BD=D1=8B=D0=B5=20?= =?UTF-8?q?=D0=BA=D0=BE=D0=BB=D0=BE=D0=BD=D0=BA=D0=B8=20=D0=B8=20=D0=BA?= =?UTF-8?q?=D0=BE=D1=81=D0=BC=D0=B5=D1=82=D0=B8=D0=BA=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../mech_rec_dept_cost_jobs.js | 73 +++---- .../fcroutlst.js | 35 ++- .../incomefromdeps.js | 26 ++- .../mech_rec_dept_cost_prod_plans.js | 203 +++++++----------- p8panels.config | 6 +- 5 files changed, 168 insertions(+), 175 deletions(-) diff --git a/app/panels/mech_rec_dept_cost_jobs/mech_rec_dept_cost_jobs.js b/app/panels/mech_rec_dept_cost_jobs/mech_rec_dept_cost_jobs.js index 3595bee..c33c5e1 100644 --- a/app/panels/mech_rec_dept_cost_jobs/mech_rec_dept_cost_jobs.js +++ b/app/panels/mech_rec_dept_cost_jobs/mech_rec_dept_cost_jobs.js @@ -8,7 +8,7 @@ //--------------------- import React, { useState, useContext, useCallback, useEffect } from "react"; //Классы React -import { Typography, Box } from "@mui/material"; //Интерфейсные элементы +import { Typography, Box, Grid } from "@mui/material"; //Интерфейсные элементы import { object2Base64XML } from "../../core/utils"; //Вспомогательные процедуры и функции import { P8PDataGrid, P8P_DATA_GRID_SIZE } from "../../components/p8p_data_grid"; //Таблица данных import { P8P_DATA_GRID_CONFIG_PROPS } from "../../config_wrapper"; //Подключение компонентов к настройкам приложения @@ -24,7 +24,17 @@ const DATA_GRID_PAGE_SIZE = 5; //Стили const STYLES = { CONTAINER: { textAlign: "center", paddingTop: "20px" }, - TITLE: { paddingBottom: "15px" } + TITLE: { paddingBottom: "15px" }, + DATA_GRID_CONTAINER: { minWidth: "95vw", maxWidth: "95vw", minHeight: "80vh", maxHeight: "80vh" }, + DATA_GRID_CELL: (row, columnDef) => ({ + padding: "8px", + textOverflow: "ellipsis", + overflow: "hidden", + whiteSpace: "pre", + ...(columnDef.name.match(/N.*_VALUE/) && row[columnDef.name] + ? { backgroundColor: row[`${columnDef.name.substring(0, 12)}_TYPE`] === 0 ? "lightgrey" : "lightgreen" } + : {}) + }) }; //------------------------------------ @@ -32,25 +42,11 @@ const STYLES = { //------------------------------------ //Генерация заливки строки исходя от значений -const dataCellRender = ({ row, columnDef }) => { - //Описываем общие свойства - let cellProps = { title: row[columnDef.name] }; - //Описываем общий стиль - let cellStyle = { padding: "8px", maxWidth: "300px", textOverflow: "ellipsis", overflow: "hidden", whiteSpace: "pre" }; - // - if (columnDef.name.match(/N.*_VALUE/) && row[columnDef.name]) { - if (row[`${columnDef.name.substring(0, 12)}_TYPE`] === 0) { - cellStyle = { ...cellStyle, backgroundColor: "lightgrey" }; - } else { - cellStyle = { ...cellStyle, backgroundColor: "lightgreen" }; - } - } - return { - cellProps, - cellStyle, - data: row[columnDef] - }; -}; +const dataCellRender = ({ row, columnDef }) => ({ + cellProps: { title: row[columnDef.name] }, + cellStyle: STYLES.DATA_GRID_CELL(row, columnDef), + data: row[columnDef] +}); //----------- //Тело модуля @@ -68,7 +64,9 @@ const MechRecDeptCostJobs = () => { rows: [], reload: true, pageNumber: 1, - morePages: true + morePages: true, + fixedHeader: false, + fixedColumns: 0 }); //Подключение к контексту взаимодействия с сервером @@ -86,12 +84,12 @@ const MechRecDeptCostJobs = () => { NPAGE_SIZE: DATA_GRID_PAGE_SIZE, NINCLUDE_DEF: costJobs.dataLoaded ? 0 : 1 }, - respArg: "COUT", - isArray: name => name === "XCOLUMNS_DEF" || name === "XROWS", - attributeValueProcessor: (name, val) => (name === "caption" ? undefined : val) + respArg: "COUT" }); setCostJobs(pv => ({ ...pv, + fixedHeader: data.XFCJOBS.XDATA.XDATA_GRID.fixedHeader, + fixedColumns: data.XFCJOBS.XDATA.XDATA_GRID.fixedColumns, subdiv: data.XINFO.SSUBDIV, columnsDef: data.XFCJOBS.XDATA.XCOLUMNS_DEF ? [...data.XFCJOBS.XDATA.XCOLUMNS_DEF] : pv.columnsDef, rows: pv.pageNumber == 1 ? [...(data.XFCJOBS.XDATA.XROWS || [])] : [...pv.rows, ...(data.XFCJOBS.XDATA.XROWS || [])], @@ -119,15 +117,18 @@ const MechRecDeptCostJobs = () => { //Генерация содержимого return (
- - {costJobs.dataLoaded ? ( - <> - - {`Загрузка станков "${costJobs.subdiv}"`} - - + + {costJobs.dataLoaded ? `Загрузка станков "${costJobs.subdiv}"` : null} + + + + + {costJobs.dataLoaded ? ( { onPagesCountChanged={handlePagesCountChanged} dataCellRender={prms => dataCellRender({ ...prms })} /> - - - ) : null} - + ) : null} + + +
); }; diff --git a/app/panels/mech_rec_dept_cost_prod_plans/fcroutlst.js b/app/panels/mech_rec_dept_cost_prod_plans/fcroutlst.js index ca13ec0..d97a60a 100644 --- a/app/panels/mech_rec_dept_cost_prod_plans/fcroutlst.js +++ b/app/panels/mech_rec_dept_cost_prod_plans/fcroutlst.js @@ -9,7 +9,7 @@ import React, { useState, useCallback, useEffect, useContext } from "react"; //Классы React import PropTypes from "prop-types"; //Контроль свойств компонента -import { Typography, Box, Paper, IconButton, Icon, Dialog, DialogContent, DialogActions, Button, TextField } from "@mui/material"; //Интерфейсные элементы +import { Typography, Box, Paper, Dialog, DialogContent, DialogActions, Button, TextField } from "@mui/material"; //Интерфейсные элементы import { P8PDataGrid, P8P_DATA_GRID_SIZE } from "../../components/p8p_data_grid"; //Таблица данных import { P8P_DATA_GRID_CONFIG_PROPS } from "../../config_wrapper"; //Подключение компонентов к настройкам приложения import { BackEndСtx } from "../../context/backend"; //Контекст взаимодействия с сервером @@ -44,7 +44,7 @@ export const rowExpandRender = ({ row }) => { }; //Форматирование значений колонок -const dataCellRender = ({ row, columnDef, handlePriorEditOpen, handleOrderEditOpen }) => { +const dataCellRender = ({ row, columnDef /*, handlePriorEditOpen, handleOrderEditOpen */ }) => { //!!! Пока отключено - не удалять // switch (columnDef.name) { // case "NPRIOR_PARTY": @@ -287,12 +287,7 @@ const CostRouteListsDataGrid = ({ task }) => { onClick={() => { pOnlineShowDictionary({ unitCode: "FaceAccounts", - inputParameters: [ - { - name: "in_NUMB", - value: costRouteLists.editOrderValue - } - ], + inputParameters: [{ name: "in_NUMB", value: costRouteLists.editOrderValue }], callBack: res => (res.success === true ? setEditOrderValue(res.outParameters.out_NUMB) : null) }); }} @@ -321,8 +316,30 @@ CostRouteListsDataGrid.propTypes = { task: PropTypes.number.isRequired }; +//Диалог с таблицей сдачи продукции +const CostRouteListsDataGridDialog = ({ task, onClose }) => { + return ( + + + + + {onClose ? ( + + + + ) : null} + + ); +}; + +//Контроль свойств - Диалог с таблицей маршрутных листов +CostRouteListsDataGridDialog.propTypes = { + task: PropTypes.number.isRequired, + onClose: PropTypes.func +}; + //---------------- //Интерфейс модуля //---------------- -export { CostRouteListsDataGrid }; +export { CostRouteListsDataGridDialog }; diff --git a/app/panels/mech_rec_dept_cost_prod_plans/incomefromdeps.js b/app/panels/mech_rec_dept_cost_prod_plans/incomefromdeps.js index e59aef0..67f9abf 100644 --- a/app/panels/mech_rec_dept_cost_prod_plans/incomefromdeps.js +++ b/app/panels/mech_rec_dept_cost_prod_plans/incomefromdeps.js @@ -9,7 +9,7 @@ import React, { useState, useCallback, useEffect, useContext } from "react"; //Классы React import PropTypes from "prop-types"; //Контроль свойств компонента -import { Typography, Box } from "@mui/material"; //Интерфейсные элементы +import { Typography, Box, Dialog, DialogContent, DialogActions, Button } from "@mui/material"; //Интерфейсные элементы import { P8PDataGrid, P8P_DATA_GRID_SIZE } from "../../components/p8p_data_grid"; //Таблица данных import { P8P_DATA_GRID_CONFIG_PROPS } from "../../config_wrapper"; //Подключение компонентов к настройкам приложения import { BackEndСtx } from "../../context/backend"; //Контекст взаимодействия с сервером @@ -113,8 +113,30 @@ IncomFromDepsDataGrid.propTypes = { task: PropTypes.number.isRequired }; +//Диалог с таблицей сдачи продукции +const IncomFromDepsDataGridDialog = ({ task, onClose }) => { + return ( + + + + + {onClose ? ( + + + + ) : null} + + ); +}; + +//Контроль свойств - Диалог с таблицей сдачи продукции +IncomFromDepsDataGridDialog.propTypes = { + task: PropTypes.number.isRequired, + onClose: PropTypes.func +}; + //---------------- //Интерфейс модуля //---------------- -export { IncomFromDepsDataGrid }; +export { IncomFromDepsDataGridDialog }; diff --git a/app/panels/mech_rec_dept_cost_prod_plans/mech_rec_dept_cost_prod_plans.js b/app/panels/mech_rec_dept_cost_prod_plans/mech_rec_dept_cost_prod_plans.js index 2dbd8f7..0c499e6 100644 --- a/app/panels/mech_rec_dept_cost_prod_plans/mech_rec_dept_cost_prod_plans.js +++ b/app/panels/mech_rec_dept_cost_prod_plans/mech_rec_dept_cost_prod_plans.js @@ -9,29 +9,15 @@ import React, { useContext, useState, useCallback, useEffect } from "react"; //Классы React import PropTypes from "prop-types"; //Контроль свойств компонента -import { - Drawer, - Fab, - Box, - List, - ListItemButton, - ListItemText, - Typography, - TextField, - Link, - Dialog, - DialogContent, - DialogActions, - Button -} from "@mui/material"; //Интерфейсные элементы +import { Drawer, Fab, Box, List, ListItemButton, ListItemText, Typography, TextField, Link, Grid } from "@mui/material"; //Интерфейсные элементы import { BackEndСtx } from "../../context/backend"; //Контекст взаимодействия с сервером import { useFilteredPlans } from "./hooks"; //Вспомогательные хуки import { object2Base64XML } from "../../core/utils"; //Вспомогательные функции import { P8PDataGrid, P8P_DATA_GRID_SIZE } from "../../components/p8p_data_grid"; //Таблица данных import { P8P_DATA_GRID_CONFIG_PROPS } from "../../config_wrapper"; //Подключение компонентов к настройкам приложения import { MessagingСtx } from "../../context/messaging"; //Контекст сообщений -import { IncomFromDepsDataGrid } from "./incomefromdeps"; //Таблица сдачи продукции -import { CostRouteListsDataGrid } from "./fcroutlst"; //Таблица маршрутных листов +import { IncomFromDepsDataGridDialog } from "./incomefromdeps"; //Диалог сдачи продукции +import { CostRouteListsDataGridDialog } from "./fcroutlst"; //Диалог маршрутных листов //--------- //Константы @@ -41,7 +27,7 @@ import { CostRouteListsDataGrid } from "./fcroutlst"; //Таблица марш const STYLES = { PLANS_FINDER: { marginTop: "10px", marginLeft: "10px", width: "93%" }, PLANS_LIST_ITEM_PRIMARY: { wordWrap: "break-word" }, - PLANS_BUTTON: { position: "absolute" }, + PLANS_BUTTON: { position: "absolute", marginTop: "10px", marginLeft: "10px" }, PLANS_DRAWER: { width: "350px", display: "inline-block", @@ -49,6 +35,12 @@ const STYLES = { [`& .MuiDrawer-paper`]: { width: "350px", display: "inline-block", boxSizing: "border-box" } }, CONTAINER: { paddingTop: "40px", margin: "5px 0px", textAlign: "center" }, + DATA_GRID_CONTAINER: { minWidth: "95vw", maxWidth: "95vw", minHeight: "80vh", maxHeight: "80vh" }, + DATA_GRID_GROUP_CELL: { padding: "2px" }, + DATA_GRID_CELL: { padding: "8px", maxWidth: "300px", textOverflow: "ellipsis", overflow: "hidden", whiteSpace: "pre" }, + DATA_GRID_CELL_STATUS: (currentStyle, row) => ({ backgroundColor: getRowBackgroudColor(row), ...currentStyle }), + DATA_GRID_CELL_PLAN_FACT: currentStyle => ({ ...currentStyle, backgroundColor: "lightgrey" }), + DATA_GRID_CELL_MATRES_CODE: (currentStyle, row) => ({ backgroundColor: getRowBackgroudColor(row), ...currentStyle }), PLAN_FACT_VALUE: { textAlign: "center", display: "flex", justifyContent: "center" }, PLAN_FACT_DELIMITER: { padding: "0px 5px" }, FACT_VALUE: { color: "blue" } @@ -60,60 +52,35 @@ const STYLES = { //Генерация представления ячейки заголовка группы export const groupCellRender = ({ group }) => ({ - cellStyle: { padding: "2px" }, + cellStyle: STYLES.DATA_GRID_GROUP_CELL, data: group.caption }); +//Вычисление цвета заливки для строки +const getRowBackgroudColor = row => { + //Факт === План + if (row["NMAIN_QUANT"] === row["NREL_FACT"]) return "lightgreen"; + //План <= (Факт + Запущено) + if (row["NMAIN_QUANT"] <= row["NREL_FACT"] + row["NFCROUTLST_QUANT"]) return "lightblue"; + //Сумма "Количество план" = 0 или < "План" + if (row["NSUM_PLAN"] === 0 || (row["NSUM_PLAN"] !== 0 && row["NSUM_PLAN"] < row["NMAIN_QUANT"])) { + //"Факт" >= "План" + if (row["NREL_FACT"] >= row["NMAIN_QUANT"]) return "#F0E68C"; + } else { + //Сумма "Количество факт" >= сумма "Количество план" + if (row["NSUM_FACT"] >= row["NSUM_PLAN"]) return "#F0E68C"; + } + return "lightcoral"; +}; + //Генерация заливки строки исходя от значений const dataCellRender = ({ row, columnDef, handleProdOrderClick, handleMatresCodeClick }) => { //Описываем общие свойства let cellProps = { title: row[columnDef.name] }; //Описываем общий стиль - let cellStyle = { padding: "8px", maxWidth: "300px", textOverflow: "ellipsis", overflow: "hidden", whiteSpace: "pre" }; + let cellStyle = STYLES.DATA_GRID_CELL; //Для колонки "Статус" - if (columnDef.name === "SSTATUS") { - //Факт === План - if (row["NMAIN_QUANT"] === row["NREL_FACT"]) { - return { - cellProps, - cellStyle: { backgroundColor: "lightgreen", ...cellStyle }, - data: row[columnDef] - }; - } - //План <= (Факт + Запущено) - if (row["NMAIN_QUANT"] <= row["NREL_FACT"] + row["NFCROUTLST_QUANT"]) { - return { - cellProps, - cellStyle: { backgroundColor: "lightblue", ...cellStyle }, - data: row[columnDef] - }; - } - //Сумма "Количество план" = 0 или < "План" - if (row["NSUM_PLAN"] === 0 || (row["NSUM_PLAN"] !== 0 && row["NSUM_PLAN"] < row["NMAIN_QUANT"])) { - //"Факт" >= "План" - if (row["NREL_FACT"] >= row["NMAIN_QUANT"]) { - return { - cellProps, - cellStyle: { backgroundColor: "#F0E68C", ...cellStyle }, - data: row[columnDef] - }; - } - } else { - //Сумма "Количество факт" >= сумма "Количество план" - if (row["NSUM_FACT"] >= row["NSUM_PLAN"]) { - return { - cellProps, - cellStyle: { backgroundColor: "#F0E68C", ...cellStyle }, - data: row[columnDef] - }; - } - } - return { - cellProps, - cellStyle: { backgroundColor: "lightcoral", ...cellStyle }, - data: row[columnDef] - }; - } + if (columnDef.name === "SSTATUS") return { cellProps, cellStyle: STYLES.DATA_GRID_CELL_STATUS(cellStyle, row), data: row[columnDef] }; //Для колонки даты if (columnDef.name.indexOf("PLAN_FACT") >= 0) { //Получаем текущий день @@ -121,10 +88,8 @@ const dataCellRender = ({ row, columnDef, handleProdOrderClick, handleMatresCode //Формируем regex для проверки let regex = new RegExp(`N_${curDay}.*`, "g"); //Если это значение текущего дня - if (columnDef.name.match(regex)) { - cellStyle = { ...cellStyle, backgroundColor: "lightgrey" }; - } - //Если в колонке есть значени + if (columnDef.name.match(regex)) cellStyle = STYLES.DATA_GRID_CELL_PLAN_FACT(cellStyle); + //Если в колонке есть значение if (row[columnDef.name]) { //Разбиваем его на план/факт let values = row[columnDef.name].split("/"); @@ -140,14 +105,7 @@ const dataCellRender = ({ row, columnDef, handleProdOrderClick, handleMatresCode ) }; - } else { - //Если значения нет - return { - cellProps, - cellStyle, - data: row[columnDef] - }; - } + } else return { cellProps, cellStyle, data: row[columnDef] }; } //Для колонки "Заказ" if (columnDef.name === "SPROD_ORDER") { @@ -162,22 +120,18 @@ const dataCellRender = ({ row, columnDef, handleProdOrderClick, handleMatresCode }; } //Для колонки "Обозначение" - if (columnDef.name === "SMATRES_CODE") { + if (columnDef.name === "SMATRES_CODE") return { cellProps, - cellStyle, + cellStyle: STYLES.DATA_GRID_CELL_MATRES_CODE(cellStyle, row), data: ( handleMatresCodeClick(row["NRN"])}> {row[columnDef.name]} ) }; - } - return { - cellProps, - cellStyle, - data: row[columnDef] - }; + //Для всех остальных + return { cellProps, cellStyle, data: row[columnDef] }; }; //Список каталогов планов @@ -237,7 +191,9 @@ const MechRecDeptCostProdPlans = () => { rows: [], reload: true, pageNumber: 1, - morePages: true + morePages: true, + fixedHeader: false, + fixedColumns: 0 }); //Состояние для фильтра каталогов @@ -287,6 +243,8 @@ const MechRecDeptCostProdPlans = () => { }); setState(pv => ({ ...pv, + fixedHeader: data.XDATA_GRID.fixedHeader, + fixedColumns: data.XDATA_GRID.fixedColumns, columnsDef: data.XCOLUMNS_DEF ? [...data.XCOLUMNS_DEF] : pv.columnsDef, rows: pv.pageNumber == 1 ? [...(data.XROWS || [])] : [...pv.rows, ...(data.XROWS || [])], dataLoaded: true, @@ -373,7 +331,7 @@ const MechRecDeptCostProdPlans = () => { //Генерация содержимого return ( - + <> setState(pv => ({ ...pv, showPlanList: !pv.showPlanList }))}> Планы @@ -393,48 +351,43 @@ const MechRecDeptCostProdPlans = () => {
{state.dataLoaded ? ( - <> - {`Производственный план цеха "${state.selectedPlan.SSUBDIV}" на ${state.selectedPlan.SPERIOD}`} - dataCellRender({ ...prms, handleProdOrderClick, handleMatresCodeClick })} - groupCellRender={groupCellRender} - /> - - ) : !state.selectedPlan.NRN ? ( - + + {`Производственный план цеха "${state.selectedPlan.SSUBDIV}" на ${state.selectedPlan.SPERIOD}`} + + ) : null} + + + + {state.dataLoaded ? ( + dataCellRender({ ...prms, handleProdOrderClick, handleMatresCodeClick })} + groupCellRender={groupCellRender} + /> + ) : !state.selectedPlan.NRN ? ( + + ) : null} + + + + {state.showIncomeFromDeps ? ( + handleProdOrderClick(null)} /> + ) : null} + {state.showFcroutelst ? ( + handleMatresCodeClick(null)} /> ) : null}
- {state.showIncomeFromDeps ? ( - handleProdOrderClick(null)} fullWidth maxWidth="xl"> - - - - - - - - ) : null} - {state.showFcroutelst ? ( - handleMatresCodeClick(null)} fullWidth maxWidth="xl"> - - - - - - - - ) : null} -
+ ); }; diff --git a/p8panels.config b/p8panels.config index 2b88bf9..a2a6abe 100644 --- a/p8panels.config +++ b/p8panels.config @@ -105,7 +105,7 @@ desc="Управление составом сменных заданий цеха/участка" url="mech_rec_cost_jobs_manage" path="mech_rec_cost_jobs_manage" - icon="free_cancellation" + icon="psychology" showInPanelsList="true" preview="./img/mech_rec_cost_prod_plans.jpg"/>