P8-Panels/app/panels/eqs_prfrm/eqs_prfrm.js

343 lines
14 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
Парус 8 - Панели мониторинга - ТОиР - Выполнение работ
Панель мониторинга: Корневая панель выполнения работ
*/
//---------------------
//Подключение библиотек
//---------------------
import React, { useState, useContext, useCallback, useEffect } from "react"; //Классы React
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"; //Контекст взаимодействия с сервером
import { ApplicationСtx } from "../../context/application"; //Контекст приложения
import { MessagingСtx } from "../../context/messaging"; //Контекст сообщений
import { headCellRender, dataCellRender, groupCellRender, DIGITS_REG_EXP, MONTH_NAME_REG_EXP, DAY_NAME_REG_EXP } from "./layouts"; //Дополнительная разметка и вёрстка клиентских элементов
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
})
};
//-----------
//Тело модуля
//-----------
//Корневая панель выполнения работ
const EqsPrfrm = () => {
//Собственное состояние - таблица данных
const [dataGrid, setDataGrid] = useState({
dataLoaded: false,
columnsDef: [],
groups: [],
rows: [],
fixedHeader: false,
fixedColumns: 0,
reload: false
});
//Состояние фильтра
const [filter, setFilter] = useState({
isOpen: false,
isDefault: false,
isSetByUser: false,
needSave: false,
values: {
belong: "",
prodObj: "",
techServ: "",
respDep: "",
fromMonth: 1,
fromYear: 1990,
toMonth: 1,
toYear: 1990
}
});
//Состояние ячейки заголовка даты (по раскрытию/скрытию)
const [activeRef, setActiveRef] = useState();
//Состояние актуальности ссылки на ячейку
const [refIsDeprecated, setRidFlag] = useState(true);
//Подключение к контексту приложения
const { pOnlineShowUnit } = useContext(ApplicationСtx);
//Подключение к контексту взаимодействия с сервером
const { executeStored } = useContext(BackEndСtx);
//Подключение к контексту сообщений
const { showMsgErr } = useContext(MessagingСtx);
//Загрузка данных таблицы с сервера
const loadData = useCallback(async () => {
if (dataGrid.reload) {
const data = await executeStored({
stored: "PKG_P8PANELS_EQUIPSRV.EQUIPSRV_GRID",
args: {
SBELONG: filter.values.belong,
SPRODOBJ: filter.values.prodObj,
STECHSERV: filter.values.techServ,
SRESPDEP: filter.values.respDep,
NFROMMONTH: filter.values.fromMonth,
NFROMYEAR: filter.values.fromYear,
NTOMONTH: filter.values.toMonth,
NTOYEAR: filter.values.toYear
},
respArg: "COUT",
attributeValueProcessor: (name, val) => (["caption", "name", "parent"].includes(name) ? undefined : val)
});
let cP = 0;
let sP = 0;
let cF = 0;
let sF = 0;
let properties = [];
if (data.XROWS != null) {
data.XROWS.map(row => {
properties = [];
Object.entries(row).forEach(([key, value]) => properties.push({ name: key, data: value }));
let info2 = properties.find(element => {
return element.name === "SINFO2";
});
if (info2 != undefined) {
if (info2.data == "План") {
properties.map(p => {
if (DAY_NAME_REG_EXP.test(p.name)) cP = cP + 1;
});
} else if (info2.data == "Факт") {
properties.map(p => {
if (DAY_NAME_REG_EXP.test(p.name)) cF = cF + 1;
});
}
} else {
properties.map(p => {
if (MONTH_NAME_REG_EXP.test(p.name)) {
let str = p.data;
let m = [];
let i = 0;
while ((m = DIGITS_REG_EXP.exec(str)) != null) {
if (i == 0) sP = sP + Number(m[0].replace(",", "."));
else {
sF = sF + Number(m[0].replace(",", "."));
}
i++;
}
}
});
}
});
}
setDataGrid(pv => ({
...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
}));
}
}, [dataGrid.reload, filter, executeStored]);
//Загрузка значений фильтра по умолчанию
const loadDefaultFilter = useCallback(async () => {
const data = await executeStored({
stored: "PKG_P8PANELS_EQUIPSRV.GET_DEFAULT_FP",
respArg: "COUT"
});
setFilter(pv => ({
...pv,
values: { ...pv.values, belong: data.JURPERS, fromMonth: 1, fromYear: data.YEAR, toMonth: 12, toYear: data.YEAR },
isDefault: true
}));
}, [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("_");
let type;
if (workType == "План") type = 0;
else type = 1;
let [year, month, day] = date.substring(1).split("_");
const data = await executeStored({
stored: "PKG_P8PANELS_EQUIPSRV.SELECT_EQUIPSRV",
args: {
SBELONG: filter.values.belong,
SPRODOBJ: filter.values.prodObj,
STECHSERV: filter.values.techServ ? filter.values.techServ : null,
SRESPDEP: filter.values.respDep ? filter.values.respDep : null,
STECHNAME: techName,
SSRVKIND: servKind,
NYEAR: Number(year),
NMONTH: Number(month),
NDAY: day ? Number(day) : null,
NWORKTYPE: type
}
});
if (data.NIDENT) {
if (type == 0) pOnlineShowUnit({ unitCode: "EquipTechServices", inputParameters: [{ name: "in_SelectList_Ident", value: data.NIDENT }] });
else pOnlineShowUnit({ unitCode: "EquipRepairSheets", inputParameters: [{ name: "in_Ident", value: data.NIDENT }] });
} else showMsgErr(TEXTS.NO_DATA_FOUND);
};
//Показать/скрыть фильтр
const setFilterOpen = isOpen => setFilter(pv => ({ ...pv, isOpen }));
//Установить значение фильтра
const setFilterValues = values => setFilter(pv => ({ ...pv, isSetByUser: true, needSave: true, values: { ...values } }));
//Отработка события скрытия/раскрытия ячейки даты
const handleClick = (e, ref) => {
const curCell = ref.current;
if (e.target.type == "button" || e.target.offsetParent.type == "button") {
setActiveRef(curCell);
setRidFlag(false);
}
};
//При необходимости обновить данные таблицы
useEffect(() => {
loadData();
}, [loadData, dataGrid.reload]);
//При изменении фильтра
useEffect(() => {
if (filter.isSetByUser) setDataGrid({ reload: true });
}, [
filter.isSetByUser,
filter.values.belong,
filter.values.prodObj,
filter.values.techServ,
filter.values.respDep,
filter.values.fromMonth,
filter.values.fromYear,
filter.values.toMonth,
filter.values.toYear
]);
//При нажатии скрытии/раскрытии ячейки даты, фокус на неё
useEffect(() => {
if (!refIsDeprecated) {
if (activeRef) {
var cellRect = activeRef.getBoundingClientRect();
window.scrollTo(window.scrollX + cellRect.left + activeRef.clientWidth / 2 - window.innerWidth / 2, 0);
setRidFlag(true);
}
}
//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(() => {
localStorage.getItem("belong") ? loadLocalFilter() : loadDefaultFilter();
}, [loadDefaultFilter, loadLocalFilter]);
//При открытии диалога фильтра
const handleFilterClick = () => setFilterOpen(true);
//При изменении фильтра в диалоге
const handleFilterOk = filter => {
setFilterValues(filter);
setFilterOpen(false);
};
//При закрытии диалога фильтра
const handleFilterCancel = () => setFilterOpen(false);
//Состояние ширины и высоты рабочей области окна
const [width, height] = useWindowResize();
//Генерация содержимого
return (
<div>
{filter.isOpen ? <FilterDialog initial={filter.values} onOk={handleFilterOk} onCancel={handleFilterCancel} /> : null}
<Filter filter={filter.values} onClick={handleFilterClick} />
{dataGrid.dataLoaded ? (
<Box sx={{ ...STYLES.GRID_PADDING, ...STYLES.BOX_ROW }}>
<P8PDataGrid
{...P8P_DATA_GRID_CONFIG_PROPS}
containerComponentProps={{
elevation: 6,
style: {
...STYLES.GRID_SIZES(width, height)
}
}}
columnsDef={dataGrid.columnsDef}
groups={dataGrid.groups}
rows={dataGrid.rows}
fixedHeader={dataGrid.fixedHeader}
fixedColumns={dataGrid.fixedColumns}
size={P8P_DATA_GRID_SIZE.LARGE}
reloading={dataGrid.reload}
headCellRender={prms => headCellRender({ ...prms }, handleClick)}
dataCellRender={prms => dataCellRender({ ...prms }, width * 0.2, showEquipSrv)}
groupCellRender={prms => groupCellRender({ ...prms })}
showCellRightBorder={true}
/>
</Box>
) : null}
</div>
);
};
//----------------
//Интерфейс модуля
//----------------
export { EqsPrfrm };