init
This commit is contained in:
commit
261f2cf490
113
hauler_anl/chart_filter.js
Normal file
113
hauler_anl/chart_filter.js
Normal file
@ -0,0 +1,113 @@
|
|||||||
|
/*
|
||||||
|
Парус 8 - Панели мониторинга - ТОиР - Гаражка
|
||||||
|
Компонент: Фильтр отбора
|
||||||
|
*/
|
||||||
|
|
||||||
|
//---------------------
|
||||||
|
//Подключение библиотек
|
||||||
|
//---------------------
|
||||||
|
|
||||||
|
import React from "react"; //Классы React
|
||||||
|
import PropTypes from "prop-types"; //Контроль свойств компонента
|
||||||
|
import { Chip, Stack, Box } from "@mui/material"; //Интерфейсные компоненты
|
||||||
|
import { APP_STYLES } from "../../../app.styles"; //Типовые стили
|
||||||
|
import { hasValue } from "../../core/utils"; //Вспомогательные функции
|
||||||
|
|
||||||
|
//---------
|
||||||
|
//Константы
|
||||||
|
//---------
|
||||||
|
|
||||||
|
//Стили
|
||||||
|
const STYLES = {
|
||||||
|
FILTERS_STACK: {
|
||||||
|
paddingBottom: "5px",
|
||||||
|
...APP_STYLES.SCROLL,
|
||||||
|
overflowY: "auto",
|
||||||
|
alignItems: "flex-end"
|
||||||
|
},
|
||||||
|
STACK_FILTER: { maxWidth: "99vw", alignItems: "flex-end" }
|
||||||
|
};
|
||||||
|
|
||||||
|
//Графики
|
||||||
|
const CHART_NAMES = {
|
||||||
|
info: "INFO",
|
||||||
|
calcs: "CALCS"
|
||||||
|
};
|
||||||
|
|
||||||
|
//--------------------------
|
||||||
|
//Вспомогательные компоненты
|
||||||
|
//--------------------------
|
||||||
|
|
||||||
|
//Считывание наименования состояния
|
||||||
|
const getStateName = state => {
|
||||||
|
return state === 0 ? "На линии" : state === 1 ? "Ремонт" : "Не определено";
|
||||||
|
};
|
||||||
|
|
||||||
|
//Элемент фильтра
|
||||||
|
const FilterItem = ({ field, caption, value, onDelete }) => {
|
||||||
|
//При удалении фильтра
|
||||||
|
const handleDelete = () => (onDelete ? onDelete(field) : null);
|
||||||
|
|
||||||
|
//Генерация содержимого
|
||||||
|
return (
|
||||||
|
<Chip
|
||||||
|
label={
|
||||||
|
<Stack direction={"row"} alignItems={"center"}>
|
||||||
|
<strong>{caption}</strong>
|
||||||
|
{value ? `:\u00A0${value}` : null}
|
||||||
|
</Stack>
|
||||||
|
}
|
||||||
|
variant="outlined"
|
||||||
|
onDelete={handleDelete}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
//Контроль свойств компонента - Элемент фильтра
|
||||||
|
FilterItem.propTypes = {
|
||||||
|
field: PropTypes.string.isRequired,
|
||||||
|
caption: PropTypes.string.isRequired,
|
||||||
|
value: PropTypes.any,
|
||||||
|
onDelete: PropTypes.func
|
||||||
|
};
|
||||||
|
|
||||||
|
//---------------
|
||||||
|
//Тело компонента
|
||||||
|
//---------------
|
||||||
|
|
||||||
|
//Фильтр отбора
|
||||||
|
const ChartFilter = ({ chartName, filter, onFilterChange }) => {
|
||||||
|
//При удалении фильтра
|
||||||
|
const handleDelete = field => onFilterChange && onFilterChange({ chartName, filter: { ...filter, [field]: null } });
|
||||||
|
//Генерация содержимого
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<Box>
|
||||||
|
<Stack direction="row" spacing={1} p={1} alignItems={"center"} sx={STYLES.STACK_FILTER}>
|
||||||
|
<Stack direction="row" spacing={1} alignItems={"center"} sx={STYLES.FILTERS_STACK}>
|
||||||
|
{chartName === CHART_NAMES.info ? (
|
||||||
|
hasValue(filter.nState) ? (
|
||||||
|
<FilterItem field={"nState"} caption={"Готовность"} value={getStateName(filter.nState)} onDelete={handleDelete} />
|
||||||
|
) : null
|
||||||
|
) : chartName === CHART_NAMES.calcs ? (
|
||||||
|
<FilterItem field={"sDepartment"} caption={"Подразделение"} value={filter.sDepartment} onDelete={handleDelete} />
|
||||||
|
) : null}
|
||||||
|
</Stack>
|
||||||
|
</Stack>
|
||||||
|
</Box>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
//Контроль свойств компонента - Фильтр отбора
|
||||||
|
ChartFilter.propTypes = {
|
||||||
|
chartName: PropTypes.string,
|
||||||
|
filter: PropTypes.object.isRequired,
|
||||||
|
onFilterChange: PropTypes.func.isRequired
|
||||||
|
};
|
||||||
|
|
||||||
|
//--------------------
|
||||||
|
//Интерфейс компонента
|
||||||
|
//--------------------
|
||||||
|
|
||||||
|
export { ChartFilter };
|
||||||
101
hauler_anl/filter.js
Normal file
101
hauler_anl/filter.js
Normal file
@ -0,0 +1,101 @@
|
|||||||
|
/*
|
||||||
|
Парус 8 - Панели мониторинга - ТОиР - Гаражка
|
||||||
|
Компонент: Фильтр отбора
|
||||||
|
*/
|
||||||
|
|
||||||
|
//---------------------
|
||||||
|
//Подключение библиотек
|
||||||
|
//---------------------
|
||||||
|
|
||||||
|
import React from "react"; //Классы React
|
||||||
|
import PropTypes from "prop-types"; //Контроль свойств компонента
|
||||||
|
import { Chip, Stack, Icon, IconButton, Box } from "@mui/material"; //Интерфейсные компоненты
|
||||||
|
import { APP_STYLES } from "../../../app.styles"; //Типовые стили
|
||||||
|
import { formatDateRF } from "../../core/utils"; //Вспомогательные функции
|
||||||
|
|
||||||
|
//---------
|
||||||
|
//Константы
|
||||||
|
//---------
|
||||||
|
|
||||||
|
//Стили
|
||||||
|
const STYLES = {
|
||||||
|
FILTERS_STACK: {
|
||||||
|
paddingBottom: "5px",
|
||||||
|
...APP_STYLES.SCROLL,
|
||||||
|
overflowY: "auto",
|
||||||
|
alignItems: "flex-end"
|
||||||
|
},
|
||||||
|
STACK_FILTER: { maxWidth: "99vw", alignItems: "flex-end" }
|
||||||
|
};
|
||||||
|
|
||||||
|
//--------------------------
|
||||||
|
//Вспомогательные компоненты
|
||||||
|
//--------------------------
|
||||||
|
|
||||||
|
//Элемент фильтра
|
||||||
|
const FilterItem = ({ caption, value, onClick }) => {
|
||||||
|
//При нажатии на элемент
|
||||||
|
const handleClick = () => (onClick ? onClick() : null);
|
||||||
|
|
||||||
|
//Генерация содержимого
|
||||||
|
return (
|
||||||
|
<Chip
|
||||||
|
label={
|
||||||
|
<Stack direction={"row"} alignItems={"center"}>
|
||||||
|
<strong>{caption}</strong>
|
||||||
|
{value ? `:\u00A0${value}` : null}
|
||||||
|
</Stack>
|
||||||
|
}
|
||||||
|
variant="outlined"
|
||||||
|
onClick={handleClick}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
//Контроль свойств компонента - Элемент фильтра
|
||||||
|
FilterItem.propTypes = {
|
||||||
|
caption: PropTypes.string.isRequired,
|
||||||
|
value: PropTypes.any,
|
||||||
|
onClick: PropTypes.func
|
||||||
|
};
|
||||||
|
|
||||||
|
//---------------
|
||||||
|
//Тело компонента
|
||||||
|
//---------------
|
||||||
|
|
||||||
|
//Фильтр отбора
|
||||||
|
const Filter = ({ filter, onFilterOpen }) => {
|
||||||
|
//При нажатии на элемент фильтра
|
||||||
|
const handleClick = () => onFilterOpen && onFilterOpen();
|
||||||
|
|
||||||
|
//Генерация содержимого
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<Box>
|
||||||
|
<Stack direction="row" spacing={1} p={1} alignItems={"center"} sx={STYLES.STACK_FILTER}>
|
||||||
|
<IconButton onClick={handleClick}>
|
||||||
|
<Icon>filter_alt</Icon>
|
||||||
|
</IconButton>
|
||||||
|
<Stack direction="row" spacing={1} alignItems={"center"} sx={STYLES.FILTERS_STACK}>
|
||||||
|
{filter.dDate ? <FilterItem caption={"На дату"} value={formatDateRF(filter.dDate)} onClick={handleClick} /> : null}
|
||||||
|
{filter.sCustomerDept ? (
|
||||||
|
<FilterItem caption={"Транспортный участок"} value={filter.sCustomerDept} onClick={handleClick} />
|
||||||
|
) : null}
|
||||||
|
</Stack>
|
||||||
|
</Stack>
|
||||||
|
</Box>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
//Контроль свойств компонента - Фильтр отбора
|
||||||
|
Filter.propTypes = {
|
||||||
|
filter: PropTypes.object.isRequired,
|
||||||
|
onFilterOpen: PropTypes.func.isRequired
|
||||||
|
};
|
||||||
|
|
||||||
|
//--------------------
|
||||||
|
//Интерфейс компонента
|
||||||
|
//--------------------
|
||||||
|
|
||||||
|
export { Filter };
|
||||||
187
hauler_anl/filter_dialog.js
Normal file
187
hauler_anl/filter_dialog.js
Normal file
@ -0,0 +1,187 @@
|
|||||||
|
/*
|
||||||
|
Парус 8 - Панели мониторинга - ТОиР - Гаражка
|
||||||
|
Компонент: Диалоговое окно фильтра отбора
|
||||||
|
*/
|
||||||
|
|
||||||
|
//---------------------
|
||||||
|
//Подключение библиотек
|
||||||
|
//---------------------
|
||||||
|
|
||||||
|
import React, { useState } from "react"; //Классы React
|
||||||
|
import PropTypes from "prop-types"; //Контроль свойств компонента
|
||||||
|
import { Dialog, DialogTitle, IconButton, Icon, DialogContent, DialogActions, Button, Box, TextField, InputAdornment } from "@mui/material"; //Интерфейсные компоненты
|
||||||
|
import { useDictionary } from "./hooks/dict_hooks"; //Хуки открытий разделов
|
||||||
|
import { hasValue, formatDateJSONDateOnly } from "../../core/utils"; //Вспомогательные функции
|
||||||
|
|
||||||
|
//---------
|
||||||
|
//Константы
|
||||||
|
//---------
|
||||||
|
|
||||||
|
//Стили
|
||||||
|
const STYLES = {
|
||||||
|
DIALOG_ACTIONS: { justifyContent: "flex-end" },
|
||||||
|
CLOSE_BUTTON: {
|
||||||
|
position: "absolute",
|
||||||
|
right: 8,
|
||||||
|
top: 8,
|
||||||
|
color: theme => theme.palette.grey[500]
|
||||||
|
},
|
||||||
|
BOX_WITH_LEGEND: { border: "1px solid #939393", marginBottom: "1px" },
|
||||||
|
LEGEND: { textAlign: "left" }
|
||||||
|
};
|
||||||
|
|
||||||
|
//--------------------------
|
||||||
|
//Вспомогательные компоненты
|
||||||
|
//--------------------------
|
||||||
|
|
||||||
|
//Проверка возможности выполнения действия
|
||||||
|
const isActionAllow = (filter, isFiltersInit = false) => {
|
||||||
|
//Если указана "На дату", а также это не инициализация
|
||||||
|
return hasValue(filter.dDate) && !isFiltersInit;
|
||||||
|
};
|
||||||
|
|
||||||
|
//---------------
|
||||||
|
//Тело компонента
|
||||||
|
//---------------
|
||||||
|
|
||||||
|
//Диалоговое окно фильтра отбора
|
||||||
|
const FilterDialog = ({ initial, isFiltersInit, onCancel, onOk }) => {
|
||||||
|
//Собственное состояние
|
||||||
|
const [filter, setFilter] = useState({ ...initial });
|
||||||
|
|
||||||
|
//Вспомогательные функции открытия раздела
|
||||||
|
const { handleInsDepartmentOpen } = useDictionary();
|
||||||
|
|
||||||
|
//Отработка воода значения в фильтр
|
||||||
|
const handleValueChanged = e => setFilter(pv => ({ ...pv, [e.target.name]: e.target.value }));
|
||||||
|
|
||||||
|
//При изменении каталога фильтра
|
||||||
|
const handleCustomerDeptSelect = () =>
|
||||||
|
handleInsDepartmentOpen({
|
||||||
|
sCode: filter.sCustomerDept,
|
||||||
|
callBack: res => {
|
||||||
|
setFilter(pv => ({ ...pv, sCustomerDept: res.outParameters.out_CODE }));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
//При загрузке текущей даты
|
||||||
|
const handleLoadCurrentDate = () => {
|
||||||
|
//Определяем текущую дату
|
||||||
|
const currentDate = formatDateJSONDateOnly(new Date());
|
||||||
|
//Устанавливаем
|
||||||
|
setFilter(pv => ({ ...pv, dDate: currentDate }));
|
||||||
|
};
|
||||||
|
|
||||||
|
//При очистке фильтра
|
||||||
|
const handleClear = () => {
|
||||||
|
setFilter({ dDate: "", sCustomerDept: "" });
|
||||||
|
};
|
||||||
|
|
||||||
|
//При закрытии диалога без изменения фильтра
|
||||||
|
const handleCancel = () => (isActionAllow(initial, isFiltersInit) ? onCancel && onCancel() : null);
|
||||||
|
|
||||||
|
//При закрытии диалога с изменением фильтра
|
||||||
|
const handleOK = () => (isActionAllow(filter) && onOk ? onOk(filter) : null);
|
||||||
|
|
||||||
|
//Генерация содержимого
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<Dialog open onClose={handleCancel} fullWidth maxWidth="sm">
|
||||||
|
<DialogTitle>Фильтр отбора</DialogTitle>
|
||||||
|
<IconButton aria-label="close" onClick={handleCancel} sx={STYLES.CLOSE_BUTTON}>
|
||||||
|
<Icon>close</Icon>
|
||||||
|
</IconButton>
|
||||||
|
<DialogContent>
|
||||||
|
<Box sx={{ display: "flex", flexDirection: "column", gap: "10px" }}>
|
||||||
|
<TextField
|
||||||
|
name="dDate"
|
||||||
|
type="date"
|
||||||
|
InputLabelProps={{ shrink: true }}
|
||||||
|
value={filter.dDate}
|
||||||
|
onChange={handleValueChanged}
|
||||||
|
label="На дату"
|
||||||
|
variant="standard"
|
||||||
|
fullWidth
|
||||||
|
required
|
||||||
|
error={!filter.dDate}
|
||||||
|
InputProps={{
|
||||||
|
endAdornment: (
|
||||||
|
<InputAdornment position="end">
|
||||||
|
<IconButton aria-label={`dDate currentDate`} onClick={handleLoadCurrentDate} edge="end">
|
||||||
|
<Icon>refresh</Icon>
|
||||||
|
</IconButton>
|
||||||
|
</InputAdornment>
|
||||||
|
)
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<TextField
|
||||||
|
name="sCustomerDept"
|
||||||
|
value={filter.sCustomerDept}
|
||||||
|
onChange={handleValueChanged}
|
||||||
|
label="Транспортный участок"
|
||||||
|
variant="standard"
|
||||||
|
InputProps={{
|
||||||
|
endAdornment: (
|
||||||
|
<InputAdornment position="end">
|
||||||
|
<IconButton aria-label={`sCustomerDept select`} onClick={handleCustomerDeptSelect} edge="end">
|
||||||
|
<Icon>list</Icon>
|
||||||
|
</IconButton>
|
||||||
|
</InputAdornment>
|
||||||
|
)
|
||||||
|
}}
|
||||||
|
fullWidth
|
||||||
|
/>
|
||||||
|
<Box sx={STYLES.BOX_WITH_LEGEND} component="fieldset">
|
||||||
|
<legend style={STYLES.LEGEND}>Расчет КОА</legend>
|
||||||
|
<TextField
|
||||||
|
name="dDateKOAFrom"
|
||||||
|
type="date"
|
||||||
|
InputLabelProps={{ shrink: true }}
|
||||||
|
value={filter.dDateKOAFrom}
|
||||||
|
onChange={handleValueChanged}
|
||||||
|
label="Дата с"
|
||||||
|
variant="standard"
|
||||||
|
fullWidth
|
||||||
|
/>
|
||||||
|
<TextField
|
||||||
|
name="dDateKOATo"
|
||||||
|
type="date"
|
||||||
|
InputLabelProps={{ shrink: true }}
|
||||||
|
value={filter.dDateKOATo}
|
||||||
|
onChange={handleValueChanged}
|
||||||
|
label="Дата по"
|
||||||
|
variant="standard"
|
||||||
|
fullWidth
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
</DialogContent>
|
||||||
|
<DialogActions sx={STYLES.DIALOG_ACTIONS}>
|
||||||
|
<Button variant="text" disabled={!isActionAllow(filter)} onClick={handleOK}>
|
||||||
|
Применить
|
||||||
|
</Button>
|
||||||
|
<Button variant="text" onClick={handleClear}>
|
||||||
|
Очистить
|
||||||
|
</Button>
|
||||||
|
<Button variant="text" disabled={!isActionAllow(initial, isFiltersInit)} onClick={handleCancel}>
|
||||||
|
Отмена
|
||||||
|
</Button>
|
||||||
|
</DialogActions>
|
||||||
|
</Dialog>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
//Контроль свойств компонента - Диалоговое окно фильтра отбора
|
||||||
|
FilterDialog.propTypes = {
|
||||||
|
initial: PropTypes.object.isRequired,
|
||||||
|
isFiltersInit: PropTypes.bool,
|
||||||
|
onOk: PropTypes.func,
|
||||||
|
onCancel: PropTypes.func
|
||||||
|
};
|
||||||
|
|
||||||
|
//--------------------
|
||||||
|
//Интерфейс компонента
|
||||||
|
//--------------------
|
||||||
|
|
||||||
|
export { FilterDialog };
|
||||||
233
hauler_anl/hauler_anl.js
Normal file
233
hauler_anl/hauler_anl.js
Normal file
@ -0,0 +1,233 @@
|
|||||||
|
/*
|
||||||
|
Парус 8 - Панели мониторинга - ТОиР - Гаражка
|
||||||
|
Панель мониторинга: Корневая панель гаражки
|
||||||
|
*/
|
||||||
|
|
||||||
|
//---------------------
|
||||||
|
//Подключение библиотек
|
||||||
|
//---------------------
|
||||||
|
|
||||||
|
import React, { useState, useEffect, useMemo } from "react"; //Классы React
|
||||||
|
import { Box, Grid, Paper, Fab, Icon } from "@mui/material"; //Интерфейсные компоненты
|
||||||
|
import { APP_BAR_HEIGHT } from "../../components/p8p_app_workspace"; //Заголовок страницы
|
||||||
|
import { P8PChart } from "../../components/p8p_chart"; //График
|
||||||
|
import { APP_STYLES } from "../../../app.styles"; //Типовые стили
|
||||||
|
import { P8PDataGrid, P8P_DATA_GRID_SIZE, P8P_DATA_GRID_MORE_HEIGHT, P8P_DATA_GRID_FILTERS_HEIGHT } from "../../components/p8p_data_grid"; //Таблица данных
|
||||||
|
import { P8P_DATA_GRID_CONFIG_PROPS } from "../../config_wrapper"; //Подключение компонентов к настройкам приложения
|
||||||
|
import { FilterDialog } from "./filter_dialog"; //Диалог фильтра
|
||||||
|
import { Filter } from "./filter"; //Фильтры
|
||||||
|
import { useFilters } from "./hooks/filter_hooks"; //Хуки фильтров
|
||||||
|
import { useChartInfo, useChartCalcs, useTableATC } from "./hooks/hooks";
|
||||||
|
import { valueFormatter } from "./layouts"; //Вспомогательные функции верстки
|
||||||
|
import { ChartFilter } from "./chart_filter"; //Фильтр графика
|
||||||
|
import { hasValue } from "../../core/utils"; //Вспомогательные функции
|
||||||
|
import { useDictionary } from "./hooks/dict_hooks"; //Хуки для открытия раздела
|
||||||
|
|
||||||
|
//---------
|
||||||
|
//Константы
|
||||||
|
//---------
|
||||||
|
|
||||||
|
//Высота графиков
|
||||||
|
const CHART_HEIGHT = "300px";
|
||||||
|
|
||||||
|
//Стили
|
||||||
|
const STYLES = {
|
||||||
|
TABLE_PROJECTS: (showCharts, morePages, filters, isChartsFiltered) => ({
|
||||||
|
height: `calc(100vh - ${APP_BAR_HEIGHT} - ${showCharts ? CHART_HEIGHT : "0px"} - ${morePages ? P8P_DATA_GRID_MORE_HEIGHT : "0px"} - ${
|
||||||
|
filters ? P8P_DATA_GRID_FILTERS_HEIGHT : "0px"
|
||||||
|
} - ${showCharts && isChartsFiltered ? "53px" : "0px"} - 90px)`,
|
||||||
|
maxWidth: `calc(100vw - 16px)`,
|
||||||
|
...APP_STYLES.SCROLL
|
||||||
|
}),
|
||||||
|
CHART: { maxHeight: CHART_HEIGHT, display: "flex", justifyContent: "center" },
|
||||||
|
CHART_PAPER: { height: "100%", paddingBottom: "5px" },
|
||||||
|
CHART_FAB: { position: "absolute", top: 80, left: 16 }
|
||||||
|
};
|
||||||
|
|
||||||
|
//Графики страницы
|
||||||
|
const CHART_NAMES = {
|
||||||
|
info: "INFO",
|
||||||
|
calcs: "CALCS"
|
||||||
|
};
|
||||||
|
|
||||||
|
//-----------
|
||||||
|
//Тело модуля
|
||||||
|
//-----------
|
||||||
|
|
||||||
|
//Корневая панель гаражки
|
||||||
|
const HaulerAnl = () => {
|
||||||
|
//Вспомогательные функции открытия раздела
|
||||||
|
const { handleEquipRepairSheetsOpen } = useDictionary();
|
||||||
|
|
||||||
|
//Собственное состояние - признак отображения фильтров
|
||||||
|
const [isFilterOpen, setIsFilterOpen] = useState(true);
|
||||||
|
|
||||||
|
//Состояния графиков
|
||||||
|
const [showCharts, setShowCharts] = useState(true);
|
||||||
|
|
||||||
|
//Собственное состояние - общие фильтры
|
||||||
|
const [filterValues, isFiltersLoaded, filtersInit, handleFilterChange] = useFilters();
|
||||||
|
|
||||||
|
//Собственное состояние - фильтры информации
|
||||||
|
const [filterInfo, setFilterInfo] = useState({ nState: null });
|
||||||
|
|
||||||
|
//Собственное состояние - фильтры расчетов
|
||||||
|
const [filterCalcs, setFilterCalcs] = useState({ sDepartment: null });
|
||||||
|
|
||||||
|
//Общие фильтры панели
|
||||||
|
const allFilters = useMemo(() => {
|
||||||
|
return { ...filterValues, nState: filterInfo.nState, sDepartment: filterCalcs.sDepartment };
|
||||||
|
}, [filterValues, filterInfo, filterCalcs]);
|
||||||
|
|
||||||
|
//Состояние графика информации АТС
|
||||||
|
const { chartInfo, handleReload: handleChartInfoReload } = useChartInfo({ storedArgs: allFilters });
|
||||||
|
|
||||||
|
//Состояние графика расчетов
|
||||||
|
const { chartCalcs, handleReload: handleChartCalcsReload } = useChartCalcs({ storedArgs: allFilters });
|
||||||
|
|
||||||
|
//Состояние таблицы ремонтных ведомостей
|
||||||
|
const {
|
||||||
|
dataGrid,
|
||||||
|
handleReload: handleTableATCReload,
|
||||||
|
handleFilterChanged,
|
||||||
|
handleOrderChanged,
|
||||||
|
handlePagesCountChanged
|
||||||
|
} = useTableATC({
|
||||||
|
storedArgs: allFilters
|
||||||
|
});
|
||||||
|
|
||||||
|
//При изменении фильтра в диалоге
|
||||||
|
const handleFilterOk = async filter => {
|
||||||
|
//Обновляем фильтры
|
||||||
|
await handleFilterChange({ filter });
|
||||||
|
//Если указан общий и внутренний фильтр по подразделению
|
||||||
|
if (filter.sCustomerDept && filterCalcs.sDepartment) {
|
||||||
|
//Очищаем внутренний
|
||||||
|
setFilterCalcs({ sDepartment: null, ignoreReload: true });
|
||||||
|
}
|
||||||
|
//Закрываем диалог фильтра
|
||||||
|
setIsFilterOpen(false);
|
||||||
|
};
|
||||||
|
|
||||||
|
//При закрытии диалога фильтра
|
||||||
|
const handleFilterCancel = () => setIsFilterOpen(false);
|
||||||
|
|
||||||
|
//При открытии диалога фильтра
|
||||||
|
const handleFilterDialogOpen = () => setIsFilterOpen(true);
|
||||||
|
|
||||||
|
//При нажатии на элемент графика "Информация АТС"
|
||||||
|
const handleChartInfoClick = ({ item }) => {
|
||||||
|
setFilterInfo({ nState: item.NSTATE });
|
||||||
|
};
|
||||||
|
|
||||||
|
//При нажатии на элемент графика расчетов
|
||||||
|
const handleChartCalcsClick = ({ item }) => {
|
||||||
|
//Если подразделение не соответствует текущему
|
||||||
|
if (item.SCODE !== filterCalcs.sDepartment && !filterValues.sCustomerDept) setFilterCalcs({ sDepartment: item.SCODE });
|
||||||
|
};
|
||||||
|
|
||||||
|
//При изменении фильтра графика
|
||||||
|
const handleChartFilterChange = ({ chartName, filter }) => {
|
||||||
|
//При изменении фильтров графика "Информация АТС"
|
||||||
|
if (chartName === CHART_NAMES.info) {
|
||||||
|
setFilterInfo({ ...filter });
|
||||||
|
}
|
||||||
|
//При изменении фильтров графика расчетов
|
||||||
|
if (chartName === CHART_NAMES.calcs) setFilterCalcs({ ...filter });
|
||||||
|
};
|
||||||
|
|
||||||
|
//При изменении фильтра
|
||||||
|
useEffect(() => {
|
||||||
|
//Если фильтр установлен
|
||||||
|
if (!filtersInit) {
|
||||||
|
handleChartInfoReload();
|
||||||
|
handleChartCalcsReload();
|
||||||
|
handleTableATCReload();
|
||||||
|
}
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
|
}, [allFilters, filtersInit]);
|
||||||
|
|
||||||
|
//Генерация содержимого
|
||||||
|
return (
|
||||||
|
<Box p={1}>
|
||||||
|
{!filtersInit ? <Filter filter={filterValues} onFilterOpen={handleFilterDialogOpen} /> : null}
|
||||||
|
<Grid container spacing={1}>
|
||||||
|
{showCharts ? (
|
||||||
|
<>
|
||||||
|
<Grid item xs={6}>
|
||||||
|
<Paper elevation={3} sx={STYLES.CHART_PAPER}>
|
||||||
|
{hasValue(filterInfo.nState) ? (
|
||||||
|
<ChartFilter chartName={CHART_NAMES.info} filter={filterInfo} onFilterChange={handleChartFilterChange} />
|
||||||
|
) : null}
|
||||||
|
{chartInfo.loaded ? (
|
||||||
|
<P8PChart {...chartInfo} style={STYLES.CHART} onClick={handleChartInfoClick} legendPosition={"top"} />
|
||||||
|
) : null}
|
||||||
|
</Paper>
|
||||||
|
</Grid>
|
||||||
|
<Grid item xs={6}>
|
||||||
|
<Paper elevation={3} sx={STYLES.CHART_PAPER}>
|
||||||
|
{hasValue(filterCalcs.sDepartment) ? (
|
||||||
|
<ChartFilter chartName={CHART_NAMES.calcs} filter={filterCalcs} onFilterChange={handleChartFilterChange} />
|
||||||
|
) : null}
|
||||||
|
{chartCalcs.loaded ? (
|
||||||
|
<P8PChart
|
||||||
|
{...chartCalcs}
|
||||||
|
style={STYLES.CHART}
|
||||||
|
options={{
|
||||||
|
scales: {
|
||||||
|
x: {
|
||||||
|
stacked: true
|
||||||
|
},
|
||||||
|
y: {
|
||||||
|
stacked: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
legendPosition={"top"}
|
||||||
|
onClick={handleChartCalcsClick}
|
||||||
|
/>
|
||||||
|
) : null}
|
||||||
|
</Paper>
|
||||||
|
</Grid>
|
||||||
|
</>
|
||||||
|
) : null}
|
||||||
|
<Grid item xs={12}>
|
||||||
|
{dataGrid.dataLoaded ? (
|
||||||
|
<P8PDataGrid
|
||||||
|
{...P8P_DATA_GRID_CONFIG_PROPS}
|
||||||
|
{...dataGrid}
|
||||||
|
size={P8P_DATA_GRID_SIZE.LARGE}
|
||||||
|
containerComponentProps={{
|
||||||
|
sx: STYLES.TABLE_PROJECTS(
|
||||||
|
showCharts,
|
||||||
|
dataGrid.morePages,
|
||||||
|
(dataGrid.filters || []).length > 0,
|
||||||
|
hasValue(filterInfo.nState) || hasValue(filterCalcs.sDepartment)
|
||||||
|
)
|
||||||
|
}}
|
||||||
|
filtersInitial={dataGrid.filters}
|
||||||
|
onOrderChanged={handleOrderChanged}
|
||||||
|
onFilterChanged={handleFilterChanged}
|
||||||
|
onPagesCountChanged={handlePagesCountChanged}
|
||||||
|
valueFormatter={prms => valueFormatter({ ...prms, onRepairSheetOpen: handleEquipRepairSheetsOpen })}
|
||||||
|
/>
|
||||||
|
) : null}
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
{chartInfo.loaded && chartCalcs.loaded ? (
|
||||||
|
<Fab size="small" color="secondary" sx={STYLES.CHART_FAB} onClick={() => setShowCharts(!showCharts)}>
|
||||||
|
<Icon>{showCharts ? "expand_less" : "expand_more"}</Icon>
|
||||||
|
</Fab>
|
||||||
|
) : null}
|
||||||
|
{isFilterOpen && isFiltersLoaded ? (
|
||||||
|
<FilterDialog initial={filterValues} isFiltersInit={filtersInit} onOk={handleFilterOk} onCancel={handleFilterCancel} />
|
||||||
|
) : null}
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
//----------------
|
||||||
|
//Интерфейс модуля
|
||||||
|
//----------------
|
||||||
|
|
||||||
|
export { HaulerAnl };
|
||||||
91
hauler_anl/hooks/dict_hooks.js
Normal file
91
hauler_anl/hooks/dict_hooks.js
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
/*
|
||||||
|
Парус 8 - Панели мониторинга - ТОиР - Гаражка
|
||||||
|
Пользовательские хуки: Хуки открытия разделов
|
||||||
|
*/
|
||||||
|
|
||||||
|
//---------------------
|
||||||
|
//Подключение библиотек
|
||||||
|
//---------------------
|
||||||
|
|
||||||
|
import { useContext, useCallback } from "react"; //Классы React
|
||||||
|
import { ApplicationСtx } from "../../../context/application"; //Контекст приложения
|
||||||
|
|
||||||
|
//-----------
|
||||||
|
//Тело модуля
|
||||||
|
//-----------
|
||||||
|
|
||||||
|
//Состояние открытия разделов
|
||||||
|
const useDictionary = () => {
|
||||||
|
//Подключение к контексту приложения
|
||||||
|
const { pOnlineShowDictionary } = useContext(ApplicationСtx);
|
||||||
|
|
||||||
|
//Отображение раздела "Штатные подразделения"
|
||||||
|
const handleInsDepartmentOpen = useCallback(
|
||||||
|
async prms => {
|
||||||
|
pOnlineShowDictionary({
|
||||||
|
unitCode: "INS_DEPARTMENT",
|
||||||
|
inputParameters: [{ name: "in_CODE", value: prms.sCode }],
|
||||||
|
callBack: res => {
|
||||||
|
res.success ? prms.callBack(res) : null;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
[pOnlineShowDictionary]
|
||||||
|
);
|
||||||
|
|
||||||
|
//Отображение раздела "Типовые работы по техническому обслуживанию и ремонту"
|
||||||
|
const handleEquipTypeWorksOpen = useCallback(
|
||||||
|
async prms => {
|
||||||
|
pOnlineShowDictionary({
|
||||||
|
unitCode: "EquipTypeWorks",
|
||||||
|
inputParameters: [{ name: "in_CODE", value: prms.sCode }],
|
||||||
|
callBack: res => {
|
||||||
|
res.success ? prms.callBack(res) : null;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
[pOnlineShowDictionary]
|
||||||
|
);
|
||||||
|
|
||||||
|
//Отображение раздела "Виды работ по техническому обслуживанию и ремонту"
|
||||||
|
const handleEquipWorkKindsOpen = useCallback(
|
||||||
|
async prms => {
|
||||||
|
pOnlineShowDictionary({
|
||||||
|
unitCode: "EquipWorkKinds",
|
||||||
|
inputParameters: [{ name: "in_CODE", value: prms.sCode }],
|
||||||
|
callBack: res => {
|
||||||
|
res.success ? prms.callBack(res) : null;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
[pOnlineShowDictionary]
|
||||||
|
);
|
||||||
|
|
||||||
|
//Отображение раздела "Ремонтные ведомости"
|
||||||
|
const handleEquipRepairSheetsOpen = useCallback(
|
||||||
|
async prms => {
|
||||||
|
pOnlineShowDictionary({
|
||||||
|
unitCode: "EquipRepairSheets",
|
||||||
|
inputParameters: [{ name: "in_RN", value: prms.nRn }],
|
||||||
|
callBack: res => {
|
||||||
|
res.success ? prms.callBack(res) : null;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
[pOnlineShowDictionary]
|
||||||
|
);
|
||||||
|
|
||||||
|
//Возвращаем функции открытия разделов
|
||||||
|
return {
|
||||||
|
handleInsDepartmentOpen,
|
||||||
|
handleEquipTypeWorksOpen,
|
||||||
|
handleEquipWorkKindsOpen,
|
||||||
|
handleEquipRepairSheetsOpen
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
//----------------
|
||||||
|
//Интерфейс модуля
|
||||||
|
//----------------
|
||||||
|
|
||||||
|
export { useDictionary };
|
||||||
92
hauler_anl/hooks/filter_hooks.js
Normal file
92
hauler_anl/hooks/filter_hooks.js
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
/*
|
||||||
|
Парус 8 - Панели мониторинга - ТОиР - Гаражка
|
||||||
|
Пользовательские хуки: Хуки фильтров
|
||||||
|
*/
|
||||||
|
|
||||||
|
//---------------------
|
||||||
|
//Подключение библиотек
|
||||||
|
//---------------------
|
||||||
|
|
||||||
|
import { useState, useContext, useCallback, useEffect } from "react"; //Классы React
|
||||||
|
import { BackEndСtx } from "../../../context/backend"; //Контекст взаимодействия с сервером
|
||||||
|
import { object2Base64XML } from "../../../core/utils"; //Вспомогательные функции
|
||||||
|
|
||||||
|
//-----------
|
||||||
|
//Тело модуля
|
||||||
|
//-----------
|
||||||
|
|
||||||
|
//Состояние открытия разделов
|
||||||
|
const useFilters = () => {
|
||||||
|
//Собственное состояние - общие значения фильтров
|
||||||
|
const [filterValues, setFilterValues] = useState({
|
||||||
|
loaded: false,
|
||||||
|
dDate: "",
|
||||||
|
sCustomerDept: "",
|
||||||
|
dDateKOAFrom: "",
|
||||||
|
dDateKOATo: ""
|
||||||
|
});
|
||||||
|
|
||||||
|
//Собственное состояние - признак загрузки настроек
|
||||||
|
const [isFiltersLoaded, setIsFiltersLoaded] = useState(false);
|
||||||
|
|
||||||
|
//Собственное состояние - признак инициализации
|
||||||
|
const [filtersInit, setFiltersInit] = useState(true);
|
||||||
|
|
||||||
|
//Подключение к контексту взаимодействия с сервером
|
||||||
|
const { executeStored, SERV_DATA_TYPE_CLOB } = useContext(BackEndСtx);
|
||||||
|
|
||||||
|
//При изменении фильтров
|
||||||
|
const handleChange = useCallback(
|
||||||
|
async ({ filter }) => {
|
||||||
|
//Формируем новые фильтры
|
||||||
|
const newFilters = { ...filterValues, ...filter };
|
||||||
|
|
||||||
|
//Если фильтры изменились - обновим их
|
||||||
|
if (JSON.stringify(filterValues) != JSON.stringify(newFilters)) {
|
||||||
|
await executeStored({
|
||||||
|
stored: "UDO_PKG_P8PANELS_USETTINGS.SETTINGS_SET",
|
||||||
|
args: {
|
||||||
|
SPANEL: "hauler_anl",
|
||||||
|
CSETTINGS: {
|
||||||
|
VALUE: object2Base64XML(newFilters, { arrayNodeName: "filters" }),
|
||||||
|
SDATA_TYPE: SERV_DATA_TYPE_CLOB
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
setFilterValues({ ...newFilters });
|
||||||
|
}
|
||||||
|
|
||||||
|
//Это не инициализация
|
||||||
|
filtersInit ? setFiltersInit(false) : false;
|
||||||
|
},
|
||||||
|
[SERV_DATA_TYPE_CLOB, executeStored, filterValues, filtersInit]
|
||||||
|
);
|
||||||
|
|
||||||
|
//При загрузке панели
|
||||||
|
useEffect(() => {
|
||||||
|
//Загрузка настроек с сервера
|
||||||
|
const loadSettings = async () => {
|
||||||
|
try {
|
||||||
|
const data = await executeStored({
|
||||||
|
stored: "UDO_PKG_P8PANELS_USETTINGS.SETTINGS_GET",
|
||||||
|
args: { SPANEL: "hauler_anl" },
|
||||||
|
respArg: "COUT"
|
||||||
|
});
|
||||||
|
//Если есть настройки - указываем
|
||||||
|
if (data) setFilterValues({ ...data });
|
||||||
|
} finally {
|
||||||
|
setIsFiltersLoaded(true);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if (!isFiltersLoaded) loadSettings();
|
||||||
|
}, [executeStored, isFiltersLoaded]);
|
||||||
|
|
||||||
|
//Возвращаем функции открытия разделов
|
||||||
|
return [filterValues, isFiltersLoaded, filtersInit, handleChange];
|
||||||
|
};
|
||||||
|
|
||||||
|
//----------------
|
||||||
|
//Интерфейс модуля
|
||||||
|
//----------------
|
||||||
|
|
||||||
|
export { useFilters };
|
||||||
184
hauler_anl/hooks/hooks.js
Normal file
184
hauler_anl/hooks/hooks.js
Normal file
@ -0,0 +1,184 @@
|
|||||||
|
/*
|
||||||
|
Парус 8 - Панели мониторинга - ТОиР - Гаражка
|
||||||
|
Пользовательские хуки: Хуки основных компонентов
|
||||||
|
*/
|
||||||
|
|
||||||
|
//---------------------
|
||||||
|
//Подключение библиотек
|
||||||
|
//---------------------
|
||||||
|
|
||||||
|
import { useState, useContext, useCallback, useEffect } from "react"; //Классы React
|
||||||
|
import { BackEndСtx } from "../../../context/backend"; //Контекст взаимодействия с сервером
|
||||||
|
import { object2Base64XML, formatDateRF } from "../../../core/utils";
|
||||||
|
|
||||||
|
//--------------------------
|
||||||
|
//Вспомогательные компоненты
|
||||||
|
//--------------------------
|
||||||
|
|
||||||
|
//-----------
|
||||||
|
//Тело модуля
|
||||||
|
//-----------
|
||||||
|
|
||||||
|
//Хук графика АТС
|
||||||
|
const useChartInfo = ({ storedArgs = {} }) => {
|
||||||
|
//Собственное состояние - график
|
||||||
|
const [chartInfo, setChartInfo] = useState({ loaded: false, reload: false });
|
||||||
|
|
||||||
|
//Подключение к контексту взаимодействия с сервером
|
||||||
|
const { executeStored } = useContext(BackEndСtx);
|
||||||
|
|
||||||
|
//При необходимости перезагрузки графика
|
||||||
|
const handleReload = useCallback(() => setChartInfo(pv => ({ ...pv, reload: true })), []);
|
||||||
|
|
||||||
|
//При подключении к странице
|
||||||
|
useEffect(() => {
|
||||||
|
//Загрузка данных графика с сервера
|
||||||
|
const loadChart = async () => {
|
||||||
|
try {
|
||||||
|
const chart = await executeStored({
|
||||||
|
stored: "UDO_PKG_P8PANELS_HAULER_ANL.CHART_ATC_INFO",
|
||||||
|
args: {
|
||||||
|
DDATE: storedArgs.dDate ? new Date(storedArgs.dDate) : null,
|
||||||
|
SDEPARTMENT: storedArgs.sCustomerDept || storedArgs.sDepartment,
|
||||||
|
NSTATE: storedArgs.nState
|
||||||
|
},
|
||||||
|
respArg: "COUT"
|
||||||
|
});
|
||||||
|
setChartInfo(pv => ({ ...pv, loaded: true, reload: false, ...chart.XCHART }));
|
||||||
|
} catch (e) {
|
||||||
|
setChartInfo(pv => ({ ...pv, loaded: false, reload: false }));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
//При необходимости перезагрузить
|
||||||
|
if (chartInfo.reload) loadChart();
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
|
}, [chartInfo.reload, executeStored]);
|
||||||
|
|
||||||
|
//Возвращаем график
|
||||||
|
return { chartInfo, handleReload };
|
||||||
|
};
|
||||||
|
|
||||||
|
//Хук графика КГТ/КОА
|
||||||
|
const useChartCalcs = ({ storedArgs = {} }) => {
|
||||||
|
//Собственное состояние - график
|
||||||
|
const [chartCalcs, setChartCalcs] = useState({ loaded: false, reload: false });
|
||||||
|
|
||||||
|
//Подключение к контексту взаимодействия с сервером
|
||||||
|
const { executeStored } = useContext(BackEndСtx);
|
||||||
|
|
||||||
|
//При необходимости перезагрузки графика
|
||||||
|
const handleReload = useCallback(() => setChartCalcs(pv => ({ ...pv, reload: true })), []);
|
||||||
|
|
||||||
|
//При подключении к странице
|
||||||
|
useEffect(() => {
|
||||||
|
//Загрузка данных графика с сервера
|
||||||
|
const loadChart = async () => {
|
||||||
|
try {
|
||||||
|
const chart = await executeStored({
|
||||||
|
stored: "UDO_PKG_P8PANELS_HAULER_ANL.CHART_ATC_KGT_KOA",
|
||||||
|
args: {
|
||||||
|
SDEPARTMENT: storedArgs.sCustomerDept || storedArgs.sDepartment,
|
||||||
|
DDATE_KOA_FROM: storedArgs.dDateKOAFrom ? new Date(storedArgs.dDateKOAFrom) : null,
|
||||||
|
DDATE_KOA_TO: storedArgs.dDateKOATo ? new Date(storedArgs.dDateKOATo) : null,
|
||||||
|
DDATE: storedArgs.dDate ? new Date(storedArgs.dDate) : null,
|
||||||
|
NSTATE: storedArgs.nState
|
||||||
|
},
|
||||||
|
respArg: "COUT"
|
||||||
|
});
|
||||||
|
setChartCalcs(pv => ({
|
||||||
|
...pv,
|
||||||
|
loaded: true,
|
||||||
|
reload: false,
|
||||||
|
labels: chart.XCHART?.labels ? [...chart.XCHART.labels] : [],
|
||||||
|
...chart.XCHART
|
||||||
|
}));
|
||||||
|
} catch (e) {
|
||||||
|
setChartCalcs(pv => ({ ...pv, loaded: false, reload: false }));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
//При необходимости перезагрузить
|
||||||
|
if (chartCalcs.reload) loadChart();
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
|
}, [chartCalcs.reload, executeStored]);
|
||||||
|
|
||||||
|
//Возвращаем график
|
||||||
|
return { chartCalcs, handleReload };
|
||||||
|
};
|
||||||
|
|
||||||
|
//Хук таблицы АТС
|
||||||
|
const useTableATC = ({ storedArgs = {} }) => {
|
||||||
|
//Собственное состояние - таблица
|
||||||
|
const [dataGrid, setDataGrid] = useState({
|
||||||
|
dataLoaded: false,
|
||||||
|
filters: [],
|
||||||
|
orders: null,
|
||||||
|
pageNumber: 1,
|
||||||
|
morePages: true,
|
||||||
|
reloading: false
|
||||||
|
});
|
||||||
|
|
||||||
|
//Подключение к контексту взаимодействия с сервером
|
||||||
|
const { executeStored, SERV_DATA_TYPE_CLOB } = useContext(BackEndСtx);
|
||||||
|
|
||||||
|
//При изменении состояния фильтра
|
||||||
|
const handleFilterChanged = ({ filters }) => setDataGrid(pv => ({ ...pv, filters: [...filters], pageNumber: 1, reloading: true }));
|
||||||
|
|
||||||
|
//При изменении состояния сортировки
|
||||||
|
const handleOrderChanged = ({ orders }) => setDataGrid(pv => ({ ...pv, orders: [...orders], pageNumber: 1, reloading: true }));
|
||||||
|
|
||||||
|
//При изменении количества отображаемых страниц
|
||||||
|
const handlePagesCountChanged = () => setDataGrid(pv => ({ ...pv, pageNumber: pv.pageNumber + 1, reloading: true }));
|
||||||
|
|
||||||
|
//При необходимости перезагрузки таблицы
|
||||||
|
const handleReload = () => setDataGrid(pv => ({ ...pv, pageNumber: 1, reloading: true }));
|
||||||
|
|
||||||
|
//При подключении к странице
|
||||||
|
useEffect(() => {
|
||||||
|
//Загрузка данных графика с сервера
|
||||||
|
const loadDataGrid = async () => {
|
||||||
|
try {
|
||||||
|
const data = await executeStored({
|
||||||
|
stored: "UDO_PKG_P8PANELS_HAULER_ANL.DATA_GRID_ATC",
|
||||||
|
args: {
|
||||||
|
CFILTERS: { VALUE: object2Base64XML(dataGrid.filters, { arrayNodeName: "filters" }), SDATA_TYPE: SERV_DATA_TYPE_CLOB },
|
||||||
|
CORDERS: { VALUE: object2Base64XML(dataGrid.orders, { arrayNodeName: "orders" }), SDATA_TYPE: SERV_DATA_TYPE_CLOB },
|
||||||
|
NPAGE_NUMBER: dataGrid.pageNumber,
|
||||||
|
NPAGE_SIZE: 10,
|
||||||
|
NINCLUDE_DEF: dataGrid.dataLoaded ? 0 : 1,
|
||||||
|
DDATE: storedArgs.dDate ? new Date(storedArgs.dDate) : null,
|
||||||
|
DDATE_KOA_FROM: storedArgs.dDateKOAFrom ? new Date(storedArgs.dDateKOAFrom) : null,
|
||||||
|
DDATE_KOA_TO: storedArgs.dDateKOATo ? new Date(storedArgs.dDateKOATo) : null,
|
||||||
|
SDEPARTMENT: storedArgs.sCustomerDept || storedArgs.sDepartment,
|
||||||
|
NSTATE: storedArgs.nState
|
||||||
|
},
|
||||||
|
attributeValueProcessor: (name, val) => (["DDOCDATE", "DDATEFACT_BEG", "DDATEFACT_END"].includes(name) ? formatDateRF(val) : val),
|
||||||
|
respArg: "COUT"
|
||||||
|
});
|
||||||
|
setDataGrid(pv => ({
|
||||||
|
...pv,
|
||||||
|
...data.XDATA_GRID,
|
||||||
|
columnsDef: data.XDATA_GRID.columnsDef ? [...data.XDATA_GRID.columnsDef] : pv.columnsDef || [],
|
||||||
|
rows: pv.pageNumber == 1 ? [...(data.XDATA_GRID.rows || [])] : [...(pv.rows || []), ...(data.XDATA_GRID.rows || [])],
|
||||||
|
dataLoaded: true,
|
||||||
|
reloading: false,
|
||||||
|
morePages: (data.XDATA_GRID.rows || []).length >= 10
|
||||||
|
}));
|
||||||
|
} catch (e) {
|
||||||
|
console.log(e);
|
||||||
|
setDataGrid(pv => ({ ...pv, loaded: false, reload: false }));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
//При необходимости перезагрузить
|
||||||
|
if (dataGrid.reloading) loadDataGrid();
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
|
}, [dataGrid.reloading, executeStored]);
|
||||||
|
|
||||||
|
//Возвращаем график
|
||||||
|
return { dataGrid, handleReload, handleFilterChanged, handleOrderChanged, handlePagesCountChanged };
|
||||||
|
};
|
||||||
|
|
||||||
|
//----------------
|
||||||
|
//Интерфейс модуля
|
||||||
|
//----------------
|
||||||
|
|
||||||
|
export { useChartInfo, useChartCalcs, useTableATC };
|
||||||
16
hauler_anl/index.js
Normal file
16
hauler_anl/index.js
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
/*
|
||||||
|
Парус 8 - Панели мониторинга - ТОиР - Гаражка
|
||||||
|
Панель мониторинга: Точка входа
|
||||||
|
*/
|
||||||
|
|
||||||
|
//---------------------
|
||||||
|
//Подключение библиотек
|
||||||
|
//---------------------
|
||||||
|
|
||||||
|
import { HaulerAnl } from "./hauler_anl"; //Корневая панель гаражки
|
||||||
|
|
||||||
|
//----------------
|
||||||
|
//Интерфейс модуля
|
||||||
|
//----------------
|
||||||
|
|
||||||
|
export const RootClass = HaulerAnl;
|
||||||
111
hauler_anl/layouts.js
Normal file
111
hauler_anl/layouts.js
Normal file
@ -0,0 +1,111 @@
|
|||||||
|
/*
|
||||||
|
Парус 8 - Панели мониторинга - ТОиР - Гаражка
|
||||||
|
Дополнительная разметка и вёрстка клиентских элементов
|
||||||
|
*/
|
||||||
|
|
||||||
|
//---------------------
|
||||||
|
//Подключение библиотек
|
||||||
|
//---------------------
|
||||||
|
|
||||||
|
import React from "react"; //Классы React
|
||||||
|
import { Icon, Stack, Link, Typography } from "@mui/material"; //Интерфейсные компоненты
|
||||||
|
import { hasValue, formatDateRF } from "../../core/utils"; //Вспомогательные функции
|
||||||
|
|
||||||
|
//---------
|
||||||
|
//Константы
|
||||||
|
//---------
|
||||||
|
|
||||||
|
//Маска разделителя
|
||||||
|
const SMASK_SEPARATE = "<|>";
|
||||||
|
|
||||||
|
//-----------
|
||||||
|
//Тело модуля
|
||||||
|
//-----------
|
||||||
|
|
||||||
|
//Формирование значения для колонки "Состояние"
|
||||||
|
const formatStateValue = (value, addText = false) => {
|
||||||
|
const [text, icon] = value == 0 ? ["На линии", "done"] : value == 1 ? ["Ремонт", "build"] : ["Не определен", "question_mark"];
|
||||||
|
return (
|
||||||
|
<Stack direction="row" gap={0.5} alignItems="center" justifyContent="center">
|
||||||
|
<Icon title={text}>{icon}</Icon>
|
||||||
|
{addText == true ? text : null}
|
||||||
|
</Stack>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
//Формирование списка значений
|
||||||
|
const formatListValue = value => {
|
||||||
|
//Считываем массив значений
|
||||||
|
const listValues = hasValue(value) ? value.split(SMASK_SEPARATE) : [];
|
||||||
|
//Формируем список значений
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{listValues.length !== 0 ? (
|
||||||
|
<Stack direction="column" gap={0.5} alignItems="flex-start" justifyContent="center">
|
||||||
|
{listValues.map((el, index) => {
|
||||||
|
return <Typography variant="body2" key={index}>{`${el}`}</Typography>;
|
||||||
|
})}
|
||||||
|
</Stack>
|
||||||
|
) : null}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
//Формирование значения для колонки "Документ ремонта"
|
||||||
|
const formatRepairDocValue = (value, onRepairSheetOpen) => {
|
||||||
|
//Считываем массив документов
|
||||||
|
const listDocs = hasValue(value) ? value.split(SMASK_SEPARATE) : [];
|
||||||
|
//Формируем список документов с ссылкой
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{listDocs.length !== 0 ? (
|
||||||
|
<Stack direction="column" gap={0.5} alignItems="flex-start" justifyContent="center">
|
||||||
|
{listDocs.map((el, index) => {
|
||||||
|
//Считываем рег. номер
|
||||||
|
const rn = el.match(/<(.*?)>/)[1];
|
||||||
|
//Считываем информацию о документе
|
||||||
|
const docInfo = el.replace(`<${rn}>`, "");
|
||||||
|
//Формируем ссылку на документ
|
||||||
|
return (
|
||||||
|
<Link
|
||||||
|
component="button"
|
||||||
|
align="left"
|
||||||
|
variant="body2"
|
||||||
|
underline="hover"
|
||||||
|
onClick={() => onRepairSheetOpen({ nRn: rn })}
|
||||||
|
key={index}
|
||||||
|
>
|
||||||
|
{docInfo}
|
||||||
|
</Link>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</Stack>
|
||||||
|
) : null}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
//Форматирование значений колонок
|
||||||
|
export const valueFormatter = ({ value, columnDef, onRepairSheetOpen }) => {
|
||||||
|
switch (columnDef.name) {
|
||||||
|
case "NSTATE":
|
||||||
|
return formatStateValue(value, false);
|
||||||
|
case "SDAMTYPE_NAME":
|
||||||
|
return formatListValue(value);
|
||||||
|
case "SEQDAMCTRL_NOTE":
|
||||||
|
return formatListValue(value);
|
||||||
|
case "SDRIVER":
|
||||||
|
return formatListValue(value);
|
||||||
|
case "SREPAIR_DOC":
|
||||||
|
return formatRepairDocValue(value, onRepairSheetOpen);
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
};
|
||||||
|
|
||||||
|
//Форматирование фильтров панелей для фильтров таблицы
|
||||||
|
export const formatFilterValues = filter => {
|
||||||
|
return [
|
||||||
|
{ name: "DDATE", from: formatDateRF(filter.dDate), to: formatDateRF(filter.dDate) },
|
||||||
|
{ name: "SCUSTOMERDEPT_FILTER", from: filter.sCustomerDept, to: "" }
|
||||||
|
];
|
||||||
|
};
|
||||||
12544
p8-panels.js
Normal file
12544
p8-panels.js
Normal file
File diff suppressed because one or more lines are too long
222
p8panels.config
Normal file
222
p8panels.config
Normal file
@ -0,0 +1,222 @@
|
|||||||
|
<?xml version="1.0"?>
|
||||||
|
<CITK.P8Panels>
|
||||||
|
<MenuItems>
|
||||||
|
<App name="ProjectPlanning">
|
||||||
|
<MenuItem parent="{BA073333-DFBC-4BA3-8EA7-172F3F6B4FEE}" separator="true"/>
|
||||||
|
<MenuItem parent="{BA073333-DFBC-4BA3-8EA7-172F3F6B4FEE}" name="ShowPrjPanelsRoot" caption="Панели мониторинга" url="Modules/P8-Panels/"/>
|
||||||
|
<MenuItem parent="{BA073333-DFBC-4BA3-8EA7-172F3F6B4FEE}" separator="true"/>
|
||||||
|
<MenuItem parent="{BA073333-DFBC-4BA3-8EA7-172F3F6B4FEE}" name="ShowPrjPanelFin" caption="Экономика проектов" panelName="PrjFin"/>
|
||||||
|
<MenuItem parent="{BA073333-DFBC-4BA3-8EA7-172F3F6B4FEE}" name="ShowPrjPanelJob" caption="Работы проектов" panelName="PrjJobs"/>
|
||||||
|
<MenuItem parent="{BA073333-DFBC-4BA3-8EA7-172F3F6B4FEE}" name="ShowPrjPanelGraph" caption="Графики проектов" panelName="PrjGraph"/>
|
||||||
|
<MenuItem parent="{BA073333-DFBC-4BA3-8EA7-172F3F6B4FEE}" name="ShowPrjPanelInfo" caption="Информация о проектах" panelName="PrjInfo"/>
|
||||||
|
<MenuItem parent="{BA073333-DFBC-4BA3-8EA7-172F3F6B4FEE}" name="ShowPrjPanelHelp" caption="Инструкции ПУП" panelName="PrjHelp"/>
|
||||||
|
</App>
|
||||||
|
<App name="EquipSrv">
|
||||||
|
<MenuItem parent="{BA073333-DFBC-4BA3-8EA7-172F3F6B4FEE}" separator="true"/>
|
||||||
|
<MenuItem parent="{BA073333-DFBC-4BA3-8EA7-172F3F6B4FEE}" name="ShowEqsPanelsRoot" caption="Панели мониторинга" url="Modules/P8-Panels/"/>
|
||||||
|
<MenuItem parent="{BA073333-DFBC-4BA3-8EA7-172F3F6B4FEE}" separator="true"/>
|
||||||
|
<MenuItem parent="{BA073333-DFBC-4BA3-8EA7-172F3F6B4FEE}" name="ShowEqsPrfrm" caption="Выполнение работ по ТОиР" panelName="EqsPrfrm"/>
|
||||||
|
<MenuItem parent="{BA073333-DFBC-4BA3-8EA7-172F3F6B4FEE}" name="ShowRepairAnlATC" caption="Аналитика по ремонтам АТС" panelName="RepairAnlATC"/>
|
||||||
|
<MenuItem parent="{BA073333-DFBC-4BA3-8EA7-172F3F6B4FEE}" name="ShowHaulerAnl" caption="Гаражка" panelName="HaulerAnl"/>
|
||||||
|
</App>
|
||||||
|
<App name="MechanicalRecords">
|
||||||
|
<MenuItem parent="{BA073333-DFBC-4BA3-8EA7-172F3F6B4FEE}" separator="true"/>
|
||||||
|
<MenuItem parent="{BA073333-DFBC-4BA3-8EA7-172F3F6B4FEE}" name="ShowMechRecPanelsRoot" caption="Панели мониторинга" url="Modules/P8-Panels/"/>
|
||||||
|
<MenuItem parent="{BA073333-DFBC-4BA3-8EA7-172F3F6B4FEE}" separator="true"/>
|
||||||
|
<MenuItem parent="{BA073333-DFBC-4BA3-8EA7-172F3F6B4FEE}" name="ShowMechRecPanelCostProdPlans" caption="Производственная программа" panelName="MechRecCostProdPlans"/>
|
||||||
|
<MenuItem parent="{BA073333-DFBC-4BA3-8EA7-172F3F6B4FEE}" name="ShowMechRecPanelDeptCostProdPlans" caption="Производственный план цеха" panelName="MechRecDeptCostProdPlans"/>
|
||||||
|
<MenuItem parent="{BA073333-DFBC-4BA3-8EA7-172F3F6B4FEE}" name="ShowMechRecPanelDeptCostJobsManage" caption="Выдача сменного задания" panelName="MechRecCostJobsManage"/>
|
||||||
|
<MenuItem parent="{BA073333-DFBC-4BA3-8EA7-172F3F6B4FEE}" name="ShowMechRecPanelDeptCostJobs" caption="Загрузка цеха" panelName="MechRecDeptCostJobs"/>
|
||||||
|
<MenuItem parent="{BA073333-DFBC-4BA3-8EA7-172F3F6B4FEE}" name="ShowMechRecPanelAssemblyMon" caption="Мониторинг сборки изделий" panelName="MechRecAssemblyMon"/>
|
||||||
|
<MenuItem parent="{BA073333-DFBC-4BA3-8EA7-172F3F6B4FEE}" name="ShowMechRecPanelHelp" caption="Руководство "Оперативное управление производством"" panelName="MechRecHelp"/>
|
||||||
|
</App>
|
||||||
|
<App name="Client">
|
||||||
|
<MenuItem parent="{BA073333-DFBC-4BA3-8EA7-172F3F6B4FEE}" separator="true"/>
|
||||||
|
<MenuItem parent="{BA073333-DFBC-4BA3-8EA7-172F3F6B4FEE}" name="ShowClntPanelsRoot" caption="Панели мониторинга" url="Modules/P8-Panels/"/>
|
||||||
|
<MenuItem parent="{CA9A9853-AC90-412A-85B1-E39927147846}" separator="true"/>
|
||||||
|
<MenuItem parent="{CA9A9853-AC90-412A-85B1-E39927147846}" name="ShowClntTaskBoard" caption="Доски задач" panelName="ClntTaskBoard"/>
|
||||||
|
</App>
|
||||||
|
</MenuItems>
|
||||||
|
<Panels urlBase="Modules/P8-Panels/#/">
|
||||||
|
<Panel
|
||||||
|
name="PrjFin"
|
||||||
|
group="Планирование и учёт в проектах"
|
||||||
|
caption="Экономика проектов"
|
||||||
|
desc="Мониторинг калькуляции проекта, графиков финансирования, договоров с поставщиками материалов и ПКИ"
|
||||||
|
url="prj_fin"
|
||||||
|
path="prj_fin"
|
||||||
|
icon="bar_chart"
|
||||||
|
showInPanelsList="true"
|
||||||
|
preview="./img/prj_fin.png"/>
|
||||||
|
<Panel
|
||||||
|
name="PrjJobs"
|
||||||
|
group="Планирование и учёт в проектах"
|
||||||
|
caption="Работы проектов"
|
||||||
|
desc="Управление и контроль сроков выполнения собственных работ по проектам"
|
||||||
|
url="prj_jobs"
|
||||||
|
path="prj_jobs"
|
||||||
|
icon="engineering"
|
||||||
|
showInPanelsList="true"
|
||||||
|
preview="./img/prj_jobs.jpg"/>
|
||||||
|
<Panel
|
||||||
|
name="PrjGraph"
|
||||||
|
group="Планирование и учёт в проектах"
|
||||||
|
caption="Графики проектов"
|
||||||
|
desc="Сводный график выполнения активных проектов компании"
|
||||||
|
url="prj_graph"
|
||||||
|
path="prj_graph"
|
||||||
|
icon="insights"
|
||||||
|
showInPanelsList="true"
|
||||||
|
preview="./img/prj_graph.jpg"/>
|
||||||
|
<Panel
|
||||||
|
name="PrjInfo"
|
||||||
|
group="Планирование и учёт в проектах"
|
||||||
|
caption="Информация о проектах"
|
||||||
|
desc="Информация о проектах"
|
||||||
|
url="prj_info"
|
||||||
|
path="prj_info"
|
||||||
|
icon="featured_play_list"
|
||||||
|
showInPanelsList="true"
|
||||||
|
preview="./img/prj_info.jpg"/>
|
||||||
|
<Panel
|
||||||
|
name="PrjHelp"
|
||||||
|
group="Планирование и учёт в проектах"
|
||||||
|
caption="Инструкции ПУП"
|
||||||
|
desc="Краткое описание работы с макетом "Управление экономикой проектов""
|
||||||
|
url="prj_help"
|
||||||
|
path="prj_help"
|
||||||
|
icon="help_outline"
|
||||||
|
showInPanelsList="true"
|
||||||
|
preview="./img/help.jpg"/>
|
||||||
|
<Panel
|
||||||
|
name="EqsPrfrm"
|
||||||
|
group="Управление техническим обслуживанием и ремонтами"
|
||||||
|
caption="Выполнение работ по ТОиР"
|
||||||
|
desc="Визуализация запланированных и выполненных работ по ТОиР предприятия (подразделения) по месяцам и дням года"
|
||||||
|
url="eqs_prfrm"
|
||||||
|
path="eqs_prfrm"
|
||||||
|
icon="build"
|
||||||
|
showInPanelsList="true"
|
||||||
|
preview="./img/eqs_prfrm.jpg"/>
|
||||||
|
<Panel
|
||||||
|
name="MechRecCostProdPlans"
|
||||||
|
group="Планирование и учёт в дискретном производстве"
|
||||||
|
caption="Производственная программа"
|
||||||
|
desc="Контроль исполнения производственной программы по срокам и количеству запуска и выпуска ДСЕ"
|
||||||
|
url="mech_rec_cost_prod_plans"
|
||||||
|
path="mech_rec_cost_prod_plans"
|
||||||
|
icon="calendar_month"
|
||||||
|
showInPanelsList="true"
|
||||||
|
preview="./img/mech_rec_cost_prod_plans.jpg"/>
|
||||||
|
<Panel
|
||||||
|
name="MechRecDeptCostProdPlans"
|
||||||
|
group="Планирование и учёт в дискретном производстве"
|
||||||
|
caption="Производственный план цеха"
|
||||||
|
desc="Мониторинг и управление (установка приоритетов партий, заказов) производственным планом цеха"
|
||||||
|
url="mech_rec_dept_cost_prod_plans"
|
||||||
|
path="mech_rec_dept_cost_prod_plans"
|
||||||
|
icon="free_cancellation"
|
||||||
|
showInPanelsList="true"
|
||||||
|
preview="./img/mech_rec_dept_cost_prod_plans.jpg"/>
|
||||||
|
<Panel
|
||||||
|
name="MechRecCostJobsManage"
|
||||||
|
group="Планирование и учёт в дискретном производстве"
|
||||||
|
caption="Выдача сменного задания"
|
||||||
|
desc="Управление составом сменных заданий цеха/участка"
|
||||||
|
url="mech_rec_cost_jobs_manage"
|
||||||
|
path="mech_rec_cost_jobs_manage"
|
||||||
|
icon="psychology"
|
||||||
|
showInPanelsList="true"
|
||||||
|
preview="./img/mech_rec_cost_jobs_manage.jpg"/>
|
||||||
|
<Panel
|
||||||
|
name="MechRecCostJobsManageMP"
|
||||||
|
group="Планирование и учёт в дискретном производстве"
|
||||||
|
caption="Выдача сменного задания на участок"
|
||||||
|
desc="Управление составом сменных заданий трудового ресурса"
|
||||||
|
url="mech_rec_cost_jobs_manage_mp"
|
||||||
|
path="mech_rec_cost_jobs_manage_mp"
|
||||||
|
icon=""
|
||||||
|
showInPanelsList="false"
|
||||||
|
preview=""/>
|
||||||
|
<Panel
|
||||||
|
name="MechRecDeptCostJobs"
|
||||||
|
group="Планирование и учёт в дискретном производстве"
|
||||||
|
caption="Загрузка цеха"
|
||||||
|
desc="Просмотр сведений о производственной загрузке цеха/участка"
|
||||||
|
url="mech_rec_dept_cost_jobs"
|
||||||
|
path="mech_rec_dept_cost_jobs"
|
||||||
|
icon="factory"
|
||||||
|
showInPanelsList="true"
|
||||||
|
preview="./img/mech_rec_dept_cost_jobs.jpg"/>
|
||||||
|
<Panel
|
||||||
|
name="MechRecAssemblyMon"
|
||||||
|
group="Планирование и учёт в дискретном производстве"
|
||||||
|
caption="Мониторинг сборки изделий"
|
||||||
|
desc="Отображение текущего состояния комплектации и сборки изделий производственными подразделениями"
|
||||||
|
url="mech_rec_assembly_mon"
|
||||||
|
path="mech_rec_assembly_mon"
|
||||||
|
icon="monitor_heart"
|
||||||
|
showInPanelsList="true"
|
||||||
|
preview="./img/mech_rec_assembly_mon.jpg"/>
|
||||||
|
<Panel
|
||||||
|
name="MechRecHelp"
|
||||||
|
group="Планирование и учёт в дискретном производстве"
|
||||||
|
caption="Руководство "Оперативное управление производством""
|
||||||
|
desc="Краткое описание работы с макетом "Оперативное управление производством""
|
||||||
|
url="mech_rec_help"
|
||||||
|
path="mech_rec_help"
|
||||||
|
icon="help_outline"
|
||||||
|
showInPanelsList="true"
|
||||||
|
preview="./img/help.jpg"/>
|
||||||
|
<Panel
|
||||||
|
name="Samples"
|
||||||
|
group=""
|
||||||
|
caption="Примеры для разработчиков"
|
||||||
|
desc="Примеры из README.md"
|
||||||
|
url="samples"
|
||||||
|
path="samples"
|
||||||
|
icon="javascript"
|
||||||
|
showInPanelsList="true"
|
||||||
|
preview="./img/default_preview.png"/>
|
||||||
|
<Panel
|
||||||
|
name="RrpConfEditor"
|
||||||
|
group=""
|
||||||
|
caption="Редактор настройки регламентированного отчёта"
|
||||||
|
desc=""
|
||||||
|
url="rrp_conf_editor"
|
||||||
|
path="rrp_conf_editor"
|
||||||
|
icon=""
|
||||||
|
showInPanelsList="false"
|
||||||
|
preview=""/>
|
||||||
|
<Panel
|
||||||
|
name="ClntTaskBoard"
|
||||||
|
group="Управление деловыми процессами"
|
||||||
|
caption="Доски задач"
|
||||||
|
desc="Мониторинг и управление назначенными задачами на Канбан-доске"
|
||||||
|
url="clnt_task_board"
|
||||||
|
path="clnt_task_board"
|
||||||
|
icon="dashboard_customize"
|
||||||
|
showInPanelsList="true"
|
||||||
|
preview="./img/clnt_task_board.jpg"/>
|
||||||
|
<Panel
|
||||||
|
name="RepairAnlATC"
|
||||||
|
group="Управление техническим обслуживанием и ремонтами"
|
||||||
|
caption="Аналитика по ремонтам АТС"
|
||||||
|
desc="Аналитика по ремонтам АТС"
|
||||||
|
url="repair_anl_atc"
|
||||||
|
path="repair_anl_atc"
|
||||||
|
icon="home_repair_service"
|
||||||
|
showInPanelsList="true"
|
||||||
|
preview="./img/default_preview.png"/>
|
||||||
|
<Panel
|
||||||
|
name="HaulerAnl"
|
||||||
|
group="Управление техническим обслуживанием и ремонтами"
|
||||||
|
caption="Гаражка"
|
||||||
|
desc="Гаражка"
|
||||||
|
url="hauler_anl"
|
||||||
|
path="hauler_anl"
|
||||||
|
icon="warehouse"
|
||||||
|
showInPanelsList="true"
|
||||||
|
preview="./img/default_preview.png"/>
|
||||||
|
</Panels>
|
||||||
|
</CITK.P8Panels>
|
||||||
118
repair_anl_atc/chart_filter.js
Normal file
118
repair_anl_atc/chart_filter.js
Normal file
@ -0,0 +1,118 @@
|
|||||||
|
/*
|
||||||
|
Парус 8 - Панели мониторинга - ТОиР - Аналитика по ремонтам АТС
|
||||||
|
Компонент: Фильтр отбора
|
||||||
|
*/
|
||||||
|
|
||||||
|
//---------------------
|
||||||
|
//Подключение библиотек
|
||||||
|
//---------------------
|
||||||
|
|
||||||
|
import React from "react"; //Классы React
|
||||||
|
import PropTypes from "prop-types"; //Контроль свойств компонента
|
||||||
|
import { Chip, Stack, Box } from "@mui/material"; //Интерфейсные компоненты
|
||||||
|
import { APP_STYLES } from "../../../app.styles"; //Типовые стили
|
||||||
|
import { hasValue } from "../../core/utils"; //Вспомогательные функции
|
||||||
|
|
||||||
|
//---------
|
||||||
|
//Константы
|
||||||
|
//---------
|
||||||
|
|
||||||
|
//Стили
|
||||||
|
const STYLES = {
|
||||||
|
FILTERS_STACK: {
|
||||||
|
paddingBottom: "5px",
|
||||||
|
...APP_STYLES.SCROLL,
|
||||||
|
overflowY: "auto",
|
||||||
|
alignItems: "flex-end"
|
||||||
|
},
|
||||||
|
STACK_FILTER: { maxWidth: "99vw", alignItems: "flex-end" }
|
||||||
|
};
|
||||||
|
|
||||||
|
//Графики
|
||||||
|
const CHART_NAMES = {
|
||||||
|
repairs: "REPAIRS",
|
||||||
|
spendings: "SPENDINGS"
|
||||||
|
};
|
||||||
|
|
||||||
|
//--------------------------
|
||||||
|
//Вспомогательные компоненты
|
||||||
|
//--------------------------
|
||||||
|
|
||||||
|
//Считывание наименования состояния
|
||||||
|
const getStateName = state => {
|
||||||
|
return state === 0 ? "Не завершенные" : "Завершенные";
|
||||||
|
};
|
||||||
|
|
||||||
|
//Считывание типа затрат
|
||||||
|
const getTypeSpendings = type => {
|
||||||
|
return type === 0 ? "Внутренние" : "Внешние";
|
||||||
|
};
|
||||||
|
|
||||||
|
//Элемент фильтра
|
||||||
|
const FilterItem = ({ field, caption, value, onDelete }) => {
|
||||||
|
//При удалении фильтра
|
||||||
|
const handleDelete = () => (onDelete ? onDelete(field) : null);
|
||||||
|
|
||||||
|
//Генерация содержимого
|
||||||
|
return (
|
||||||
|
<Chip
|
||||||
|
label={
|
||||||
|
<Stack direction={"row"} alignItems={"center"}>
|
||||||
|
<strong>{caption}</strong>
|
||||||
|
{value ? `:\u00A0${value}` : null}
|
||||||
|
</Stack>
|
||||||
|
}
|
||||||
|
variant="outlined"
|
||||||
|
onDelete={handleDelete}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
//Контроль свойств компонента - Элемент фильтра
|
||||||
|
FilterItem.propTypes = {
|
||||||
|
field: PropTypes.string.isRequired,
|
||||||
|
caption: PropTypes.string.isRequired,
|
||||||
|
value: PropTypes.any,
|
||||||
|
onDelete: PropTypes.func
|
||||||
|
};
|
||||||
|
|
||||||
|
//---------------
|
||||||
|
//Тело компонента
|
||||||
|
//---------------
|
||||||
|
|
||||||
|
//Фильтр отбора
|
||||||
|
const ChartFilter = ({ chartName, filter, onFilterChange }) => {
|
||||||
|
//При удалении фильтра
|
||||||
|
const handleDelete = field => onFilterChange && onFilterChange({ chartName, filter: { ...filter, [field]: null } });
|
||||||
|
//Генерация содержимого
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<Box>
|
||||||
|
<Stack direction="row" spacing={1} p={1} alignItems={"center"} sx={STYLES.STACK_FILTER}>
|
||||||
|
<Stack direction="row" spacing={1} alignItems={"center"} sx={STYLES.FILTERS_STACK}>
|
||||||
|
{chartName === CHART_NAMES.repairs ? (
|
||||||
|
hasValue(filter.nState) ? (
|
||||||
|
<FilterItem field={"nState"} caption={"Состояние"} value={getStateName(filter.nState)} onDelete={handleDelete} />
|
||||||
|
) : null
|
||||||
|
) : chartName === CHART_NAMES.spendings ? (
|
||||||
|
<FilterItem field={"nType"} caption={"Тип затрат"} value={getTypeSpendings(filter.nType)} onDelete={handleDelete} />
|
||||||
|
) : null}
|
||||||
|
</Stack>
|
||||||
|
</Stack>
|
||||||
|
</Box>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
//Контроль свойств компонента - Фильтр отбора
|
||||||
|
ChartFilter.propTypes = {
|
||||||
|
chartName: PropTypes.string,
|
||||||
|
filter: PropTypes.object.isRequired,
|
||||||
|
onFilterChange: PropTypes.func.isRequired
|
||||||
|
};
|
||||||
|
|
||||||
|
//--------------------
|
||||||
|
//Интерфейс компонента
|
||||||
|
//--------------------
|
||||||
|
|
||||||
|
export { ChartFilter };
|
||||||
104
repair_anl_atc/filter.js
Normal file
104
repair_anl_atc/filter.js
Normal file
@ -0,0 +1,104 @@
|
|||||||
|
/*
|
||||||
|
Парус 8 - Панели мониторинга - ТОиР - Аналитика по ремонтам АТС
|
||||||
|
Компонент: Фильтр отбора
|
||||||
|
*/
|
||||||
|
|
||||||
|
//---------------------
|
||||||
|
//Подключение библиотек
|
||||||
|
//---------------------
|
||||||
|
|
||||||
|
import React from "react"; //Классы React
|
||||||
|
import PropTypes from "prop-types"; //Контроль свойств компонента
|
||||||
|
import { Chip, Stack, Icon, IconButton, Box } from "@mui/material"; //Интерфейсные компоненты
|
||||||
|
import { APP_STYLES } from "../../../app.styles"; //Типовые стили
|
||||||
|
import { formatDateRF } from "../../core/utils"; //Вспомогательные функции
|
||||||
|
|
||||||
|
//---------
|
||||||
|
//Константы
|
||||||
|
//---------
|
||||||
|
|
||||||
|
//Стили
|
||||||
|
const STYLES = {
|
||||||
|
FILTERS_STACK: {
|
||||||
|
paddingBottom: "5px",
|
||||||
|
...APP_STYLES.SCROLL,
|
||||||
|
overflowY: "auto",
|
||||||
|
alignItems: "flex-end"
|
||||||
|
},
|
||||||
|
STACK_FILTER: { maxWidth: "99vw", alignItems: "flex-end" }
|
||||||
|
};
|
||||||
|
|
||||||
|
//--------------------------
|
||||||
|
//Вспомогательные компоненты
|
||||||
|
//--------------------------
|
||||||
|
|
||||||
|
//Элемент фильтра
|
||||||
|
const FilterItem = ({ caption, value, onClick }) => {
|
||||||
|
//При нажатии на элемент
|
||||||
|
const handleClick = () => (onClick ? onClick() : null);
|
||||||
|
|
||||||
|
//Генерация содержимого
|
||||||
|
return (
|
||||||
|
<Chip
|
||||||
|
label={
|
||||||
|
<Stack direction={"row"} alignItems={"center"}>
|
||||||
|
<strong>{caption}</strong>
|
||||||
|
{value ? `:\u00A0${value}` : null}
|
||||||
|
</Stack>
|
||||||
|
}
|
||||||
|
variant="outlined"
|
||||||
|
onClick={handleClick}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
//Контроль свойств компонента - Элемент фильтра
|
||||||
|
FilterItem.propTypes = {
|
||||||
|
caption: PropTypes.string.isRequired,
|
||||||
|
value: PropTypes.any,
|
||||||
|
onClick: PropTypes.func
|
||||||
|
};
|
||||||
|
|
||||||
|
//---------------
|
||||||
|
//Тело компонента
|
||||||
|
//---------------
|
||||||
|
|
||||||
|
//Фильтр отбора
|
||||||
|
const Filter = ({ filter, onFilterOpen }) => {
|
||||||
|
//При нажатии на элемент фильтра
|
||||||
|
const handleClick = () => onFilterOpen && onFilterOpen();
|
||||||
|
|
||||||
|
//Генерация содержимого
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<Box>
|
||||||
|
<Stack direction="row" spacing={1} p={1} alignItems={"center"} sx={STYLES.STACK_FILTER}>
|
||||||
|
<IconButton onClick={handleClick}>
|
||||||
|
<Icon>filter_alt</Icon>
|
||||||
|
</IconButton>
|
||||||
|
<Stack direction="row" spacing={1} alignItems={"center"} sx={STYLES.FILTERS_STACK}>
|
||||||
|
{filter.dDateBegin ? <FilterItem caption={"Дата с"} value={formatDateRF(filter.dDateBegin)} onClick={handleClick} /> : null}
|
||||||
|
{filter.dDateEnd ? <FilterItem caption={"Дата по"} value={formatDateRF(filter.dDateEnd)} onClick={handleClick} /> : null}
|
||||||
|
{filter.sCustomerDept ? (
|
||||||
|
<FilterItem caption={"Транспортный участок"} value={filter.sCustomerDept} onClick={handleClick} />
|
||||||
|
) : null}
|
||||||
|
{filter.sWorkType ? <FilterItem caption={"Типовая работа"} value={filter.sWorkType} onClick={handleClick} /> : null}
|
||||||
|
{filter.sWorkKind ? <FilterItem caption={"Вид типовых работ"} value={filter.sWorkKind} onClick={handleClick} /> : null}
|
||||||
|
</Stack>
|
||||||
|
</Stack>
|
||||||
|
</Box>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
//Контроль свойств компонента - Фильтр отбора
|
||||||
|
Filter.propTypes = {
|
||||||
|
filter: PropTypes.object.isRequired,
|
||||||
|
onFilterOpen: PropTypes.func.isRequired
|
||||||
|
};
|
||||||
|
|
||||||
|
//--------------------
|
||||||
|
//Интерфейс компонента
|
||||||
|
//--------------------
|
||||||
|
|
||||||
|
export { Filter };
|
||||||
209
repair_anl_atc/filter_dialog.js
Normal file
209
repair_anl_atc/filter_dialog.js
Normal file
@ -0,0 +1,209 @@
|
|||||||
|
/*
|
||||||
|
Парус 8 - Панели мониторинга - ТОиР - Аналитика по ремонтам АТС
|
||||||
|
Компонент: Диалоговое окно фильтра отбора
|
||||||
|
*/
|
||||||
|
|
||||||
|
//---------------------
|
||||||
|
//Подключение библиотек
|
||||||
|
//---------------------
|
||||||
|
|
||||||
|
import React, { useState } from "react"; //Классы React
|
||||||
|
import PropTypes from "prop-types"; //Контроль свойств компонента
|
||||||
|
import { Dialog, DialogTitle, IconButton, Icon, DialogContent, DialogActions, Button, Box, TextField, InputAdornment } from "@mui/material"; //Интерфейсные компоненты
|
||||||
|
import { useDictionary } from "./hooks/dict_hooks"; //Хуки открытий разделов
|
||||||
|
import { hasValue } from "../../core/utils"; //Вспомогательные функции
|
||||||
|
|
||||||
|
//---------
|
||||||
|
//Константы
|
||||||
|
//---------
|
||||||
|
|
||||||
|
//Стили
|
||||||
|
const STYLES = {
|
||||||
|
DIALOG_ACTIONS: { justifyContent: "flex-end" },
|
||||||
|
CLOSE_BUTTON: {
|
||||||
|
position: "absolute",
|
||||||
|
right: 8,
|
||||||
|
top: 8,
|
||||||
|
color: theme => theme.palette.grey[500]
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
//--------------------------
|
||||||
|
//Вспомогательные компоненты
|
||||||
|
//--------------------------
|
||||||
|
|
||||||
|
//Проверка возможности выполнения действия
|
||||||
|
const isActionAllow = (filter, isFiltersInit = false) => {
|
||||||
|
//Если указана "Дата с" и "Дата по", а также это не инициализация
|
||||||
|
return hasValue(filter.dDateBegin) && hasValue(filter.dDateEnd) && !isFiltersInit;
|
||||||
|
};
|
||||||
|
|
||||||
|
//---------------
|
||||||
|
//Тело компонента
|
||||||
|
//---------------
|
||||||
|
|
||||||
|
//Диалоговое окно фильтра отбора
|
||||||
|
const FilterDialog = ({ initial, isFiltersInit, onCancel, onOk }) => {
|
||||||
|
//Собственное состояние
|
||||||
|
const [filter, setFilter] = useState({ ...initial });
|
||||||
|
|
||||||
|
//Вспомогательные функции открытия раздела
|
||||||
|
const { handleInsDepartmentOpen, handleEquipTypeWorksOpen, handleEquipWorkKindsOpen } = useDictionary();
|
||||||
|
|
||||||
|
//Отработка воода значения в фильтр
|
||||||
|
const handleValueChanged = e => setFilter(pv => ({ ...pv, [e.target.name]: e.target.value }));
|
||||||
|
|
||||||
|
//При изменении каталога фильтра
|
||||||
|
const handleCustomerDeptSelect = () =>
|
||||||
|
handleInsDepartmentOpen({
|
||||||
|
sCode: filter.sCustomerDept,
|
||||||
|
callBack: res => {
|
||||||
|
setFilter(pv => ({ ...pv, sCustomerDept: res.outParameters.out_CODE }));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
//При изменении типовой работы
|
||||||
|
const handleTypeWorkSelect = () =>
|
||||||
|
handleEquipTypeWorksOpen({
|
||||||
|
sCode: filter.sWorkType,
|
||||||
|
callBack: res => {
|
||||||
|
setFilter(pv => ({ ...pv, sWorkType: res.outParameters.out_CODE }));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
//При изменении вида типовых работ
|
||||||
|
const handleWorkKindSelect = () =>
|
||||||
|
handleEquipWorkKindsOpen({
|
||||||
|
sCode: filter.sWorkKind,
|
||||||
|
callBack: res => {
|
||||||
|
setFilter(pv => ({ ...pv, sWorkKind: res.outParameters.out_CODE }));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
//При очистке фильтра
|
||||||
|
const handleClear = () => {
|
||||||
|
setFilter({ dDateBegin: "", dDateEnd: "", sCustomerDept: "", sWorkType: "", sWorkKind: "" });
|
||||||
|
};
|
||||||
|
|
||||||
|
//При закрытии диалога без изменения фильтра
|
||||||
|
const handleCancel = () => (isActionAllow(initial, isFiltersInit) ? onCancel && onCancel() : null);
|
||||||
|
|
||||||
|
//При закрытии диалога с изменением фильтра
|
||||||
|
const handleOK = () => (isActionAllow(filter) && onOk ? onOk(filter) : null);
|
||||||
|
|
||||||
|
//Генерация содержимого
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<Dialog open onClose={handleCancel} fullWidth maxWidth="sm">
|
||||||
|
<DialogTitle>Фильтр отбора</DialogTitle>
|
||||||
|
<IconButton aria-label="close" onClick={handleCancel} sx={STYLES.CLOSE_BUTTON}>
|
||||||
|
<Icon>close</Icon>
|
||||||
|
</IconButton>
|
||||||
|
<DialogContent>
|
||||||
|
<Box sx={{ display: "flex", flexDirection: "column", gap: "10px" }}>
|
||||||
|
<TextField
|
||||||
|
name="dDateBegin"
|
||||||
|
type="date"
|
||||||
|
InputLabelProps={{ shrink: true }}
|
||||||
|
value={filter.dDateBegin}
|
||||||
|
onChange={handleValueChanged}
|
||||||
|
label="Дата с"
|
||||||
|
variant="standard"
|
||||||
|
fullWidth
|
||||||
|
required
|
||||||
|
error={!filter.dDateBegin}
|
||||||
|
/>
|
||||||
|
<TextField
|
||||||
|
name="dDateEnd"
|
||||||
|
type="date"
|
||||||
|
InputLabelProps={{ shrink: true }}
|
||||||
|
value={filter.dDateEnd}
|
||||||
|
onChange={handleValueChanged}
|
||||||
|
label="Дата по"
|
||||||
|
variant="standard"
|
||||||
|
fullWidth
|
||||||
|
required
|
||||||
|
error={!filter.dDateEnd}
|
||||||
|
/>
|
||||||
|
<TextField
|
||||||
|
name="sCustomerDept"
|
||||||
|
value={filter.sCustomerDept}
|
||||||
|
onChange={handleValueChanged}
|
||||||
|
label="Транспортный участок"
|
||||||
|
variant="standard"
|
||||||
|
InputProps={{
|
||||||
|
endAdornment: (
|
||||||
|
<InputAdornment position="end">
|
||||||
|
<IconButton aria-label={`sCustomerDept select`} onClick={handleCustomerDeptSelect} edge="end">
|
||||||
|
<Icon>list</Icon>
|
||||||
|
</IconButton>
|
||||||
|
</InputAdornment>
|
||||||
|
)
|
||||||
|
}}
|
||||||
|
fullWidth
|
||||||
|
/>
|
||||||
|
<TextField
|
||||||
|
name="sWorkType"
|
||||||
|
value={filter.sWorkType}
|
||||||
|
onChange={handleValueChanged}
|
||||||
|
label="Типовая работа"
|
||||||
|
variant="standard"
|
||||||
|
InputProps={{
|
||||||
|
endAdornment: (
|
||||||
|
<InputAdornment position="end">
|
||||||
|
<IconButton aria-label={`sWorkType select`} onClick={handleTypeWorkSelect} edge="end">
|
||||||
|
<Icon>list</Icon>
|
||||||
|
</IconButton>
|
||||||
|
</InputAdornment>
|
||||||
|
)
|
||||||
|
}}
|
||||||
|
fullWidth
|
||||||
|
/>
|
||||||
|
<TextField
|
||||||
|
name="sWorkKind"
|
||||||
|
value={filter.sWorkKind}
|
||||||
|
onChange={handleValueChanged}
|
||||||
|
label="Вид типовых работ"
|
||||||
|
variant="standard"
|
||||||
|
InputProps={{
|
||||||
|
endAdornment: (
|
||||||
|
<InputAdornment position="end">
|
||||||
|
<IconButton aria-label={`sWorkKind select`} onClick={handleWorkKindSelect} edge="end">
|
||||||
|
<Icon>list</Icon>
|
||||||
|
</IconButton>
|
||||||
|
</InputAdornment>
|
||||||
|
)
|
||||||
|
}}
|
||||||
|
fullWidth
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
</DialogContent>
|
||||||
|
<DialogActions sx={STYLES.DIALOG_ACTIONS}>
|
||||||
|
<Button variant="text" disabled={!isActionAllow(filter)} onClick={handleOK}>
|
||||||
|
Применить
|
||||||
|
</Button>
|
||||||
|
<Button variant="text" onClick={handleClear}>
|
||||||
|
Очистить
|
||||||
|
</Button>
|
||||||
|
<Button variant="text" disabled={!isActionAllow(initial, isFiltersInit)} onClick={handleCancel}>
|
||||||
|
Отмена
|
||||||
|
</Button>
|
||||||
|
</DialogActions>
|
||||||
|
</Dialog>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
//Контроль свойств компонента - Диалоговое окно фильтра отбора
|
||||||
|
FilterDialog.propTypes = {
|
||||||
|
initial: PropTypes.object.isRequired,
|
||||||
|
isFiltersInit: PropTypes.bool,
|
||||||
|
onOk: PropTypes.func,
|
||||||
|
onCancel: PropTypes.func
|
||||||
|
};
|
||||||
|
|
||||||
|
//--------------------
|
||||||
|
//Интерфейс компонента
|
||||||
|
//--------------------
|
||||||
|
|
||||||
|
export { FilterDialog };
|
||||||
91
repair_anl_atc/hooks/dict_hooks.js
Normal file
91
repair_anl_atc/hooks/dict_hooks.js
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
/*
|
||||||
|
Парус 8 - Панели мониторинга - ТОиР - Аналитика по ремонтам АТС
|
||||||
|
Пользовательские хуки: Хуки открытия разделов
|
||||||
|
*/
|
||||||
|
|
||||||
|
//---------------------
|
||||||
|
//Подключение библиотек
|
||||||
|
//---------------------
|
||||||
|
|
||||||
|
import { useContext, useCallback } from "react"; //Классы React
|
||||||
|
import { ApplicationСtx } from "../../../context/application"; //Контекст приложения
|
||||||
|
|
||||||
|
//-----------
|
||||||
|
//Тело модуля
|
||||||
|
//-----------
|
||||||
|
|
||||||
|
//Состояние открытия разделов
|
||||||
|
const useDictionary = () => {
|
||||||
|
//Подключение к контексту приложения
|
||||||
|
const { pOnlineShowDictionary } = useContext(ApplicationСtx);
|
||||||
|
|
||||||
|
//Отображение раздела "Штатные подразделения"
|
||||||
|
const handleInsDepartmentOpen = useCallback(
|
||||||
|
async prms => {
|
||||||
|
pOnlineShowDictionary({
|
||||||
|
unitCode: "INS_DEPARTMENT",
|
||||||
|
inputParameters: [{ name: "in_CODE", value: prms.sCode }],
|
||||||
|
callBack: res => {
|
||||||
|
res.success ? prms.callBack(res) : null;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
[pOnlineShowDictionary]
|
||||||
|
);
|
||||||
|
|
||||||
|
//Отображение раздела "Типовые работы по техническому обслуживанию и ремонту"
|
||||||
|
const handleEquipTypeWorksOpen = useCallback(
|
||||||
|
async prms => {
|
||||||
|
pOnlineShowDictionary({
|
||||||
|
unitCode: "EquipTypeWorks",
|
||||||
|
inputParameters: [{ name: "in_CODE", value: prms.sCode }],
|
||||||
|
callBack: res => {
|
||||||
|
res.success ? prms.callBack(res) : null;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
[pOnlineShowDictionary]
|
||||||
|
);
|
||||||
|
|
||||||
|
//Отображение раздела "Виды работ по техническому обслуживанию и ремонту"
|
||||||
|
const handleEquipWorkKindsOpen = useCallback(
|
||||||
|
async prms => {
|
||||||
|
pOnlineShowDictionary({
|
||||||
|
unitCode: "EquipWorkKinds",
|
||||||
|
inputParameters: [{ name: "in_CODE", value: prms.sCode }],
|
||||||
|
callBack: res => {
|
||||||
|
res.success ? prms.callBack(res) : null;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
[pOnlineShowDictionary]
|
||||||
|
);
|
||||||
|
|
||||||
|
//Отображение раздела "Ремонтные ведомости"
|
||||||
|
const handleEquipRepairSheetsOpen = useCallback(
|
||||||
|
async prms => {
|
||||||
|
pOnlineShowDictionary({
|
||||||
|
unitCode: "EquipRepairSheets",
|
||||||
|
inputParameters: [{ name: "in_RN", value: prms.nRn }],
|
||||||
|
callBack: res => {
|
||||||
|
res.success ? prms.callBack(res) : null;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
[pOnlineShowDictionary]
|
||||||
|
);
|
||||||
|
|
||||||
|
//Возвращаем функции открытия разделов
|
||||||
|
return {
|
||||||
|
handleInsDepartmentOpen,
|
||||||
|
handleEquipTypeWorksOpen,
|
||||||
|
handleEquipWorkKindsOpen,
|
||||||
|
handleEquipRepairSheetsOpen
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
//----------------
|
||||||
|
//Интерфейс модуля
|
||||||
|
//----------------
|
||||||
|
|
||||||
|
export { useDictionary };
|
||||||
93
repair_anl_atc/hooks/filter_hooks.js
Normal file
93
repair_anl_atc/hooks/filter_hooks.js
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
/*
|
||||||
|
Парус 8 - Панели мониторинга - ТОиР - Аналитика по ремонтам АТС
|
||||||
|
Пользовательские хуки: Хуки фильтров
|
||||||
|
*/
|
||||||
|
|
||||||
|
//---------------------
|
||||||
|
//Подключение библиотек
|
||||||
|
//---------------------
|
||||||
|
|
||||||
|
import { useState, useContext, useCallback, useEffect } from "react"; //Классы React
|
||||||
|
import { BackEndСtx } from "../../../context/backend"; //Контекст взаимодействия с сервером
|
||||||
|
import { object2Base64XML } from "../../../core/utils"; //Вспомогательные функции
|
||||||
|
|
||||||
|
//-----------
|
||||||
|
//Тело модуля
|
||||||
|
//-----------
|
||||||
|
|
||||||
|
//Состояние открытия разделов
|
||||||
|
const useFilters = () => {
|
||||||
|
//Собственное состояние - общие значения фильтров
|
||||||
|
const [filterValues, setFilterValues] = useState({
|
||||||
|
loaded: false,
|
||||||
|
dDateBegin: "",
|
||||||
|
dDateEnd: "",
|
||||||
|
sCustomerDept: "",
|
||||||
|
sWorkType: "",
|
||||||
|
sWorkKind: ""
|
||||||
|
});
|
||||||
|
|
||||||
|
//Собственное состояние - признак загрузки настроек
|
||||||
|
const [isFiltersLoaded, setIsFiltersLoaded] = useState(false);
|
||||||
|
|
||||||
|
//Собственное состояние - признак инициализации
|
||||||
|
const [filtersInit, setFiltersInit] = useState(true);
|
||||||
|
|
||||||
|
//Подключение к контексту взаимодействия с сервером
|
||||||
|
const { executeStored, SERV_DATA_TYPE_CLOB } = useContext(BackEndСtx);
|
||||||
|
|
||||||
|
//При изменении фильтров
|
||||||
|
const handleChange = useCallback(
|
||||||
|
async ({ filter }) => {
|
||||||
|
//Формируем новые фильтры
|
||||||
|
const newFilters = { ...filterValues, ...filter };
|
||||||
|
|
||||||
|
//Если фильтры изменились - обновим их
|
||||||
|
if (JSON.stringify(filterValues) != JSON.stringify(newFilters)) {
|
||||||
|
await executeStored({
|
||||||
|
stored: "UDO_PKG_P8PANELS_USETTINGS.SETTINGS_SET",
|
||||||
|
args: {
|
||||||
|
SPANEL: "repair_anl_atc",
|
||||||
|
CSETTINGS: {
|
||||||
|
VALUE: object2Base64XML(newFilters, { arrayNodeName: "filters" }),
|
||||||
|
SDATA_TYPE: SERV_DATA_TYPE_CLOB
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
setFilterValues({ ...newFilters });
|
||||||
|
}
|
||||||
|
|
||||||
|
//Это не инициализация
|
||||||
|
filtersInit ? setFiltersInit(false) : false;
|
||||||
|
},
|
||||||
|
[SERV_DATA_TYPE_CLOB, executeStored, filterValues, filtersInit]
|
||||||
|
);
|
||||||
|
|
||||||
|
//При загрузке панели
|
||||||
|
useEffect(() => {
|
||||||
|
//Загрузка настроек с сервера
|
||||||
|
const loadSettings = async () => {
|
||||||
|
try {
|
||||||
|
const data = await executeStored({
|
||||||
|
stored: "UDO_PKG_P8PANELS_USETTINGS.SETTINGS_GET",
|
||||||
|
args: { SPANEL: "repair_anl_atc" },
|
||||||
|
respArg: "COUT"
|
||||||
|
});
|
||||||
|
//Если есть настройки - указываем
|
||||||
|
if (data) setFilterValues({ ...data });
|
||||||
|
} finally {
|
||||||
|
setIsFiltersLoaded(true);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if (!isFiltersLoaded) loadSettings();
|
||||||
|
}, [executeStored, isFiltersLoaded]);
|
||||||
|
|
||||||
|
//Возвращаем функции открытия разделов
|
||||||
|
return [filterValues, isFiltersLoaded, filtersInit, handleChange];
|
||||||
|
};
|
||||||
|
|
||||||
|
//----------------
|
||||||
|
//Интерфейс модуля
|
||||||
|
//----------------
|
||||||
|
|
||||||
|
export { useFilters };
|
||||||
182
repair_anl_atc/hooks/hooks.js
Normal file
182
repair_anl_atc/hooks/hooks.js
Normal file
@ -0,0 +1,182 @@
|
|||||||
|
/*
|
||||||
|
Парус 8 - Панели мониторинга - ТОиР - Аналитика по ремонтам АТС
|
||||||
|
Пользовательские хуки: Хуки основных компонентов
|
||||||
|
*/
|
||||||
|
|
||||||
|
//---------------------
|
||||||
|
//Подключение библиотек
|
||||||
|
//---------------------
|
||||||
|
|
||||||
|
import { useState, useContext, useCallback, useEffect } from "react"; //Классы React
|
||||||
|
import { BackEndСtx } from "../../../context/backend"; //Контекст взаимодействия с сервером
|
||||||
|
import { object2Base64XML, formatDateRF } from "../../../core/utils";
|
||||||
|
|
||||||
|
//--------------------------
|
||||||
|
//Вспомогательные компоненты
|
||||||
|
//--------------------------
|
||||||
|
|
||||||
|
//-----------
|
||||||
|
//Тело модуля
|
||||||
|
//-----------
|
||||||
|
|
||||||
|
//Хук графика статусов
|
||||||
|
const useChartStatuses = ({ storedArgs = {} }) => {
|
||||||
|
//Собственное состояние - график
|
||||||
|
const [chartStatuses, setChartStatuses] = useState({ loaded: false, reload: false });
|
||||||
|
|
||||||
|
//Подключение к контексту взаимодействия с сервером
|
||||||
|
const { executeStored } = useContext(BackEndСtx);
|
||||||
|
|
||||||
|
//При необходимости перезагрузки графика
|
||||||
|
const handleReload = useCallback(() => setChartStatuses(pv => ({ ...pv, reload: true })), []);
|
||||||
|
|
||||||
|
//При подключении к странице
|
||||||
|
useEffect(() => {
|
||||||
|
//Загрузка данных графика с сервера
|
||||||
|
const loadChart = async () => {
|
||||||
|
try {
|
||||||
|
const chart = await executeStored({
|
||||||
|
stored: "UDO_PKG_P8PANELS_RPR_ANL.CHART_STATUSES",
|
||||||
|
args: {
|
||||||
|
DDATE_FROM: storedArgs.dDateBegin ? new Date(storedArgs.dDateBegin) : null,
|
||||||
|
DDATE_TO: storedArgs.dDateEnd ? new Date(storedArgs.dDateEnd) : null,
|
||||||
|
SINS_DEPARTMENT: storedArgs.sCustomerDept,
|
||||||
|
SEQTYPEWRK: storedArgs.sWorkType,
|
||||||
|
SEQWRKKIND: storedArgs.sWorkKind,
|
||||||
|
NSTATE: storedArgs.nState,
|
||||||
|
NTYPESPEND: storedArgs.nType
|
||||||
|
},
|
||||||
|
respArg: "COUT"
|
||||||
|
});
|
||||||
|
setChartStatuses(pv => ({ ...pv, loaded: true, reload: false, ...chart.XCHART }));
|
||||||
|
} catch (e) {
|
||||||
|
setChartStatuses(pv => ({ ...pv, loaded: false, reload: false }));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
//При необходимости перезагрузить
|
||||||
|
if (chartStatuses.reload) loadChart();
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
|
}, [chartStatuses.reload, executeStored]);
|
||||||
|
|
||||||
|
//Возвращаем график
|
||||||
|
return { chartStatuses, handleReload };
|
||||||
|
};
|
||||||
|
|
||||||
|
//Хук графика трудовых затрат
|
||||||
|
const useChartSpendings = ({ storedArgs = {} }) => {
|
||||||
|
//Собственное состояние - график
|
||||||
|
const [chartSpendings, setChartSpendings] = useState({ loaded: false, reload: false });
|
||||||
|
|
||||||
|
//Подключение к контексту взаимодействия с сервером
|
||||||
|
const { executeStored } = useContext(BackEndСtx);
|
||||||
|
|
||||||
|
//При необходимости перезагрузки графика
|
||||||
|
const handleReload = useCallback(() => setChartSpendings(pv => ({ ...pv, reload: true })), []);
|
||||||
|
|
||||||
|
//При подключении к странице
|
||||||
|
useEffect(() => {
|
||||||
|
//Загрузка данных графика с сервера
|
||||||
|
const loadChart = async () => {
|
||||||
|
try {
|
||||||
|
const chart = await executeStored({
|
||||||
|
stored: "UDO_PKG_P8PANELS_RPR_ANL.CHART_SPENDINGS",
|
||||||
|
args: {
|
||||||
|
DDATE_FROM: storedArgs.dDateBegin ? new Date(storedArgs.dDateBegin) : null,
|
||||||
|
DDATE_TO: storedArgs.dDateEnd ? new Date(storedArgs.dDateEnd) : null,
|
||||||
|
SINS_DEPARTMENT: storedArgs.sCustomerDept,
|
||||||
|
SEQTYPEWRK: storedArgs.sWorkType,
|
||||||
|
SEQWRKKIND: storedArgs.sWorkKind,
|
||||||
|
NSTATE: storedArgs.nState,
|
||||||
|
NTYPESPEND: storedArgs.nType
|
||||||
|
},
|
||||||
|
respArg: "COUT"
|
||||||
|
});
|
||||||
|
setChartSpendings(pv => ({ ...pv, loaded: true, reload: false, ...chart.XCHART }));
|
||||||
|
} catch (e) {
|
||||||
|
setChartSpendings(pv => ({ ...pv, loaded: false, reload: false }));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
//При необходимости перезагрузить
|
||||||
|
if (chartSpendings.reload) loadChart();
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
|
}, [chartSpendings.reload, executeStored]);
|
||||||
|
|
||||||
|
//Возвращаем график
|
||||||
|
return { chartSpendings, handleReload };
|
||||||
|
};
|
||||||
|
|
||||||
|
//Хук таблицы ремотных ведомостей
|
||||||
|
const useTableRepairs = ({ storedArgs = [] }) => {
|
||||||
|
//Собственное состояние - таблица
|
||||||
|
const [dataGrid, setDataGrid] = useState({
|
||||||
|
dataLoaded: false,
|
||||||
|
filters: [],
|
||||||
|
orders: null,
|
||||||
|
pageNumber: 1,
|
||||||
|
morePages: true,
|
||||||
|
reloading: false
|
||||||
|
});
|
||||||
|
|
||||||
|
//Подключение к контексту взаимодействия с сервером
|
||||||
|
const { executeStored, SERV_DATA_TYPE_CLOB } = useContext(BackEndСtx);
|
||||||
|
|
||||||
|
//При изменении состояния фильтра
|
||||||
|
const handleFilterChanged = ({ filters }) => setDataGrid(pv => ({ ...pv, filters: [...filters], pageNumber: 1, reloading: true }));
|
||||||
|
|
||||||
|
//При изменении состояния сортировки
|
||||||
|
const handleOrderChanged = ({ orders }) => setDataGrid(pv => ({ ...pv, orders: [...orders], pageNumber: 1, reloading: true }));
|
||||||
|
|
||||||
|
//При изменении количества отображаемых страниц
|
||||||
|
const handlePagesCountChanged = () => setDataGrid(pv => ({ ...pv, pageNumber: pv.pageNumber + 1, reloading: true }));
|
||||||
|
|
||||||
|
//При необходимости перезагрузки таблицы
|
||||||
|
const handleReload = () => setDataGrid(pv => ({ ...pv, pageNumber: 1, reloading: true }));
|
||||||
|
|
||||||
|
//При подключении к странице
|
||||||
|
useEffect(() => {
|
||||||
|
//Загрузка данных графика с сервера
|
||||||
|
const loadDataGrid = async () => {
|
||||||
|
try {
|
||||||
|
const data = await executeStored({
|
||||||
|
stored: "UDO_PKG_P8PANELS_RPR_ANL.DATA_GRID",
|
||||||
|
args: {
|
||||||
|
CFILTERS: {
|
||||||
|
VALUE: object2Base64XML([...dataGrid.filters, ...storedArgs], { arrayNodeName: "filters" }),
|
||||||
|
SDATA_TYPE: SERV_DATA_TYPE_CLOB
|
||||||
|
},
|
||||||
|
CORDERS: { VALUE: object2Base64XML(dataGrid.orders, { arrayNodeName: "orders" }), SDATA_TYPE: SERV_DATA_TYPE_CLOB },
|
||||||
|
NPAGE_NUMBER: dataGrid.pageNumber,
|
||||||
|
NPAGE_SIZE: 10,
|
||||||
|
NINCLUDE_DEF: dataGrid.dataLoaded ? 0 : 1
|
||||||
|
},
|
||||||
|
attributeValueProcessor: (name, val) => (["DDOCDATE", "DDATEFACT_BEG", "DDATEFACT_END"].includes(name) ? formatDateRF(val) : val),
|
||||||
|
respArg: "COUT"
|
||||||
|
});
|
||||||
|
setDataGrid(pv => ({
|
||||||
|
...pv,
|
||||||
|
...data.XDATA_GRID,
|
||||||
|
columnsDef: data.XDATA_GRID.columnsDef ? [...data.XDATA_GRID.columnsDef] : pv.columnsDef || [],
|
||||||
|
rows: pv.pageNumber == 1 ? [...(data.XDATA_GRID.rows || [])] : [...(pv.rows || []), ...(data.XDATA_GRID.rows || [])],
|
||||||
|
dataLoaded: true,
|
||||||
|
reloading: false,
|
||||||
|
morePages: (data.XDATA_GRID.rows || []).length >= 10
|
||||||
|
}));
|
||||||
|
} catch (e) {
|
||||||
|
console.log(e);
|
||||||
|
setDataGrid(pv => ({ ...pv, loaded: false, reload: false }));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
//При необходимости перезагрузить
|
||||||
|
if (dataGrid.reloading) loadDataGrid();
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
|
}, [dataGrid.reloading, executeStored]);
|
||||||
|
|
||||||
|
//Возвращаем график
|
||||||
|
return { dataGrid, handleReload, handleFilterChanged, handleOrderChanged, handlePagesCountChanged };
|
||||||
|
};
|
||||||
|
|
||||||
|
//----------------
|
||||||
|
//Интерфейс модуля
|
||||||
|
//----------------
|
||||||
|
|
||||||
|
export { useChartStatuses, useChartSpendings, useTableRepairs };
|
||||||
16
repair_anl_atc/index.js
Normal file
16
repair_anl_atc/index.js
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
/*
|
||||||
|
Парус 8 - Панели мониторинга - ТОиР - Аналитика по ремонтам АТС
|
||||||
|
Панель мониторинга: Точка входа
|
||||||
|
*/
|
||||||
|
|
||||||
|
//---------------------
|
||||||
|
//Подключение библиотек
|
||||||
|
//---------------------
|
||||||
|
|
||||||
|
import { RepairAnlATC } from "./repair_anl_atc"; //Корневая панель аналитики по ремонтам АТС
|
||||||
|
|
||||||
|
//----------------
|
||||||
|
//Интерфейс модуля
|
||||||
|
//----------------
|
||||||
|
|
||||||
|
export const RootClass = RepairAnlATC;
|
||||||
77
repair_anl_atc/layouts.js
Normal file
77
repair_anl_atc/layouts.js
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
/*
|
||||||
|
Парус 8 - Панели мониторинга - ТОиР - Аналитика по ремонтам АТС
|
||||||
|
Дополнительная разметка и вёрстка клиентских элементов
|
||||||
|
*/
|
||||||
|
|
||||||
|
//---------------------
|
||||||
|
//Подключение библиотек
|
||||||
|
//---------------------
|
||||||
|
|
||||||
|
import React from "react"; //Классы React
|
||||||
|
import { Icon, Stack, Link } from "@mui/material"; //Интерфейсные компоненты
|
||||||
|
import { formatDateRF } from "../../core/utils"; //Вспомогательные функции
|
||||||
|
|
||||||
|
//---------
|
||||||
|
//Константы
|
||||||
|
//---------
|
||||||
|
|
||||||
|
//-----------
|
||||||
|
//Тело модуля
|
||||||
|
//-----------
|
||||||
|
|
||||||
|
//Формирование значения для колонки "Состояние"
|
||||||
|
const formatStateValue = (value, addText = false) => {
|
||||||
|
const [text, icon] =
|
||||||
|
value == 0
|
||||||
|
? ["Не утвержден", "clear"]
|
||||||
|
: value == 2
|
||||||
|
? ["Утвержден", "done"]
|
||||||
|
: value == 3
|
||||||
|
? ["Закрыт", "lock_outlined"]
|
||||||
|
: ["Не определен", "question_mark"];
|
||||||
|
return (
|
||||||
|
<Stack direction="row" gap={0.5} alignItems="center" justifyContent="center">
|
||||||
|
<Icon title={text}>{icon}</Icon>
|
||||||
|
{addText == true ? text : null}
|
||||||
|
</Stack>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
//Формирование значения для колонки "Номер документа"
|
||||||
|
const formatNumbValue = (row, columnDef, showEquipRepairSheets) => {
|
||||||
|
console.log(columnDef.name);
|
||||||
|
return (
|
||||||
|
<Link component="button" variant="body2" align="left" underline="hover" onClick={() => showEquipRepairSheets({ nRn: row["NRN"] })}>
|
||||||
|
{row[columnDef.name]}
|
||||||
|
</Link>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
//Генерация представления ячейки c данными
|
||||||
|
export const dataCellRender = ({ row, columnDef, showEquipRepairSheets }) => {
|
||||||
|
switch (columnDef.name) {
|
||||||
|
case "SNUMB":
|
||||||
|
return { data: formatNumbValue(row, columnDef, showEquipRepairSheets) };
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
//Форматирование значений колонок
|
||||||
|
export const valueFormatter = ({ value, columnDef }) => {
|
||||||
|
switch (columnDef.name) {
|
||||||
|
case "NSTATE":
|
||||||
|
return formatStateValue(value, false);
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
};
|
||||||
|
|
||||||
|
//Форматирование фильтров панелей для фильтров таблицы
|
||||||
|
export const formatFilterValues = filter => {
|
||||||
|
return [
|
||||||
|
{ name: "DDATEBEGIN_FILTER", from: formatDateRF(filter.dDateBegin), to: formatDateRF(filter.dDateEnd) },
|
||||||
|
{ name: "SCUSTOMERDEPT_FILTER", from: filter.sCustomerDept, to: "" },
|
||||||
|
{ name: "SWORKTYPE_FILTER", from: filter.sWorkType, to: "" },
|
||||||
|
{ name: "SWORKKIND_FILTER", from: filter.sWorkKind, to: "" },
|
||||||
|
{ name: "NSTATE_FILTER", from: filter.nState, to: "" },
|
||||||
|
{ name: "NTYPESPEND_FILTER", from: filter.nType, to: "" }
|
||||||
|
];
|
||||||
|
};
|
||||||
233
repair_anl_atc/repair_anl_atc.js
Normal file
233
repair_anl_atc/repair_anl_atc.js
Normal file
@ -0,0 +1,233 @@
|
|||||||
|
/*
|
||||||
|
Парус 8 - Панели мониторинга - ТОиР - Аналитика по ремонтам АТС
|
||||||
|
Панель мониторинга: Корневая панель аналитики по ремонтам АТС
|
||||||
|
*/
|
||||||
|
|
||||||
|
//---------------------
|
||||||
|
//Подключение библиотек
|
||||||
|
//---------------------
|
||||||
|
|
||||||
|
import React, { useState, useEffect, useMemo } from "react"; //Классы React
|
||||||
|
import { Box, Grid, Paper, Fab, Icon } from "@mui/material"; //Интерфейсные компоненты
|
||||||
|
import { APP_BAR_HEIGHT } from "../../components/p8p_app_workspace"; //Заголовок страницы
|
||||||
|
import { P8PChart } from "../../components/p8p_chart"; //График
|
||||||
|
import { APP_STYLES } from "../../../app.styles"; //Типовые стили
|
||||||
|
import { P8PDataGrid, P8P_DATA_GRID_SIZE, P8P_DATA_GRID_MORE_HEIGHT, P8P_DATA_GRID_FILTERS_HEIGHT } from "../../components/p8p_data_grid"; //Таблица данных
|
||||||
|
import { P8P_DATA_GRID_CONFIG_PROPS } from "../../config_wrapper"; //Подключение компонентов к настройкам приложения
|
||||||
|
import { FilterDialog } from "./filter_dialog"; //Диалог фильтра
|
||||||
|
import { Filter } from "./filter"; //Фильтры
|
||||||
|
import { useFilters } from "./hooks/filter_hooks"; //Хуки фильтров
|
||||||
|
import { useChartStatuses, useChartSpendings, useTableRepairs } from "./hooks/hooks";
|
||||||
|
import { useDictionary } from "./hooks/dict_hooks";
|
||||||
|
import { dataCellRender, valueFormatter, formatFilterValues } from "./layouts";
|
||||||
|
import { ChartFilter } from "./chart_filter";
|
||||||
|
import { hasValue } from "../../core/utils";
|
||||||
|
|
||||||
|
//---------
|
||||||
|
//Константы
|
||||||
|
//---------
|
||||||
|
|
||||||
|
//Высота графиков
|
||||||
|
const CHART_HEIGHT = "300px";
|
||||||
|
|
||||||
|
//Стили
|
||||||
|
const STYLES = {
|
||||||
|
TABLE_PROJECTS: (showCharts, morePages, filters, isChartsFiltered) => ({
|
||||||
|
height: `calc(100vh - ${APP_BAR_HEIGHT} - ${showCharts ? CHART_HEIGHT : "0px"} - ${morePages ? P8P_DATA_GRID_MORE_HEIGHT : "0px"} - ${
|
||||||
|
filters ? P8P_DATA_GRID_FILTERS_HEIGHT : "0px"
|
||||||
|
} - ${showCharts && isChartsFiltered ? "53px" : "0px"} - 90px)`,
|
||||||
|
maxWidth: `calc(100vw - 16px)`,
|
||||||
|
...APP_STYLES.SCROLL
|
||||||
|
}),
|
||||||
|
CHART: { maxHeight: CHART_HEIGHT, display: "flex", justifyContent: "center" },
|
||||||
|
CHART_PAPER: { height: "100%", paddingBottom: "5px" },
|
||||||
|
CHART_FAB: { position: "absolute", top: 80, left: 16 }
|
||||||
|
};
|
||||||
|
|
||||||
|
//Графики страницы
|
||||||
|
const CHART_NAMES = {
|
||||||
|
repairs: "REPAIRS",
|
||||||
|
spendings: "SPENDINGS"
|
||||||
|
};
|
||||||
|
|
||||||
|
//-----------
|
||||||
|
//Тело модуля
|
||||||
|
//-----------
|
||||||
|
|
||||||
|
//Корневая панель аналитики по ремонтам АТС
|
||||||
|
const RepairAnlATC = () => {
|
||||||
|
//Собственное состояние - признак отображения фильтров
|
||||||
|
const [isFilterOpen, setIsFilterOpen] = useState(true);
|
||||||
|
|
||||||
|
//Состояния графиков
|
||||||
|
const [showCharts, setShowCharts] = useState(true);
|
||||||
|
|
||||||
|
//Собственное состояние - общие фильтры
|
||||||
|
const [filterValues, isFiltersLoaded, filtersInit, handleFilterChange] = useFilters();
|
||||||
|
|
||||||
|
//Собственное состояние - фильтры ремонтов
|
||||||
|
const [filterRepairs, setFilterRepairs] = useState({ nState: null });
|
||||||
|
|
||||||
|
//Собственное состояние - фильтры затрат
|
||||||
|
const [filterSpendings, setFilterSpendings] = useState({ nType: null });
|
||||||
|
|
||||||
|
//Общие фильтры панели
|
||||||
|
const allFilters = useMemo(() => {
|
||||||
|
return { ...filterValues, nState: filterRepairs.nState, nType: filterSpendings.nType };
|
||||||
|
}, [filterRepairs.nState, filterSpendings.nType, filterValues]);
|
||||||
|
|
||||||
|
//Состояние графика статусов
|
||||||
|
const { chartStatuses, handleReload: handleChartStatusesReload } = useChartStatuses({ storedArgs: allFilters });
|
||||||
|
|
||||||
|
//Состояние графика трудовых затрат
|
||||||
|
const { chartSpendings, handleReload: handleChartSpendingsReload } = useChartSpendings({ storedArgs: allFilters });
|
||||||
|
|
||||||
|
//Состояние таблицы ремонтных ведомостей
|
||||||
|
const {
|
||||||
|
dataGrid,
|
||||||
|
handleReload: handleTableRepairsReload,
|
||||||
|
handleFilterChanged,
|
||||||
|
handleOrderChanged,
|
||||||
|
handlePagesCountChanged
|
||||||
|
} = useTableRepairs({
|
||||||
|
storedArgs: formatFilterValues(allFilters)
|
||||||
|
});
|
||||||
|
|
||||||
|
//Вспомогательные функции открытия раздела
|
||||||
|
const { handleEquipRepairSheetsOpen } = useDictionary();
|
||||||
|
|
||||||
|
//При изменении фильтра в диалоге
|
||||||
|
const handleFilterOk = filter => {
|
||||||
|
//Обновляем фильтры
|
||||||
|
handleFilterChange({ filter });
|
||||||
|
//Закрываем диалог фильтра
|
||||||
|
setIsFilterOpen(false);
|
||||||
|
};
|
||||||
|
|
||||||
|
//При закрытии диалога фильтра
|
||||||
|
const handleFilterCancel = () => setIsFilterOpen(false);
|
||||||
|
|
||||||
|
//При открытии диалога фильтра
|
||||||
|
const handleFilterDialogOpen = () => setIsFilterOpen(true);
|
||||||
|
|
||||||
|
//При нажатии на элемент графика "Ремонты"
|
||||||
|
const handleChartStatusesClick = ({ item }) => {
|
||||||
|
setFilterRepairs({ nState: item.NSTATE });
|
||||||
|
};
|
||||||
|
|
||||||
|
//При нажатии на элемент графика "Трудовые затраты"
|
||||||
|
const handleChartSpendingsClick = ({ item }) => {
|
||||||
|
//Если тип не соответствует текущему
|
||||||
|
if (item.NTYPE !== filterSpendings.nType) setFilterSpendings({ nType: item.NTYPE });
|
||||||
|
};
|
||||||
|
|
||||||
|
//При изменении фильтра графика
|
||||||
|
const handleChartFilterChange = ({ chartName, filter }) => {
|
||||||
|
//При изменении фильтров графика "Ремонты"
|
||||||
|
if (chartName === CHART_NAMES.repairs) {
|
||||||
|
setFilterRepairs({ ...filter });
|
||||||
|
}
|
||||||
|
//При изменении фильтров графика "Трудовые затраты"
|
||||||
|
if (chartName === CHART_NAMES.spendings) setFilterSpendings({ ...filter });
|
||||||
|
};
|
||||||
|
|
||||||
|
//При изменении фильтра
|
||||||
|
useEffect(() => {
|
||||||
|
//Если фильтр установлен
|
||||||
|
if (!filtersInit) {
|
||||||
|
handleChartStatusesReload();
|
||||||
|
handleChartSpendingsReload();
|
||||||
|
handleTableRepairsReload();
|
||||||
|
}
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
|
}, [allFilters, filtersInit]);
|
||||||
|
|
||||||
|
//Генерация содержимого
|
||||||
|
return (
|
||||||
|
<Box p={1}>
|
||||||
|
{!filtersInit ? <Filter filter={filterValues} onFilterOpen={handleFilterDialogOpen} /> : null}
|
||||||
|
<Grid container spacing={1}>
|
||||||
|
{showCharts ? (
|
||||||
|
<>
|
||||||
|
<Grid item xs={6}>
|
||||||
|
<Paper elevation={3} sx={STYLES.CHART_PAPER}>
|
||||||
|
{hasValue(filterRepairs.nState) ? (
|
||||||
|
<ChartFilter chartName={CHART_NAMES.repairs} filter={filterRepairs} onFilterChange={handleChartFilterChange} />
|
||||||
|
) : null}
|
||||||
|
{chartStatuses.loaded ? (
|
||||||
|
<P8PChart {...chartStatuses} style={STYLES.CHART} onClick={handleChartStatusesClick} legendPosition={"top"} />
|
||||||
|
) : null}
|
||||||
|
</Paper>
|
||||||
|
</Grid>
|
||||||
|
<Grid item xs={6}>
|
||||||
|
<Paper elevation={3} sx={STYLES.CHART_PAPER}>
|
||||||
|
{hasValue(filterSpendings.nType) ? (
|
||||||
|
<ChartFilter
|
||||||
|
chartName={CHART_NAMES.spendings}
|
||||||
|
filter={filterSpendings}
|
||||||
|
onFilterChange={handleChartFilterChange}
|
||||||
|
/>
|
||||||
|
) : null}
|
||||||
|
{chartSpendings.loaded ? (
|
||||||
|
<P8PChart
|
||||||
|
{...chartSpendings}
|
||||||
|
style={STYLES.CHART}
|
||||||
|
options={{
|
||||||
|
scales: {
|
||||||
|
x: {
|
||||||
|
stacked: true
|
||||||
|
},
|
||||||
|
y: {
|
||||||
|
stacked: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
legendPosition={"top"}
|
||||||
|
onClick={handleChartSpendingsClick}
|
||||||
|
/>
|
||||||
|
) : null}
|
||||||
|
</Paper>
|
||||||
|
</Grid>
|
||||||
|
</>
|
||||||
|
) : null}
|
||||||
|
<Grid item xs={12}>
|
||||||
|
{dataGrid.dataLoaded ? (
|
||||||
|
<P8PDataGrid
|
||||||
|
{...P8P_DATA_GRID_CONFIG_PROPS}
|
||||||
|
{...dataGrid}
|
||||||
|
size={P8P_DATA_GRID_SIZE.LARGE}
|
||||||
|
containerComponentProps={{
|
||||||
|
sx: STYLES.TABLE_PROJECTS(
|
||||||
|
showCharts,
|
||||||
|
dataGrid.morePages,
|
||||||
|
(dataGrid.filters || []).length > 0,
|
||||||
|
hasValue(filterRepairs.nState) || hasValue(filterSpendings.nType)
|
||||||
|
)
|
||||||
|
}}
|
||||||
|
filtersInitial={dataGrid.filters}
|
||||||
|
onOrderChanged={handleOrderChanged}
|
||||||
|
onFilterChanged={handleFilterChanged}
|
||||||
|
onPagesCountChanged={handlePagesCountChanged}
|
||||||
|
dataCellRender={prms => dataCellRender({ ...prms, showEquipRepairSheets: handleEquipRepairSheetsOpen })}
|
||||||
|
valueFormatter={valueFormatter}
|
||||||
|
/>
|
||||||
|
) : null}
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
{chartStatuses.loaded && chartSpendings.loaded ? (
|
||||||
|
<Fab size="small" color="secondary" sx={STYLES.CHART_FAB} onClick={() => setShowCharts(!showCharts)}>
|
||||||
|
<Icon>{showCharts ? "expand_less" : "expand_more"}</Icon>
|
||||||
|
</Fab>
|
||||||
|
) : null}
|
||||||
|
{isFilterOpen && isFiltersLoaded ? (
|
||||||
|
<FilterDialog initial={filterValues} isFiltersInit={filtersInit} onOk={handleFilterOk} onCancel={handleFilterCancel} />
|
||||||
|
) : null}
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
//----------------
|
||||||
|
//Интерфейс модуля
|
||||||
|
//----------------
|
||||||
|
|
||||||
|
export { RepairAnlATC };
|
||||||
Loading…
x
Reference in New Issue
Block a user