diff --git a/app/panels/eqs_prfrm/eqs_prfrm.js b/app/panels/eqs_prfrm/eqs_prfrm.js
index f49142b..01e4014 100644
--- a/app/panels/eqs_prfrm/eqs_prfrm.js
+++ b/app/panels/eqs_prfrm/eqs_prfrm.js
@@ -8,7 +8,7 @@
//---------------------
import React, { useState, useContext, useCallback, useEffect } from "react"; //Классы React
-import { Grid, Paper, Box } from "@mui/material"; //Интерфейсные компоненты
+import { Box } 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"; //Контекст взаимодействия с сервером
@@ -18,6 +18,33 @@ import { headCellRender, dataCellRender, groupCellRender, DIGITS_REG_EXP, MONTH_
import { TEXTS } from "../../../app.text"; //Тектовые ресурсы и константы
import { Filter } from "./filter"; //Компонент фильтра
import { FilterDialog } from "./filter_dialog"; //Компонент диалогового окна фильтра отбора
+import { useWindowResize } from "./hooks"; //Пользовательские хуки
+
+//---------
+//Константы
+//---------
+
+//Высота меню Парус (пиксели)
+const pxOuterMenuH = 53;
+//Высота заголовка панели (пиксели)
+const pxPanelHeaderH = 64;
+//Минимальная ширина таблицы (пиксели)
+const minGridW = 800;
+//Минимальная высота таблицы (пиксели)
+const minGridH = 200;
+
+//Стили
+const STYLES = {
+ BOX_ROW: { display: "flex", justifyContent: "center", alignItems: "center" },
+ GRID_PADDING: { paddingTop: 1, paddingBottom: 1 },
+ GRID_SIZES: (width, height) => ({
+ padding: "0px",
+ minWidth: minGridW,
+ maxWidth: width * 0.975 > minGridW ? width * 0.975 : minGridW,
+ minHeight: minGridH,
+ maxHeight: (height - pxOuterMenuH - pxPanelHeaderH) * 0.975 > minGridH ? (height - pxOuterMenuH - pxPanelHeaderH) * 0.975 : minGridH
+ })
+};
//-----------
//Тело модуля
@@ -31,6 +58,8 @@ const EqsPrfrm = () => {
columnsDef: [],
groups: [],
rows: [],
+ fixedHeader: false,
+ fixedColumns: 0,
reload: false
});
@@ -39,6 +68,7 @@ const EqsPrfrm = () => {
isOpen: false,
isDefault: false,
isSetByUser: false,
+ needSave: false,
values: {
belong: "",
prodObj: "",
@@ -128,6 +158,8 @@ const EqsPrfrm = () => {
...pv,
columnsDef: data.XCOLUMNS_DEF ? [...data.XCOLUMNS_DEF] : pv.columnsDef,
rows: [...(data.XROWS || [])],
+ fixedHeader: data.XDATA_GRID.fixedHeader,
+ fixedColumns: data.XDATA_GRID.fixedColumns,
groups: [...(data.XGROUPS || [])],
dataLoaded: true,
reload: false
@@ -135,7 +167,7 @@ const EqsPrfrm = () => {
}
}, [dataGrid.reload, filter, executeStored]);
- //Загрузка значений фильра по умолчанию
+ //Загрузка значений фильтра по умолчанию
const loadDefaultFilter = useCallback(async () => {
const data = await executeStored({
stored: "PKG_P8PANELS_EQUIPSRV.GET_DEFAULT_FP",
@@ -148,6 +180,17 @@ const EqsPrfrm = () => {
}));
}, [executeStored]);
+ //Загрузка значений фильтра из локального хранилища браузера
+ const loadLocalFilter = useCallback(async () => {
+ let vs = filter.values;
+ Object.keys(vs).map(function (k) {
+ vs[k] =
+ k == "fromMonth" || k == "fromYear" || k == "toMonth" || k == "toYear" ? Number(localStorage.getItem(k)) : localStorage.getItem(k);
+ });
+ setFilter(pv => ({ ...pv, isDefault: true, values: { ...vs } }));
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, []);
+
//Отбор документа (ТОиР или Ремонтных ведомостей) по ячейке даты
const showEquipSrv = async ({ date, workType, info }) => {
const [techName, servKind] = info.split("_");
@@ -180,7 +223,7 @@ const EqsPrfrm = () => {
const setFilterOpen = isOpen => setFilter(pv => ({ ...pv, isOpen }));
//Установить значение фильтра
- const setFilterValues = values => setFilter(pv => ({ ...pv, isSetByUser: true, values: { ...values } }));
+ const setFilterValues = values => setFilter(pv => ({ ...pv, isSetByUser: true, needSave: true, values: { ...values } }));
//Отработка события скрытия/раскрытия ячейки даты
const handleClick = (e, ref) => {
@@ -223,16 +266,26 @@ const EqsPrfrm = () => {
//eslint-disable-next-line react-hooks/exhaustive-deps
}, [refIsDeprecated]);
+ //При закрытии панели
+ useEffect(() => {
+ filter.needSave
+ ? window.addEventListener("beforeunload", function () {
+ Object.keys(filter.values).map(function (k) {
+ localStorage.setItem(k, filter.values[k]);
+ });
+ })
+ : null;
+ }, [filter.needSave, filter.values]);
+
//При загрузке фильтра по умолчанию
useEffect(() => {
if (filter.isDefault) setFilterOpen(true);
}, [filter.isDefault]);
- //При подключении к страницк
+ //При подключении к странице
useEffect(() => {
- loadDefaultFilter();
- // eslint-disable-next-line react-hooks/exhaustive-deps
- }, []);
+ localStorage.getItem("belong") ? loadLocalFilter() : loadDefaultFilter();
+ }, [loadDefaultFilter, loadLocalFilter]);
//При открытии диалога фильтра
const handleFilterClick = () => setFilterOpen(true);
@@ -246,32 +299,37 @@ const EqsPrfrm = () => {
//При закрытии диалога фильтра
const handleFilterCancel = () => setFilterOpen(false);
+ //Состояние ширины и высоты рабочей области окна
+ const [width, height] = useWindowResize();
+
//Генерация содержимого
return (
{filter.isOpen ?
: null}
{dataGrid.dataLoaded ? (
-
-
-
-
- headCellRender({ ...prms }, handleClick)}
- dataCellRender={prms => dataCellRender({ ...prms }, showEquipSrv)}
- groupCellRender={prms => groupCellRender({ ...prms })}
- showCellRightBorder={true}
- />
-
-
-
-
+
+ headCellRender({ ...prms }, handleClick)}
+ dataCellRender={prms => dataCellRender({ ...prms }, width * 0.2, showEquipSrv)}
+ groupCellRender={prms => groupCellRender({ ...prms })}
+ showCellRightBorder={true}
+ />
+
) : null}
);
diff --git a/app/panels/eqs_prfrm/hooks.js b/app/panels/eqs_prfrm/hooks.js
new file mode 100644
index 0000000..4637885
--- /dev/null
+++ b/app/panels/eqs_prfrm/hooks.js
@@ -0,0 +1,36 @@
+/*
+ Парус 8 - Панели мониторинга - ТОиР - Выполнение работ
+ Пользовательские хуки
+*/
+
+//---------------------
+//Подключение библиотек
+//---------------------
+
+import { useState, useLayoutEffect } from "react"; //Классы React
+
+//-----------
+//Тело модуля
+//-----------
+
+//Хук для отработки изменений ширины и высоты рабочей области окна
+const useWindowResize = () => {
+ //Состояние размера рабочей области
+ const [size, setSize] = useState([0, 0]);
+ //При изменении размера
+ useLayoutEffect(() => {
+ function updateSize() {
+ setSize([document.documentElement.clientWidth, document.documentElement.clientHeight]);
+ }
+ window.addEventListener("resize", updateSize);
+ updateSize();
+ return () => window.removeEventListener("resize", updateSize);
+ }, []);
+ return size;
+};
+
+//--------------
+//Интерфейс хука
+//--------------
+
+export { useWindowResize };
diff --git a/app/panels/eqs_prfrm/layouts.js b/app/panels/eqs_prfrm/layouts.js
index 82b08cb..c854873 100644
--- a/app/panels/eqs_prfrm/layouts.js
+++ b/app/panels/eqs_prfrm/layouts.js
@@ -20,7 +20,7 @@ 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 = {
+const STYLES = {
HIDE_CELL_STYLE: { display: "none" },
HCR_MAIN_STYLE: { border: "1px solid rgba(0, 0, 0)", textAlign: "center" },
HCR_DATE_STYLE: { padding: "5px", minWidth: "25px", maxWidth: "25px" },
@@ -31,7 +31,12 @@ export const STYLES = {
DCR_FACT_NOT_RELATED_CELL_STYLE: { cursor: "pointer", backgroundColor: "crimson", border: "1px solid rgba(0, 0, 0) !important" },
DCR_DOUBLE_CELL: { padding: "unset" },
DCR_DOUBLE_CELL_GRID_ITEM: backgroundColor => ({ cursor: "pointer", backgroundColor }),
- HIDDEN_PARAGRAPH: { display: "none" }
+ HIDDEN_PARAGRAPH: { display: "none" },
+ STICKY_WIDTH_UNSET: { minWidth: "unset", maxWidth: "unset" },
+ FIRST_STICKY_CELL: { left: "0px" },
+ OBJINFO_WIDTH: width => ({ minWidth: width, maxWidth: width }),
+ OBJINFO_WRKNAME_WIDTH: width => ({ minWidth: width * 0.6, maxWidth: width * 0.6 }),
+ WRKTYPE_WIDTH: width => ({ left: width * 0.6, minWidth: width - width * 0.4, maxWidth: width - width * 0.4 })
};
//-----------
@@ -71,7 +76,11 @@ export const headCellRender = ({ columnDef }, hClick) => {
//Объединение нужных колонок и строк
if (columnDef.name == "SINFO" || columnDef.name == "SWRKTYPE") {
cellProps = { colSpan: 2 };
- if (columnDef.name == "SINFO") cellProps = { ...cellProps, rowSpan: 2 };
+ cellStyle = { ...cellStyle, ...STYLES.STICKY_WIDTH_UNSET };
+ if (columnDef.name == "SINFO") {
+ cellProps = { ...cellProps, rowSpan: 2 };
+ cellStyle = { ...cellStyle, ...STYLES.FIRST_STICKY_CELL };
+ }
}
//Изменения в заголовках с датами
if (columnDef.visible && DAY_NAME_REG_EXP.test(columnDef.name)) {
@@ -82,7 +91,7 @@ export const headCellRender = ({ columnDef }, hClick) => {
};
//Генерация представления ячейки
-export const dataCellRender = ({ row, columnDef }, showEquipSrv) => {
+export const dataCellRender = ({ row, columnDef }, width, showEquipSrv) => {
let curParent = "";
let cellDate;
let cellStyle = STYLES.DCR_MAIN_STYLE;
@@ -93,10 +102,10 @@ export const dataCellRender = ({ row, columnDef }, showEquipSrv) => {
//Ячейка "Информация по объекту ремонта"
if (columnDef.name == "SOBJINFO") {
cellProps = { colSpan: 2 };
- cellStyle = { ...cellStyle, ...STYLES.DCR_OBJECT_INFO_STYLE };
+ cellStyle = { ...cellStyle, ...STYLES.DCR_OBJECT_INFO_STYLE, ...STYLES.OBJINFO_WIDTH(width) };
}
//Ячейка "Тип работ"
- if (columnDef.name == "SWRKTYPE") cellStyle = STYLES.HIDE_CELL_STYLE;
+ if (columnDef.name == "SWRKTYPE") cellStyle = { ...STYLES.HIDE_CELL_STYLE };
//Ячейки колонок месяцев
if (columnDef.parent == "" && columnDef.expandable == true && columnDef.expanded == false) {
curParent = columnDef.name;
@@ -118,13 +127,17 @@ export const dataCellRender = ({ row, columnDef }, showEquipSrv) => {
}
//Строка плана по объекту ремонта
if (columnDef.name == "SOBJINFO" && row["SWRKTYPE"] == "План") {
- cellStyle = { ...cellStyle };
+ cellStyle = { ...cellStyle, ...STYLES.FIRST_STICKY_CELL, ...STYLES.OBJINFO_WRKNAME_WIDTH(width) };
cellProps = { rowSpan: 2 };
}
//Строка факта по объекту ремонта
if (columnDef.name == "SOBJINFO" && row["SWRKTYPE"] == "Факт") {
cellStyle = { display: "none" };
}
+ //Ячейка план/факт
+ if (columnDef.name == "SWRKTYPE") {
+ cellStyle = { ...cellStyle, ...STYLES.WRKTYPE_WIDTH(width) };
+ }
//Закрашивание ячеек
switch (row[columnDef.name]) {
case "blue":
diff --git a/db/PKG_P8PANELS_EQUIPSRV.pck b/db/PKG_P8PANELS_EQUIPSRV.pck
index e748fc5..e11f20d 100644
--- a/db/PKG_P8PANELS_EQUIPSRV.pck
+++ b/db/PKG_P8PANELS_EQUIPSRV.pck
@@ -399,21 +399,24 @@ create or replace package body PKG_P8PANELS_EQUIPSRV as
/* Определим дату конца периода */
NTODATE := LAST_DAY(TO_DATE('01.' || LPAD(TO_CHAR(NTOMONTH), 2, '0') || '.' || TO_CHAR(NTOYEAR), 'dd.mm.yyyy'));
/* Инициализируем таблицу данных */
- RDG := PKG_P8PANELS_VISUAL.TDATA_GRID_MAKE();
+ RDG := PKG_P8PANELS_VISUAL.TDATA_GRID_MAKE(BFIXED_HEADER => true, NFIXED_COLUMNS => 2);
/* Формируем структуру заголовка */
PKG_P8PANELS_VISUAL.TDATA_GRID_ADD_COL_DEF(RDATA_GRID => RDG,
SNAME => 'SOBJINFO',
SCAPTION => 'Информация по объекту ремонта',
- SDATA_TYPE => PKG_P8PANELS_VISUAL.SDATA_TYPE_STR);
+ SDATA_TYPE => PKG_P8PANELS_VISUAL.SDATA_TYPE_STR,
+ NWIDTH => 80);
PKG_P8PANELS_VISUAL.TDATA_GRID_ADD_COL_DEF(RDATA_GRID => RDG,
SNAME => 'SINFO',
SCAPTION => 'Объект ремонта',
- SDATA_TYPE => PKG_P8PANELS_VISUAL.SDATA_TYPE_STR);
+ SDATA_TYPE => PKG_P8PANELS_VISUAL.SDATA_TYPE_STR,
+ NWIDTH => 80);
PKG_P8PANELS_VISUAL.TDATA_GRID_ADD_COL_DEF(RDATA_GRID => RDG,
SNAME => 'SWRKTYPE',
SCAPTION => 'Тип работ',
SDATA_TYPE => PKG_P8PANELS_VISUAL.SDATA_TYPE_STR,
- SPARENT => 'SINFO');
+ SPARENT => 'SINFO',
+ NWIDTH => 80);
PKG_P8PANELS_VISUAL.TDATA_GRID_ADD_COL_DEF(RDATA_GRID => RDG,
SNAME => 'NRN',
SCAPTION => 'Рег. номер',