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