From 67905adaf2f638a70962f579edaafe3fe5e09e89 Mon Sep 17 00:00:00 2001 From: davay-popozhe Date: Tue, 11 Jun 2024 15:44:53 +0300 Subject: [PATCH 1/2] =?UTF-8?q?=D0=A6=D0=98=D0=A2=D0=9A-839=20=D1=871?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/panels/eqs_prfrm/eqs_prfrm.js | 25 ++++--------- app/panels/eqs_prfrm/layouts.js | 47 ++++++++++++------------ db/PKG_P8PANELS_EQUIPSRV.pck | 60 +++++++++++++++---------------- 3 files changed, 62 insertions(+), 70 deletions(-) diff --git a/app/panels/eqs_prfrm/eqs_prfrm.js b/app/panels/eqs_prfrm/eqs_prfrm.js index debbcaf..6d540c6 100644 --- a/app/panels/eqs_prfrm/eqs_prfrm.js +++ b/app/panels/eqs_prfrm/eqs_prfrm.js @@ -51,9 +51,6 @@ const EqsPrfrm = () => { reload: false }); - // Состояние информации о трудоёмкости - const [info, setInfo] = useState({ cntP: 0, sumP: 0, cntF: 0, sumF: 0 }); - // Состояние фильтра const [filter, setFilter] = useState({ belong: "", @@ -65,17 +62,22 @@ const EqsPrfrm = () => { toMonth: 1, toYear: 1990 }); + // Состояние открытия фильтра const [filterOpen, setFilterOpen] = useState(true); + // Состояние данных по умолчанию для фильтра const [defaultLoaded, setDefaultLoaded] = useState(false); + // Состояние хранения копии фильтра const [filterCopy, setFilterCopy] = useState({ ...filter }); + // Состояние ограничения редактирования фильтра const [filterLock, setFilterLock] = useState(false); // Состояние ячейки заголовка даты (по раскрытию/скрытию) const [activeRef, setActiveRef] = useState(); + // Состояние актуальности ссылки на ячейку const [refIsDeprecated, setRidFlag] = useState(true); @@ -146,7 +148,6 @@ const EqsPrfrm = () => { } }); } - setInfo({ cntP: cP, sumP: sP, cntF: cF, sumF: sF }); setDataGrid(pv => ({ ...pv, columnsDef: data.XCOLUMNS_DEF ? [...data.XCOLUMNS_DEF] : pv.columnsDef, @@ -164,7 +165,6 @@ const EqsPrfrm = () => { stored: "PKG_P8PANELS_EQUIPSRV.GET_DEFAULT_FP", respArg: "COUT" }); - setFilter(pv => ({ ...pv, belong: data.JURPERS, fromMonth: 1, fromYear: data.YEAR, toMonth: 12, toYear: data.YEAR })); setDefaultLoaded(true); }, [executeStored]); @@ -173,14 +173,9 @@ const EqsPrfrm = () => { const showEquipSrv = async ({ date, workType, info }) => { const [techName, servKind] = info.split("_"); let type; - if (workType == "План") type = 0; else type = 1; - let [year, month, day] = date.substring(1).split("_"); - - //if (day == undefined) day = null; - const data = await executeStored({ stored: "PKG_P8PANELS_EQUIPSRV.SELECT_EQUIPSRV", args: { @@ -544,7 +539,6 @@ const EqsPrfrm = () => { - + - - - - + Фильтр отбора: {filter.belong ? `Принадлежность: ${filter.belong}` : ""}{" "} {filter.prodObj ? `Производственный объект: ${filter.prodObj}` : ""} {filter.techServ ? `Техническая служба: ${filter.techServ}` : ""}{" "} diff --git a/app/panels/eqs_prfrm/filter_dialog.js b/app/panels/eqs_prfrm/filter_dialog.js new file mode 100644 index 0000000..8786ffa --- /dev/null +++ b/app/panels/eqs_prfrm/filter_dialog.js @@ -0,0 +1,257 @@ +/* + Парус 8 - Панели мониторинга - ТОиР - Выполнение работ + Панель мониторинга: Диалоговое окно фильтра отбора +*/ + +//--------------------- +//Подключение библиотек +//--------------------- + +import React, { useState, useContext, useEffect, useCallback } from "react"; //Классы React +import PropTypes from "prop-types"; //Контроль свойств компонента +import { Dialog, DialogTitle, IconButton, Icon, DialogContent, DialogActions, Button, Paper, Box, Grid } from "@mui/material"; //Интерфейсные компоненты +import { FilterInputField } from "./filter_input_field"; //Компонент поля ввода +import { ApplicationСtx } from "../../context/application"; //Контекст приложения +import { STYLES } from "./layouts"; //Стили + +//--------- +//Константы +//--------- + +//Массив месяцев +export const MONTH_ARRAY = ["Январь", "Февраль", "Март", "Апрель", "Май", "Июнь", "Июль", "Август", "Сентябрь", "Октябрь", "Ноябрь", "Декабрь"]; + +//--------------- +//Тело компонента +//--------------- + +//Диалоговое окно фильтра отбора +const FilterDialog = props => { + //Свойства + const { filter, filterCopy, filterOpen, setFilter, setFilterOpen, setDataGrid } = props; + + //Состояние ограничения редактирования фильтра + const [filterLock, setFilterLock] = useState(false); + + //Состояние массива лет + const [years, setYears] = useState({ array: [1990], filled: false }); + + //Подключение к контексту приложения + const { pOnlineShowDictionary } = useContext(ApplicationСtx); + + //Закрыть фильтр + const closeFilter = e => { + if (filterLock && e != undefined) setFilter(filterCopy); + setFilterOpen(false); + }; + + //Очистить фильтр + const clearFilter = () => { + setFilter({ + belong: "", + prodObj: "", + techServ: "", + respDep: "", + fromMonth: "", + fromYear: "", + toMonth: "", + toYear: "" + }); + }; + + //Заполнение состояния массива лет + const getYearArray = useCallback(async () => { + const today = new Date(); + for (let i = years.array[0] + 1; i <= today.getFullYear(); i++) { + setYears(pv => ({ ...pv, array: [...pv.array, i] })); + } + setYears(pv => ({ ...pv, filled: true })); + //eslint-disable-next-line react-hooks/exhaustive-deps + }, []); + + //Только при первичном рендере + useEffect(() => { + if (filterOpen && !years.filled) getYearArray(); + }, [filterOpen, getYearArray, years.filled]); + + //Генерация содержимого + return ( +
+ + Фильтр отбора + theme.palette.grey[500] + }} + > + close + + + + + { + pOnlineShowDictionary({ + unitCode: "JuridicalPersons", + callBack: res => + res.success === true ? setFilter(pv => ({ ...pv, belong: res.outParameters.out_CODE })) : null + }); + }} + required={true} + /> + + + { + pOnlineShowDictionary({ + unitCode: "EquipConfiguration", + callBack: res => + res.success === true ? setFilter(pv => ({ ...pv, prodObj: res.outParameters.out_CODE })) : null + }); + }} + required={true} + /> + + + { + pOnlineShowDictionary({ + unitCode: "INS_DEPARTMENT", + callBack: res => + res.success === true ? setFilter(pv => ({ ...pv, techServ: res.outParameters.out_CODE })) : null + }); + }} + /> + + + { + pOnlineShowDictionary({ + unitCode: "INS_DEPARTMENT", + callBack: res => + res.success === true ? setFilter(pv => ({ ...pv, respDep: res.outParameters.out_CODE })) : null + }); + }} + /> + + + + + Начало периода: + + + setFilter(pv => ({ ...pv, fromMonth: e.target.value }))} + required={true} + isDateField={true} + /> + + + setFilter(pv => ({ ...pv, fromYear: e.target.value }))} + required={true} + isDateField={true} + yearArray={years.array} + /> + + + + + + + Конец периода: + + + setFilter(pv => ({ ...pv, toMonth: e.target.value }))} + required={true} + isDateField={true} + /> + + + setFilter(pv => ({ ...pv, toYear: e.target.value }))} + required={true} + isDateField={true} + yearArray={years.array} + /> + + + + + + + + + + + +
+ ); +}; + +//Контроль свойств компонента - Диалоговое окно фильтра отбора +FilterDialog.propTypes = { + filter: PropTypes.object.isRequired, + filterCopy: PropTypes.object.isRequired, + filterOpen: PropTypes.bool.isRequired, + setFilter: PropTypes.func.isRequired, + setFilterOpen: PropTypes.func.isRequired, + setDataGrid: PropTypes.func.isRequired +}; + +//-------------------- +//Интерфейс компонента +//-------------------- + +export { FilterDialog }; diff --git a/app/panels/eqs_prfrm/filter_input_field.js b/app/panels/eqs_prfrm/filter_input_field.js new file mode 100644 index 0000000..65f6a04 --- /dev/null +++ b/app/panels/eqs_prfrm/filter_input_field.js @@ -0,0 +1,121 @@ +/* + Парус 8 - Панели мониторинга - ТОиР - Выполнение работ + Панель мониторинга: Компонент поля ввода +*/ + +//--------------------- +//Подключение библиотек +//--------------------- + +import React, { useEffect, useState, useCallback } from "react"; //Классы React +import PropTypes from "prop-types"; //Контроль свойств компонента +import { FormControl, InputLabel, Input, InputAdornment, IconButton, Icon, FormHelperText, Select, MenuItem } from "@mui/material"; //Интерфейсные компоненты +import { MONTH_ARRAY } from "./filter_dialog"; //Название месяцев + +//--------------- +//Тело компонента +//--------------- + +//Поле ввода +const FilterInputField = props => { + //Свойства + const { elementCode, elementValue, labelText, changeFunc, required, isDateField, yearArray } = props; + + //Состояние идентификатора элемента + const [elementId, setElementId] = useState(""); + + //Формирование идентификатора элемента + const generateId = useCallback(async () => { + setElementId(!isDateField ? `${elementCode}-input` : `${elementCode}-select`); + }, [elementCode, isDateField]); + + //При рендере поля ввода + useEffect(() => { + generateId(); + }, [generateId]); + + //Генерация поля с выбором из словаря Парус + const renderInput = () => { + return ( + + + list + + + } + aria-describedby={`${elementId}-helper-text`} + label={labelText} + /> + ); + }; + + //Генерация поля с выпадающим списком + const renderSelect = () => { + return ( + + ); + }; + + //Генерация содержимого + return ( + + {labelText} + {isDateField ? renderSelect() : renderInput()} + {required && !elementValue ? ( + + *Обязательное поле + + ) : null} + + ); +}; + +//Контроль свойств - Поле ввода +FilterInputField.propTypes = { + elementCode: PropTypes.string.isRequired, + elementValue: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), + labelText: PropTypes.string.isRequired, + changeFunc: PropTypes.func.isRequired, + required: PropTypes.bool, + isDateField: PropTypes.bool, + yearArray: PropTypes.arrayOf(PropTypes.number) +}; + +//Значения по умолчанию - Поле ввода +FilterInputField.defaultProps = { + required: false, + isDateField: false +}; + +//-------------------- +//Интерфейс компонента +//-------------------- + +export { FilterInputField }; diff --git a/app/panels/eqs_prfrm/layouts.js b/app/panels/eqs_prfrm/layouts.js index 7f74271..af12aed 100644 --- a/app/panels/eqs_prfrm/layouts.js +++ b/app/panels/eqs_prfrm/layouts.js @@ -8,7 +8,7 @@ //--------------------- import React, { createRef } from "react"; //Классы React -import { Grid, Stack } from "@mui/material"; +import { Grid, Stack } from "@mui/material"; //Интерфейсные компоненты //--------- //Константы @@ -19,6 +19,7 @@ export const DIGITS_REG_EXP = /\d+,?\d*/g; export const MONTH_NAME_REG_EXP = /_\d{4}_\d{1,2}/; export const DAY_NAME_REG_EXP = /_\d{4}_\d{1,2}_\d{1,2}/; +//Стили export const STYLES = { HIDE_CELL_STYLE: { display: "none" }, HCR_MAIN_STYLE: { border: "1px solid rgba(0, 0, 0)", textAlign: "center" }, @@ -27,29 +28,30 @@ export const STYLES = { DCR_OBJECT_INFO_STYLE: { textAlign: "right", fontWeight: "bold" }, DCR_PLAN_CELL_STYLE: { cursor: "pointer", backgroundColor: "lightblue", border: "1px solid rgba(0, 0, 0) !important" }, DCR_FACT_RELATED_CELL_STYLE: { cursor: "pointer", backgroundColor: "green", border: "1px solid rgba(0, 0, 0) !important" }, - DCR_FACT_NOT_REALATED_CELL_STYLE: { cursor: "pointer", backgroundColor: "crimson", border: "1px solid rgba(0, 0, 0) !important" } + DCR_FACT_NOT_RELATED_CELL_STYLE: { cursor: "pointer", backgroundColor: "crimson", border: "1px solid rgba(0, 0, 0) !important" }, + FILTER_DIALOG_ACTIONS: { justifyContent: "center" } }; -let curParent = ""; -let x = 0; - //----------- //Тело модуля //----------- -const formatDate = date => { - const [year, month, day] = date.substring(1).split("_"); - let nd; - if (day == null) nd = `${month < 10 ? "0" + month : month}.${year}`; - else nd = `${day < 10 ? "0" + day : day}.${month < 10 ? "0" + month : month}.${year}`; - return nd; +//Формирование даты полной и даты без дней из наименования ячейки +const formatDate = dateCellName => { + const [year, month, day] = dateCellName.substring(1).split("_"); + let date; + if (day == null) date = `${month < 10 ? "0" + month : month}.${year}`; + else date = `${day < 10 ? "0" + day : day}.${month < 10 ? "0" + month : month}.${year}`; + return date; }; +//Генерация представления заголовка колонки export const headCellRender = ({ columnDef }, hClick) => { - let cellStyle = STYLES.HCR_MAIN_STYLE; //{ border: "1px solid rgba(0, 0, 0)", textAlign: "center" }; + let cellStyle = STYLES.HCR_MAIN_STYLE; let cellProps = {}; let stackStyle = {}; let data = columnDef.caption; + //Для разворачивающихся колонок if (columnDef.expandable) { const ref = createRef(); cellStyle = { ...cellStyle, padding: "5px" }; @@ -62,42 +64,49 @@ export const headCellRender = ({ columnDef }, hClick) => { }; stackStyle = { flexDirection: "column" }; } - if (columnDef.name == "SOBJINFO" || columnDef.name == "SWRKTYPE") cellStyle = STYLES.HIDE_CELL_STYLE; //{ display: "none" }; + //Скрываем ненужные колонки + if (columnDef.name == "SOBJINFO" || columnDef.name == "SWRKTYPE") cellStyle = STYLES.HIDE_CELL_STYLE; + //Объединение нужных колонок и строк if (columnDef.name == "SINFO" || columnDef.name == "SWRKTYPE") { cellProps = { colSpan: 2 }; if (columnDef.name == "SINFO") cellProps = { ...cellProps, rowSpan: 2 }; } - //if (columnDef.name == "SWRKTYPE") cellStyle = STYLES.HIDE_CELL_STYLE; //{ display: "none" }; + //Изменения в заголовках с датами if (columnDef.visible && DAY_NAME_REG_EXP.test(columnDef.name)) { - cellStyle = { ...cellStyle, ...STYLES.HCR_DATE_STYLE }; //{ ...cellStyle, padding: "5px", minWidth: "25px", maxWidth: "25px" }; + cellStyle = { ...cellStyle, ...STYLES.HCR_DATE_STYLE }; stackStyle = { justifyContent: "center" }; } return { cellStyle, cellProps, stackStyle, data }; }; +//Генерация представления ячейки export const dataCellRender = ({ row, columnDef }, showEquipSrv) => { - let cellStyle = STYLES.DCR_MAIN_STYLE; /*{ - padding: "2px", - border: "1px solid rgba(0, 0, 0) !important", - textAlign: "center" - };*/ + let curParent = ""; + let cellDate; + let cellStyle = STYLES.DCR_MAIN_STYLE; let cellProps = {}; let data = " "; + //Если строка с трудоёмкостью по объекту ремонта if (row["SWRKTYPE"] == undefined) { + //Ячейка "Информация по объекту ремонта" if (columnDef.name == "SOBJINFO") { cellProps = { colSpan: 2 }; - cellStyle = { ...cellStyle, ...STYLES.DCR_OBJECT_INFO_STYLE }; //{ ...cellStyle, textAlign: "right", fontWeight: "bold" }; + cellStyle = { ...cellStyle, ...STYLES.DCR_OBJECT_INFO_STYLE }; } - if (columnDef.name == "SWRKTYPE") cellStyle = STYLES.HIDE_CELL_STYLE; //{ display: "none" }; + //Ячейка "Тип работ" + if (columnDef.name == "SWRKTYPE") cellStyle = STYLES.HIDE_CELL_STYLE; + //Ячейки колонок месяцев if (columnDef.parent == "" && columnDef.expandable == true && columnDef.expanded == false) { curParent = columnDef.name; return { cellStyle: { ...cellStyle, height: "25px" }, data }; - } else if (columnDef.name != "SWRKTYPE" && columnDef.parent != "" && columnDef.expandable == false && columnDef.expanded == true) { + } + //Поиск развёрнутых месяцев + else if (columnDef.name != "SWRKTYPE" && columnDef.parent != "" && columnDef.expandable == false && columnDef.expanded == true) { if (columnDef.name.endsWith("_1")) { curParent = columnDef.parent; const [year, month] = curParent.substring(1).split("_"); - x = new Date(year, month, 0).getDate(); - cellProps = { colSpan: x }; + cellDate = new Date(year, month, 0).getDate(); + cellProps = { colSpan: cellDate }; data = row[curParent]; return { cellStyle, cellProps, data }; } else { @@ -105,16 +114,19 @@ export const dataCellRender = ({ row, columnDef }, showEquipSrv) => { } } } + //Строка плана по объекту ремонта if (columnDef.name == "SOBJINFO" && row["SWRKTYPE"] == "План") { cellStyle = { ...cellStyle }; cellProps = { rowSpan: 2 }; } + //Строка факта по объекту ремонта if (columnDef.name == "SOBJINFO" && row["SWRKTYPE"] == "Факт") { cellStyle = { display: "none" }; } + //Закрашивание ячеек switch (row[columnDef.name]) { case "blue": - cellStyle = { ...cellStyle, ...STYLES.DCR_PLAN_CELL_STYLE }; //{ ...cellStyle, cursor: "pointer", backgroundColor: "lightblue", border: "1px solid rgba(0, 0, 0) !important" }; + cellStyle = { ...cellStyle, ...STYLES.DCR_PLAN_CELL_STYLE }; cellProps = { title: formatDate(columnDef.name), onClick: () => { @@ -123,7 +135,7 @@ export const dataCellRender = ({ row, columnDef }, showEquipSrv) => { }; return { cellStyle, cellProps, data }; case "green": - cellStyle = { ...cellStyle, ...STYLES.DCR_FACT_RELATED_CELL_STYLE }; //{ ...cellStyle, cursor: "pointer", backgroundColor: "green", border: "1px solid rgba(0, 0, 0) !important" }; + cellStyle = { ...cellStyle, ...STYLES.DCR_FACT_RELATED_CELL_STYLE }; cellProps = { title: formatDate(columnDef.name), onClick: () => { @@ -132,7 +144,7 @@ export const dataCellRender = ({ row, columnDef }, showEquipSrv) => { }; return { cellStyle, cellProps, data }; case "red": - cellStyle = { ...cellStyle, ...STYLES.DCR_FACT_NOT_RELATED_CELL_STYLE }; //{ ...cellStyle, cursor: "pointer", backgroundColor: "crimson", border: "1px solid rgba(0, 0, 0) !important" }; + cellStyle = { ...cellStyle, ...STYLES.DCR_FACT_NOT_RELATED_CELL_STYLE }; cellProps = { title: formatDate(columnDef.name), onClick: () => { @@ -140,6 +152,7 @@ export const dataCellRender = ({ row, columnDef }, showEquipSrv) => { } }; return { cellStyle, cellProps, data }; + //Случай двойного закрашивания месяца case "green red": case "red green": cellStyle = { ...cellStyle, padding: "unset" }; @@ -170,7 +183,9 @@ export const dataCellRender = ({ row, columnDef }, showEquipSrv) => { return { cellStyle, cellProps }; }; +//Генерация представления заголовка группы export const groupCellRender = () => { - let cellStyle = STYLES.HIDE_CELL_STYLE; //{ display: "none" }; + //Скрываем все группы + let cellStyle = STYLES.HIDE_CELL_STYLE; return { cellStyle }; };