forked from CITKParus/P8-Panels
ЦИТК-826, ЦИТК-827, ЦИТК-828, ЦИТК-852 - Общее изменение панелей ПУДП
This commit is contained in:
parent
8d12d71cad
commit
745c3a3983
@ -25,7 +25,8 @@ const STYLES = {
|
|||||||
BOX_INFO_MAIN: {
|
BOX_INFO_MAIN: {
|
||||||
border: "1px solid",
|
border: "1px solid",
|
||||||
borderRadius: "25px",
|
borderRadius: "25px",
|
||||||
height: "35vh"
|
height: "35vh",
|
||||||
|
backgroundColor: "background.detail_table"
|
||||||
},
|
},
|
||||||
BOX_INFO_SUB: isMessage => ({
|
BOX_INFO_SUB: isMessage => ({
|
||||||
overflow: "hidden",
|
overflow: "hidden",
|
||||||
@ -45,7 +46,8 @@ const STYLES = {
|
|||||||
alignItems: "center",
|
alignItems: "center",
|
||||||
border: "1px solid",
|
border: "1px solid",
|
||||||
borderRadius: "25px",
|
borderRadius: "25px",
|
||||||
height: "17vh"
|
height: "17vh",
|
||||||
|
backgroundColor: "background.detail_info"
|
||||||
},
|
},
|
||||||
PRODUCT_SELECTOR_CONTAINER: {
|
PRODUCT_SELECTOR_CONTAINER: {
|
||||||
display: "flex",
|
display: "flex",
|
||||||
@ -55,7 +57,8 @@ const STYLES = {
|
|||||||
border: "1px solid",
|
border: "1px solid",
|
||||||
borderRadius: "25px",
|
borderRadius: "25px",
|
||||||
height: "53vh",
|
height: "53vh",
|
||||||
marginTop: "16px"
|
marginTop: "16px",
|
||||||
|
backgroundColor: "background.product_selector"
|
||||||
},
|
},
|
||||||
PRODUCT_SELECTOR_MODEL: { width: "70%" },
|
PRODUCT_SELECTOR_MODEL: { width: "70%" },
|
||||||
PLAN_INFO_MAIN: {
|
PLAN_INFO_MAIN: {
|
||||||
@ -69,45 +72,55 @@ const STYLES = {
|
|||||||
width: "280px",
|
width: "280px",
|
||||||
borderBottom: "1px solid"
|
borderBottom: "1px solid"
|
||||||
},
|
},
|
||||||
TABLE_DETAILS: { height: "240px" },
|
TABLE_DETAILS: { backgroundColor: "background.detail_table", height: "240px" },
|
||||||
TABLE_DETAILS_HEADER_CELL: maxWidth => ({
|
TABLE_DETAILS_HEADER_CELL: maxWidth => ({
|
||||||
|
backgroundColor: "background.detail_table",
|
||||||
|
color: "text.detail_table.fontColor",
|
||||||
padding: "2px 2px",
|
padding: "2px 2px",
|
||||||
fontSize: "11px",
|
fontSize: "11px",
|
||||||
textAlign: "center",
|
textAlign: "center",
|
||||||
lineHeight: "1rem",
|
lineHeight: "1rem",
|
||||||
...(maxWidth ? { maxWidth } : {})
|
...(maxWidth ? { maxWidth } : {})
|
||||||
}),
|
}),
|
||||||
TABLE_DETAILS_DATA_CELL: textAlign => ({ padding: "2px 2px", fontSize: "11px", ...(textAlign ? { textAlign } : {}) }),
|
TABLE_DETAILS_DATA_CELL: textAlign => ({
|
||||||
TABLE_DETAILS_MORE_BUTTON: { borderRadius: "25px", height: "20px" },
|
backgroundColor: "background.detail_table",
|
||||||
|
color: "text.detail_table.fontColor",
|
||||||
|
padding: "2px 2px",
|
||||||
|
fontSize: "11px",
|
||||||
|
...(textAlign ? { textAlign } : {})
|
||||||
|
}),
|
||||||
|
TABLE_DETAILS_MORE_BUTTON: { borderRadius: "25px", height: "20px", color: "text.more_button.fontColor" },
|
||||||
|
TABLE_DETAILS_TEXT: { color: "text.detail_table.fontColor" },
|
||||||
CARD_DETAILS_CONTAINER: { minWidth: "1200px", maxWidth: "1400px" },
|
CARD_DETAILS_CONTAINER: { minWidth: "1200px", maxWidth: "1400px" },
|
||||||
CARD_DETAILS_NAVIGATION_STACK: { width: "100%" }
|
CARD_DETAILS_NAVIGATION_STACK: { width: "100%" },
|
||||||
|
NAVIGATE_BUTTONS: { color: "text.title.fontColor" }
|
||||||
};
|
};
|
||||||
|
|
||||||
//------------------------------------
|
//------------------------------------
|
||||||
//Вспомогательные функции и компоненты
|
//Вспомогательные функции и компоненты
|
||||||
//------------------------------------
|
//------------------------------------
|
||||||
|
|
||||||
//Информация о плане
|
//Информация о выпуске плана
|
||||||
const PlanInfo = ({ plan }) => {
|
const PlanSpecInfo = ({ planSpec }) => {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Box sx={STYLES.PLAN_INFO_MAIN}>
|
<Box sx={STYLES.PLAN_INFO_MAIN}>
|
||||||
<Box sx={STYLES.PLAN_INFO_SUB}>
|
<Box sx={STYLES.PLAN_INFO_SUB}>
|
||||||
<Typography variant="UDO_body1" mt={1}>
|
<Typography variant="PlanSpecInfo" mt={1}>
|
||||||
Номер борта:
|
Номер борта:
|
||||||
</Typography>
|
</Typography>
|
||||||
<Typography variant="subtitle2">{plan.SNUMB}</Typography>
|
<Typography variant="subtitle2">{planSpec.SNUMB}</Typography>
|
||||||
</Box>
|
</Box>
|
||||||
<Box sx={STYLES.PLAN_INFO_SUB}>
|
<Box sx={STYLES.PLAN_INFO_SUB}>
|
||||||
<Typography variant="UDO_body1" mt={1}>
|
<Typography variant="PlanSpecInfo" mt={1}>
|
||||||
Год выпуска:
|
Год выпуска:
|
||||||
</Typography>
|
</Typography>
|
||||||
<Typography variant="subtitle2">{plan.NYEAR}</Typography>
|
<Typography variant="subtitle2">{planSpec.NYEAR}</Typography>
|
||||||
</Box>
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
<ProgressBox
|
<ProgressBox
|
||||||
progress={plan.NPROGRESS}
|
progress={planSpec.NPROGRESS}
|
||||||
detail={plan.SDETAIL}
|
detail={planSpec.SDETAIL}
|
||||||
width={"110px"}
|
width={"110px"}
|
||||||
height={"110px"}
|
height={"110px"}
|
||||||
progressVariant={"subtitle2"}
|
progressVariant={"subtitle2"}
|
||||||
@ -117,13 +130,13 @@ const PlanInfo = ({ plan }) => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
//Контроль свойств - Информация о плане
|
//Контроль свойств - Информация о спецификации плана
|
||||||
PlanInfo.propTypes = {
|
PlanSpecInfo.propTypes = {
|
||||||
plan: PropTypes.object
|
planSpec: PropTypes.object
|
||||||
};
|
};
|
||||||
|
|
||||||
//Модель выпуска плана
|
//Модель выпуска плана
|
||||||
const PlanProductCompositionModel = ({ model, products, onProductSelect }) => {
|
const PlanSpecProductCompositionModel = ({ model, products, onProductSelect }) => {
|
||||||
//При выборе детали на модели
|
//При выборе детали на модели
|
||||||
const handleProductClick = ({ item }) => {
|
const handleProductClick = ({ item }) => {
|
||||||
const product = products.find(p => p.SMODEL_ID == item.id);
|
const product = products.find(p => p.SMODEL_ID == item.id);
|
||||||
@ -150,7 +163,7 @@ const PlanProductCompositionModel = ({ model, products, onProductSelect }) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
//Контроль свойств - Модель выпуска плана
|
//Контроль свойств - Модель выпуска плана
|
||||||
PlanProductCompositionModel.propTypes = {
|
PlanSpecProductCompositionModel.propTypes = {
|
||||||
model: PropTypes.any,
|
model: PropTypes.any,
|
||||||
products: PropTypes.array,
|
products: PropTypes.array,
|
||||||
onProductSelect: PropTypes.func
|
onProductSelect: PropTypes.func
|
||||||
@ -171,12 +184,12 @@ const dataCellRender = ({ row, columnDef }) => ({
|
|||||||
});
|
});
|
||||||
|
|
||||||
//Таблица детализации изделия
|
//Таблица детализации изделия
|
||||||
const ProductDetailsTable = ({ plan, product, stored, noProductMessage, noDataFoundMessage, title }) => {
|
const ProductDetailsTable = ({ planSpec, product, stored, noProductMessage, noPlanSpecMessage, noDataFoundMessage, title }) => {
|
||||||
//Собственное состояние
|
//Собственное состояние
|
||||||
const [state, setState] = useState({ plan: null, product: null, orders: null, pageNumber: 1 });
|
const [state, setState] = useState({ planSpec: null, product: null, orders: null, pageNumber: 1 });
|
||||||
|
|
||||||
//Собственное состояние - данные таблицы
|
//Собственное состояние - данные таблицы
|
||||||
const { data, isLoading } = useProductDetailsTable(state.plan, state.product, state.orders, state.pageNumber, stored);
|
const { data, isLoading } = useProductDetailsTable(state.planSpec, state.product, state.orders, state.pageNumber, stored);
|
||||||
|
|
||||||
//При изменении состояния сортировки
|
//При изменении состояния сортировки
|
||||||
const handleOrderChanged = ({ orders }) => setState(pv => ({ ...pv, orders: [...orders], pageNumber: 1 }));
|
const handleOrderChanged = ({ orders }) => setState(pv => ({ ...pv, orders: [...orders], pageNumber: 1 }));
|
||||||
@ -186,19 +199,25 @@ const ProductDetailsTable = ({ plan, product, stored, noProductMessage, noDataFo
|
|||||||
|
|
||||||
//При изменении изделия
|
//При изменении изделия
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setState(pv => ({ ...pv, plan, product, orders: null, pageNumber: 1 }));
|
setState(pv => ({ ...pv, planSpec, product, orders: null, pageNumber: 1 }));
|
||||||
}, [product, plan]);
|
}, [product, planSpec]);
|
||||||
|
|
||||||
//Генерация содержимого
|
//Генерация содержимого
|
||||||
return (
|
return (
|
||||||
<Box sx={STYLES.BOX_INFO_SUB(!product || data.rows.length === 0)}>
|
<Box sx={STYLES.BOX_INFO_SUB(!product || data.rows.length === 0)}>
|
||||||
{!product ? (
|
{!product ? (
|
||||||
<Typography variant="UDO_body2">{noProductMessage}</Typography>
|
<Typography variant="ProductDetailMessage" sx={STYLES.TABLE_DETAILS_TEXT}>
|
||||||
|
{noProductMessage}
|
||||||
|
</Typography>
|
||||||
|
) : !planSpec ? (
|
||||||
|
<Typography variant="ProductDetailMessage" sx={STYLES.TABLE_DETAILS_TEXT}>
|
||||||
|
{noPlanSpecMessage}
|
||||||
|
</Typography>
|
||||||
) : (
|
) : (
|
||||||
<>
|
<>
|
||||||
<Stack direction="row" spacing={2} justifyContent="center" alignItems="center">
|
<Stack direction="row" spacing={2} justifyContent="center" alignItems="center">
|
||||||
<CircularProgress size={18} sx={{ opacity: isLoading ? 1 : 0 }} />
|
<CircularProgress size={18} sx={{ opacity: isLoading ? 1 : 0 }} />
|
||||||
<Typography variant="h4">
|
<Typography variant="h4" sx={STYLES.TABLE_DETAILS_TEXT}>
|
||||||
<b>{title}</b>
|
<b>{title}</b>
|
||||||
</Typography>
|
</Typography>
|
||||||
</Stack>
|
</Stack>
|
||||||
@ -225,10 +244,11 @@ const ProductDetailsTable = ({ plan, product, stored, noProductMessage, noDataFo
|
|||||||
|
|
||||||
//Контроль свойств - Таблица детализации изделия
|
//Контроль свойств - Таблица детализации изделия
|
||||||
ProductDetailsTable.propTypes = {
|
ProductDetailsTable.propTypes = {
|
||||||
plan: PropTypes.number.isRequired,
|
planSpec: PropTypes.number,
|
||||||
product: PropTypes.number,
|
product: PropTypes.number,
|
||||||
stored: PropTypes.string.isRequired,
|
stored: PropTypes.string.isRequired,
|
||||||
noProductMessage: PropTypes.string.isRequired,
|
noProductMessage: PropTypes.string.isRequired,
|
||||||
|
noPlanSpecMessage: PropTypes.string.isRequired,
|
||||||
noDataFoundMessage: PropTypes.string.isRequired,
|
noDataFoundMessage: PropTypes.string.isRequired,
|
||||||
title: PropTypes.string.isRequired
|
title: PropTypes.string.isRequired
|
||||||
};
|
};
|
||||||
@ -238,9 +258,9 @@ ProductDetailsTable.propTypes = {
|
|||||||
//-----------
|
//-----------
|
||||||
|
|
||||||
//Детализация по объекту
|
//Детализация по объекту
|
||||||
const PlanDetail = ({ plan, disableNavigatePrev = false, disableNavigateNext = false, onNavigate, onBack }) => {
|
const PlanSpecDetail = ({ planSpec, disableNavigatePrev = false, disableNavigateNext = false, onNavigate, onBack }) => {
|
||||||
//Собственное состояние - данные производственных составов SVG
|
//Собственное состояние - данные производственных составов SVG
|
||||||
const [costProductComposition, setCostProductComposition] = useCostProductComposition(plan.NRN);
|
const [costProductComposition, setCostProductComposition] = useCostProductComposition(planSpec.NRN);
|
||||||
|
|
||||||
//Выбор элемента изделия
|
//Выбор элемента изделия
|
||||||
const setProduct = product => {
|
const setProduct = product => {
|
||||||
@ -260,14 +280,14 @@ const PlanDetail = ({ plan, disableNavigatePrev = false, disableNavigateNext = f
|
|||||||
<Grid item display="flex" justifyContent="center" xs={1}>
|
<Grid item display="flex" justifyContent="center" xs={1}>
|
||||||
<Stack display="flex" direction="row" justifyContent="flex-end" alignItems="center" sx={STYLES.CARD_DETAILS_NAVIGATION_STACK}>
|
<Stack display="flex" direction="row" justifyContent="flex-end" alignItems="center" sx={STYLES.CARD_DETAILS_NAVIGATION_STACK}>
|
||||||
<IconButton disabled={disableNavigatePrev} onClick={() => handleNavigate(-1)}>
|
<IconButton disabled={disableNavigatePrev} onClick={() => handleNavigate(-1)}>
|
||||||
<Icon>navigate_before</Icon>
|
<Icon sx={STYLES.NAVIGATE_BUTTONS}>navigate_before</Icon>
|
||||||
</IconButton>
|
</IconButton>
|
||||||
</Stack>
|
</Stack>
|
||||||
</Grid>
|
</Grid>
|
||||||
<Grid item xs={10}>
|
<Grid item xs={10}>
|
||||||
<Container maxWidth={false}>
|
<Container maxWidth={false}>
|
||||||
<Button onClick={() => (onBack ? onBack() : null)}>
|
<Button onClick={() => (onBack ? onBack() : null)}>
|
||||||
<Stack direction="row">
|
<Stack direction="row" color="text.title.fontColor">
|
||||||
<Icon>chevron_left</Icon>Назад
|
<Icon>chevron_left</Icon>Назад
|
||||||
</Stack>
|
</Stack>
|
||||||
</Button>
|
</Button>
|
||||||
@ -276,31 +296,33 @@ const PlanDetail = ({ plan, disableNavigatePrev = false, disableNavigateNext = f
|
|||||||
<Grid item xs={5}>
|
<Grid item xs={5}>
|
||||||
<Box sx={STYLES.BOX_INFO_MAIN}>
|
<Box sx={STYLES.BOX_INFO_MAIN}>
|
||||||
<ProductDetailsTable
|
<ProductDetailsTable
|
||||||
plan={plan.NRN}
|
planSpec={costProductComposition.selectedProduct?.NFCPRODPLANSP_LINK}
|
||||||
product={costProductComposition.selectedProduct?.NRN}
|
product={costProductComposition.selectedProduct?.NRN}
|
||||||
stored={"PKG_P8PANELS_MECHREC.FCROUTLST_DG_BY_PRDCMPSP_GET"}
|
stored={"PKG_P8PANELS_MECHREC.FCROUTLST_DG_BY_LINKED_GET"}
|
||||||
noProductMessage={"Укажите элемент модели, чтобы увидеть информацию о маршрутных картах"}
|
noProductMessage={"Укажите элемент модели, чтобы увидеть информацию о маршрутных картах"}
|
||||||
|
noPlanSpecMessage={"Не определена связанная запись производственной программы"}
|
||||||
noDataFoundMessage={"Маршрутные карты не найдены"}
|
noDataFoundMessage={"Маршрутные карты не найдены"}
|
||||||
title={"Маршрутные карты"}
|
title={"Маршрутные карты"}
|
||||||
/>
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
<Box sx={STYLES.BOX_INFO_MAIN} mt={2}>
|
<Box sx={STYLES.BOX_INFO_MAIN} mt={2}>
|
||||||
<ProductDetailsTable
|
<ProductDetailsTable
|
||||||
plan={plan.NRN}
|
planSpec={costProductComposition.selectedProduct?.NFCPRODPLANSP_LINK}
|
||||||
product={costProductComposition.selectedProduct?.NRN}
|
product={costProductComposition.selectedProduct?.NRN}
|
||||||
stored={"PKG_P8PANELS_MECHREC.FCDELIVSH_DG_BY_PRDCMPSP_GET"}
|
stored={"PKG_P8PANELS_MECHREC.FCDELIVSH_DG_BY_LINKED_GET"}
|
||||||
noProductMessage={"Укажите элемент модели, чтобы увидеть информацию о комплектовочных ведомостях"}
|
noProductMessage={"Укажите элемент модели, чтобы увидеть информацию о комплектовочных ведомостях"}
|
||||||
|
noPlanSpecMessage={"Не определена связанная запись производственной программы"}
|
||||||
noDataFoundMessage={"Комплектовочные ведомости не найдены"}
|
noDataFoundMessage={"Комплектовочные ведомости не найдены"}
|
||||||
title={"Дефицит комплектации"}
|
title={"Дефицит комплектующих"}
|
||||||
/>
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
</Grid>
|
</Grid>
|
||||||
<Grid item xs={7}>
|
<Grid item xs={7}>
|
||||||
<Box sx={STYLES.DETAIL_INFO}>
|
<Box sx={STYLES.DETAIL_INFO}>
|
||||||
<PlanInfo plan={plan} />
|
<PlanSpecInfo planSpec={planSpec} />
|
||||||
</Box>
|
</Box>
|
||||||
<Box sx={STYLES.PRODUCT_SELECTOR_CONTAINER}>
|
<Box sx={STYLES.PRODUCT_SELECTOR_CONTAINER}>
|
||||||
<PlanProductCompositionModel
|
<PlanSpecProductCompositionModel
|
||||||
model={costProductComposition.model}
|
model={costProductComposition.model}
|
||||||
products={costProductComposition.products}
|
products={costProductComposition.products}
|
||||||
onProductSelect={setProduct}
|
onProductSelect={setProduct}
|
||||||
@ -313,7 +335,7 @@ const PlanDetail = ({ plan, disableNavigatePrev = false, disableNavigateNext = f
|
|||||||
<Grid item display="flex" justifyContent="center" xs={1}>
|
<Grid item display="flex" justifyContent="center" xs={1}>
|
||||||
<Stack display="flex" direction="row" justifyContent="flex-start" alignItems="center" sx={STYLES.CARD_DETAILS_NAVIGATION_STACK}>
|
<Stack display="flex" direction="row" justifyContent="flex-start" alignItems="center" sx={STYLES.CARD_DETAILS_NAVIGATION_STACK}>
|
||||||
<IconButton disabled={disableNavigateNext} onClick={() => handleNavigate(1)}>
|
<IconButton disabled={disableNavigateNext} onClick={() => handleNavigate(1)}>
|
||||||
<Icon>navigate_next</Icon>
|
<Icon sx={STYLES.NAVIGATE_BUTTONS}>navigate_next</Icon>
|
||||||
</IconButton>
|
</IconButton>
|
||||||
</Stack>
|
</Stack>
|
||||||
</Grid>
|
</Grid>
|
||||||
@ -323,8 +345,8 @@ const PlanDetail = ({ plan, disableNavigatePrev = false, disableNavigateNext = f
|
|||||||
};
|
};
|
||||||
|
|
||||||
//Контроль свойств - Детализация по объекту
|
//Контроль свойств - Детализация по объекту
|
||||||
PlanDetail.propTypes = {
|
PlanSpecDetail.propTypes = {
|
||||||
plan: PropTypes.object,
|
planSpec: PropTypes.object,
|
||||||
disableNavigatePrev: PropTypes.bool,
|
disableNavigatePrev: PropTypes.bool,
|
||||||
disableNavigateNext: PropTypes.bool,
|
disableNavigateNext: PropTypes.bool,
|
||||||
onNavigate: PropTypes.func,
|
onNavigate: PropTypes.func,
|
||||||
@ -335,4 +357,4 @@ PlanDetail.propTypes = {
|
|||||||
//Интерфейс модуля
|
//Интерфейс модуля
|
||||||
//----------------
|
//----------------
|
||||||
|
|
||||||
export { PlanDetail };
|
export { PlanSpecDetail };
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
Парус 8 - Панели мониторинга - ПУП - Мониторинг сборки изделий
|
Парус 8 - Панели мониторинга - ПУП - Мониторинг сборки изделий
|
||||||
Компонент: Список планов
|
Компонент: Список выпусков планов
|
||||||
*/
|
*/
|
||||||
|
|
||||||
//---------------------
|
//---------------------
|
||||||
@ -10,7 +10,7 @@
|
|||||||
import React, { useState } from "react"; //Классы React
|
import React, { useState } from "react"; //Классы React
|
||||||
import { Container, Grid, IconButton, Icon } from "@mui/material"; //Интерфейсные элементы
|
import { Container, Grid, IconButton, Icon } from "@mui/material"; //Интерфейсные элементы
|
||||||
import PropTypes from "prop-types"; //Контроль свойств компонента
|
import PropTypes from "prop-types"; //Контроль свойств компонента
|
||||||
import { PlansListItem } from "./plans_list_item"; //Элемент списка планов
|
import { PlanSpecsListItem } from "./plans_list_item"; //Элемент списка выпусков планов
|
||||||
|
|
||||||
//---------
|
//---------
|
||||||
//Константы
|
//Константы
|
||||||
@ -21,23 +21,24 @@ const DEFAULT_PAGE_SIZE = 5;
|
|||||||
|
|
||||||
//Стили
|
//Стили
|
||||||
const STYLES = {
|
const STYLES = {
|
||||||
PLAN_DOCUMENTS_LIST: { minWidth: "1024px" }
|
PLAN_DOCUMENTS_LIST: { minWidth: "1024px" },
|
||||||
|
NAVIGATE_BUTTONS: { color: "text.title.fontColor" }
|
||||||
};
|
};
|
||||||
|
|
||||||
//-----------
|
//-----------
|
||||||
//Тело модуля
|
//Тело модуля
|
||||||
//-----------
|
//-----------
|
||||||
|
|
||||||
//Список планов
|
//Список выпусков планов
|
||||||
const PlansList = ({ plans, pageSize = DEFAULT_PAGE_SIZE, onItemClick }) => {
|
const PlanSpecsList = ({ planSpecs, pageSize = DEFAULT_PAGE_SIZE, onItemClick }) => {
|
||||||
//Состояние прокрутки списка отображаемых планов
|
//Состояние прокрутки списка отображаемых планов
|
||||||
const [scroll, setScroll] = useState(0);
|
const [scroll, setScroll] = useState(0);
|
||||||
|
|
||||||
//Отработка нажатия на прокрутку списка планов влево
|
//Отработка нажатия на прокрутку списка выпусков планов влево
|
||||||
const handleScrollLeft = () => setScroll(pv => (pv <= 1 ? 0 : pv - 1));
|
const handleScrollLeft = () => setScroll(pv => (pv <= 1 ? 0 : pv - 1));
|
||||||
|
|
||||||
//Отработка нажатия на прокрутку списка планов вправо
|
//Отработка нажатия на прокрутку списка выпусков планов вправо
|
||||||
const handleScrollRight = () => setScroll(pv => (pv + pageSize >= plans.length ? pv : pv + 1));
|
const handleScrollRight = () => setScroll(pv => (pv + pageSize >= planSpecs.length ? pv : pv + 1));
|
||||||
|
|
||||||
//Сборка представления
|
//Сборка представления
|
||||||
return (
|
return (
|
||||||
@ -45,13 +46,13 @@ const PlansList = ({ plans, pageSize = DEFAULT_PAGE_SIZE, onItemClick }) => {
|
|||||||
<Grid container direction="row" justifyContent="center" alignItems="center" spacing={2} sx={STYLES.PLAN_DOCUMENTS_LIST}>
|
<Grid container direction="row" justifyContent="center" alignItems="center" spacing={2} sx={STYLES.PLAN_DOCUMENTS_LIST}>
|
||||||
<Grid item display="flex" justifyContent="center" xs={1}>
|
<Grid item display="flex" justifyContent="center" xs={1}>
|
||||||
<IconButton onClick={handleScrollLeft} disabled={scroll <= 0}>
|
<IconButton onClick={handleScrollLeft} disabled={scroll <= 0}>
|
||||||
<Icon>navigate_before</Icon>
|
<Icon sx={STYLES.NAVIGATE_BUTTONS}>navigate_before</Icon>
|
||||||
</IconButton>
|
</IconButton>
|
||||||
</Grid>
|
</Grid>
|
||||||
{plans.map((el, i) =>
|
{planSpecs.map((el, i) =>
|
||||||
i >= scroll && i < scroll + pageSize ? (
|
i >= scroll && i < scroll + pageSize ? (
|
||||||
<Grid item key={`${el.NRN}_${i}`} xs={2}>
|
<Grid item key={`${el.NRN}_${i}`} xs={2}>
|
||||||
<PlansListItem
|
<PlanSpecsListItem
|
||||||
card={el}
|
card={el}
|
||||||
cardIndex={i}
|
cardIndex={i}
|
||||||
onClick={(card, cardIndex) => (onItemClick ? onItemClick(card, cardIndex) : null)}
|
onClick={(card, cardIndex) => (onItemClick ? onItemClick(card, cardIndex) : null)}
|
||||||
@ -60,8 +61,8 @@ const PlansList = ({ plans, pageSize = DEFAULT_PAGE_SIZE, onItemClick }) => {
|
|||||||
) : null
|
) : null
|
||||||
)}
|
)}
|
||||||
<Grid item display="flex" justifyContent="center" xs={1}>
|
<Grid item display="flex" justifyContent="center" xs={1}>
|
||||||
<IconButton onClick={handleScrollRight} disabled={scroll + pageSize >= plans.length}>
|
<IconButton onClick={handleScrollRight} disabled={scroll + pageSize >= planSpecs.length}>
|
||||||
<Icon>navigate_next</Icon>
|
<Icon sx={STYLES.NAVIGATE_BUTTONS}>navigate_next</Icon>
|
||||||
</IconButton>
|
</IconButton>
|
||||||
</Grid>
|
</Grid>
|
||||||
</Grid>
|
</Grid>
|
||||||
@ -69,9 +70,9 @@ const PlansList = ({ plans, pageSize = DEFAULT_PAGE_SIZE, onItemClick }) => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
//Контроль свойств - Список планов
|
//Контроль свойств - Список выпусков планов
|
||||||
PlansList.propTypes = {
|
PlanSpecsList.propTypes = {
|
||||||
plans: PropTypes.arrayOf(PropTypes.object),
|
planSpecs: PropTypes.arrayOf(PropTypes.object),
|
||||||
pageSize: PropTypes.number,
|
pageSize: PropTypes.number,
|
||||||
onItemClick: PropTypes.func
|
onItemClick: PropTypes.func
|
||||||
};
|
};
|
||||||
@ -80,4 +81,4 @@ PlansList.propTypes = {
|
|||||||
//Интерфейс модуля
|
//Интерфейс модуля
|
||||||
//----------------
|
//----------------
|
||||||
|
|
||||||
export { PlansList };
|
export { PlanSpecsList };
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
Парус 8 - Панели мониторинга - ПУП - Мониторинг сборки изделий
|
Парус 8 - Панели мониторинга - ПУП - Мониторинг сборки изделий
|
||||||
Компонент: Элемент списка планов
|
Компонент: Элемент списка выпусков планов
|
||||||
*/
|
*/
|
||||||
|
|
||||||
//---------------------
|
//---------------------
|
||||||
@ -26,8 +26,10 @@ const STYLES = {
|
|||||||
gap: "24px",
|
gap: "24px",
|
||||||
border: "1px solid",
|
border: "1px solid",
|
||||||
borderRadius: "25px",
|
borderRadius: "25px",
|
||||||
cursor: "pointer"
|
cursor: "pointer",
|
||||||
|
backgroundColor: "background.secondary"
|
||||||
},
|
},
|
||||||
|
TEXT_INFO_FIELD: { color: "text.secondary.fontColor" },
|
||||||
IMAGE_BOX: { width: "180px", height: "180px", alignItems: "center", justifyContent: "center", display: "flex" },
|
IMAGE_BOX: { width: "180px", height: "180px", alignItems: "center", justifyContent: "center", display: "flex" },
|
||||||
IMAGE_LIST_ITEM: { textAlign: "center" },
|
IMAGE_LIST_ITEM: { textAlign: "center" },
|
||||||
IMAGE_IMG: { width: "160px" }
|
IMAGE_IMG: { width: "160px" }
|
||||||
@ -38,7 +40,7 @@ const STYLES = {
|
|||||||
//------------------------------------
|
//------------------------------------
|
||||||
|
|
||||||
//Изображение для элемента
|
//Изображение для элемента
|
||||||
const PlansListItemImage = ({ card }) => {
|
const PlanSpecsListItemImage = ({ card }) => {
|
||||||
return (
|
return (
|
||||||
<Box sx={STYLES.IMAGE_BOX}>
|
<Box sx={STYLES.IMAGE_BOX}>
|
||||||
<ImageList variant="masonry" cols={1} gap={8}>
|
<ImageList variant="masonry" cols={1} gap={8}>
|
||||||
@ -55,7 +57,7 @@ const PlansListItemImage = ({ card }) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
//Контроль свойств - Изображение для элемента
|
//Контроль свойств - Изображение для элемента
|
||||||
PlansListItemImage.propTypes = {
|
PlanSpecsListItemImage.propTypes = {
|
||||||
card: PropTypes.object
|
card: PropTypes.object
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -63,13 +65,13 @@ PlansListItemImage.propTypes = {
|
|||||||
//Тело модуля
|
//Тело модуля
|
||||||
//-----------
|
//-----------
|
||||||
|
|
||||||
//Элемент списка планов
|
//Элемент списка выпусков планов
|
||||||
const PlansListItem = ({ card, cardIndex, onClick }) => {
|
const PlanSpecsListItem = ({ card, cardIndex, onClick }) => {
|
||||||
return (
|
return (
|
||||||
<Box sx={STYLES.CONTAINER} onClick={() => (onClick ? onClick(card, cardIndex) : null)}>
|
<Box sx={STYLES.CONTAINER} onClick={() => (onClick ? onClick(card, cardIndex) : null)}>
|
||||||
<PlansListItemImage card={card} />
|
<PlanSpecsListItemImage card={card} />
|
||||||
<Box textAlign="center">
|
<Box textAlign="center">
|
||||||
<Typography variant="UDO_body1" color="text.secondary.fontColor">
|
<Typography variant="PlanSpecInfo" sx={STYLES.TEXT_INFO_FIELD}>
|
||||||
Номер борта
|
Номер борта
|
||||||
</Typography>
|
</Typography>
|
||||||
<Typography variant="h2">{card.SNUMB}</Typography>
|
<Typography variant="h2">{card.SNUMB}</Typography>
|
||||||
@ -80,10 +82,10 @@ const PlansListItem = ({ card, cardIndex, onClick }) => {
|
|||||||
width={"155px"}
|
width={"155px"}
|
||||||
height={"155px"}
|
height={"155px"}
|
||||||
progressVariant={"h3"}
|
progressVariant={"h3"}
|
||||||
detailVariant={"UDO_body2"}
|
detailVariant={"PlanSpecProgressDetail"}
|
||||||
/>
|
/>
|
||||||
<Box>
|
<Box>
|
||||||
<Typography variant="UDO_body1" color="text.secondary.fontColor">
|
<Typography variant="PlanSpecInfo" sx={STYLES.TEXT_INFO_FIELD}>
|
||||||
Год выпуска:
|
Год выпуска:
|
||||||
</Typography>
|
</Typography>
|
||||||
<Typography variant="subtitle1" mt={-1}>
|
<Typography variant="subtitle1" mt={-1}>
|
||||||
@ -94,8 +96,8 @@ const PlansListItem = ({ card, cardIndex, onClick }) => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
//Контроль свойств - Элемент списка планов
|
//Контроль свойств - Элемент списка выпусков планов
|
||||||
PlansListItem.propTypes = {
|
PlanSpecsListItem.propTypes = {
|
||||||
card: PropTypes.object,
|
card: PropTypes.object,
|
||||||
cardIndex: PropTypes.number,
|
cardIndex: PropTypes.number,
|
||||||
onClick: PropTypes.func
|
onClick: PropTypes.func
|
||||||
@ -105,4 +107,4 @@ PlansListItem.propTypes = {
|
|||||||
//Интерфейс модуля
|
//Интерфейс модуля
|
||||||
//----------------
|
//----------------
|
||||||
|
|
||||||
export { PlansListItem };
|
export { PlanSpecsListItem };
|
||||||
|
@ -24,6 +24,7 @@ const STYLES = {
|
|||||||
flexDirection: "column",
|
flexDirection: "column",
|
||||||
margin: "0px 32px",
|
margin: "0px 32px",
|
||||||
borderRadius: "50%",
|
borderRadius: "50%",
|
||||||
|
backgroundColor: "background.progress",
|
||||||
...(width ? { width } : {}),
|
...(width ? { width } : {}),
|
||||||
...(height ? { height } : {})
|
...(height ? { height } : {})
|
||||||
})
|
})
|
||||||
|
@ -16,7 +16,7 @@ import { object2Base64XML } from "../../core/utils"; //Вспомогатель
|
|||||||
//---------
|
//---------
|
||||||
|
|
||||||
//Размер страницы данных
|
//Размер страницы данных
|
||||||
const DATA_GRID_PAGE_SIZE = 50;
|
const DATA_GRID_PAGE_SIZE = 5;
|
||||||
|
|
||||||
//-----------
|
//-----------
|
||||||
//Тело модуля
|
//Тело модуля
|
||||||
@ -44,9 +44,9 @@ const useMechRecAssemblyMon = () => {
|
|||||||
planCtlgs: [],
|
planCtlgs: [],
|
||||||
planCtlgsLoaded: false,
|
planCtlgsLoaded: false,
|
||||||
selectedPlanCtlg: {},
|
selectedPlanCtlg: {},
|
||||||
plans: [],
|
planSpecs: [],
|
||||||
plansLoaded: false,
|
planSpecsLoaded: false,
|
||||||
selectedPlan: {}
|
selectedPlanSpec: {}
|
||||||
});
|
});
|
||||||
|
|
||||||
//Подключение к контексту взаимодействия с сервером
|
//Подключение к контексту взаимодействия с сервером
|
||||||
@ -76,7 +76,7 @@ const useMechRecAssemblyMon = () => {
|
|||||||
respArg: "COUT",
|
respArg: "COUT",
|
||||||
isArray: name => name === "XFCPRODPLAN_INFO"
|
isArray: name => name === "XFCPRODPLAN_INFO"
|
||||||
});
|
});
|
||||||
setState(pv => ({ ...pv, init: true, plans: [...(data?.XFCPRODPLAN_INFO || [])], plansLoaded: true }));
|
setState(pv => ({ ...pv, init: true, planSpecs: [...(data?.XFCPRODPLAN_INFO || [])], planSpecsLoaded: true }));
|
||||||
}
|
}
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
},
|
},
|
||||||
@ -88,7 +88,7 @@ const useMechRecAssemblyMon = () => {
|
|||||||
setState(pv => ({
|
setState(pv => ({
|
||||||
...pv,
|
...pv,
|
||||||
selectedPlanCtlg: { ...planCtlg },
|
selectedPlanCtlg: { ...planCtlg },
|
||||||
selectedPlan: {},
|
selectedPlanSpec: {},
|
||||||
showPlanList: false
|
showPlanList: false
|
||||||
}));
|
}));
|
||||||
};
|
};
|
||||||
@ -98,7 +98,7 @@ const useMechRecAssemblyMon = () => {
|
|||||||
setState(pv => ({
|
setState(pv => ({
|
||||||
...pv,
|
...pv,
|
||||||
selectedPlanCtlg: {},
|
selectedPlanCtlg: {},
|
||||||
selectedPlan: {},
|
selectedPlanSpec: {},
|
||||||
showPlanList: false
|
showPlanList: false
|
||||||
}));
|
}));
|
||||||
|
|
||||||
@ -114,7 +114,7 @@ const useMechRecAssemblyMon = () => {
|
|||||||
if (state.selectedPlanCtlg) {
|
if (state.selectedPlanCtlg) {
|
||||||
loadPlans(state.selectedPlanCtlg.NRN);
|
loadPlans(state.selectedPlanCtlg.NRN);
|
||||||
} else {
|
} else {
|
||||||
setState(pv => ({ ...pv, plans: [], plansLoaded: false }));
|
setState(pv => ({ ...pv, planSpecs: [], planSpecsLoaded: false }));
|
||||||
}
|
}
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, [state.selectedPlanCtlg]);
|
}, [state.selectedPlanCtlg]);
|
||||||
@ -123,7 +123,7 @@ const useMechRecAssemblyMon = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
//Хук для информации по производственным составам
|
//Хук для информации по производственным составам
|
||||||
const useCostProductComposition = plan => {
|
const useCostProductComposition = planSpec => {
|
||||||
//Собственное состояние
|
//Собственное состояние
|
||||||
let [costProductComposition, setCostProductComposition] = useState({
|
let [costProductComposition, setCostProductComposition] = useState({
|
||||||
showPlanList: false,
|
showPlanList: false,
|
||||||
@ -141,7 +141,7 @@ const useCostProductComposition = plan => {
|
|||||||
const loadData = async () => {
|
const loadData = async () => {
|
||||||
const data = await executeStored({
|
const data = await executeStored({
|
||||||
stored: "PKG_P8PANELS_MECHREC.FCPRODCMP_DETAILS_GET",
|
stored: "PKG_P8PANELS_MECHREC.FCPRODCMP_DETAILS_GET",
|
||||||
args: { NFCPRODPLAN: plan },
|
args: { NFCPRODPLANSP: planSpec },
|
||||||
respArg: "COUT",
|
respArg: "COUT",
|
||||||
isArray: name => name === "XFCPRODCMP"
|
isArray: name => name === "XFCPRODCMP"
|
||||||
});
|
});
|
||||||
@ -153,15 +153,15 @@ const useCostProductComposition = plan => {
|
|||||||
selectedProduct: null
|
selectedProduct: null
|
||||||
}));
|
}));
|
||||||
};
|
};
|
||||||
if (plan) loadData();
|
if (planSpec) loadData();
|
||||||
}, [plan, executeStored]);
|
}, [planSpec, executeStored]);
|
||||||
|
|
||||||
//Вернём данные
|
//Вернём данные
|
||||||
return [costProductComposition, setCostProductComposition];
|
return [costProductComposition, setCostProductComposition];
|
||||||
};
|
};
|
||||||
|
|
||||||
//Хук для таблицы детализации изделия
|
//Хук для таблицы детализации изделия
|
||||||
const useProductDetailsTable = (plan, product, orders, pageNumber, stored) => {
|
const useProductDetailsTable = (planSpec, product, orders, pageNumber, stored) => {
|
||||||
//Собственное состояние - флаг загрузки
|
//Собственное состояние - флаг загрузки
|
||||||
const [isLoading, setLoading] = useState(false);
|
const [isLoading, setLoading] = useState(false);
|
||||||
|
|
||||||
@ -184,8 +184,7 @@ const useProductDetailsTable = (plan, product, orders, pageNumber, stored) => {
|
|||||||
const data = await executeStored({
|
const data = await executeStored({
|
||||||
stored,
|
stored,
|
||||||
args: {
|
args: {
|
||||||
NPRODCMPSP: product,
|
NFCPRODPLANSP: planSpec,
|
||||||
NFCPRODPLAN: plan,
|
|
||||||
CORDERS: { VALUE: object2Base64XML(orders, { arrayNodeName: "orders" }), SDATA_TYPE: SERV_DATA_TYPE_CLOB },
|
CORDERS: { VALUE: object2Base64XML(orders, { arrayNodeName: "orders" }), SDATA_TYPE: SERV_DATA_TYPE_CLOB },
|
||||||
NPAGE_NUMBER: pageNumber,
|
NPAGE_NUMBER: pageNumber,
|
||||||
NPAGE_SIZE: DATA_GRID_PAGE_SIZE,
|
NPAGE_SIZE: DATA_GRID_PAGE_SIZE,
|
||||||
@ -205,8 +204,8 @@ const useProductDetailsTable = (plan, product, orders, pageNumber, stored) => {
|
|||||||
setLoading(false);
|
setLoading(false);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
if (plan && product) loadData();
|
if (planSpec && product) loadData();
|
||||||
}, [plan, product, orders, pageNumber, stored, executeStored, SERV_DATA_TYPE_CLOB]);
|
}, [planSpec, product, orders, pageNumber, stored, executeStored, SERV_DATA_TYPE_CLOB]);
|
||||||
|
|
||||||
//Вернём данные
|
//Вернём данные
|
||||||
return { data, isLoading };
|
return { data, isLoading };
|
||||||
|
@ -7,14 +7,29 @@
|
|||||||
//Подключение библиотек
|
//Подключение библиотек
|
||||||
//---------------------
|
//---------------------
|
||||||
|
|
||||||
import React, { useState, useContext } from "react"; //Классы React
|
import React, { useState } from "react"; //Классы React
|
||||||
import PropTypes from "prop-types"; //Контроль свойств компонента
|
import PropTypes from "prop-types"; //Контроль свойств компонента
|
||||||
import { Drawer, Fab, Box, List, ListItemButton, ListItemText, Typography, TextField, FormGroup, FormControlLabel, Checkbox } from "@mui/material"; //Интерфейсные элементы
|
import {
|
||||||
|
Drawer,
|
||||||
|
Fab,
|
||||||
|
Box,
|
||||||
|
List,
|
||||||
|
ListItemButton,
|
||||||
|
ListItemText,
|
||||||
|
Typography,
|
||||||
|
TextField,
|
||||||
|
FormGroup,
|
||||||
|
FormControlLabel,
|
||||||
|
Checkbox,
|
||||||
|
Container,
|
||||||
|
IconButton,
|
||||||
|
Stack,
|
||||||
|
Icon
|
||||||
|
} from "@mui/material"; //Интерфейсные элементы
|
||||||
import { ThemeProvider } from "@mui/material/styles"; //Подключение темы
|
import { ThemeProvider } from "@mui/material/styles"; //Подключение темы
|
||||||
import { MessagingСtx } from "../../context/messaging"; //Контекст сообщений
|
import { PlanSpecsList } from "./components/plans_list"; //Список планов
|
||||||
import { PlansList } from "./components/plans_list"; //Список планов
|
import { PlanSpecDetail } from "./components/plan_detail"; //Детали плана
|
||||||
import { PlanDetail } from "./components/plan_detail"; //Детали плана
|
import { lightTheme, darkTheme } from "./styles/themes"; //Стиль темы
|
||||||
import { theme } from "./styles/themes"; //Стиль темы
|
|
||||||
import { useMechRecAssemblyMon, useFilteredPlanCtlgs } from "./hooks"; //Вспомогательные хуки
|
import { useMechRecAssemblyMon, useFilteredPlanCtlgs } from "./hooks"; //Вспомогательные хуки
|
||||||
|
|
||||||
//---------
|
//---------
|
||||||
@ -23,9 +38,19 @@ import { useMechRecAssemblyMon, useFilteredPlanCtlgs } from "./hooks"; //Всп
|
|||||||
|
|
||||||
//Стили
|
//Стили
|
||||||
const STYLES = {
|
const STYLES = {
|
||||||
PLANS_FINDER: { marginTop: "10px", marginLeft: "10px", width: "93%" },
|
PLANS_FINDER: {
|
||||||
PLANS_CHECKBOX_HAVEDOCS: { alignContent: "space-around" },
|
marginTop: "10px",
|
||||||
PLANS_LIST_ITEM_ZERODOCS: { backgroundColor: "#ebecec" },
|
marginLeft: "10px",
|
||||||
|
width: "93%",
|
||||||
|
[`& .MuiFormLabel-root.Mui-focused`]: { color: "text.title.fontColor" },
|
||||||
|
[`& .MuiInputBase-root`]: { color: "text.plans_finder.fontColor" },
|
||||||
|
[`& .MuiInputBase-root.Mui-focused::after`]: { borderBottom: "2px solid black" }
|
||||||
|
},
|
||||||
|
PLANS_CHECKBOX_HAVEDOCS: {
|
||||||
|
alignContent: "space-around",
|
||||||
|
[`& .MuiCheckbox-root.Mui-checked`]: { color: "text.title.fontColor" }
|
||||||
|
},
|
||||||
|
PLANS_LIST_ITEM_ZERODOCS: { backgroundColor: "background.plans_zero_docs" },
|
||||||
PLANS_LIST_ITEM_PRIMARY: { wordWrap: "break-word" },
|
PLANS_LIST_ITEM_PRIMARY: { wordWrap: "break-word" },
|
||||||
PLANS_LIST_ITEM_SECONDARY: { wordWrap: "break-word", fontSize: "0.6rem", textTransform: "uppercase" },
|
PLANS_LIST_ITEM_SECONDARY: { wordWrap: "break-word", fontSize: "0.6rem", textTransform: "uppercase" },
|
||||||
PLANS_BUTTON: { position: "absolute" },
|
PLANS_BUTTON: { position: "absolute" },
|
||||||
@ -33,9 +58,18 @@ const STYLES = {
|
|||||||
width: "350px",
|
width: "350px",
|
||||||
display: "inline-block",
|
display: "inline-block",
|
||||||
flexShrink: 0,
|
flexShrink: 0,
|
||||||
[`& .MuiDrawer-paper`]: { width: "350px", display: "inline-block", boxSizing: "border-box" }
|
[`& .MuiDrawer-paper`]: {
|
||||||
|
width: "350px",
|
||||||
|
display: "inline-block",
|
||||||
|
boxSizing: "border-box",
|
||||||
|
backgroundColor: "background.plans_drawer_paper",
|
||||||
|
color: "text.plans_finder.fontColor"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
PLANS_LIST_BOX: { paddingTop: "20px" }
|
PLANS_LIST_BOX: { paddingTop: "20px" },
|
||||||
|
ROOT_BG: { backgroundColor: "background.main", minHeight: "calc(100vh - 64px)", overflow: "hidden" },
|
||||||
|
THEME_CHANGER: { color: "text.title.fontColor" },
|
||||||
|
MAIN_TITLE: { textAlign: "center", color: "text.title.fontColor", marginTop: "-24px" }
|
||||||
};
|
};
|
||||||
|
|
||||||
//------------------------------------
|
//------------------------------------
|
||||||
@ -116,6 +150,8 @@ PlanCtlgsList.propTypes = {
|
|||||||
|
|
||||||
//Корневая панель мониторинга сборки изделий
|
//Корневая панель мониторинга сборки изделий
|
||||||
const MechRecAssemblyMon = () => {
|
const MechRecAssemblyMon = () => {
|
||||||
|
//Состояние - текущая тема
|
||||||
|
const [theme, setTheme] = useState(lightTheme);
|
||||||
//Собственное состояние
|
//Собственное состояние
|
||||||
const [state, setState, selectPlanCtlg, unselectPlanCtlg] = useMechRecAssemblyMon();
|
const [state, setState, selectPlanCtlg, unselectPlanCtlg] = useMechRecAssemblyMon();
|
||||||
|
|
||||||
@ -132,9 +168,6 @@ const MechRecAssemblyMon = () => {
|
|||||||
//Массив отфильтрованных каталогов
|
//Массив отфильтрованных каталогов
|
||||||
const filteredPlanCtgls = useFilteredPlanCtlgs(state.planCtlgs, filter);
|
const filteredPlanCtgls = useFilteredPlanCtlgs(state.planCtlgs, filter);
|
||||||
|
|
||||||
//Подключение к контексту сообщений
|
|
||||||
const { InlineMsgInfo } = useContext(MessagingСtx);
|
|
||||||
|
|
||||||
//Обработка нажатия на элемент в списке каталогов планов
|
//Обработка нажатия на элемент в списке каталогов планов
|
||||||
const handlePlanCtlgClick = planCtlg => {
|
const handlePlanCtlgClick = planCtlg => {
|
||||||
if (state.selectedPlanCtlg.NRN != planCtlg.NRN) selectPlanCtlg(planCtlg);
|
if (state.selectedPlanCtlg.NRN != planCtlg.NRN) selectPlanCtlg(planCtlg);
|
||||||
@ -144,15 +177,15 @@ const MechRecAssemblyMon = () => {
|
|||||||
//Перемещение к нужному плану
|
//Перемещение к нужному плану
|
||||||
const navigateToPlan = planIndex => {
|
const navigateToPlan = planIndex => {
|
||||||
if (planIndex < 0) planIndex = 0;
|
if (planIndex < 0) planIndex = 0;
|
||||||
if (planIndex > state.plans.length - 1) planIndex = state.plans.length - 1;
|
if (planIndex > state.planSpecs.length - 1) planIndex = state.planSpecs.length - 1;
|
||||||
setState(pv => ({
|
setState(pv => ({
|
||||||
...pv,
|
...pv,
|
||||||
selectedPlan: { ...state.plans[planIndex] }
|
selectedPlanSpec: { ...state.planSpecs[planIndex] }
|
||||||
}));
|
}));
|
||||||
setPlanDetailNavigation(pv => ({
|
setPlanDetailNavigation(pv => ({
|
||||||
...pv,
|
...pv,
|
||||||
disableNavigatePrev: planIndex == 0 ? true : false,
|
disableNavigatePrev: planIndex == 0 ? true : false,
|
||||||
disableNavigateNext: planIndex == state.plans.length - 1 ? true : false,
|
disableNavigateNext: planIndex == state.planSpecs.length - 1 ? true : false,
|
||||||
currentPlanIndex: planIndex
|
currentPlanIndex: planIndex
|
||||||
}));
|
}));
|
||||||
};
|
};
|
||||||
@ -162,12 +195,17 @@ const MechRecAssemblyMon = () => {
|
|||||||
|
|
||||||
//Обработка нажатия на кнопку "Назад"
|
//Обработка нажатия на кнопку "Назад"
|
||||||
const handlePlanDetailBackClick = () => {
|
const handlePlanDetailBackClick = () => {
|
||||||
setState(pv => ({ ...pv, selectedPlan: {} }));
|
setState(pv => ({ ...pv, selectedPlanSpec: {} }));
|
||||||
};
|
};
|
||||||
|
|
||||||
//Обработка навигации из карточки с деталями плана
|
//Обработка навигации из карточки с деталями плана
|
||||||
const handlePlanDetailNavigateClick = direction => navigateToPlan(planDetailNavigation.currentPlanIndex + direction);
|
const handlePlanDetailNavigateClick = direction => navigateToPlan(planDetailNavigation.currentPlanIndex + direction);
|
||||||
|
|
||||||
|
//Обработка изменения темы
|
||||||
|
const handleThemeChange = () => {
|
||||||
|
setTheme(theme.palette.type === "light" ? darkTheme : lightTheme);
|
||||||
|
};
|
||||||
|
|
||||||
//Формирование текста заголовка
|
//Формирование текста заголовка
|
||||||
const title = `${state.selectedPlanCtlg.SNAME} на ${state.selectedPlanCtlg.NMIN_YEAR} ${
|
const title = `${state.selectedPlanCtlg.SNAME} на ${state.selectedPlanCtlg.NMIN_YEAR} ${
|
||||||
state.selectedPlanCtlg.NMIN_YEAR == state.selectedPlanCtlg.NMAX_YEAR ? "г." : `- ${state.selectedPlanCtlg.NMAX_YEAR} г.г.`
|
state.selectedPlanCtlg.NMIN_YEAR == state.selectedPlanCtlg.NMAX_YEAR ? "г." : `- ${state.selectedPlanCtlg.NMAX_YEAR} г.г.`
|
||||||
@ -175,10 +213,11 @@ const MechRecAssemblyMon = () => {
|
|||||||
|
|
||||||
//Генерация содержимого
|
//Генерация содержимого
|
||||||
return (
|
return (
|
||||||
<Box p={2}>
|
|
||||||
<ThemeProvider theme={theme}>
|
<ThemeProvider theme={theme}>
|
||||||
|
<Container maxWidth={false} disableGutters sx={STYLES.ROOT_BG}>
|
||||||
|
<Box p={2}>
|
||||||
<Fab variant="extended" sx={STYLES.PLANS_BUTTON} onClick={() => setState(pv => ({ ...pv, showPlanList: !pv.showPlanList }))}>
|
<Fab variant="extended" sx={STYLES.PLANS_BUTTON} onClick={() => setState(pv => ({ ...pv, showPlanList: !pv.showPlanList }))}>
|
||||||
Программы
|
Каталоги планов
|
||||||
</Fab>
|
</Fab>
|
||||||
<Drawer
|
<Drawer
|
||||||
anchor={"left"}
|
anchor={"left"}
|
||||||
@ -194,16 +233,21 @@ const MechRecAssemblyMon = () => {
|
|||||||
onClick={handlePlanCtlgClick}
|
onClick={handlePlanCtlgClick}
|
||||||
/>
|
/>
|
||||||
</Drawer>
|
</Drawer>
|
||||||
|
<Stack display="flex" direction="row" justifyContent="flex-end" alignItems="center">
|
||||||
|
<IconButton onClick={() => handleThemeChange()}>
|
||||||
|
<Icon sx={STYLES.THEME_CHANGER}>{theme.palette.type === "light" ? "brightness_4" : "brightness_7"}</Icon>
|
||||||
|
</IconButton>
|
||||||
|
</Stack>
|
||||||
{state.init == true ? (
|
{state.init == true ? (
|
||||||
state.selectedPlanCtlg.NRN ? (
|
state.selectedPlanCtlg.NRN ? (
|
||||||
<>
|
<>
|
||||||
<Typography variant="h3" align="center" color="text.title.fontColor" py={2}>
|
<Typography variant="h3" sx={STYLES.MAIN_TITLE} pb={2}>
|
||||||
{title}
|
{title}
|
||||||
</Typography>
|
</Typography>
|
||||||
{state.plansLoaded == true ? (
|
{state.planSpecsLoaded == true ? (
|
||||||
state.selectedPlan.NRN ? (
|
state.selectedPlanSpec.NRN ? (
|
||||||
<PlanDetail
|
<PlanSpecDetail
|
||||||
plan={state.selectedPlan}
|
planSpec={state.selectedPlanSpec}
|
||||||
disableNavigatePrev={planDetailNavigation.disableNavigatePrev}
|
disableNavigatePrev={planDetailNavigation.disableNavigatePrev}
|
||||||
disableNavigateNext={planDetailNavigation.disableNavigateNext}
|
disableNavigateNext={planDetailNavigation.disableNavigateNext}
|
||||||
onNavigate={handlePlanDetailNavigateClick}
|
onNavigate={handlePlanDetailNavigateClick}
|
||||||
@ -211,17 +255,20 @@ const MechRecAssemblyMon = () => {
|
|||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<Box sx={STYLES.PLANS_LIST_BOX}>
|
<Box sx={STYLES.PLANS_LIST_BOX}>
|
||||||
<PlansList plans={state.plans} onItemClick={handlePlanClick} />
|
<PlanSpecsList planSpecs={state.planSpecs} onItemClick={handlePlanClick} />
|
||||||
</Box>
|
</Box>
|
||||||
)
|
)
|
||||||
) : null}
|
) : null}
|
||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
<InlineMsgInfo okBtn={false} text={"Укажите каталог планов для отображения его спецификаций"} />
|
<Typography variant="h4" sx={STYLES.MAIN_TITLE}>
|
||||||
|
Укажите каталог планов для отображения спецификаций
|
||||||
|
</Typography>
|
||||||
)
|
)
|
||||||
) : null}
|
) : null}
|
||||||
</ThemeProvider>
|
|
||||||
</Box>
|
</Box>
|
||||||
|
</Container>
|
||||||
|
</ThemeProvider>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,67 +1,130 @@
|
|||||||
import { createTheme } from "@mui/material/styles"; //Интерфейсные элементы
|
import { createTheme } from "@mui/material/styles"; //Интерфейсные элементы
|
||||||
|
|
||||||
//Описание темы
|
//---------
|
||||||
const theme = createTheme({
|
//Константы
|
||||||
palette: {
|
//---------
|
||||||
text: {
|
|
||||||
title: { fontColor: "rgba(0, 0, 0, 0.65)" },
|
//Насыщенность шрифта
|
||||||
secondary: { fontColor: "rgba(0, 0, 0, 0.298)" }
|
const FONT_WEIGHT_NORMAL = 400;
|
||||||
}
|
const FONT_WEIGHT_BOLD = 700;
|
||||||
},
|
|
||||||
typography: {
|
//Выравнивание текста
|
||||||
|
const TEXT_ALIGN_CENTER = "center";
|
||||||
|
|
||||||
|
//Стиль для детализации прогресса и сообщения таблицы детализации
|
||||||
|
const smallSizedText = {
|
||||||
|
fontSize: "12px",
|
||||||
|
fontWeight: FONT_WEIGHT_NORMAL,
|
||||||
|
whiteSpace: "pre-line",
|
||||||
|
textAlign: TEXT_ALIGN_CENTER,
|
||||||
|
wordWrap: "break-word",
|
||||||
|
letterSpacing: "0.00938em",
|
||||||
|
lineHeight: "1.5"
|
||||||
|
};
|
||||||
|
|
||||||
|
//Стили кастомных шрифтов
|
||||||
|
const customTypography = {
|
||||||
h1: {
|
h1: {
|
||||||
fontSize: "40px",
|
fontSize: "40px",
|
||||||
fontWeight: 400,
|
fontWeight: FONT_WEIGHT_NORMAL,
|
||||||
textAlign: "center"
|
textAlign: TEXT_ALIGN_CENTER
|
||||||
},
|
},
|
||||||
h2: {
|
h2: {
|
||||||
fontSize: "40px",
|
fontSize: "40px",
|
||||||
fontWeight: 700,
|
fontWeight: FONT_WEIGHT_BOLD,
|
||||||
textAlign: "center"
|
textAlign: TEXT_ALIGN_CENTER
|
||||||
},
|
},
|
||||||
h3: {
|
h3: {
|
||||||
fontSize: "30px",
|
fontSize: "30px",
|
||||||
fontWeight: 700,
|
fontWeight: FONT_WEIGHT_BOLD,
|
||||||
textAlign: "center"
|
textAlign: TEXT_ALIGN_CENTER
|
||||||
},
|
},
|
||||||
h4: {
|
h4: {
|
||||||
fontSize: "16px",
|
fontSize: "16px",
|
||||||
fontWeight: 400,
|
fontWeight: FONT_WEIGHT_NORMAL,
|
||||||
textAlign: "center"
|
textAlign: TEXT_ALIGN_CENTER
|
||||||
},
|
},
|
||||||
subtitle1: {
|
subtitle1: {
|
||||||
fontSize: "30px",
|
fontSize: "30px",
|
||||||
fontWeight: 400,
|
fontWeight: FONT_WEIGHT_NORMAL,
|
||||||
textAlign: "center"
|
textAlign: TEXT_ALIGN_CENTER
|
||||||
},
|
},
|
||||||
subtitle2: {
|
subtitle2: {
|
||||||
fontSize: "20px",
|
fontSize: "20px",
|
||||||
fontWeight: 700,
|
fontWeight: FONT_WEIGHT_BOLD,
|
||||||
textAlign: "center"
|
textAlign: TEXT_ALIGN_CENTER
|
||||||
},
|
|
||||||
UDO_body1: {
|
|
||||||
fontSize: "14px",
|
|
||||||
fontWeight: 400,
|
|
||||||
textAlign: "center",
|
|
||||||
wordWrap: "break-word",
|
|
||||||
letterSpacing: "0.00938em",
|
|
||||||
lineHeight: "1.5"
|
|
||||||
},
|
|
||||||
UDO_body2: {
|
|
||||||
fontSize: "12px",
|
|
||||||
fontWeight: 400,
|
|
||||||
whiteSpace: "pre-line",
|
|
||||||
textAlign: "center",
|
|
||||||
wordWrap: "break-word",
|
|
||||||
letterSpacing: "0.00938em",
|
|
||||||
lineHeight: "1.5"
|
|
||||||
},
|
},
|
||||||
body3: {
|
body3: {
|
||||||
fontSize: "9px",
|
fontSize: "9px",
|
||||||
whiteSpace: "pre-line",
|
whiteSpace: "pre-line",
|
||||||
textAlign: "center"
|
textAlign: TEXT_ALIGN_CENTER
|
||||||
|
},
|
||||||
|
PlanSpecInfo: {
|
||||||
|
fontSize: "14px",
|
||||||
|
fontWeight: FONT_WEIGHT_NORMAL,
|
||||||
|
textAlign: TEXT_ALIGN_CENTER,
|
||||||
|
wordWrap: "break-word",
|
||||||
|
letterSpacing: "0.00938em",
|
||||||
|
lineHeight: "1.5"
|
||||||
|
},
|
||||||
|
PlanSpecProgressDetail: {
|
||||||
|
...smallSizedText
|
||||||
|
},
|
||||||
|
ProductDetailMessage: {
|
||||||
|
...smallSizedText
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
//---------
|
||||||
|
//Описание темы
|
||||||
|
//---------
|
||||||
|
|
||||||
|
const lightTheme = createTheme({
|
||||||
|
palette: {
|
||||||
|
type: "light",
|
||||||
|
background: {
|
||||||
|
main: "#fff",
|
||||||
|
secondary: "#fff",
|
||||||
|
progress: "#fff",
|
||||||
|
detail_table: "#fff",
|
||||||
|
detail_info: "#fff",
|
||||||
|
product_selector: "#fff",
|
||||||
|
plans_zero_docs: "#ebecec",
|
||||||
|
plans_drawer_paper: "#fff"
|
||||||
|
},
|
||||||
|
text: {
|
||||||
|
title: { fontColor: "rgba(0, 0, 0, 0.65)" },
|
||||||
|
detail_table: { fontColor: "rgba(0, 0, 0, 0.87)" },
|
||||||
|
secondary: { fontColor: "rgba(0, 0, 0, 0.298)" },
|
||||||
|
plans_finder: { fontColor: "black" },
|
||||||
|
more_button: { fontColor: "#1976d2" }
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
typography: { ...customTypography }
|
||||||
});
|
});
|
||||||
|
|
||||||
export { theme };
|
const darkTheme = createTheme({
|
||||||
|
palette: {
|
||||||
|
type: "dark",
|
||||||
|
background: {
|
||||||
|
main: "#161616",
|
||||||
|
secondary: "#d2d2d2",
|
||||||
|
progress: "#e8e8e8",
|
||||||
|
detail_table: "#3f3f3f",
|
||||||
|
detail_info: "#d0d0d0",
|
||||||
|
product_selector: "#eee",
|
||||||
|
plans_zero_docs: "#323232",
|
||||||
|
plans_drawer_paper: "#3f3f3f"
|
||||||
|
},
|
||||||
|
text: {
|
||||||
|
title: { fontColor: "#fff" },
|
||||||
|
detail_table: { fontColor: "#fff" },
|
||||||
|
secondary: { fontColor: "rgba(0, 0, 0, 0.298)" },
|
||||||
|
plans_finder: { fontColor: "#fff" },
|
||||||
|
more_button: { fontColor: "#fff" }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
typography: { ...customTypography }
|
||||||
|
});
|
||||||
|
|
||||||
|
export { lightTheme, darkTheme };
|
||||||
|
@ -1,337 +0,0 @@
|
|||||||
//---------------------
|
|
||||||
//Подключение библиотек
|
|
||||||
//---------------------
|
|
||||||
|
|
||||||
import { useState, useCallback, useEffect, useContext } from "react"; //Классы React
|
|
||||||
import { BackEndСtx } from "../../context/backend"; //Контекст взаимодействия с сервером
|
|
||||||
import { object2Base64XML } from "../../core/utils"; //Вспомогательные функции
|
|
||||||
|
|
||||||
//---------
|
|
||||||
//Константы
|
|
||||||
//---------
|
|
||||||
|
|
||||||
//Размер страницы данных
|
|
||||||
const DATA_GRID_PAGE_SIZE = 5;
|
|
||||||
const DATA_GRID_PAGE_FCEQUIPMENT = 10;
|
|
||||||
|
|
||||||
//---------------------------------------------
|
|
||||||
//Вспомогательные функции форматирования данных
|
|
||||||
//---------------------------------------------
|
|
||||||
|
|
||||||
//Переиницализация выбранных значений строк (необходимо при сортировке или добавлении записей строк)
|
|
||||||
const updatingSelected = (rows, selectedRows) => {
|
|
||||||
//Если полученный массив строк не пустой
|
|
||||||
if (rows.length > 0 && selectedRows.length > 0) {
|
|
||||||
//Устанавливаем выбор там, где он был установлен
|
|
||||||
let updatedRows = rows.map(item => {
|
|
||||||
if (selectedRows.includes(item.NRN)) {
|
|
||||||
return { ...item, NSELECT: 1 };
|
|
||||||
} else {
|
|
||||||
return item;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return updatedRows;
|
|
||||||
}
|
|
||||||
//Возвращаем
|
|
||||||
return rows;
|
|
||||||
};
|
|
||||||
|
|
||||||
//-----------
|
|
||||||
//Тело модуля
|
|
||||||
//-----------
|
|
||||||
|
|
||||||
//Хук для таблицы маршрутных листов
|
|
||||||
const useCostRouteLists = (task, processIdent) => {
|
|
||||||
//Собственное состояние - таблица данных
|
|
||||||
const [costRouteLists, setCostRouteLists] = useState({
|
|
||||||
task: null,
|
|
||||||
dataLoaded: false,
|
|
||||||
columnsDef: [],
|
|
||||||
orders: null,
|
|
||||||
rows: [],
|
|
||||||
selectedRows: [],
|
|
||||||
reload: true,
|
|
||||||
pageNumber: 1,
|
|
||||||
morePages: true
|
|
||||||
});
|
|
||||||
|
|
||||||
//Подключение к контексту взаимодействия с сервером
|
|
||||||
const { executeStored, SERV_DATA_TYPE_CLOB } = useContext(BackEndСtx);
|
|
||||||
|
|
||||||
//Загрузка данных таблицы с сервера
|
|
||||||
const loadData = useCallback(async () => {
|
|
||||||
if (costRouteLists.reload) {
|
|
||||||
const data = await executeStored({
|
|
||||||
stored: "PKG_P8PANELS_MECHREC.FCJOBSSP_FCROUTLST_DG_GET",
|
|
||||||
args: {
|
|
||||||
NFCJOBS: task,
|
|
||||||
CORDERS: { VALUE: object2Base64XML(costRouteLists.orders, { arrayNodeName: "orders" }), SDATA_TYPE: SERV_DATA_TYPE_CLOB },
|
|
||||||
NPAGE_NUMBER: costRouteLists.pageNumber,
|
|
||||||
NPAGE_SIZE: DATA_GRID_PAGE_SIZE,
|
|
||||||
NINCLUDE_DEF: costRouteLists.dataLoaded ? 0 : 1
|
|
||||||
},
|
|
||||||
respArg: "COUT",
|
|
||||||
attributeValueProcessor: (name, val) => (["NSELECT"].includes(name) ? val === 1 : val)
|
|
||||||
});
|
|
||||||
setCostRouteLists(pv => ({
|
|
||||||
...pv,
|
|
||||||
task: task,
|
|
||||||
columnsDef: data.XCOLUMNS_DEF ? [...data.XCOLUMNS_DEF] : pv.columnsDef,
|
|
||||||
rows:
|
|
||||||
pv.pageNumber == 1
|
|
||||||
? updatingSelected([...(data.XROWS || [])], costRouteLists.selectedRows)
|
|
||||||
: updatingSelected([...pv.rows, ...(data.XROWS || [])], costRouteLists.selectedRows),
|
|
||||||
dataLoaded: true,
|
|
||||||
reload: false,
|
|
||||||
morePages: (data.XROWS || []).length >= DATA_GRID_PAGE_SIZE
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
||||||
}, [
|
|
||||||
costRouteLists.reload,
|
|
||||||
costRouteLists.filters,
|
|
||||||
costRouteLists.orders,
|
|
||||||
costRouteLists.dataLoaded,
|
|
||||||
costRouteLists.pageNumber,
|
|
||||||
executeStored,
|
|
||||||
SERV_DATA_TYPE_CLOB
|
|
||||||
]);
|
|
||||||
|
|
||||||
//Добавление/удаление записи в селектлисте
|
|
||||||
const modifySelectList = useCallback(
|
|
||||||
async prms => {
|
|
||||||
try {
|
|
||||||
if (prms.NSELECT) {
|
|
||||||
await executeStored({
|
|
||||||
stored: "PKG_P8PANELS_MECHREC.SELECTLIST_FCROUTLST_ADD",
|
|
||||||
args: { NIDENT: processIdent, NFCROUTLST: prms.NFCROUTLST }
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
await executeStored({
|
|
||||||
stored: "PKG_P8PANELS_MECHREC.SELECTLIST_FCROUTLST_DEL",
|
|
||||||
args: { NIDENT: processIdent, NFCROUTLST: prms.NFCROUTLST }
|
|
||||||
});
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
throw new Error(e.message);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
||||||
[executeStored]
|
|
||||||
);
|
|
||||||
|
|
||||||
//При необходимости обновить данные таблицы
|
|
||||||
useEffect(() => {
|
|
||||||
loadData();
|
|
||||||
}, [costRouteLists.reload, loadData]);
|
|
||||||
|
|
||||||
//При изменении сменного задания
|
|
||||||
useEffect(() => {
|
|
||||||
setCostRouteLists(pv => ({
|
|
||||||
...pv,
|
|
||||||
dataLoaded: false,
|
|
||||||
columnsDef: [],
|
|
||||||
orders: null,
|
|
||||||
rows: [],
|
|
||||||
selectedRows: [],
|
|
||||||
reload: true,
|
|
||||||
pageNumber: 1,
|
|
||||||
morePages: true
|
|
||||||
}));
|
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
||||||
}, [task]);
|
|
||||||
|
|
||||||
return [costRouteLists, setCostRouteLists, modifySelectList];
|
|
||||||
};
|
|
||||||
|
|
||||||
//Хук для таблицы операций
|
|
||||||
const useCostJobsSpecs = (task, fcroutlstList, processIdent) => {
|
|
||||||
//Собственное состояние - таблица данных
|
|
||||||
const [costJobsSpecs, setCostJobsSpecs] = useState({
|
|
||||||
task: null,
|
|
||||||
dataLoaded: false,
|
|
||||||
columnsDef: [],
|
|
||||||
orders: null,
|
|
||||||
rows: [],
|
|
||||||
selectedRows: [],
|
|
||||||
reload: true,
|
|
||||||
pageNumber: 1,
|
|
||||||
morePages: true
|
|
||||||
});
|
|
||||||
|
|
||||||
//Подключение к контексту взаимодействия с сервером
|
|
||||||
const { executeStored, SERV_DATA_TYPE_CLOB } = useContext(BackEndСtx);
|
|
||||||
|
|
||||||
//Загрузка данных таблицы с сервера
|
|
||||||
const loadData = useCallback(async () => {
|
|
||||||
if (costJobsSpecs.reload) {
|
|
||||||
const data = await executeStored({
|
|
||||||
stored: "PKG_P8PANELS_MECHREC.FCJOBSSP_DG_GET",
|
|
||||||
args: {
|
|
||||||
NFCJOBS: task,
|
|
||||||
NIDENT: processIdent,
|
|
||||||
//SFCROUTLST_LIST: fcroutlstList.join(","),
|
|
||||||
CORDERS: { VALUE: object2Base64XML(costJobsSpecs.orders, { arrayNodeName: "orders" }), SDATA_TYPE: SERV_DATA_TYPE_CLOB },
|
|
||||||
NPAGE_NUMBER: costJobsSpecs.pageNumber,
|
|
||||||
NPAGE_SIZE: DATA_GRID_PAGE_SIZE,
|
|
||||||
NINCLUDE_DEF: costJobsSpecs.dataLoaded ? 0 : 1
|
|
||||||
},
|
|
||||||
respArg: "COUT",
|
|
||||||
attributeValueProcessor: (name, val) => (["NSELECT"].includes(name) ? val === 1 : val)
|
|
||||||
});
|
|
||||||
setCostJobsSpecs(pv => ({
|
|
||||||
...pv,
|
|
||||||
task: task,
|
|
||||||
columnsDef: data.XCOLUMNS_DEF ? [...data.XCOLUMNS_DEF] : pv.columnsDef,
|
|
||||||
rows:
|
|
||||||
pv.pageNumber == 1
|
|
||||||
? updatingSelected([...(data.XROWS || [])], costJobsSpecs.selectedRows)
|
|
||||||
: updatingSelected([...pv.rows, ...(data.XROWS || [])], costJobsSpecs.selectedRows),
|
|
||||||
dataLoaded: true,
|
|
||||||
reload: false,
|
|
||||||
morePages: (data.XROWS || []).length >= DATA_GRID_PAGE_SIZE
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
||||||
}, [
|
|
||||||
costJobsSpecs.reload,
|
|
||||||
costJobsSpecs.filters,
|
|
||||||
costJobsSpecs.orders,
|
|
||||||
costJobsSpecs.dataLoaded,
|
|
||||||
costJobsSpecs.pageNumber,
|
|
||||||
executeStored,
|
|
||||||
SERV_DATA_TYPE_CLOB
|
|
||||||
]);
|
|
||||||
|
|
||||||
//Выдача задания
|
|
||||||
const issueCostJobsSpecs = useCallback(
|
|
||||||
async prms => {
|
|
||||||
try {
|
|
||||||
await executeStored({
|
|
||||||
stored: "PKG_P8PANELS_MECHREC.FCJOBSSP_ISSUE",
|
|
||||||
args: { NFCJOBS: prms.NFCJOBS, SFCJOBSSP_LIST: prms.SFCJOBSSP_LIST }
|
|
||||||
});
|
|
||||||
} catch (e) {
|
|
||||||
throw new Error(e.message);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
[executeStored]
|
|
||||||
);
|
|
||||||
|
|
||||||
//При необходимости обновить данные таблицы
|
|
||||||
useEffect(() => {
|
|
||||||
loadData();
|
|
||||||
}, [costJobsSpecs.reload, loadData]);
|
|
||||||
|
|
||||||
//При изменении сменного задания
|
|
||||||
useEffect(() => {
|
|
||||||
setCostJobsSpecs(pv => ({
|
|
||||||
...pv,
|
|
||||||
dataLoaded: false,
|
|
||||||
columnsDef: [],
|
|
||||||
orders: null,
|
|
||||||
rows: [],
|
|
||||||
selectedRows: [],
|
|
||||||
reload: true,
|
|
||||||
pageNumber: 1,
|
|
||||||
morePages: true
|
|
||||||
}));
|
|
||||||
}, [task, fcroutlstList]);
|
|
||||||
|
|
||||||
return [costJobsSpecs, setCostJobsSpecs, issueCostJobsSpecs];
|
|
||||||
};
|
|
||||||
|
|
||||||
//Хук для таблицы рабочих центров
|
|
||||||
const useCostEquipment = () => {
|
|
||||||
//Собственное состояние - таблица данных
|
|
||||||
const [costEquipment, setCostEquipment] = useState({
|
|
||||||
dataLoaded: false,
|
|
||||||
columnsDef: [],
|
|
||||||
orders: null,
|
|
||||||
rows: [],
|
|
||||||
selectedRows: [],
|
|
||||||
selectedLoaded: false,
|
|
||||||
reload: true,
|
|
||||||
pageNumber: 1,
|
|
||||||
morePages: true
|
|
||||||
});
|
|
||||||
|
|
||||||
//Подключение к контексту взаимодействия с сервером
|
|
||||||
const { executeStored, SERV_DATA_TYPE_CLOB } = useContext(BackEndСtx);
|
|
||||||
|
|
||||||
//Загрузка данных таблицы с сервера
|
|
||||||
const loadData = useCallback(async () => {
|
|
||||||
if (costEquipment.reload) {
|
|
||||||
const data = await executeStored({
|
|
||||||
stored: "PKG_P8PANELS_MECHREC.FCEQUIPMENT_DG_GET",
|
|
||||||
args: {
|
|
||||||
CORDERS: { VALUE: object2Base64XML(costEquipment.orders, { arrayNodeName: "orders" }), SDATA_TYPE: SERV_DATA_TYPE_CLOB },
|
|
||||||
NPAGE_NUMBER: costEquipment.pageNumber,
|
|
||||||
NPAGE_SIZE: DATA_GRID_PAGE_FCEQUIPMENT,
|
|
||||||
NINCLUDE_DEF: costEquipment.dataLoaded ? 0 : 1
|
|
||||||
},
|
|
||||||
respArg: "COUT",
|
|
||||||
attributeValueProcessor: (name, val) => (["NSELECT"].includes(name) ? val === 1 : val)
|
|
||||||
});
|
|
||||||
setCostEquipment(pv => ({
|
|
||||||
...pv,
|
|
||||||
columnsDef: data.XCOLUMNS_DEF ? [...data.XCOLUMNS_DEF] : pv.columnsDef,
|
|
||||||
rows:
|
|
||||||
pv.pageNumber == 1
|
|
||||||
? updatingSelected([...(data.XROWS || [])], costEquipment.selectedRows)
|
|
||||||
: updatingSelected([...pv.rows, ...(data.XROWS || [])], costEquipment.selectedRows),
|
|
||||||
dataLoaded: true,
|
|
||||||
reload: false,
|
|
||||||
morePages: (data.XROWS || []).length >= DATA_GRID_PAGE_FCEQUIPMENT
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
||||||
}, [
|
|
||||||
costEquipment.reload,
|
|
||||||
costEquipment.filters,
|
|
||||||
costEquipment.orders,
|
|
||||||
costEquipment.dataLoaded,
|
|
||||||
costEquipment.pageNumber,
|
|
||||||
executeStored,
|
|
||||||
SERV_DATA_TYPE_CLOB
|
|
||||||
]);
|
|
||||||
|
|
||||||
//Включение оборудования в операции
|
|
||||||
const includeCostEquipment = useCallback(
|
|
||||||
async prms => {
|
|
||||||
try {
|
|
||||||
await executeStored({
|
|
||||||
stored: "PKG_P8PANELS_MECHREC.FCJOBSSP_INC_FCEQUIPMENT",
|
|
||||||
args: { NFCEQUIPMENT: prms.NFCEQUIPMENT, NFCJOBS: prms.NFCJOBS, SFCJOBSSP_LIST: prms.SFCJOBSSP_LIST }
|
|
||||||
});
|
|
||||||
} catch (e) {
|
|
||||||
throw new Error(e.message);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
[executeStored]
|
|
||||||
);
|
|
||||||
|
|
||||||
//Исключение оборудования из операции
|
|
||||||
const excludeCostEquipment = useCallback(
|
|
||||||
async prms => {
|
|
||||||
try {
|
|
||||||
await executeStored({
|
|
||||||
stored: "PKG_P8PANELS_MECHREC.FCJOBSSP_EXC_FCEQUIPMENT",
|
|
||||||
args: { NFCEQUIPMENT: prms.NFCEQUIPMENT, NFCJOBS: prms.NFCJOBS, SFCJOBSSP_LIST: prms.SFCJOBSSP_LIST }
|
|
||||||
});
|
|
||||||
} catch (e) {
|
|
||||||
throw new Error(e.message);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
[executeStored]
|
|
||||||
);
|
|
||||||
|
|
||||||
//При необходимости обновить данные таблицы
|
|
||||||
useEffect(() => {
|
|
||||||
loadData();
|
|
||||||
}, [costEquipment.reload, loadData]);
|
|
||||||
|
|
||||||
return [costEquipment, setCostEquipment, includeCostEquipment, excludeCostEquipment];
|
|
||||||
};
|
|
||||||
|
|
||||||
export { useCostRouteLists, useCostJobsSpecs, useCostEquipment, updatingSelected };
|
|
@ -1,124 +1,139 @@
|
|||||||
/*
|
/*
|
||||||
Парус 8 - Панели мониторинга - ПУП - Выдача сменного задания
|
Парус 8 - Панели мониторинга - ПУП - Выдача сменного задания
|
||||||
Компонент панели: Таблица информации об операциях сменного задания
|
Компонент панели: Таблица информации о строках сменного задания
|
||||||
*/
|
*/
|
||||||
|
|
||||||
//---------------------
|
//---------------------
|
||||||
//Подключение библиотек
|
//Подключение библиотек
|
||||||
//---------------------
|
//---------------------
|
||||||
|
|
||||||
import React from "react"; //Классы React
|
import React, { useState } from "react"; //Классы React
|
||||||
import PropTypes from "prop-types"; //Контроль свойств компонента
|
import PropTypes from "prop-types"; //Контроль свойств компонента
|
||||||
import { Typography, Box, Checkbox, Grid, Icon, Button } from "@mui/material"; //Интерфейсные элементы
|
import { Typography, Box, Checkbox, Grid, Icon, Button, Dialog, DialogContent, TextField, DialogActions, Tooltip } from "@mui/material"; //Интерфейсные элементы
|
||||||
import { P8PDataGrid, P8P_DATA_GRID_SIZE } from "../../components/p8p_data_grid"; //Таблица данных
|
import { P8PDataGrid, P8P_DATA_GRID_SIZE } from "../../components/p8p_data_grid"; //Таблица данных
|
||||||
import { P8P_DATA_GRID_CONFIG_PROPS } from "../../config_wrapper"; //Подключение компонентов к настройкам приложения
|
import { P8P_DATA_GRID_CONFIG_PROPS } from "../../config_wrapper"; //Подключение компонентов к настройкам приложения
|
||||||
import { useCostRouteLists, useCostJobsSpecs, useCostEquipment } from "./backend"; //Собственные хуки таблиц
|
import { useCostJobsSpecs, useEquipConfiguration } from "./hooks"; //Собственные хуки таблиц
|
||||||
|
|
||||||
//---------
|
//---------
|
||||||
//Константы
|
//Константы
|
||||||
//---------
|
//---------
|
||||||
|
|
||||||
const sUnitCostRouteLists = "CostRouteLists"; //Мнемокод раздела маршрутных листов
|
|
||||||
const sUnitCostJobsSpecs = "CostJobsSpecs"; //Мнемокод раздела операций
|
const sUnitCostJobsSpecs = "CostJobsSpecs"; //Мнемокод раздела операций
|
||||||
const sUnitCostEquipment = "CostEquipment"; //Мнемокод раздела рабочих центров
|
const sUnitCostEquipment = "CostEquipment"; //Мнемокод раздела рабочих центров
|
||||||
|
|
||||||
//Стили
|
//Стили
|
||||||
const STYLES = {
|
const STYLES = {
|
||||||
CONTAINER: { textAlign: "center" },
|
CONTAINER: { textAlign: "center" },
|
||||||
|
DATA_GRID_CONTAINER: { minHeight: "65vh", maxHeight: "65vh" },
|
||||||
TABLE: { paddingTop: "15px" },
|
TABLE: { paddingTop: "15px" },
|
||||||
TABLE_SUM: { textAlign: "right", paddingTop: "5px", paddingRight: "15px" },
|
|
||||||
TABLE_BUTTONS: { display: "flex", justifyContent: "flex-end" },
|
TABLE_BUTTONS: { display: "flex", justifyContent: "flex-end" },
|
||||||
CHECK_BOX: { textAlign: "center" },
|
CHECK_BOX: { textAlign: "center" },
|
||||||
OPERATIONS_SEPARATOR: { padding: "3px 0px", backgroundColor: "lightblue" },
|
JOBS_INFO: { minWidth: "60%", maxWidth: "60%", textAlign: "center" },
|
||||||
INFORMATION_HALF: { minWidth: "50%", maxWidth: "50%", textAlign: "center" }
|
EQUIPMENT_INFO: { minWidth: "40%", maxWidth: "40%", textAlign: "center" }
|
||||||
|
};
|
||||||
|
|
||||||
|
//Цвета
|
||||||
|
const colors = {
|
||||||
|
LINKED: "#bce0de",
|
||||||
|
UNAVAILABLE: "#949494",
|
||||||
|
WITH_EQCONFIG: "#82df83"
|
||||||
};
|
};
|
||||||
|
|
||||||
//---------------------------------------------
|
//---------------------------------------------
|
||||||
//Вспомогательные функции форматирования данных
|
//Вспомогательные функции и компоненты
|
||||||
//---------------------------------------------
|
//---------------------------------------------
|
||||||
|
|
||||||
//Формирование списка отмеченных записей
|
|
||||||
function selectedReducer(accumulator, current) {
|
|
||||||
if (current.NSELECT == 1) {
|
|
||||||
accumulator.push(current.NRN);
|
|
||||||
}
|
|
||||||
return accumulator;
|
|
||||||
}
|
|
||||||
|
|
||||||
//Форматирование значения ячейки
|
//Форматирование значения ячейки
|
||||||
const dataCellRender = ({ row, columnDef, handleSelectChange, sUnit, selectedEquip }) => {
|
const dataCellRender = ({ row, columnDef, handleSelectChange, sUnit, selectedRow, selectedJobSpec }) => {
|
||||||
//Инициализируем доступность выбора
|
//Стиль
|
||||||
let disabled = false;
|
let cellStyle = {};
|
||||||
//Если это рабочие центры
|
//Если это рабочие центры
|
||||||
if (sUnit === sUnitCostEquipment) {
|
if (sUnit === sUnitCostEquipment) {
|
||||||
//Для колонки выбора
|
//Признак недоступности
|
||||||
if (columnDef.name === "NSELECT") {
|
let disabled = true;
|
||||||
return {
|
//Если в выбранной строке смены указано рабочее место
|
||||||
data: (
|
if (selectedJobSpec.NEQCONFIG) {
|
||||||
<Box sx={STYLES.CHECK_BOX}>
|
//Если это текущее рабочее место
|
||||||
<Checkbox
|
if (row["NRN"] === selectedJobSpec.NEQCONFIG) {
|
||||||
disabled={selectedEquip.length === 1 && selectedEquip[0] !== row["NRN"]}
|
//Подсвечиваем строку рабочего места
|
||||||
checked={row[columnDef.name]}
|
cellStyle = { backgroundColor: colors.LINKED };
|
||||||
//checked={row[columnDef.name] === 1}
|
|
||||||
onChange={() => handleSelectChange(row["NRN"], sUnit, row["NCOEFF"] <= row["NLOADING"])}
|
|
||||||
/>
|
|
||||||
</Box>
|
|
||||||
)
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
//Если оборудование загружено
|
} else {
|
||||||
if (row["NCOEFF"] <= row["NLOADING"]) {
|
//Если выбрана строка смены
|
||||||
|
if (selectedJobSpec.NRN) {
|
||||||
|
//Если на текущее рабочее место возможно добавить задание
|
||||||
|
if (row["NLOADING"] < 100 && row["NEQUIPMENT"] === selectedJobSpec.NEQUIP_PLAN) {
|
||||||
|
//Подсвечиваем строку рабочего места
|
||||||
|
cellStyle = { backgroundColor: colors.LINKED };
|
||||||
|
disabled = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//Если рабочий центр загружен
|
||||||
|
if (row["NLOADING"] >= 100) {
|
||||||
//Если поле не поле выбора
|
//Если поле не поле выбора
|
||||||
if (columnDef.name !== "NSELECT") {
|
if (columnDef.name !== "NSELECT") {
|
||||||
return {
|
//Указываем, что рабочее место недоступно
|
||||||
cellStyle: { color: "lightgrey" },
|
cellStyle = { ...cellStyle, color: colors.UNAVAILABLE };
|
||||||
data: row[columnDef.name]
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//Если это операции
|
|
||||||
if (sUnit === sUnitCostJobsSpecs) {
|
|
||||||
//Если "Оборудование план" операции сходится с выбранным оборудованием
|
|
||||||
if (selectedEquip.includes(row["NEQUIP_PLAN"])) {
|
|
||||||
//Если колонка выбора
|
|
||||||
if (columnDef.name === "NSELECT") {
|
|
||||||
return {
|
|
||||||
cellStyle: { backgroundColor: "#bce0de" },
|
|
||||||
data: (
|
|
||||||
<Box sx={STYLES.CHECK_BOX}>
|
|
||||||
<Checkbox
|
|
||||||
disabled={disabled}
|
|
||||||
checked={row[columnDef.name]}
|
|
||||||
//checked={row[columnDef.name] === 1}
|
|
||||||
onChange={() => handleSelectChange(row["NRN"], sUnit)}
|
|
||||||
/>
|
|
||||||
</Box>
|
|
||||||
)
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
return {
|
|
||||||
cellStyle: { backgroundColor: "#bce0de" },
|
|
||||||
data: row[columnDef.name]
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//Для колонки выбора
|
//Для колонки выбора
|
||||||
if (columnDef.name === "NSELECT") {
|
if (columnDef.name === "NSELECT") {
|
||||||
return {
|
return {
|
||||||
|
cellStyle,
|
||||||
data: (
|
data: (
|
||||||
<Box sx={STYLES.CHECK_BOX}>
|
<Box sx={STYLES.CHECK_BOX}>
|
||||||
<Checkbox
|
<Checkbox
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
checked={row[columnDef.name]}
|
checked={row["NRN"] === selectedRow}
|
||||||
//checked={row[columnDef.name] === 1}
|
onChange={() => handleSelectChange({ NRN: row["NRN"], SUNIT: sUnit, BFULL_LOADED: row["NLOADING"] >= 100 })}
|
||||||
onChange={() => handleSelectChange(row["NRN"], sUnit)}
|
|
||||||
/>
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
//Отформатированная колонка
|
||||||
|
return {
|
||||||
|
cellStyle,
|
||||||
|
data: row[columnDef.name]
|
||||||
|
};
|
||||||
|
}
|
||||||
|
//Если это сменное задание
|
||||||
|
if (sUnit === sUnitCostJobsSpecs) {
|
||||||
|
//Если указан станок
|
||||||
|
if (row["SEQCONFIG"]) {
|
||||||
|
//Подсвечиваем сменное задание зеленым
|
||||||
|
cellStyle = { ...cellStyle, backgroundColor: colors.WITH_EQCONFIG };
|
||||||
|
}
|
||||||
|
//Для колонки выбора
|
||||||
|
if (columnDef.name === "NSELECT") {
|
||||||
|
return {
|
||||||
|
cellStyle,
|
||||||
|
data: (
|
||||||
|
<Box sx={STYLES.CHECK_BOX}>
|
||||||
|
<Checkbox
|
||||||
|
disabled={row["DBEG_FACT"] ? true : false}
|
||||||
|
checked={row["NRN"] === selectedRow}
|
||||||
|
onChange={() =>
|
||||||
|
handleSelectChange({
|
||||||
|
NRN: row["NRN"],
|
||||||
|
SUNIT: sUnit,
|
||||||
|
NEQCONFIG: row["NEQCONFIG"],
|
||||||
|
NEQUIP_PLAN: row["NEQUIP_PLAN"],
|
||||||
|
NQUANT_PLAN: row["NQUANT_PLAN"]
|
||||||
|
})
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
//Отформатированная колонка
|
||||||
|
return {
|
||||||
|
cellStyle,
|
||||||
|
data: row[columnDef.name]
|
||||||
|
};
|
||||||
|
}
|
||||||
|
//Необрабатываемый раздел
|
||||||
return {
|
return {
|
||||||
data: row[columnDef.name]
|
data: row[columnDef.name]
|
||||||
};
|
};
|
||||||
@ -139,26 +154,108 @@ export const headCellRender = ({ columnDef }) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
//Диалог включения станка в сменное задание
|
||||||
|
const CostJobsSpecsInclude = ({ includeEquipment, setIncludeEquipment, setCostJobsSpecs, setEquipConfiguration, includeEquipConfiguration }) => {
|
||||||
|
//Собственное состояние - Значение приоритета
|
||||||
|
const [state, setState] = useState(includeEquipment.NVALUE);
|
||||||
|
|
||||||
|
//При закрытии включения станка
|
||||||
|
const handlePriorEditClose = () => {
|
||||||
|
setIncludeEquipment({
|
||||||
|
NFCJOBSSP: null,
|
||||||
|
NEQCONFIG: null,
|
||||||
|
NVALUE: 0
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
//При включении станка в строку сменного задания
|
||||||
|
const costJobsSpecIncludeCostEquipment = () => {
|
||||||
|
//Делаем асинхронно, чтобы при ошибке ничего не обновлять
|
||||||
|
const includeAsync = async () => {
|
||||||
|
//Включаем станок в строку сменного задания
|
||||||
|
try {
|
||||||
|
await includeEquipConfiguration({
|
||||||
|
NEQCONFIG: includeEquipment.NEQCONFIG,
|
||||||
|
NFCJOBSSP: includeEquipment.NFCJOBSSP,
|
||||||
|
NQUANT_PLAN: state
|
||||||
|
});
|
||||||
|
//Необходимо обновить все данные
|
||||||
|
setCostJobsSpecs(pv => ({ ...pv, selectedRow: {}, pageNumber: 1, reload: true }));
|
||||||
|
setEquipConfiguration(pv => ({ ...pv, selectedRow: {}, pageNumber: 1, reload: true }));
|
||||||
|
handlePriorEditClose();
|
||||||
|
} catch (e) {
|
||||||
|
throw new Error(e.message);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
//Включаем станок асинхронно
|
||||||
|
includeAsync();
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Dialog open onClose={() => handlePriorEditClose()}>
|
||||||
|
<DialogContent>
|
||||||
|
<Box>
|
||||||
|
<TextField
|
||||||
|
name="editInculdeValue"
|
||||||
|
label="Количество"
|
||||||
|
variant="standard"
|
||||||
|
fullWidth
|
||||||
|
InputProps={{
|
||||||
|
type: "number",
|
||||||
|
inputProps: {
|
||||||
|
max: includeEquipment.NVALUE,
|
||||||
|
min: 0
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
value={state}
|
||||||
|
onChange={event => {
|
||||||
|
var value = parseInt(event.target.value, 10);
|
||||||
|
if (value > includeEquipment.NVALUE) {
|
||||||
|
value = includeEquipment.NVALUE;
|
||||||
|
}
|
||||||
|
if (value < 0) {
|
||||||
|
value = 0;
|
||||||
|
}
|
||||||
|
setState(value);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<Box>
|
||||||
|
<Button onClick={costJobsSpecIncludeCostEquipment} variant="contained" sx={STYLES.DIALOG_BUTTONS}>
|
||||||
|
Включить в задание
|
||||||
|
</Button>
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
</DialogContent>
|
||||||
|
<DialogActions>
|
||||||
|
<Button onClick={() => handlePriorEditClose(null)}>Закрыть</Button>
|
||||||
|
</DialogActions>
|
||||||
|
</Dialog>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
//Контроль свойств - Диалог включения станка в сменное задание
|
||||||
|
CostJobsSpecsInclude.propTypes = {
|
||||||
|
includeEquipment: PropTypes.object.isRequired,
|
||||||
|
setIncludeEquipment: PropTypes.func.isRequired,
|
||||||
|
setCostJobsSpecs: PropTypes.func.isRequired,
|
||||||
|
setEquipConfiguration: PropTypes.func.isRequired,
|
||||||
|
includeEquipConfiguration: PropTypes.func.isRequired
|
||||||
|
};
|
||||||
|
|
||||||
//-----------
|
//-----------
|
||||||
//Тело модуля
|
//Тело модуля
|
||||||
//-----------
|
//-----------
|
||||||
|
|
||||||
//Таблица информации об операциях сменного задания
|
//Таблица информации о строках сменного задания
|
||||||
const CostJobsSpecsDataGrid = ({ task, processIdent, clearSelectlist }) => {
|
const CostJobsSpecsDataGrid = ({ task, haveNote }) => {
|
||||||
//Собственное состояние - таблица данных маршрутных листов
|
//Собственное состояние - Включение в задание
|
||||||
const [costRouteLists, setCostRouteLists, modifySelectList] = useCostRouteLists(task, processIdent);
|
const [includeEquipment, setIncludeEquipment] = useState({ NFCJOBSSP: null, NEQCONFIG: null, NVALUE: 0 });
|
||||||
|
|
||||||
//Собственное состояние - таблица данных операций
|
//Собственное состояние - таблица данных сменных заданий
|
||||||
const [costJobsSpecs, setCostJobsSpecs, issueCostJobsSpecs] = useCostJobsSpecs(task, costRouteLists.selectedRows, processIdent);
|
const [costJobsSpecs, setCostJobsSpecs, issueCostJobsSpecs] = useCostJobsSpecs(task);
|
||||||
|
|
||||||
//Собственное состояние - таблица рабочих центров
|
//Собственное состояние - таблица рабочих центров
|
||||||
const [costEquipment, setCostEquipment, includeCostEquipment, excludeCostEquipment] = useCostEquipment();
|
const [equipConfiguration, setEquipConfiguration, includeEquipConfiguration, excludeEquipConfiguration] = useEquipConfiguration(task);
|
||||||
|
|
||||||
//При изменении состояния сортировки маршрутных листов
|
|
||||||
const costRouteListOrderChanged = ({ orders }) => setCostRouteLists(pv => ({ ...pv, orders: [...orders], pageNumber: 1, reload: true }));
|
|
||||||
|
|
||||||
//При изменении количества отображаемых страниц маршрутных листов
|
|
||||||
const costRouteListPagesCountChanged = () => setCostRouteLists(pv => ({ ...pv, pageNumber: pv.pageNumber + 1, reload: true }));
|
|
||||||
|
|
||||||
//При изменении состояния сортировки операций
|
//При изменении состояния сортировки операций
|
||||||
const costJobsSpecOrderChanged = ({ orders }) => setCostJobsSpecs(pv => ({ ...pv, orders: [...orders], pageNumber: 1, reload: true }));
|
const costJobsSpecOrderChanged = ({ orders }) => setCostJobsSpecs(pv => ({ ...pv, orders: [...orders], pageNumber: 1, reload: true }));
|
||||||
@ -167,52 +264,28 @@ const CostJobsSpecsDataGrid = ({ task, processIdent, clearSelectlist }) => {
|
|||||||
const costJobsSpecPagesCountChanged = () => setCostJobsSpecs(pv => ({ ...pv, pageNumber: pv.pageNumber + 1, reload: true }));
|
const costJobsSpecPagesCountChanged = () => setCostJobsSpecs(pv => ({ ...pv, pageNumber: pv.pageNumber + 1, reload: true }));
|
||||||
|
|
||||||
//При изменении состояния сортировки рабочих центров
|
//При изменении состояния сортировки рабочих центров
|
||||||
const costEquipmentOrderChanged = ({ orders }) => setCostEquipment(pv => ({ ...pv, orders: [...orders], pageNumber: 1, reload: true }));
|
const costEquipmentOrderChanged = ({ orders }) => setEquipConfiguration(pv => ({ ...pv, orders: [...orders], pageNumber: 1, reload: true }));
|
||||||
|
|
||||||
//При изменении количества отображаемых страниц рабочих центров
|
//При изменении количества отображаемых страниц рабочих центров
|
||||||
const costEquipmentPagesCountChanged = () => setCostEquipment(pv => ({ ...pv, pageNumber: pv.pageNumber + 1, reload: true }));
|
const costEquipmentPagesCountChanged = () => setEquipConfiguration(pv => ({ ...pv, pageNumber: pv.pageNumber + 1, reload: true }));
|
||||||
|
|
||||||
//При включении оборудования в операции
|
//При исключении станка из строки сменного задания
|
||||||
const costJobsSpecIncludeCostEquipment = () => {
|
|
||||||
//Делаем асинхронно, чтобы при ошибке ничего не обновлять
|
|
||||||
const includeAsync = async () => {
|
|
||||||
//Включаем оборудование в операции
|
|
||||||
try {
|
|
||||||
await includeCostEquipment({
|
|
||||||
NFCEQUIPMENT: costEquipment.selectedRows[0],
|
|
||||||
NFCJOBS: task,
|
|
||||||
SFCJOBSSP_LIST: costJobsSpecs.selectedRows.join(";")
|
|
||||||
});
|
|
||||||
//Необходимо обновить все данные
|
|
||||||
setCostJobsSpecs(pv => ({ ...pv, selectedRows: [], reload: true }));
|
|
||||||
setCostEquipment(pv => ({ ...pv, selectedRows: [], selectedLoaded: false, reload: true }));
|
|
||||||
} catch (e) {
|
|
||||||
throw new Error(e.message);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
//Включаем оборудование асинхронно
|
|
||||||
includeAsync();
|
|
||||||
};
|
|
||||||
|
|
||||||
//При исключении оборудования из операции
|
|
||||||
const costJobsSpecExcludeCostEquipment = () => {
|
const costJobsSpecExcludeCostEquipment = () => {
|
||||||
//Делаем асинхронно, чтобы при ошибке ничего не обновлять
|
//Делаем асинхронно, чтобы при ошибке ничего не обновлять
|
||||||
const excludeAsync = async () => {
|
const excludeAsync = async () => {
|
||||||
//Включаем оборудование в операции
|
//Исключаем станок из строки сменного задания
|
||||||
try {
|
try {
|
||||||
await excludeCostEquipment({
|
await excludeEquipConfiguration({
|
||||||
NFCEQUIPMENT: costEquipment.selectedRows[0],
|
NFCJOBSSP: costJobsSpecs.selectedRow.NRN
|
||||||
NFCJOBS: task,
|
|
||||||
SFCJOBSSP_LIST: costJobsSpecs.selectedRows.join(";")
|
|
||||||
});
|
});
|
||||||
//Необходимо обновить данные о маршрутных листах и оборудовании
|
//Необходимо обновить данные
|
||||||
setCostJobsSpecs(pv => ({ ...pv, selectedRows: [], reload: true }));
|
setCostJobsSpecs(pv => ({ ...pv, selectedRow: {}, pageNumber: 1, reload: true }));
|
||||||
setCostEquipment(pv => ({ ...pv, selectedRows: [], reload: true }));
|
setEquipConfiguration(pv => ({ ...pv, selectedRow: {}, pageNumber: 1, reload: true }));
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
throw new Error(e.message);
|
throw new Error(e.message);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
//Исключаем операции асинхронно
|
//Исключаем станок асинхронно
|
||||||
excludeAsync();
|
excludeAsync();
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -222,14 +295,10 @@ const CostJobsSpecsDataGrid = ({ task, processIdent, clearSelectlist }) => {
|
|||||||
const issueAsync = async () => {
|
const issueAsync = async () => {
|
||||||
//Включаем оборудование в операции
|
//Включаем оборудование в операции
|
||||||
try {
|
try {
|
||||||
await issueCostJobsSpecs({
|
await issueCostJobsSpecs({ NFCJOBS: task });
|
||||||
NFCJOBS: task,
|
//Необходимо обновить данные
|
||||||
SFCJOBSSP_LIST: costJobsSpecs.selectedRows.join(";")
|
setCostJobsSpecs(pv => ({ ...pv, selectedRow: {}, pageNumber: 1, reload: true }));
|
||||||
});
|
setEquipConfiguration(pv => ({ ...pv, selectedRow: {}, pageNumber: 1, reload: true }));
|
||||||
//Необходимо обновить данные о маршрутных листах и оборудовании
|
|
||||||
clearSelectlist(processIdent);
|
|
||||||
setCostRouteLists(pv => ({ ...pv, selectedRows: [], reload: true }));
|
|
||||||
setCostEquipment(pv => ({ ...pv, selectedRows: [], reload: true }));
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
throw new Error(e.message);
|
throw new Error(e.message);
|
||||||
}
|
}
|
||||||
@ -239,49 +308,33 @@ const CostJobsSpecsDataGrid = ({ task, processIdent, clearSelectlist }) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
//При изменение состояния выбора
|
//При изменение состояния выбора
|
||||||
const handleSelectChange = (NRN, sUnit, selectedLoaded) => {
|
const handleSelectChange = prms => {
|
||||||
//Инициализируем строки таблицы
|
//Выбранный элемент
|
||||||
let rows = [];
|
let selectedRow = null;
|
||||||
//Индекс элемента в массиве
|
|
||||||
let indexRow = null;
|
|
||||||
//Исходим от раздела
|
//Исходим от раздела
|
||||||
switch (sUnit) {
|
switch (prms.SUNIT) {
|
||||||
//Маршрутные листы
|
//Сменное задание
|
||||||
case sUnitCostRouteLists:
|
|
||||||
//Инициализируем маршрутными листами
|
|
||||||
rows = costRouteLists.rows;
|
|
||||||
//Определяем индекс элемента в массиве
|
|
||||||
indexRow = rows.findIndex(obj => obj.NRN == NRN);
|
|
||||||
//Изменяем значение выбора
|
|
||||||
rows[indexRow].NSELECT = !rows[indexRow].NSELECT;
|
|
||||||
//Добавляем/удаляем маршрутный лист из селектлиста
|
|
||||||
modifySelectList({ NFCROUTLST: NRN, NSELECT: rows[indexRow].NSELECT });
|
|
||||||
//Актуализируем строки
|
|
||||||
setCostRouteLists(pv => ({ ...pv, rows: rows, selectedRows: rows.reduce(selectedReducer, []) }));
|
|
||||||
//Выходим
|
|
||||||
break;
|
|
||||||
//Операции
|
|
||||||
case sUnitCostJobsSpecs:
|
case sUnitCostJobsSpecs:
|
||||||
//Инициализируем операциями
|
//Определяем это новое отмеченное сменное задание или сброс старого
|
||||||
rows = costJobsSpecs.rows;
|
selectedRow = costJobsSpecs.selectedRow.NRN ? (costJobsSpecs.selectedRow.NRN === prms.NRN ? null : prms.NRN) : prms.NRN;
|
||||||
//Определяем индекс элемента в массиве
|
|
||||||
indexRow = rows.findIndex(obj => obj.NRN == NRN);
|
|
||||||
//Изменяем значение выбора
|
|
||||||
rows[indexRow].NSELECT = !rows[indexRow].NSELECT;
|
|
||||||
//Актуализируем строки
|
//Актуализируем строки
|
||||||
setCostJobsSpecs(pv => ({ ...pv, rows: rows, selectedRows: rows.reduce(selectedReducer, []) }));
|
setCostJobsSpecs(pv => ({
|
||||||
|
...pv,
|
||||||
|
selectedRow: selectedRow
|
||||||
|
? { NRN: selectedRow, NEQCONFIG: prms.NEQCONFIG, NEQUIP_PLAN: prms.NEQUIP_PLAN, NQUANT_PLAN: prms.NQUANT_PLAN }
|
||||||
|
: { NRN: null, NEQCONFIG: null, NEQUIP_PLAN: null, NQUANT_PLAN: null }
|
||||||
|
}));
|
||||||
//Выходим
|
//Выходим
|
||||||
break;
|
break;
|
||||||
//Рабочие центры
|
//Рабочие центры
|
||||||
case sUnitCostEquipment:
|
case sUnitCostEquipment:
|
||||||
//Инициализируем рабочими центрами
|
//Определяем это новое отмеченное сменное задание или сброс старого
|
||||||
rows = costEquipment.rows;
|
selectedRow = equipConfiguration.selectedRow.NRN ? (equipConfiguration.selectedRow.NRN === prms.NRN ? null : prms.NRN) : prms.NRN;
|
||||||
//Определяем индекс элемента в массиве
|
|
||||||
indexRow = rows.findIndex(obj => obj.NRN == NRN);
|
|
||||||
//Изменяем значение выбора
|
|
||||||
rows[indexRow].NSELECT = !rows[indexRow].NSELECT;
|
|
||||||
//Актуализируем строки
|
//Актуализируем строки
|
||||||
setCostEquipment(pv => ({ ...pv, rows: rows, selectedRows: rows.reduce(selectedReducer, []), selectedLoaded: selectedLoaded }));
|
setEquipConfiguration(pv => ({
|
||||||
|
...pv,
|
||||||
|
selectedRow: selectedRow ? { NRN: selectedRow, BFULL_LOADED: prms.BFULL_LOADED } : { NRN: null, BFULL_LOADED: null }
|
||||||
|
}));
|
||||||
//Выходим
|
//Выходим
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@ -289,42 +342,37 @@ const CostJobsSpecsDataGrid = ({ task, processIdent, clearSelectlist }) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
//При открытии окна включения в задание
|
||||||
|
const handleIncludeEquipmentOpen = () => {
|
||||||
|
//Актуализируем строки
|
||||||
|
setIncludeEquipment({
|
||||||
|
NFCJOBSSP: costJobsSpecs.selectedRow.NRN,
|
||||||
|
NEQCONFIG: equipConfiguration.selectedRow.NRN,
|
||||||
|
NVALUE: costJobsSpecs.selectedRow.NQUANT_PLAN
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
//Генерация содержимого
|
//Генерация содержимого
|
||||||
return (
|
return (
|
||||||
<div style={STYLES.CONTAINER}>
|
<div style={STYLES.CONTAINER}>
|
||||||
<Grid container spacing={2}>
|
<Grid container spacing={2}>
|
||||||
<Grid item sx={STYLES.INFORMATION_HALF}>
|
<Grid item sx={STYLES.JOBS_INFO}>
|
||||||
<Typography variant={"h6"}>Маршрутные листы</Typography>
|
<Typography variant={"h6"}>Сменное задание</Typography>
|
||||||
{costRouteLists.dataLoaded ? (
|
{costJobsSpecs.dataLoaded ? (
|
||||||
<>
|
<>
|
||||||
<Box sx={STYLES.TABLE_BUTTONS}>
|
<Box sx={STYLES.TABLE_BUTTONS}>
|
||||||
<Button
|
<Tooltip title={haveNote ? "Сменное задание имеет строку с примечанием" : null}>
|
||||||
variant="contained"
|
<Box>
|
||||||
size="small"
|
<Button variant="contained" size="small" disabled={haveNote} onClick={costJobsSpecIssue}>
|
||||||
disabled={costJobsSpecs.selectedRows.length === 0}
|
|
||||||
onClick={costJobsSpecIssue}
|
|
||||||
>
|
|
||||||
Выдать задания
|
Выдать задания
|
||||||
</Button>
|
</Button>
|
||||||
</Box>
|
</Box>
|
||||||
|
</Tooltip>
|
||||||
|
</Box>
|
||||||
<Box sx={STYLES.TABLE}>
|
<Box sx={STYLES.TABLE}>
|
||||||
<P8PDataGrid
|
<P8PDataGrid
|
||||||
{...P8P_DATA_GRID_CONFIG_PROPS}
|
{...P8P_DATA_GRID_CONFIG_PROPS}
|
||||||
columnsDef={costRouteLists.columnsDef}
|
containerComponentProps={{ sx: STYLES.DATA_GRID_CONTAINER, elevation: 1 }}
|
||||||
rows={costRouteLists.rows}
|
|
||||||
size={P8P_DATA_GRID_SIZE.SMALL}
|
|
||||||
morePages={costRouteLists.morePages}
|
|
||||||
reloading={costRouteLists.reload}
|
|
||||||
onOrderChanged={costRouteListOrderChanged}
|
|
||||||
onPagesCountChanged={costRouteListPagesCountChanged}
|
|
||||||
dataCellRender={prms => dataCellRender({ ...prms, handleSelectChange, sUnit: sUnitCostRouteLists })}
|
|
||||||
headCellRender={prms => headCellRender({ ...prms })}
|
|
||||||
/>
|
|
||||||
{costRouteLists.selectedRows.length > 0 ? (
|
|
||||||
<>
|
|
||||||
<Box sx={STYLES.OPERATIONS_SEPARATOR}>Операции выбранных маршрутных листов</Box>
|
|
||||||
<P8PDataGrid
|
|
||||||
{...P8P_DATA_GRID_CONFIG_PROPS}
|
|
||||||
columnsDef={costJobsSpecs.columnsDef}
|
columnsDef={costJobsSpecs.columnsDef}
|
||||||
rows={costJobsSpecs.rows}
|
rows={costJobsSpecs.rows}
|
||||||
size={P8P_DATA_GRID_SIZE.SMALL}
|
size={P8P_DATA_GRID_SIZE.SMALL}
|
||||||
@ -337,31 +385,31 @@ const CostJobsSpecsDataGrid = ({ task, processIdent, clearSelectlist }) => {
|
|||||||
...prms,
|
...prms,
|
||||||
handleSelectChange,
|
handleSelectChange,
|
||||||
sUnit: sUnitCostJobsSpecs,
|
sUnit: sUnitCostJobsSpecs,
|
||||||
selectedEquip: costEquipment.selectedRows
|
selectedRow: costJobsSpecs.selectedRow.NRN,
|
||||||
|
selectedJobSpec: costJobsSpecs.selectedRow
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
headCellRender={prms => headCellRender({ ...prms })}
|
headCellRender={prms => headCellRender({ ...prms })}
|
||||||
|
fixedHeader={true}
|
||||||
/>
|
/>
|
||||||
</>
|
|
||||||
) : null}
|
|
||||||
</Box>
|
</Box>
|
||||||
</>
|
</>
|
||||||
) : null}
|
) : null}
|
||||||
</Grid>
|
</Grid>
|
||||||
<Grid item sx={STYLES.INFORMATION_HALF}>
|
<Grid item sx={STYLES.EQUIPMENT_INFO}>
|
||||||
<Typography variant={"h6"}>Рабочие центры</Typography>
|
<Typography variant={"h6"}>Рабочие центры</Typography>
|
||||||
{costEquipment.dataLoaded ? (
|
{equipConfiguration.dataLoaded ? (
|
||||||
<>
|
<>
|
||||||
<Box sx={STYLES.TABLE_BUTTONS}>
|
<Box sx={STYLES.TABLE_BUTTONS}>
|
||||||
<Button
|
<Button
|
||||||
variant="contained"
|
variant="contained"
|
||||||
size="small"
|
size="small"
|
||||||
disabled={
|
disabled={
|
||||||
costEquipment.selectedRows.length !== 1 ||
|
!equipConfiguration.selectedRow.NRN ||
|
||||||
(costEquipment.selectedRows.length === 1 && costJobsSpecs.selectedRows.length === 0) ||
|
!costJobsSpecs.selectedRow.NRN ||
|
||||||
costEquipment.selectedLoaded
|
(equipConfiguration.selectedRow.NRN && equipConfiguration.selectedRow.BFULL_LOADED)
|
||||||
}
|
}
|
||||||
onClick={costJobsSpecIncludeCostEquipment}
|
onClick={handleIncludeEquipmentOpen}
|
||||||
>
|
>
|
||||||
Включить в задание
|
Включить в задание
|
||||||
</Button>
|
</Button>
|
||||||
@ -369,10 +417,7 @@ const CostJobsSpecsDataGrid = ({ task, processIdent, clearSelectlist }) => {
|
|||||||
<Button
|
<Button
|
||||||
variant="contained"
|
variant="contained"
|
||||||
size="small"
|
size="small"
|
||||||
disabled={
|
disabled={!costJobsSpecs.selectedRow.NRN || !costJobsSpecs.selectedRow.NEQCONFIG}
|
||||||
costEquipment.selectedRows.length !== 1 ||
|
|
||||||
(costEquipment.selectedRows.length === 1 && costJobsSpecs.selectedRows.length === 0)
|
|
||||||
}
|
|
||||||
onClick={costJobsSpecExcludeCostEquipment}
|
onClick={costJobsSpecExcludeCostEquipment}
|
||||||
>
|
>
|
||||||
Исключить из задания
|
Исключить из задания
|
||||||
@ -382,11 +427,12 @@ const CostJobsSpecsDataGrid = ({ task, processIdent, clearSelectlist }) => {
|
|||||||
<Box sx={STYLES.TABLE}>
|
<Box sx={STYLES.TABLE}>
|
||||||
<P8PDataGrid
|
<P8PDataGrid
|
||||||
{...P8P_DATA_GRID_CONFIG_PROPS}
|
{...P8P_DATA_GRID_CONFIG_PROPS}
|
||||||
columnsDef={costEquipment.columnsDef}
|
containerComponentProps={{ sx: STYLES.DATA_GRID_CONTAINER, elevation: 1 }}
|
||||||
rows={costEquipment.rows}
|
columnsDef={equipConfiguration.columnsDef}
|
||||||
|
rows={equipConfiguration.rows}
|
||||||
size={P8P_DATA_GRID_SIZE.SMALL}
|
size={P8P_DATA_GRID_SIZE.SMALL}
|
||||||
morePages={costEquipment.morePages}
|
morePages={equipConfiguration.morePages}
|
||||||
reloading={costEquipment.reload}
|
reloading={equipConfiguration.reload}
|
||||||
onOrderChanged={costEquipmentOrderChanged}
|
onOrderChanged={costEquipmentOrderChanged}
|
||||||
onPagesCountChanged={costEquipmentPagesCountChanged}
|
onPagesCountChanged={costEquipmentPagesCountChanged}
|
||||||
dataCellRender={prms =>
|
dataCellRender={prms =>
|
||||||
@ -394,25 +440,35 @@ const CostJobsSpecsDataGrid = ({ task, processIdent, clearSelectlist }) => {
|
|||||||
...prms,
|
...prms,
|
||||||
handleSelectChange,
|
handleSelectChange,
|
||||||
sUnit: sUnitCostEquipment,
|
sUnit: sUnitCostEquipment,
|
||||||
selectedEquip: costEquipment.selectedRows
|
selectedRow: equipConfiguration.selectedRow.NRN,
|
||||||
|
selectedJobSpec: costJobsSpecs.selectedRow
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
headCellRender={prms => headCellRender({ ...prms })}
|
headCellRender={prms => headCellRender({ ...prms })}
|
||||||
|
fixedHeader={true}
|
||||||
/>
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
</>
|
</>
|
||||||
) : null}
|
) : null}
|
||||||
</Grid>
|
</Grid>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
{includeEquipment.NFCJOBSSP && includeEquipment.NFCJOBSSP ? (
|
||||||
|
<CostJobsSpecsInclude
|
||||||
|
includeEquipment={includeEquipment}
|
||||||
|
setIncludeEquipment={setIncludeEquipment}
|
||||||
|
setCostJobsSpecs={setCostJobsSpecs}
|
||||||
|
setEquipConfiguration={setEquipConfiguration}
|
||||||
|
includeEquipConfiguration={includeEquipConfiguration}
|
||||||
|
/>
|
||||||
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
//Контроль свойств - Таблица информации об операциях сменного задания
|
//Контроль свойств - Таблица информации о строках сменного задания
|
||||||
CostJobsSpecsDataGrid.propTypes = {
|
CostJobsSpecsDataGrid.propTypes = {
|
||||||
task: PropTypes.number.isRequired,
|
task: PropTypes.number.isRequired,
|
||||||
processIdent: PropTypes.number,
|
haveNote: PropTypes.bool.isRequired
|
||||||
clearSelectlist: PropTypes.func
|
|
||||||
};
|
};
|
||||||
|
|
||||||
//----------------
|
//----------------
|
||||||
|
@ -1,13 +1,21 @@
|
|||||||
/*
|
|
||||||
Парус 8 - Панели мониторинга - ПУП - Выдача сменного задания
|
|
||||||
Кастомные хуки
|
|
||||||
*/
|
|
||||||
|
|
||||||
//---------------------
|
//---------------------
|
||||||
//Подключение библиотек
|
//Подключение библиотек
|
||||||
//---------------------
|
//---------------------
|
||||||
|
|
||||||
import React from "react"; //Классы React
|
import React, { useState, useCallback, useEffect, useContext } from "react"; //Классы React
|
||||||
|
import { BackEndСtx } from "../../context/backend"; //Контекст взаимодействия с сервером
|
||||||
|
import { object2Base64XML } from "../../core/utils"; //Вспомогательные функции
|
||||||
|
|
||||||
|
//---------
|
||||||
|
//Константы
|
||||||
|
//---------
|
||||||
|
|
||||||
|
//Размер страницы данных
|
||||||
|
const DATA_GRID_PAGE_SIZE = 50;
|
||||||
|
|
||||||
|
//---------------------------------------------
|
||||||
|
//Вспомогательные функции форматирования данных
|
||||||
|
//---------------------------------------------
|
||||||
|
|
||||||
//-----------
|
//-----------
|
||||||
//Тело модуля
|
//Тело модуля
|
||||||
@ -21,3 +29,242 @@ export const useFilteredFcjobs = (jobs, filter) => {
|
|||||||
|
|
||||||
return filteredJobs;
|
return filteredJobs;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
//Хук для основной таблицы
|
||||||
|
const useCostJobs = () => {
|
||||||
|
//Собственное состояние - таблица данных
|
||||||
|
const [state, setState] = useState({
|
||||||
|
init: false,
|
||||||
|
showJobList: false,
|
||||||
|
jobList: [],
|
||||||
|
jobListLoaded: false,
|
||||||
|
selectedJob: {},
|
||||||
|
dataLoaded: false
|
||||||
|
});
|
||||||
|
|
||||||
|
//Подключение к контексту взаимодействия с сервером
|
||||||
|
const { executeStored } = useContext(BackEndСtx);
|
||||||
|
|
||||||
|
//При подключении компонента к странице
|
||||||
|
useEffect(() => {
|
||||||
|
const initPlans = async () => {
|
||||||
|
const data = await executeStored({
|
||||||
|
stored: "PKG_P8PANELS_MECHREC.FCJOBS_INIT",
|
||||||
|
args: {},
|
||||||
|
respArg: "COUT",
|
||||||
|
isArray: name => name === "XFCJOBS",
|
||||||
|
attributeValueProcessor: (name, val) => (["NHAVE_NOTE"].includes(name) ? val == 1 : val)
|
||||||
|
});
|
||||||
|
setState(pv => ({
|
||||||
|
...pv,
|
||||||
|
init: true,
|
||||||
|
jobList: [...(data.XFCJOBS || [])],
|
||||||
|
jobListLoaded: true
|
||||||
|
}));
|
||||||
|
};
|
||||||
|
if (!state.init) {
|
||||||
|
initPlans();
|
||||||
|
}
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return [state, setState];
|
||||||
|
};
|
||||||
|
|
||||||
|
//Хук для таблицы операций
|
||||||
|
const useCostJobsSpecs = task => {
|
||||||
|
//Собственное состояние - таблица данных
|
||||||
|
const [costJobsSpecs, setCostJobsSpecs] = useState({
|
||||||
|
task: null,
|
||||||
|
dataLoaded: false,
|
||||||
|
columnsDef: [],
|
||||||
|
orders: null,
|
||||||
|
rows: [],
|
||||||
|
selectedRow: {},
|
||||||
|
reload: true,
|
||||||
|
pageNumber: 1,
|
||||||
|
morePages: true
|
||||||
|
});
|
||||||
|
|
||||||
|
//Подключение к контексту взаимодействия с сервером
|
||||||
|
const { executeStored, SERV_DATA_TYPE_CLOB } = useContext(BackEndСtx);
|
||||||
|
|
||||||
|
//Выдача задания
|
||||||
|
const issueCostJobsSpecs = useCallback(
|
||||||
|
async prms => {
|
||||||
|
try {
|
||||||
|
await executeStored({
|
||||||
|
stored: "PKG_P8PANELS_MECHREC.FCJOBSSP_ISSUE",
|
||||||
|
args: { NFCJOBS: prms.NFCJOBS, SFCJOBSSP_LIST: prms.SFCJOBSSP_LIST }
|
||||||
|
});
|
||||||
|
} catch (e) {
|
||||||
|
throw new Error(e.message);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[executeStored]
|
||||||
|
);
|
||||||
|
|
||||||
|
//При необходимости обновить данные таблицы
|
||||||
|
useEffect(() => {
|
||||||
|
//Если изменилось сменное задание - обновляем состояние
|
||||||
|
if (costJobsSpecs.dataLoaded && costJobsSpecs.task !== task) {
|
||||||
|
setCostJobsSpecs(pv => ({
|
||||||
|
...pv,
|
||||||
|
dataLoaded: false,
|
||||||
|
columnsDef: [],
|
||||||
|
orders: null,
|
||||||
|
rows: [],
|
||||||
|
selectedRow: {},
|
||||||
|
reload: true,
|
||||||
|
pageNumber: 1,
|
||||||
|
morePages: true
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
//Если необходимо перезагрузить
|
||||||
|
if (costJobsSpecs.reload) {
|
||||||
|
const loadData = async () => {
|
||||||
|
const data = await executeStored({
|
||||||
|
stored: "PKG_P8PANELS_MECHREC.FCJOBSSP_DG_GET",
|
||||||
|
args: {
|
||||||
|
NFCJOBS: task,
|
||||||
|
NPAGE_NUMBER: costJobsSpecs.pageNumber,
|
||||||
|
NPAGE_SIZE: DATA_GRID_PAGE_SIZE,
|
||||||
|
CORDERS: { VALUE: object2Base64XML(costJobsSpecs.orders, { arrayNodeName: "orders" }), SDATA_TYPE: SERV_DATA_TYPE_CLOB },
|
||||||
|
NINCLUDE_DEF: costJobsSpecs.dataLoaded ? 0 : 1
|
||||||
|
},
|
||||||
|
respArg: "COUT",
|
||||||
|
attributeValueProcessor: (name, val) => (["NSELECT"].includes(name) ? val === 1 : val)
|
||||||
|
});
|
||||||
|
setCostJobsSpecs(pv => ({
|
||||||
|
...pv,
|
||||||
|
task: task,
|
||||||
|
columnsDef: data.XCOLUMNS_DEF ? [...data.XCOLUMNS_DEF] : pv.columnsDef,
|
||||||
|
rows: pv.pageNumber == 1 ? [...(data.XROWS || [])] : [...pv.rows, ...(data.XROWS || [])],
|
||||||
|
dataLoaded: true,
|
||||||
|
reload: false,
|
||||||
|
morePages: (data.XROWS || []).length >= DATA_GRID_PAGE_SIZE
|
||||||
|
}));
|
||||||
|
};
|
||||||
|
loadData();
|
||||||
|
}
|
||||||
|
}, [
|
||||||
|
SERV_DATA_TYPE_CLOB,
|
||||||
|
costJobsSpecs.dataLoaded,
|
||||||
|
costJobsSpecs.orders,
|
||||||
|
costJobsSpecs.pageNumber,
|
||||||
|
costJobsSpecs.reload,
|
||||||
|
costJobsSpecs.selectedRow,
|
||||||
|
costJobsSpecs.task,
|
||||||
|
executeStored,
|
||||||
|
task
|
||||||
|
]);
|
||||||
|
|
||||||
|
return [costJobsSpecs, setCostJobsSpecs, issueCostJobsSpecs];
|
||||||
|
};
|
||||||
|
|
||||||
|
//Хук для таблицы рабочих центров
|
||||||
|
const useEquipConfiguration = task => {
|
||||||
|
//Собственное состояние - таблица данных
|
||||||
|
const [equipConfiguration, setEquipConfiguration] = useState({
|
||||||
|
task: null,
|
||||||
|
dataLoaded: false,
|
||||||
|
columnsDef: [],
|
||||||
|
orders: null,
|
||||||
|
rows: [],
|
||||||
|
selectedRow: {},
|
||||||
|
reload: true,
|
||||||
|
pageNumber: 1,
|
||||||
|
morePages: true
|
||||||
|
});
|
||||||
|
|
||||||
|
//Подключение к контексту взаимодействия с сервером
|
||||||
|
const { executeStored, SERV_DATA_TYPE_CLOB } = useContext(BackEndСtx);
|
||||||
|
|
||||||
|
//Включение станка в строку сменного задания
|
||||||
|
const includeEquipConfiguration = useCallback(
|
||||||
|
async prms => {
|
||||||
|
try {
|
||||||
|
await executeStored({
|
||||||
|
stored: "PKG_P8PANELS_MECHREC.FCJOBSSP_INC_EQCONFIG",
|
||||||
|
args: { NEQCONFIG: prms.NEQCONFIG, NFCJOBSSP: prms.NFCJOBSSP, NQUANT_PLAN: prms.NQUANT_PLAN }
|
||||||
|
});
|
||||||
|
} catch (e) {
|
||||||
|
throw new Error(e.message);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[executeStored]
|
||||||
|
);
|
||||||
|
|
||||||
|
//Исключение станка из строки сменного задания
|
||||||
|
const excludeEquipConfiguration = useCallback(
|
||||||
|
async prms => {
|
||||||
|
try {
|
||||||
|
await executeStored({
|
||||||
|
stored: "PKG_P8PANELS_MECHREC.FCJOBSSP_EXC_EQCONFIG",
|
||||||
|
args: { NFCJOBSSP: prms.NFCJOBSSP }
|
||||||
|
});
|
||||||
|
} catch (e) {
|
||||||
|
throw new Error(e.message);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[executeStored]
|
||||||
|
);
|
||||||
|
|
||||||
|
//При необходимости обновить данные таблицы
|
||||||
|
useEffect(() => {
|
||||||
|
//Если изменилось сменное задание - обновляем состояние
|
||||||
|
if (equipConfiguration.dataLoaded && equipConfiguration.task !== task) {
|
||||||
|
setEquipConfiguration(pv => ({
|
||||||
|
...pv,
|
||||||
|
dataLoaded: false,
|
||||||
|
columnsDef: [],
|
||||||
|
orders: null,
|
||||||
|
rows: [],
|
||||||
|
selectedRow: {},
|
||||||
|
reload: true,
|
||||||
|
pageNumber: 1,
|
||||||
|
morePages: true
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
if (equipConfiguration.reload) {
|
||||||
|
const loadData = async () => {
|
||||||
|
const data = await executeStored({
|
||||||
|
stored: "PKG_P8PANELS_MECHREC.EQCONFIG_DG_GET",
|
||||||
|
args: {
|
||||||
|
NFCJOBS: task,
|
||||||
|
CORDERS: { VALUE: object2Base64XML(equipConfiguration.orders, { arrayNodeName: "orders" }), SDATA_TYPE: SERV_DATA_TYPE_CLOB },
|
||||||
|
NPAGE_NUMBER: equipConfiguration.pageNumber,
|
||||||
|
NPAGE_SIZE: DATA_GRID_PAGE_SIZE,
|
||||||
|
NINCLUDE_DEF: equipConfiguration.dataLoaded ? 0 : 1
|
||||||
|
},
|
||||||
|
respArg: "COUT",
|
||||||
|
attributeValueProcessor: (name, val) => (["NSELECT"].includes(name) ? val === 1 : val)
|
||||||
|
});
|
||||||
|
setEquipConfiguration(pv => ({
|
||||||
|
...pv,
|
||||||
|
task: task,
|
||||||
|
columnsDef: data.XCOLUMNS_DEF ? [...data.XCOLUMNS_DEF] : pv.columnsDef,
|
||||||
|
rows: pv.pageNumber == 1 ? [...(data.XROWS || [])] : [...pv.rows, ...(data.XROWS || [])],
|
||||||
|
dataLoaded: true,
|
||||||
|
reload: false,
|
||||||
|
morePages: (data.XROWS || []).length >= DATA_GRID_PAGE_SIZE
|
||||||
|
}));
|
||||||
|
};
|
||||||
|
loadData();
|
||||||
|
}
|
||||||
|
}, [
|
||||||
|
SERV_DATA_TYPE_CLOB,
|
||||||
|
equipConfiguration.dataLoaded,
|
||||||
|
equipConfiguration.orders,
|
||||||
|
equipConfiguration.pageNumber,
|
||||||
|
equipConfiguration.reload,
|
||||||
|
equipConfiguration.selectedRow,
|
||||||
|
equipConfiguration.task,
|
||||||
|
task,
|
||||||
|
executeStored
|
||||||
|
]);
|
||||||
|
|
||||||
|
return [equipConfiguration, setEquipConfiguration, includeEquipConfiguration, excludeEquipConfiguration];
|
||||||
|
};
|
||||||
|
|
||||||
|
export { useCostJobs, useCostJobsSpecs, useEquipConfiguration };
|
||||||
|
@ -7,13 +7,12 @@
|
|||||||
//Подключение библиотек
|
//Подключение библиотек
|
||||||
//---------------------
|
//---------------------
|
||||||
|
|
||||||
import React, { useContext, useState, useCallback, useEffect } from "react"; //Классы React
|
import React, { useContext, useState } from "react"; //Классы React
|
||||||
import PropTypes from "prop-types"; //Контроль свойств компонента
|
import PropTypes from "prop-types"; //Контроль свойств компонента
|
||||||
import { Drawer, Fab, Box, List, ListItemButton, ListItemText, Typography, TextField } from "@mui/material"; //Интерфейсные элементы
|
import { Drawer, Fab, Box, List, ListItemButton, ListItemText, Typography, TextField } from "@mui/material"; //Интерфейсные элементы
|
||||||
import { BackEndСtx } from "../../context/backend"; //Контекст взаимодействия с сервером
|
|
||||||
import { MessagingСtx } from "../../context/messaging"; //Контекст сообщений
|
import { MessagingСtx } from "../../context/messaging"; //Контекст сообщений
|
||||||
import { useFilteredFcjobs } from "./hooks"; //Вспомогательные хуки
|
|
||||||
import { CostJobsSpecsDataGrid } from "./fcjobssp"; //Собственные хуки таблиц
|
import { CostJobsSpecsDataGrid } from "./fcjobssp"; //Собственные хуки таблиц
|
||||||
|
import { useCostJobs, useFilteredFcjobs } from "./hooks"; //Вспомогательные хуки
|
||||||
|
|
||||||
//---------
|
//---------
|
||||||
//Константы
|
//Константы
|
||||||
@ -30,7 +29,7 @@ const STYLES = {
|
|||||||
flexShrink: 0,
|
flexShrink: 0,
|
||||||
[`& .MuiDrawer-paper`]: { width: "350px", display: "inline-block", boxSizing: "border-box" }
|
[`& .MuiDrawer-paper`]: { width: "350px", display: "inline-block", boxSizing: "border-box" }
|
||||||
},
|
},
|
||||||
CONTAINER: { margin: "5px 0px", textAlign: "center" }
|
CONTAINER: { textAlign: "center" }
|
||||||
};
|
};
|
||||||
|
|
||||||
//------------------------------------
|
//------------------------------------
|
||||||
@ -80,15 +79,7 @@ JobList.propTypes = {
|
|||||||
//Корневая панель выдачи сменного задания
|
//Корневая панель выдачи сменного задания
|
||||||
const MechRecCostJobs = () => {
|
const MechRecCostJobs = () => {
|
||||||
//Собственное состояние - таблица данных
|
//Собственное состояние - таблица данных
|
||||||
const [state, setState] = useState({
|
const [state, setState] = useCostJobs();
|
||||||
init: false,
|
|
||||||
showJobList: false,
|
|
||||||
jobList: [],
|
|
||||||
jobListLoaded: false,
|
|
||||||
selectedJob: {},
|
|
||||||
processIdent: null,
|
|
||||||
dataLoaded: false
|
|
||||||
});
|
|
||||||
|
|
||||||
//Состояние для фильтра каталогов
|
//Состояние для фильтра каталогов
|
||||||
const [filter, setFilter] = useState({ jobName: "" });
|
const [filter, setFilter] = useState({ jobName: "" });
|
||||||
@ -96,57 +87,11 @@ const MechRecCostJobs = () => {
|
|||||||
//Массив отфильтрованных каталогов
|
//Массив отфильтрованных каталогов
|
||||||
const filteredJobs = useFilteredFcjobs(state.jobList, filter);
|
const filteredJobs = useFilteredFcjobs(state.jobList, filter);
|
||||||
|
|
||||||
//Подключение к контексту взаимодействия с сервером
|
|
||||||
const { executeStored } = useContext(BackEndСtx);
|
|
||||||
|
|
||||||
//Подключение к контексту сообщений
|
//Подключение к контексту сообщений
|
||||||
const { InlineMsgInfo } = useContext(MessagingСtx);
|
const { InlineMsgInfo } = useContext(MessagingСtx);
|
||||||
|
|
||||||
//Инициализация каталогов планов
|
|
||||||
const initPlans = useCallback(async () => {
|
|
||||||
if (!state.init) {
|
|
||||||
const data = await executeStored({
|
|
||||||
stored: "PKG_P8PANELS_MECHREC.FCJOBS_INIT",
|
|
||||||
args: {},
|
|
||||||
respArg: "COUT",
|
|
||||||
fullResponse: true,
|
|
||||||
isArray: name => name === "XFCJOBS"
|
|
||||||
});
|
|
||||||
setState(pv => ({
|
|
||||||
...pv,
|
|
||||||
init: true,
|
|
||||||
jobList: [...(data.XPAYLOAD?.XFCJOBS || [])],
|
|
||||||
jobListLoaded: true,
|
|
||||||
processIdent: data.XPAYLOAD.XINFO.NPROCESS_IDENT
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
}, [state.init, executeStored]);
|
|
||||||
|
|
||||||
//При подключении компонента к странице
|
|
||||||
useEffect(() => {
|
|
||||||
initPlans();
|
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
//Очистка селектлиста по идентификатору процесса
|
|
||||||
const clearSelectlist = useCallback(
|
|
||||||
async NIDENT => {
|
|
||||||
try {
|
|
||||||
await executeStored({
|
|
||||||
stored: "P_SELECTLIST_CLEAR",
|
|
||||||
args: { NIDENT: NIDENT }
|
|
||||||
});
|
|
||||||
} catch (e) {
|
|
||||||
throw new Error(e.message);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
[executeStored]
|
|
||||||
);
|
|
||||||
|
|
||||||
//Выбор плана
|
//Выбор плана
|
||||||
const selectJob = job => {
|
const selectJob = job => {
|
||||||
//Очищаем селектлист
|
|
||||||
clearSelectlist(state.processIdent);
|
|
||||||
//Обновляем состояние
|
//Обновляем состояние
|
||||||
setState(pv => ({
|
setState(pv => ({
|
||||||
...pv,
|
...pv,
|
||||||
@ -158,8 +103,6 @@ const MechRecCostJobs = () => {
|
|||||||
|
|
||||||
//Сброс выбора плана
|
//Сброс выбора плана
|
||||||
const unselectJob = () => {
|
const unselectJob = () => {
|
||||||
//Очищаем селектлист
|
|
||||||
clearSelectlist(state.processIdent);
|
|
||||||
//Обновляем состояние
|
//Обновляем состояние
|
||||||
setState(pv => ({
|
setState(pv => ({
|
||||||
...pv,
|
...pv,
|
||||||
@ -187,11 +130,12 @@ const MechRecCostJobs = () => {
|
|||||||
<div style={STYLES.CONTAINER}>
|
<div style={STYLES.CONTAINER}>
|
||||||
{state.selectedJob.NRN ? (
|
{state.selectedJob.NRN ? (
|
||||||
<>
|
<>
|
||||||
<Typography variant={"h6"}>{`Сменное задание "${state.selectedJob.SSUBDIV}" на ${state.selectedJob.SPERIOD}`}</Typography>
|
<Typography variant={"h6"}>{`Сменное задание №${state.selectedJob.SDOC_NUMB} на ${state.selectedJob.SPERIOD}`}</Typography>
|
||||||
<CostJobsSpecsDataGrid task={state.selectedJob.NRN} processIdent={state.processIdent} clearSelectlist={clearSelectlist} />
|
<Typography variant={"h6"}>{`${state.selectedJob.SSUBDIV}`}</Typography>
|
||||||
|
<CostJobsSpecsDataGrid task={state.selectedJob.NRN} haveNote={state.selectedJob.NHAVE_NOTE} />
|
||||||
</>
|
</>
|
||||||
) : !state.selectedJob.NRN ? (
|
) : !state.selectedJob.NRN ? (
|
||||||
<InlineMsgInfo okBtn={false} text={"Укажите сменное задание"} />
|
<InlineMsgInfo okBtn={false} text={"Укажите сменное задание для отображения информации"} />
|
||||||
) : null}
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
</Box>
|
</Box>
|
||||||
|
137
app/panels/mech_rec_dept_cost_jobs/components/filter.js
Normal file
137
app/panels/mech_rec_dept_cost_jobs/components/filter.js
Normal file
@ -0,0 +1,137 @@
|
|||||||
|
/*
|
||||||
|
Парус 8 - Панели мониторинга - ПУП - Загрузка цеха
|
||||||
|
Компонент панели: Фильтр
|
||||||
|
*/
|
||||||
|
|
||||||
|
//---------------------
|
||||||
|
//Подключение библиотек
|
||||||
|
//---------------------
|
||||||
|
|
||||||
|
import React from "react"; //Классы React
|
||||||
|
import PropTypes from "prop-types"; //Контроль свойств компонента
|
||||||
|
import {
|
||||||
|
Typography,
|
||||||
|
Box,
|
||||||
|
Dialog,
|
||||||
|
DialogContent,
|
||||||
|
DialogActions,
|
||||||
|
Button,
|
||||||
|
IconButton,
|
||||||
|
Icon,
|
||||||
|
FormControl,
|
||||||
|
InputLabel,
|
||||||
|
OutlinedInput,
|
||||||
|
InputAdornment
|
||||||
|
} from "@mui/material"; //Интерфейсные элементы
|
||||||
|
import { InsDepartmentDataGrid } from "./ins_department_dg"; //Таблица подразделений цехов
|
||||||
|
|
||||||
|
//---------
|
||||||
|
//Константы
|
||||||
|
//---------
|
||||||
|
|
||||||
|
//Текущая дата
|
||||||
|
const currentDate = new Date();
|
||||||
|
const currentMonth = currentDate.getUTCMonth() + 1;
|
||||||
|
const currentYear = currentDate.getUTCFullYear();
|
||||||
|
|
||||||
|
//Стили
|
||||||
|
const STYLES = {
|
||||||
|
FILTER_BLOCK: { maxWidth: "200px" }
|
||||||
|
};
|
||||||
|
|
||||||
|
//------------------------------------
|
||||||
|
//Вспомогательные функции и компоненты
|
||||||
|
//------------------------------------
|
||||||
|
|
||||||
|
//Диалог выбора подразделения
|
||||||
|
const DepartmentsDataGrid = ({ filter, setFilter, handleSelectDeparture }) => {
|
||||||
|
return (
|
||||||
|
<Dialog fullWidth open onClose={() => setFilter(pv => ({ ...pv, openedDepartment: false }))}>
|
||||||
|
<DialogContent>
|
||||||
|
<InsDepartmentDataGrid fullDate={filter.date.fullDate} handleSelectDeparture={handleSelectDeparture} />
|
||||||
|
</DialogContent>
|
||||||
|
<DialogActions>
|
||||||
|
<Button onClick={() => setFilter(pv => ({ ...pv, openedDepartment: false }))}>Закрыть</Button>
|
||||||
|
</DialogActions>
|
||||||
|
</Dialog>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
//Контроль свойств - Диалог выбора подразделения
|
||||||
|
DepartmentsDataGrid.propTypes = {
|
||||||
|
filter: PropTypes.object.isRequired,
|
||||||
|
setFilter: PropTypes.func.isRequired,
|
||||||
|
handleSelectDeparture: PropTypes.func.isRequired
|
||||||
|
};
|
||||||
|
|
||||||
|
//-----------
|
||||||
|
//Тело модуля
|
||||||
|
//-----------
|
||||||
|
|
||||||
|
//Компонент фильтра
|
||||||
|
const FilterComponent = ({ filter, setFilter, handleMonthChange, handleSelectDeparture }) => {
|
||||||
|
return (
|
||||||
|
<Box display="flex" flexDirection="row" justifyContent="flex-start" alignItems="flex-end" pt={1.5} pl={1}>
|
||||||
|
<FormControl sx={STYLES.FILTER_BLOCK} readOnly fullWidth variant="outlined">
|
||||||
|
<InputLabel required={!filter.department.SCODE} htmlFor="department-outlined">
|
||||||
|
Цех
|
||||||
|
</InputLabel>
|
||||||
|
<OutlinedInput
|
||||||
|
disabled
|
||||||
|
id="department-outlined"
|
||||||
|
value={filter.department.SCODE}
|
||||||
|
endAdornment={
|
||||||
|
<InputAdornment position="end">
|
||||||
|
<IconButton
|
||||||
|
aria-label="department select"
|
||||||
|
onClick={() => setFilter(pv => ({ ...pv, openedDepartment: true }))}
|
||||||
|
edge="end"
|
||||||
|
>
|
||||||
|
<Icon>list</Icon>
|
||||||
|
</IconButton>
|
||||||
|
</InputAdornment>
|
||||||
|
}
|
||||||
|
aria-describedby="department-outlined-helper-text"
|
||||||
|
label="Цех"
|
||||||
|
/>
|
||||||
|
</FormControl>
|
||||||
|
<Box sx={STYLES.FILTER_BLOCK} display="flex" pb={1}>
|
||||||
|
<Box>
|
||||||
|
<IconButton onClick={() => handleMonthChange(-1)}>
|
||||||
|
<Icon>navigate_before</Icon>
|
||||||
|
</IconButton>
|
||||||
|
</Box>
|
||||||
|
<Typography variant="h5" pt={0.5}>
|
||||||
|
{filter.date.fullDate}
|
||||||
|
</Typography>
|
||||||
|
<Box>
|
||||||
|
<IconButton
|
||||||
|
onClick={() => handleMonthChange(1)}
|
||||||
|
disabled={filter.date.year === currentYear && filter.date.month === currentMonth}
|
||||||
|
>
|
||||||
|
<Icon>navigate_next</Icon>
|
||||||
|
</IconButton>
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
<Typography variant="subtitle2" pl={2} pb={2}>{`Рабочих дней: ${filter.workDays}`}</Typography>
|
||||||
|
<Typography variant="subtitle2" pl={3.5} pb={2}>{`Рабочих часов: ${filter.totalWorkHours}`}</Typography>
|
||||||
|
{filter.openedDepartment ? (
|
||||||
|
<DepartmentsDataGrid filter={filter} setFilter={setFilter} handleSelectDeparture={handleSelectDeparture} />
|
||||||
|
) : null}
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
//Контроль свойств - Компонент фильтра
|
||||||
|
FilterComponent.propTypes = {
|
||||||
|
filter: PropTypes.object.isRequired,
|
||||||
|
setFilter: PropTypes.func.isRequired,
|
||||||
|
handleMonthChange: PropTypes.func.isRequired,
|
||||||
|
handleSelectDeparture: PropTypes.func.isRequired
|
||||||
|
};
|
||||||
|
|
||||||
|
//----------------
|
||||||
|
//Интерфейс модуля
|
||||||
|
//----------------
|
||||||
|
|
||||||
|
export { FilterComponent };
|
@ -0,0 +1,85 @@
|
|||||||
|
/*
|
||||||
|
Парус 8 - Панели мониторинга - ПУП - Загрузка цеха
|
||||||
|
Компонент панели: Таблица строк подразделений цехов
|
||||||
|
*/
|
||||||
|
|
||||||
|
//---------------------
|
||||||
|
//Подключение библиотек
|
||||||
|
//---------------------
|
||||||
|
|
||||||
|
import React from "react"; //Классы React
|
||||||
|
import PropTypes from "prop-types"; //Контроль свойств компонента
|
||||||
|
import { Typography } from "@mui/material"; //Интерфейсные элементы
|
||||||
|
import { P8PDataGrid, P8P_DATA_GRID_SIZE } from "../../../components/p8p_data_grid"; //Таблица данных
|
||||||
|
import { P8P_DATA_GRID_CONFIG_PROPS } from "../../../config_wrapper"; //Подключение компонентов к настройкам приложения
|
||||||
|
import { useInsDepartment } from "../hooks"; //Состояние таблицы подразделений цехов
|
||||||
|
|
||||||
|
//---------
|
||||||
|
//Константы
|
||||||
|
//---------
|
||||||
|
|
||||||
|
//Стили
|
||||||
|
const STYLES = {
|
||||||
|
CONTAINER: { margin: "5px 0px", textAlign: "center" }
|
||||||
|
};
|
||||||
|
|
||||||
|
//------------------------------------
|
||||||
|
//Вспомогательные функции и компоненты
|
||||||
|
//------------------------------------
|
||||||
|
|
||||||
|
//Генерация ссылок на строках
|
||||||
|
const dataCellRender = ({ row, columnDef, handleSelectDeparture }) => {
|
||||||
|
return {
|
||||||
|
cellStyle: { cursor: "pointer", backgroundColor: "#ADD8E6" },
|
||||||
|
cellProps: {
|
||||||
|
onClick: () => {
|
||||||
|
handleSelectDeparture({ NRN: row["NRN"], SCODE: row["SCODE"].toString(), SNAME: row["SNAME"] });
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data: row[columnDef.name]
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
//-----------
|
||||||
|
//Тело модуля
|
||||||
|
//-----------
|
||||||
|
|
||||||
|
//Таблица строк подразделений цехов
|
||||||
|
const InsDepartmentDataGrid = ({ fullDate, handleSelectDeparture }) => {
|
||||||
|
//Собственное состояние
|
||||||
|
let [insDepartments, setInsDepartments] = useInsDepartment(fullDate);
|
||||||
|
|
||||||
|
//При изменении количества отображаемых страниц
|
||||||
|
const handlePagesCountChanged = () => setInsDepartments(pv => ({ ...pv, pageNumber: pv.pageNumber + 1, reload: true }));
|
||||||
|
|
||||||
|
//Генерация содержимого
|
||||||
|
return (
|
||||||
|
<div style={STYLES.CONTAINER}>
|
||||||
|
<Typography variant={"subtitle2"}>Подразделения цехов</Typography>
|
||||||
|
{insDepartments.dataLoaded ? (
|
||||||
|
<P8PDataGrid
|
||||||
|
{...P8P_DATA_GRID_CONFIG_PROPS}
|
||||||
|
columnsDef={insDepartments.columnsDef}
|
||||||
|
rows={insDepartments.rows}
|
||||||
|
size={P8P_DATA_GRID_SIZE.LARGE}
|
||||||
|
morePages={insDepartments.morePages}
|
||||||
|
reloading={insDepartments.reload}
|
||||||
|
onPagesCountChanged={handlePagesCountChanged}
|
||||||
|
dataCellRender={prms => dataCellRender({ ...prms, handleSelectDeparture })}
|
||||||
|
/>
|
||||||
|
) : null}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
//Контроль свойств - Таблица строк подразделений цехов
|
||||||
|
InsDepartmentDataGrid.propTypes = {
|
||||||
|
fullDate: PropTypes.string.isRequired,
|
||||||
|
handleSelectDeparture: PropTypes.func.isRequired
|
||||||
|
};
|
||||||
|
|
||||||
|
//----------------
|
||||||
|
//Интерфейс модуля
|
||||||
|
//----------------
|
||||||
|
|
||||||
|
export { InsDepartmentDataGrid };
|
198
app/panels/mech_rec_dept_cost_jobs/hooks.js
Normal file
198
app/panels/mech_rec_dept_cost_jobs/hooks.js
Normal file
@ -0,0 +1,198 @@
|
|||||||
|
/*
|
||||||
|
Парус 8 - Панели мониторинга - ПУП - Загрузка цеха
|
||||||
|
Кастомные хуки
|
||||||
|
*/
|
||||||
|
|
||||||
|
//---------------------
|
||||||
|
//Подключение библиотек
|
||||||
|
//---------------------
|
||||||
|
|
||||||
|
import { useState, useCallback, useEffect, useContext } from "react"; //Классы React
|
||||||
|
import { BackEndСtx } from "../../context/backend"; //Контекст взаимодействия с сервером
|
||||||
|
import { object2Base64XML, formatDateRF } from "../../core/utils"; //Вспомогательные функции
|
||||||
|
|
||||||
|
//---------
|
||||||
|
//Константы
|
||||||
|
//---------
|
||||||
|
|
||||||
|
//Размер страницы данных
|
||||||
|
const DATA_GRID_PAGE_SIZE_SMALL = 5;
|
||||||
|
const DATA_GRID_PAGE_SIZE_LARGE = 12;
|
||||||
|
|
||||||
|
//-----------
|
||||||
|
//Тело модуля
|
||||||
|
//-----------
|
||||||
|
|
||||||
|
//Хук для основной таблицы панели
|
||||||
|
const useMechRecDeptCostJobs = (subdiv, fullDate, workHours) => {
|
||||||
|
//Собственное состояние - таблица данных
|
||||||
|
const [costJobs, setCostJobs] = useState({
|
||||||
|
dataLoaded: false,
|
||||||
|
columnsDef: [],
|
||||||
|
orders: null,
|
||||||
|
rows: [],
|
||||||
|
reload: true,
|
||||||
|
pageNumber: 1,
|
||||||
|
morePages: true,
|
||||||
|
fixedHeader: false,
|
||||||
|
fixedColumns: 0,
|
||||||
|
date: null
|
||||||
|
});
|
||||||
|
|
||||||
|
//Подключение к контексту взаимодействия с сервером
|
||||||
|
const { executeStored, SERV_DATA_TYPE_CLOB } = useContext(BackEndСtx);
|
||||||
|
|
||||||
|
//При необходимости обновить данные таблицы
|
||||||
|
useEffect(() => {
|
||||||
|
//Если указано подразделение и необходимо обновить, либо изменилась дата
|
||||||
|
if (subdiv && (costJobs.reload || costJobs.date !== fullDate)) {
|
||||||
|
const loadData = async () => {
|
||||||
|
const data = await executeStored({
|
||||||
|
stored: "PKG_P8PANELS_MECHREC.FCJOBS_DEP_LOAD_DG_GET",
|
||||||
|
args: {
|
||||||
|
NSUBDIV: subdiv,
|
||||||
|
SMONTH_YEAR: fullDate,
|
||||||
|
NWORKHOURS: workHours,
|
||||||
|
CORDERS: { VALUE: object2Base64XML(costJobs.orders, { arrayNodeName: "orders" }), SDATA_TYPE: SERV_DATA_TYPE_CLOB },
|
||||||
|
NPAGE_NUMBER: costJobs.pageNumber,
|
||||||
|
NPAGE_SIZE: DATA_GRID_PAGE_SIZE_LARGE,
|
||||||
|
NINCLUDE_DEF: 1
|
||||||
|
},
|
||||||
|
respArg: "COUT"
|
||||||
|
});
|
||||||
|
setCostJobs(pv => ({
|
||||||
|
...pv,
|
||||||
|
fixedHeader: data.XDATA_GRID.fixedHeader,
|
||||||
|
fixedColumns: data.XDATA_GRID.fixedColumns,
|
||||||
|
columnsDef: data.XCOLUMNS_DEF ? [...data.XCOLUMNS_DEF] : pv.columnsDef,
|
||||||
|
rows: pv.pageNumber == 1 ? [...(data.XROWS || [])] : [...pv.rows, ...(data.XROWS || [])],
|
||||||
|
dataLoaded: true,
|
||||||
|
reload: false,
|
||||||
|
morePages: (data.XROWS || []).length >= DATA_GRID_PAGE_SIZE_LARGE,
|
||||||
|
date: fullDate
|
||||||
|
}));
|
||||||
|
};
|
||||||
|
loadData();
|
||||||
|
}
|
||||||
|
}, [costJobs.reload, subdiv, fullDate, costJobs.date, costJobs.orders, costJobs.pageNumber, executeStored, workHours, SERV_DATA_TYPE_CLOB]);
|
||||||
|
|
||||||
|
return [costJobs, setCostJobs];
|
||||||
|
};
|
||||||
|
|
||||||
|
//Хук таблицы подразделений цехов
|
||||||
|
const useInsDepartment = fullDate => {
|
||||||
|
//Собственное состояние
|
||||||
|
let [insDepartments, setInsDepartments] = useState({
|
||||||
|
dataLoaded: false,
|
||||||
|
columnsDef: [],
|
||||||
|
rows: [],
|
||||||
|
reload: true,
|
||||||
|
pageNumber: 1,
|
||||||
|
morePages: true
|
||||||
|
});
|
||||||
|
|
||||||
|
//Подключение к контексту взаимодействия с сервером
|
||||||
|
const { executeStored } = useContext(BackEndСtx);
|
||||||
|
|
||||||
|
//При необходимости обновить данные таблицы
|
||||||
|
useEffect(() => {
|
||||||
|
const loadData = async () => {
|
||||||
|
const data = await executeStored({
|
||||||
|
stored: "PKG_P8PANELS_MECHREC.INS_DEPARTMENT_DG_GET",
|
||||||
|
args: {
|
||||||
|
SMONTH_YEAR: fullDate,
|
||||||
|
NPAGE_SIZE: DATA_GRID_PAGE_SIZE_SMALL,
|
||||||
|
NINCLUDE_DEF: insDepartments.dataLoaded ? 0 : 1
|
||||||
|
},
|
||||||
|
respArg: "COUT",
|
||||||
|
attributeValueProcessor: (name, val) => (["DBGNDATE", "DENDDATE"].includes(name) ? formatDateRF(val) : val)
|
||||||
|
});
|
||||||
|
setInsDepartments(pv => ({
|
||||||
|
...pv,
|
||||||
|
columnsDef: data.XCOLUMNS_DEF ? [...data.XCOLUMNS_DEF] : pv.columnsDef,
|
||||||
|
rows: pv.pageNumber == 1 ? [...(data.XROWS || [])] : [...pv.rows, ...(data.XROWS || [])],
|
||||||
|
dataLoaded: true,
|
||||||
|
reload: false,
|
||||||
|
morePages: (data.XROWS || []).length >= DATA_GRID_PAGE_SIZE_SMALL
|
||||||
|
}));
|
||||||
|
};
|
||||||
|
if (insDepartments.reload) {
|
||||||
|
loadData();
|
||||||
|
}
|
||||||
|
}, [executeStored, fullDate, insDepartments.dataLoaded, insDepartments.reload]);
|
||||||
|
|
||||||
|
return [insDepartments, setInsDepartments];
|
||||||
|
};
|
||||||
|
|
||||||
|
//Хук для диалога фильтра
|
||||||
|
const useFilter = (currentMonth, currentYear) => {
|
||||||
|
//Собственное состояние - фильтр
|
||||||
|
const [filter, setFilter] = useState({
|
||||||
|
init: true,
|
||||||
|
openedDepartment: false,
|
||||||
|
date: {
|
||||||
|
month: currentMonth,
|
||||||
|
year: currentYear,
|
||||||
|
fullDate: currentMonth.toString().padStart(2, "0") + "." + currentYear
|
||||||
|
},
|
||||||
|
department: { NRN: null, SCODE: "", SNAME: "" },
|
||||||
|
workDays: 0,
|
||||||
|
workHours: 0,
|
||||||
|
totalWorkHours: 0
|
||||||
|
});
|
||||||
|
|
||||||
|
//Подключение к контексту взаимодействия с сервером
|
||||||
|
const { executeStored } = useContext(BackEndСtx);
|
||||||
|
|
||||||
|
//Считываем количества рабочих дней
|
||||||
|
const getWorkDays = useCallback(
|
||||||
|
async ({ newDate, init }) => {
|
||||||
|
const data = await executeStored({
|
||||||
|
stored: "PKG_P8PANELS_MECHREC.ENPERIOD_WORKDAYS_GET",
|
||||||
|
args: { SMONTH_YEAR: newDate.fullDate }
|
||||||
|
});
|
||||||
|
if (init) {
|
||||||
|
setFilter(pv => ({ ...pv, workDays: data.NWORKDAYS, init: false }));
|
||||||
|
} else {
|
||||||
|
setFilter(pv => ({
|
||||||
|
...pv,
|
||||||
|
date: { ...newDate },
|
||||||
|
department: filter.department,
|
||||||
|
workDays: data.NWORKDAYS,
|
||||||
|
totalWorkHours: data.NWORKDAYS * filter.workHours
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[executeStored, filter]
|
||||||
|
);
|
||||||
|
|
||||||
|
//Считываем количество рабочих часов
|
||||||
|
const getWorkHours = useCallback(
|
||||||
|
async department => {
|
||||||
|
const data = await executeStored({
|
||||||
|
stored: "PKG_P8PANELS_MECHREC.INS_DEPARTMENT_WORKHOURS_GET",
|
||||||
|
args: { NSUBDIV: department.NRN }
|
||||||
|
});
|
||||||
|
setFilter(pv => ({
|
||||||
|
...pv,
|
||||||
|
openedDepartment: false,
|
||||||
|
department: { ...department },
|
||||||
|
workHours: data.NWORKHOURS,
|
||||||
|
totalWorkHours: filter.workDays * data.NWORKHOURS
|
||||||
|
}));
|
||||||
|
},
|
||||||
|
[executeStored, filter.workDays]
|
||||||
|
);
|
||||||
|
|
||||||
|
//При необходимости обновить данные таблицы
|
||||||
|
useEffect(() => {
|
||||||
|
if (filter.init) {
|
||||||
|
getWorkDays({ newDate: { month: filter.date.month, year: filter.date.year, fullDate: filter.date.fullDate }, init: filter.init });
|
||||||
|
}
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
|
}, [filter.init]);
|
||||||
|
|
||||||
|
return [filter, setFilter, getWorkDays, getWorkHours];
|
||||||
|
};
|
||||||
|
|
||||||
|
export { useMechRecDeptCostJobs, useInsDepartment, useFilter };
|
@ -7,34 +7,62 @@
|
|||||||
//Подключение библиотек
|
//Подключение библиотек
|
||||||
//---------------------
|
//---------------------
|
||||||
|
|
||||||
import React, { useState, useContext, useCallback, useEffect } from "react"; //Классы React
|
import React from "react"; //Классы React
|
||||||
import { Typography, Box, Grid } from "@mui/material"; //Интерфейсные элементы
|
import { Typography, Box } from "@mui/material"; //Интерфейсные элементы
|
||||||
import { object2Base64XML } from "../../core/utils"; //Вспомогательные процедуры и функции
|
|
||||||
import { P8PDataGrid, P8P_DATA_GRID_SIZE } from "../../components/p8p_data_grid"; //Таблица данных
|
import { P8PDataGrid, P8P_DATA_GRID_SIZE } from "../../components/p8p_data_grid"; //Таблица данных
|
||||||
import { P8P_DATA_GRID_CONFIG_PROPS } from "../../config_wrapper"; //Подключение компонентов к настройкам приложения
|
import { P8P_DATA_GRID_CONFIG_PROPS } from "../../config_wrapper"; //Подключение компонентов к настройкам приложения
|
||||||
import { BackEndСtx } from "../../context/backend"; //Контекст взаимодействия с сервером
|
import { useMechRecDeptCostJobs, useFilter } from "./hooks"; //Кастомные состояния
|
||||||
|
import { FilterComponent } from "./components/filter"; //Компонент фильтра
|
||||||
|
|
||||||
//---------
|
//---------
|
||||||
//Константы
|
//Константы
|
||||||
//---------
|
//---------
|
||||||
|
|
||||||
//Размер страницы данных
|
//Текущая дата
|
||||||
const DATA_GRID_PAGE_SIZE = 5;
|
const currentDate = new Date();
|
||||||
|
const currentMonth = currentDate.getUTCMonth() + 1;
|
||||||
|
const currentYear = currentDate.getUTCFullYear();
|
||||||
|
|
||||||
|
//Кастомные цвета
|
||||||
|
const colors = {
|
||||||
|
lightred: "#ef8989",
|
||||||
|
lightyellow: "#f5f5b0",
|
||||||
|
blue: "#0097ff"
|
||||||
|
};
|
||||||
|
|
||||||
//Стили
|
//Стили
|
||||||
const STYLES = {
|
const STYLES = {
|
||||||
CONTAINER: { textAlign: "center", paddingTop: "20px" },
|
CONTAINER: { textAlign: "center", paddingTop: "10px" },
|
||||||
TITLE: { paddingBottom: "15px" },
|
TITLE: { paddingBottom: "15px" },
|
||||||
DATA_GRID_CONTAINER: { minWidth: "95vw", maxWidth: "95vw", minHeight: "80vh", maxHeight: "80vh" },
|
DATA_GRID_CONTAINER: {
|
||||||
DATA_GRID_CELL: (row, columnDef) => ({
|
minWidth: "700px",
|
||||||
|
maxWidth: "100vw",
|
||||||
|
minHeight: "calc(100vh - 250px)",
|
||||||
|
maxHeight: "calc(100vh - 250px)"
|
||||||
|
},
|
||||||
|
DATA_GRID_CELL: (row, columnDef) => {
|
||||||
|
//Определяем тип дня
|
||||||
|
let dayType = columnDef.name.match(/N.*_VALUE/) ? row[`${columnDef.name.substring(0, 12)}_TYPE`] : null;
|
||||||
|
//Определяем процент загрузки
|
||||||
|
let procentLoad = columnDef.name === "SNAME" ? row["NPROCENT_LOAD"] : null;
|
||||||
|
return {
|
||||||
padding: "8px",
|
padding: "8px",
|
||||||
textOverflow: "ellipsis",
|
textOverflow: "ellipsis",
|
||||||
overflow: "hidden",
|
overflow: "hidden",
|
||||||
whiteSpace: "pre",
|
whiteSpace: "pre",
|
||||||
...(columnDef.name.match(/N.*_VALUE/) && row[columnDef.name]
|
...(dayType
|
||||||
? { backgroundColor: row[`${columnDef.name.substring(0, 12)}_TYPE`] === 0 ? "lightgrey" : "lightgreen" }
|
? {
|
||||||
|
backgroundColor: [1, 3].includes(dayType) ? "lightgrey" : dayType === 4 ? "lightgreen" : null,
|
||||||
|
color: [2, 3].includes(dayType) ? colors.blue : null
|
||||||
|
}
|
||||||
|
: procentLoad || procentLoad === 0
|
||||||
|
? {
|
||||||
|
backgroundColor:
|
||||||
|
procentLoad >= 85 ? "lightgreen" : procentLoad >= 50 ? colors.lightyellow : procentLoad > 0 ? colors.lightred : "lightgrey"
|
||||||
|
}
|
||||||
: {})
|
: {})
|
||||||
})
|
};
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
//------------------------------------
|
//------------------------------------
|
||||||
@ -54,54 +82,11 @@ const dataCellRender = ({ row, columnDef }) => ({
|
|||||||
|
|
||||||
//Корневая панель загрузки цеха
|
//Корневая панель загрузки цеха
|
||||||
const MechRecDeptCostJobs = () => {
|
const MechRecDeptCostJobs = () => {
|
||||||
|
//Собственное состояние - фильтр
|
||||||
|
const [filter, setFilter, getWorkDays, getWorkHours] = useFilter(currentMonth, currentYear);
|
||||||
|
|
||||||
//Собственное состояние - таблица данных
|
//Собственное состояние - таблица данных
|
||||||
const [costJobs, setCostJobs] = useState({
|
const [costJobs, setCostJobs] = useMechRecDeptCostJobs(filter.department.NRN, filter.date.fullDate, filter.totalWorkHours);
|
||||||
subdiv: null,
|
|
||||||
dataLoaded: false,
|
|
||||||
columnsDef: [],
|
|
||||||
filters: [],
|
|
||||||
orders: null,
|
|
||||||
rows: [],
|
|
||||||
reload: true,
|
|
||||||
pageNumber: 1,
|
|
||||||
morePages: true,
|
|
||||||
fixedHeader: false,
|
|
||||||
fixedColumns: 0
|
|
||||||
});
|
|
||||||
|
|
||||||
//Подключение к контексту взаимодействия с сервером
|
|
||||||
const { executeStored, SERV_DATA_TYPE_CLOB } = useContext(BackEndСtx);
|
|
||||||
|
|
||||||
//Загрузка данных таблицы с сервера
|
|
||||||
const loadData = useCallback(async () => {
|
|
||||||
if (costJobs.reload) {
|
|
||||||
const data = await executeStored({
|
|
||||||
stored: "PKG_P8PANELS_MECHREC.FCJOBS_DEP_LOAD_DG_GET",
|
|
||||||
args: {
|
|
||||||
CFILTERS: { VALUE: object2Base64XML(costJobs.filters, { arrayNodeName: "filters" }), SDATA_TYPE: SERV_DATA_TYPE_CLOB },
|
|
||||||
CORDERS: { VALUE: object2Base64XML(costJobs.orders, { arrayNodeName: "orders" }), SDATA_TYPE: SERV_DATA_TYPE_CLOB },
|
|
||||||
NPAGE_NUMBER: costJobs.pageNumber,
|
|
||||||
NPAGE_SIZE: DATA_GRID_PAGE_SIZE,
|
|
||||||
NINCLUDE_DEF: costJobs.dataLoaded ? 0 : 1
|
|
||||||
},
|
|
||||||
respArg: "COUT"
|
|
||||||
});
|
|
||||||
setCostJobs(pv => ({
|
|
||||||
...pv,
|
|
||||||
fixedHeader: data.XFCJOBS.XDATA.XDATA_GRID.fixedHeader,
|
|
||||||
fixedColumns: data.XFCJOBS.XDATA.XDATA_GRID.fixedColumns,
|
|
||||||
subdiv: data.XINFO.SSUBDIV,
|
|
||||||
columnsDef: data.XFCJOBS.XDATA.XCOLUMNS_DEF ? [...data.XFCJOBS.XDATA.XCOLUMNS_DEF] : pv.columnsDef,
|
|
||||||
rows: pv.pageNumber == 1 ? [...(data.XFCJOBS.XDATA.XROWS || [])] : [...pv.rows, ...(data.XFCJOBS.XDATA.XROWS || [])],
|
|
||||||
dataLoaded: true,
|
|
||||||
reload: false,
|
|
||||||
morePages: (data.XFCJOBS.XDATA.XROWS || []).length >= DATA_GRID_PAGE_SIZE
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
}, [costJobs.reload, costJobs.filters, costJobs.orders, costJobs.dataLoaded, costJobs.pageNumber, executeStored, SERV_DATA_TYPE_CLOB]);
|
|
||||||
|
|
||||||
//При изменении состояния фильтра
|
|
||||||
const handleFilterChanged = ({ filters }) => setCostJobs(pv => ({ ...pv, filters: [...filters], pageNumber: 1, reload: true }));
|
|
||||||
|
|
||||||
//При изменении состояния сортировки
|
//При изменении состояния сортировки
|
||||||
const handleOrderChanged = ({ orders }) => setCostJobs(pv => ({ ...pv, orders: [...orders], pageNumber: 1, reload: true }));
|
const handleOrderChanged = ({ orders }) => setCostJobs(pv => ({ ...pv, orders: [...orders], pageNumber: 1, reload: true }));
|
||||||
@ -109,19 +94,49 @@ const MechRecDeptCostJobs = () => {
|
|||||||
//При изменении количества отображаемых страниц
|
//При изменении количества отображаемых страниц
|
||||||
const handlePagesCountChanged = () => setCostJobs(pv => ({ ...pv, pageNumber: pv.pageNumber + 1, reload: true }));
|
const handlePagesCountChanged = () => setCostJobs(pv => ({ ...pv, pageNumber: pv.pageNumber + 1, reload: true }));
|
||||||
|
|
||||||
//При необходимости обновить данные таблицы
|
//При изменении месяца
|
||||||
useEffect(() => {
|
const handleMonthChange = side => {
|
||||||
loadData();
|
//Исходим от стороны, в которую идем
|
||||||
}, [costJobs.reload, loadData]);
|
let newDate =
|
||||||
|
side === 1
|
||||||
|
? filter.date.month === 12
|
||||||
|
? { month: 1, year: filter.date.year + 1 }
|
||||||
|
: { month: filter.date.month + 1, year: filter.date.year }
|
||||||
|
: filter.date.month === 1
|
||||||
|
? { month: 12, year: filter.date.year - 1 }
|
||||||
|
: { month: filter.date.month - 1, year: filter.date.year };
|
||||||
|
//Формируем полное представление даты
|
||||||
|
newDate.fullDate = newDate.month.toString().padStart(2, "0") + "." + newDate.year;
|
||||||
|
//Считываем количество рабочих дней и обновляем состояние
|
||||||
|
getWorkDays({ newDate, init: filter.init });
|
||||||
|
};
|
||||||
|
|
||||||
|
//При выборе подразделения
|
||||||
|
const handleSelectDeparture = department => {
|
||||||
|
//Если подразделение изменилось
|
||||||
|
if (department.NRN !== filter.department.NRN) {
|
||||||
|
//Получаем количество рабочих часов
|
||||||
|
getWorkHours(department);
|
||||||
|
//Обновляем таблицу загрузки цеха
|
||||||
|
setCostJobs(pv => ({ ...pv, pageNumber: 1, reload: true }));
|
||||||
|
} else {
|
||||||
|
setFilter(pv => ({ ...pv, openedDepartment: false }));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
//Генерация содержимого
|
//Генерация содержимого
|
||||||
return (
|
return (
|
||||||
|
<Box>
|
||||||
|
<FilterComponent
|
||||||
|
filter={filter}
|
||||||
|
setFilter={setFilter}
|
||||||
|
handleMonthChange={handleMonthChange}
|
||||||
|
handleSelectDeparture={handleSelectDeparture}
|
||||||
|
/>
|
||||||
<div style={STYLES.CONTAINER}>
|
<div style={STYLES.CONTAINER}>
|
||||||
<Typography sx={STYLES.TITLE} variant={"h6"}>
|
<Typography sx={STYLES.TITLE} variant={"h6"}>
|
||||||
{costJobs.dataLoaded ? `Загрузка станков "${costJobs.subdiv}"` : null}
|
{costJobs.dataLoaded ? `Загрузка станков "${filter.department.SNAME}"` : null}
|
||||||
</Typography>
|
</Typography>
|
||||||
<Grid container spacing={1}>
|
|
||||||
<Grid item xs={12}>
|
|
||||||
<Box pt={1} display="flex" justifyContent="center" alignItems="center">
|
<Box pt={1} display="flex" justifyContent="center" alignItems="center">
|
||||||
{costJobs.dataLoaded ? (
|
{costJobs.dataLoaded ? (
|
||||||
<P8PDataGrid
|
<P8PDataGrid
|
||||||
@ -135,15 +150,13 @@ const MechRecDeptCostJobs = () => {
|
|||||||
morePages={costJobs.morePages}
|
morePages={costJobs.morePages}
|
||||||
reloading={costJobs.reload}
|
reloading={costJobs.reload}
|
||||||
onOrderChanged={handleOrderChanged}
|
onOrderChanged={handleOrderChanged}
|
||||||
onFilterChanged={handleFilterChanged}
|
|
||||||
onPagesCountChanged={handlePagesCountChanged}
|
onPagesCountChanged={handlePagesCountChanged}
|
||||||
dataCellRender={prms => dataCellRender({ ...prms })}
|
dataCellRender={prms => dataCellRender({ ...prms })}
|
||||||
/>
|
/>
|
||||||
) : null}
|
) : null}
|
||||||
</Box>
|
</Box>
|
||||||
</Grid>
|
|
||||||
</Grid>
|
|
||||||
</div>
|
</div>
|
||||||
|
</Box>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -7,14 +7,14 @@
|
|||||||
//Подключение библиотек
|
//Подключение библиотек
|
||||||
//---------------------
|
//---------------------
|
||||||
|
|
||||||
import React, { useState, useCallback, useEffect, useContext } from "react"; //Классы React
|
import React, { useState, useContext } from "react"; //Классы React
|
||||||
import PropTypes from "prop-types"; //Контроль свойств компонента
|
import PropTypes from "prop-types"; //Контроль свойств компонента
|
||||||
import { Typography, Box, Paper, Dialog, DialogContent, DialogActions, Button, TextField, IconButton, Icon } from "@mui/material"; //Интерфейсные элементы
|
import { Typography, Box, Paper, Dialog, DialogContent, DialogActions, Button, TextField, IconButton, Icon } from "@mui/material"; //Интерфейсные элементы
|
||||||
import { P8PDataGrid, P8P_DATA_GRID_SIZE } from "../../components/p8p_data_grid"; //Таблица данных
|
import { P8PDataGrid, P8P_DATA_GRID_SIZE } from "../../components/p8p_data_grid"; //Таблица данных
|
||||||
import { P8P_DATA_GRID_CONFIG_PROPS } from "../../config_wrapper"; //Подключение компонентов к настройкам приложения
|
import { P8P_DATA_GRID_CONFIG_PROPS } from "../../config_wrapper"; //Подключение компонентов к настройкам приложения
|
||||||
import { BackEndСtx } from "../../context/backend"; //Контекст взаимодействия с сервером
|
import { BackEndСtx } from "../../context/backend"; //Контекст взаимодействия с сервером
|
||||||
import { object2Base64XML } from "../../core/utils"; //Вспомогательные функции
|
|
||||||
import { CostRouteListsSpecsDataGrid } from "./fcroutlstsp"; //Состояние таблицы заказов маршрутных листов
|
import { CostRouteListsSpecsDataGrid } from "./fcroutlstsp"; //Состояние таблицы заказов маршрутных листов
|
||||||
|
import { useCostRouteLists } from "./hooks.js"; //Хук состояния таблицы маршрутных листов
|
||||||
|
|
||||||
//---------
|
//---------
|
||||||
//Константы
|
//Константы
|
||||||
@ -24,12 +24,11 @@ import { CostRouteListsSpecsDataGrid } from "./fcroutlstsp"; //Состояни
|
|||||||
const STYLES = {
|
const STYLES = {
|
||||||
CONTAINER: { textAlign: "center" },
|
CONTAINER: { textAlign: "center" },
|
||||||
TABLE: { paddingTop: "15px" },
|
TABLE: { paddingTop: "15px" },
|
||||||
TABLE_SUM: { textAlign: "right", paddingTop: "5px", paddingRight: "15px" },
|
|
||||||
DIALOG_BUTTONS: { marginTop: "10px", width: "240px" }
|
DIALOG_BUTTONS: { marginTop: "10px", width: "240px" }
|
||||||
};
|
};
|
||||||
|
|
||||||
//---------------------------------------------
|
//---------------------------------------------
|
||||||
//Вспомогательные функции форматирования данных
|
//Вспомогательные функции и компоненты
|
||||||
//---------------------------------------------
|
//---------------------------------------------
|
||||||
|
|
||||||
//Генерация представления расширения строки
|
//Генерация представления расширения строки
|
||||||
@ -43,14 +42,13 @@ export const rowExpandRender = ({ row }) => {
|
|||||||
|
|
||||||
//Форматирование значений колонок
|
//Форматирование значений колонок
|
||||||
const dataCellRender = ({ row, columnDef, handlePriorEditOpen }) => {
|
const dataCellRender = ({ row, columnDef, handlePriorEditOpen }) => {
|
||||||
//!!! Пока отключено - не удалять
|
//Если колонка "Приоритет партии"
|
||||||
switch (columnDef.name) {
|
if (columnDef.name === "NPRIOR_PARTY") {
|
||||||
case "NPRIOR_PARTY":
|
|
||||||
return {
|
return {
|
||||||
data: (
|
data: (
|
||||||
<>
|
<>
|
||||||
{row["NPRIOR_PARTY"]}
|
{row["NPRIOR_PARTY"]}
|
||||||
<IconButton edge="end" title="Изменить приоритет" onClick={() => handlePriorEditOpen(row["NRN"], row["NPRIOR_PARTY"])}>
|
<IconButton edge="end" title="Изменить приоритет" onClick={() => handlePriorEditOpen(row["NRN"])}>
|
||||||
<Icon>edit</Icon>
|
<Icon>edit</Icon>
|
||||||
</IconButton>
|
</IconButton>
|
||||||
</>
|
</>
|
||||||
@ -62,94 +60,23 @@ const dataCellRender = ({ row, columnDef, handlePriorEditOpen }) => {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
//-----------
|
//Диалог с изменением приоритета маршрутного листа
|
||||||
//Тело модуля
|
const CostRouteListPriorChange = ({ costRouteLists, setCostRouteLists, executeStored }) => {
|
||||||
//-----------
|
//Считывание изначального значения приоритета МЛ
|
||||||
|
const initPrior = costRouteLists.rows[costRouteLists.rows.findIndex(obj => obj.NRN == costRouteLists.editPriorNRN)].NPRIOR_PARTY;
|
||||||
|
|
||||||
//Таблица маршрутных листов
|
//Собственное состояние - Значение приоритета
|
||||||
const CostRouteListsDataGrid = ({ task }) => {
|
const [state, setState] = useState(initPrior);
|
||||||
//Собственное состояние - таблица данных
|
|
||||||
const [costRouteLists, setCostRouteLists] = useState({
|
|
||||||
dataLoaded: false,
|
|
||||||
columnsDef: [],
|
|
||||||
orders: null,
|
|
||||||
rows: [],
|
|
||||||
reload: true,
|
|
||||||
pageNumber: 1,
|
|
||||||
morePages: true,
|
|
||||||
editPriorNRN: null,
|
|
||||||
editPriorValue: null
|
|
||||||
});
|
|
||||||
|
|
||||||
//Подключение к контексту взаимодействия с сервером
|
|
||||||
const { executeStored, SERV_DATA_TYPE_CLOB } = useContext(BackEndСtx);
|
|
||||||
|
|
||||||
//Размер страницы данных
|
|
||||||
const DATA_GRID_PAGE_SIZE = 5;
|
|
||||||
|
|
||||||
//Загрузка данных таблицы с сервера
|
|
||||||
const loadData = useCallback(async () => {
|
|
||||||
if (costRouteLists.reload) {
|
|
||||||
const data = await executeStored({
|
|
||||||
stored: "PKG_P8PANELS_MECHREC.FCROUTLST_DEPT_DG_GET",
|
|
||||||
args: {
|
|
||||||
NFCPRODPLANSP: task,
|
|
||||||
CORDERS: { VALUE: object2Base64XML(costRouteLists.orders, { arrayNodeName: "orders" }), SDATA_TYPE: SERV_DATA_TYPE_CLOB },
|
|
||||||
NPAGE_NUMBER: costRouteLists.pageNumber,
|
|
||||||
NPAGE_SIZE: DATA_GRID_PAGE_SIZE,
|
|
||||||
NINCLUDE_DEF: costRouteLists.dataLoaded ? 0 : 1
|
|
||||||
},
|
|
||||||
respArg: "COUT"
|
|
||||||
});
|
|
||||||
setCostRouteLists(pv => ({
|
|
||||||
...pv,
|
|
||||||
columnsDef: data.XCOLUMNS_DEF ? [...data.XCOLUMNS_DEF] : pv.columnsDef,
|
|
||||||
rows: pv.pageNumber == 1 ? [...(data.XROWS || [])] : [...pv.rows, ...(data.XROWS || [])],
|
|
||||||
dataLoaded: true,
|
|
||||||
reload: false,
|
|
||||||
morePages: (data.XROWS || []).length >= DATA_GRID_PAGE_SIZE
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
||||||
}, [
|
|
||||||
costRouteLists.reload,
|
|
||||||
costRouteLists.filters,
|
|
||||||
costRouteLists.orders,
|
|
||||||
costRouteLists.dataLoaded,
|
|
||||||
costRouteLists.pageNumber,
|
|
||||||
executeStored,
|
|
||||||
SERV_DATA_TYPE_CLOB
|
|
||||||
]);
|
|
||||||
|
|
||||||
//При необходимости обновить данные таблицы
|
|
||||||
useEffect(() => {
|
|
||||||
loadData();
|
|
||||||
}, [costRouteLists.reload, loadData]);
|
|
||||||
|
|
||||||
//При изменении состояния сортировки
|
|
||||||
const handleOrderChanged = ({ orders }) => setCostRouteLists(pv => ({ ...pv, orders: [...orders], pageNumber: 1, reload: true }));
|
|
||||||
|
|
||||||
//При изменении количества отображаемых страниц
|
|
||||||
const handlePagesCountChanged = () => setCostRouteLists(pv => ({ ...pv, pageNumber: pv.pageNumber + 1, reload: true }));
|
|
||||||
|
|
||||||
//При открытии изменения приоритета партии
|
|
||||||
const handlePriorEditOpen = (NRN, nPriorValue) => {
|
|
||||||
setCostRouteLists(pv => ({ ...pv, editPriorNRN: NRN, editPriorValue: nPriorValue }));
|
|
||||||
};
|
|
||||||
|
|
||||||
//При закрытии изменения приоритета партии
|
//При закрытии изменения приоритета партии
|
||||||
const handlePriorEditClose = () => {
|
const handlePriorEditClose = () => {
|
||||||
setCostRouteLists(pv => ({ ...pv, editPriorNRN: null, editPriorValue: null }));
|
setCostRouteLists(pv => ({ ...pv, editPriorNRN: null }));
|
||||||
};
|
};
|
||||||
|
|
||||||
//При изменении значения приоритета партии
|
//При нажатии на изменение приоритета партии
|
||||||
const handlePriorFormChanged = e => {
|
const handlePriorChange = () => {
|
||||||
setCostRouteLists(pv => ({ ...pv, editPriorValue: e.target.value }));
|
//Асинхронное изменение
|
||||||
};
|
const asyncChange = async (NRN, PriorValue, rows) => {
|
||||||
|
|
||||||
//Изменение приоритета
|
|
||||||
const priorChange = useCallback(
|
|
||||||
async (NRN, PriorValue, rows) => {
|
|
||||||
try {
|
try {
|
||||||
await executeStored({
|
await executeStored({
|
||||||
stored: "PKG_P8PANELS_MECHREC.FCROUTLST_PRIOR_PARTY_UPDATE",
|
stored: "PKG_P8PANELS_MECHREC.FCROUTLST_PRIOR_PARTY_UPDATE",
|
||||||
@ -164,14 +91,68 @@ const CostRouteListsDataGrid = ({ task }) => {
|
|||||||
} catch (e) {
|
} catch (e) {
|
||||||
throw new Error(e.message);
|
throw new Error(e.message);
|
||||||
}
|
}
|
||||||
},
|
};
|
||||||
[executeStored]
|
|
||||||
);
|
|
||||||
|
|
||||||
//При нажатии на изменение приоритета партии
|
|
||||||
const handlePriorChange = () => {
|
|
||||||
//Изменяем значение
|
//Изменяем значение
|
||||||
priorChange(costRouteLists.editPriorNRN, costRouteLists.editPriorValue, costRouteLists.rows);
|
asyncChange(costRouteLists.editPriorNRN, state, costRouteLists.rows);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Dialog open onClose={() => handlePriorEditClose()}>
|
||||||
|
<DialogContent>
|
||||||
|
<Box>
|
||||||
|
<TextField
|
||||||
|
name="editPriorValue"
|
||||||
|
label="Новое значение приоритета"
|
||||||
|
variant="standard"
|
||||||
|
fullWidth
|
||||||
|
type="number"
|
||||||
|
value={state}
|
||||||
|
onChange={event => {
|
||||||
|
setState(event.target.value);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<Box>
|
||||||
|
<Button onClick={handlePriorChange} variant="contained" sx={STYLES.DIALOG_BUTTONS}>
|
||||||
|
Изменить
|
||||||
|
</Button>
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
</DialogContent>
|
||||||
|
<DialogActions>
|
||||||
|
<Button onClick={() => handlePriorEditClose(null)}>Закрыть</Button>
|
||||||
|
</DialogActions>
|
||||||
|
</Dialog>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
//Контроль свойств - Диалог с изменением приоритета маршрутного листа
|
||||||
|
CostRouteListPriorChange.propTypes = {
|
||||||
|
costRouteLists: PropTypes.object.isRequired,
|
||||||
|
setCostRouteLists: PropTypes.func.isRequired,
|
||||||
|
executeStored: PropTypes.func.isRequired
|
||||||
|
};
|
||||||
|
|
||||||
|
//-----------
|
||||||
|
//Тело модуля
|
||||||
|
//-----------
|
||||||
|
|
||||||
|
//Таблица маршрутных листов
|
||||||
|
const CostRouteListsDataGrid = ({ task }) => {
|
||||||
|
//Собственное состояние - таблица данных
|
||||||
|
const [costRouteLists, setCostRouteLists] = useCostRouteLists(task);
|
||||||
|
|
||||||
|
//Подключение к контексту взаимодействия с сервером
|
||||||
|
const { executeStored } = useContext(BackEndСtx);
|
||||||
|
|
||||||
|
//При изменении состояния сортировки
|
||||||
|
const handleOrderChanged = ({ orders }) => setCostRouteLists(pv => ({ ...pv, orders: [...orders], pageNumber: 1, reload: true }));
|
||||||
|
|
||||||
|
//При изменении количества отображаемых страниц
|
||||||
|
const handlePagesCountChanged = () => setCostRouteLists(pv => ({ ...pv, pageNumber: pv.pageNumber + 1, reload: true }));
|
||||||
|
|
||||||
|
//При открытии изменения приоритета партии
|
||||||
|
const handlePriorEditOpen = NRN => {
|
||||||
|
setCostRouteLists(pv => ({ ...pv, editPriorNRN: NRN }));
|
||||||
};
|
};
|
||||||
|
|
||||||
//Генерация содержимого
|
//Генерация содержимого
|
||||||
@ -198,29 +179,7 @@ const CostRouteListsDataGrid = ({ task }) => {
|
|||||||
</>
|
</>
|
||||||
) : null}
|
) : null}
|
||||||
{costRouteLists.editPriorNRN ? (
|
{costRouteLists.editPriorNRN ? (
|
||||||
<Dialog open onClose={() => handlePriorEditClose(null)}>
|
<CostRouteListPriorChange costRouteLists={costRouteLists} setCostRouteLists={setCostRouteLists} executeStored={executeStored} />
|
||||||
<DialogContent>
|
|
||||||
<Box>
|
|
||||||
<TextField
|
|
||||||
name="editPriorValue"
|
|
||||||
label="Новое значение приоритета"
|
|
||||||
variant="standard"
|
|
||||||
fullWidth
|
|
||||||
type="number"
|
|
||||||
value={costRouteLists.editPriorValue}
|
|
||||||
onChange={handlePriorFormChanged}
|
|
||||||
/>
|
|
||||||
<Box>
|
|
||||||
<Button onClick={handlePriorChange} variant="contained" sx={STYLES.DIALOG_BUTTONS}>
|
|
||||||
Изменить
|
|
||||||
</Button>
|
|
||||||
</Box>
|
|
||||||
</Box>
|
|
||||||
</DialogContent>
|
|
||||||
<DialogActions>
|
|
||||||
<Button onClick={() => handlePriorEditClose(null)}>Закрыть</Button>
|
|
||||||
</DialogActions>
|
|
||||||
</Dialog>
|
|
||||||
) : null}
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@ -7,13 +7,12 @@
|
|||||||
//Подключение библиотек
|
//Подключение библиотек
|
||||||
//---------------------
|
//---------------------
|
||||||
|
|
||||||
import React, { useState, useCallback, useEffect, useContext } from "react"; //Классы React
|
import React from "react"; //Классы React
|
||||||
import PropTypes from "prop-types"; //Контроль свойств компонента
|
import PropTypes from "prop-types"; //Контроль свойств компонента
|
||||||
import { Typography } from "@mui/material"; //Интерфейсные элементы
|
import { Typography } from "@mui/material"; //Интерфейсные элементы
|
||||||
import { P8PDataGrid, P8P_DATA_GRID_SIZE } from "../../components/p8p_data_grid"; //Таблица данных
|
import { P8PDataGrid, P8P_DATA_GRID_SIZE } from "../../components/p8p_data_grid"; //Таблица данных
|
||||||
import { P8P_DATA_GRID_CONFIG_PROPS } from "../../config_wrapper"; //Подключение компонентов к настройкам приложения
|
import { P8P_DATA_GRID_CONFIG_PROPS } from "../../config_wrapper"; //Подключение компонентов к настройкам приложения
|
||||||
import { BackEndСtx } from "../../context/backend"; //Контекст взаимодействия с сервером
|
import { useCostRouteListsSpecs } from "./hooks.js"; //Хук состояния таблицы строк маршрутного листа
|
||||||
import { object2Base64XML } from "../../core/utils"; //Вспомогательные функции
|
|
||||||
|
|
||||||
//---------
|
//---------
|
||||||
//Константы
|
//Константы
|
||||||
@ -31,60 +30,7 @@ const STYLES = {
|
|||||||
//Таблица строк маршрутного листа
|
//Таблица строк маршрутного листа
|
||||||
const CostRouteListsSpecsDataGrid = ({ mainRowRN }) => {
|
const CostRouteListsSpecsDataGrid = ({ mainRowRN }) => {
|
||||||
//Собственное состояние - таблица данных
|
//Собственное состояние - таблица данных
|
||||||
const [costRouteListsSpecs, setCostRouteListsSpecs] = useState({
|
const [costRouteListsSpecs, setCostRouteListsSpecs] = useCostRouteListsSpecs(mainRowRN);
|
||||||
dataLoaded: false,
|
|
||||||
columnsDef: [],
|
|
||||||
orders: null,
|
|
||||||
rows: [],
|
|
||||||
reload: true,
|
|
||||||
pageNumber: 1,
|
|
||||||
morePages: true
|
|
||||||
});
|
|
||||||
|
|
||||||
//Подключение к контексту взаимодействия с сервером
|
|
||||||
const { executeStored, SERV_DATA_TYPE_CLOB } = useContext(BackEndСtx);
|
|
||||||
|
|
||||||
//Размер страницы данных
|
|
||||||
const DATA_GRID_PAGE_SIZE = 10;
|
|
||||||
|
|
||||||
//Загрузка данных таблицы с сервера
|
|
||||||
const loadData = useCallback(async () => {
|
|
||||||
if (costRouteListsSpecs.reload) {
|
|
||||||
const data = await executeStored({
|
|
||||||
stored: "PKG_P8PANELS_MECHREC.FCROUTLSTSP_DEPT_DG_GET",
|
|
||||||
args: {
|
|
||||||
NFCROUTLST: mainRowRN,
|
|
||||||
CORDERS: { VALUE: object2Base64XML(costRouteListsSpecs.orders, { arrayNodeName: "orders" }), SDATA_TYPE: SERV_DATA_TYPE_CLOB },
|
|
||||||
NPAGE_NUMBER: costRouteListsSpecs.pageNumber,
|
|
||||||
NPAGE_SIZE: DATA_GRID_PAGE_SIZE,
|
|
||||||
NINCLUDE_DEF: costRouteListsSpecs.dataLoaded ? 0 : 1
|
|
||||||
},
|
|
||||||
respArg: "COUT"
|
|
||||||
});
|
|
||||||
setCostRouteListsSpecs(pv => ({
|
|
||||||
...pv,
|
|
||||||
columnsDef: data.XCOLUMNS_DEF ? [...data.XCOLUMNS_DEF] : pv.columnsDef,
|
|
||||||
rows: pv.pageNumber == 1 ? [...(data.XROWS || [])] : [...pv.rows, ...(data.XROWS || [])],
|
|
||||||
dataLoaded: true,
|
|
||||||
reload: false,
|
|
||||||
morePages: (data.XROWS || []).length >= DATA_GRID_PAGE_SIZE
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
||||||
}, [
|
|
||||||
costRouteListsSpecs.reload,
|
|
||||||
costRouteListsSpecs.filters,
|
|
||||||
costRouteListsSpecs.orders,
|
|
||||||
costRouteListsSpecs.dataLoaded,
|
|
||||||
costRouteListsSpecs.pageNumber,
|
|
||||||
executeStored,
|
|
||||||
SERV_DATA_TYPE_CLOB
|
|
||||||
]);
|
|
||||||
|
|
||||||
//При необходимости обновить данные таблицы
|
|
||||||
useEffect(() => {
|
|
||||||
loadData();
|
|
||||||
}, [costRouteListsSpecs.reload, loadData]);
|
|
||||||
|
|
||||||
//При изменении состояния сортировки
|
//При изменении состояния сортировки
|
||||||
const handleOrderChanged = ({ orders }) => setCostRouteListsSpecs(pv => ({ ...pv, orders: [...orders], pageNumber: 1, reload: true }));
|
const handleOrderChanged = ({ orders }) => setCostRouteListsSpecs(pv => ({ ...pv, orders: [...orders], pageNumber: 1, reload: true }));
|
||||||
|
@ -7,7 +7,17 @@
|
|||||||
//Подключение библиотек
|
//Подключение библиотек
|
||||||
//---------------------
|
//---------------------
|
||||||
|
|
||||||
import React from "react"; //Классы React
|
import React, { useState, useEffect, useContext } from "react"; //Классы React
|
||||||
|
import { BackEndСtx } from "../../context/backend"; //Контекст взаимодействия с сервером
|
||||||
|
import { object2Base64XML, formatDateRF } from "../../core/utils"; //Вспомогательные функции
|
||||||
|
|
||||||
|
//---------
|
||||||
|
//Константы
|
||||||
|
//---------
|
||||||
|
|
||||||
|
//Размер страницы данных
|
||||||
|
const DATA_GRID_PAGE_SIZE_SMALL = 5;
|
||||||
|
const DATA_GRID_PAGE_SIZE_LARGE = 10;
|
||||||
|
|
||||||
//-----------
|
//-----------
|
||||||
//Тело модуля
|
//Тело модуля
|
||||||
@ -21,3 +31,246 @@ export const useFilteredPlans = (plans, filter) => {
|
|||||||
|
|
||||||
return filteredPlans;
|
return filteredPlans;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
//Хук для основной таблицы
|
||||||
|
const useDeptCostProdPlans = () => {
|
||||||
|
//Собственное состояние - таблица данных
|
||||||
|
const [state, setState] = useState({
|
||||||
|
init: false,
|
||||||
|
showPlanList: false,
|
||||||
|
showIncomeFromDeps: null,
|
||||||
|
showFcroutelst: null,
|
||||||
|
planList: [],
|
||||||
|
planListLoaded: false,
|
||||||
|
selectedPlan: {},
|
||||||
|
dataLoaded: false,
|
||||||
|
columnsDef: [],
|
||||||
|
orders: null,
|
||||||
|
rows: [],
|
||||||
|
reload: true,
|
||||||
|
pageNumber: 1,
|
||||||
|
morePages: true,
|
||||||
|
fixedHeader: false,
|
||||||
|
fixedColumns: 0
|
||||||
|
});
|
||||||
|
|
||||||
|
//Подключение к контексту взаимодействия с сервером
|
||||||
|
const { executeStored, SERV_DATA_TYPE_CLOB } = useContext(BackEndСtx);
|
||||||
|
|
||||||
|
//При необходимости обновить данные таблицы
|
||||||
|
useEffect(() => {
|
||||||
|
if (state.selectedPlan.NRN) {
|
||||||
|
const loadData = async () => {
|
||||||
|
const data = await executeStored({
|
||||||
|
stored: "PKG_P8PANELS_MECHREC.FCPRODPLANSP_DEPT_DG_GET",
|
||||||
|
args: {
|
||||||
|
NFCPRODPLAN: state.selectedPlan.NRN,
|
||||||
|
CORDERS: { VALUE: object2Base64XML(state.orders, { arrayNodeName: "orders" }), SDATA_TYPE: SERV_DATA_TYPE_CLOB },
|
||||||
|
NPAGE_NUMBER: state.pageNumber,
|
||||||
|
NPAGE_SIZE: DATA_GRID_PAGE_SIZE_LARGE,
|
||||||
|
NINCLUDE_DEF: state.dataLoaded ? 0 : 1
|
||||||
|
},
|
||||||
|
respArg: "COUT",
|
||||||
|
attributeValueProcessor: (name, val) => (name === "caption" ? undefined : val)
|
||||||
|
});
|
||||||
|
setState(pv => ({
|
||||||
|
...pv,
|
||||||
|
fixedHeader: data.XDATA_GRID.fixedHeader,
|
||||||
|
fixedColumns: data.XDATA_GRID.fixedColumns,
|
||||||
|
columnsDef: data.XCOLUMNS_DEF ? [...data.XCOLUMNS_DEF] : pv.columnsDef,
|
||||||
|
rows: pv.pageNumber == 1 ? [...(data.XROWS || [])] : [...pv.rows, ...(data.XROWS || [])],
|
||||||
|
dataLoaded: true,
|
||||||
|
reload: false,
|
||||||
|
morePages: (data.XROWS || []).length >= DATA_GRID_PAGE_SIZE_LARGE
|
||||||
|
}));
|
||||||
|
};
|
||||||
|
if (state.reload) {
|
||||||
|
loadData();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, [state.selectedPlan, state.reload, state.orders, state.pageNumber, state.dataLoaded, executeStored, SERV_DATA_TYPE_CLOB]);
|
||||||
|
|
||||||
|
//При подключении компонента к странице
|
||||||
|
useEffect(() => {
|
||||||
|
const initPlans = async () => {
|
||||||
|
const data = await executeStored({
|
||||||
|
stored: "PKG_P8PANELS_MECHREC.FCPRODPLAN_DEPT_INIT",
|
||||||
|
args: {},
|
||||||
|
respArg: "COUT",
|
||||||
|
isArray: name => name === "XFCPRODPLANS",
|
||||||
|
attributeValueProcessor: (name, val) => (name === "SPERIOD" ? undefined : val)
|
||||||
|
});
|
||||||
|
setState(pv => ({ ...pv, init: true, planList: [...(data?.XFCPRODPLANS || [])], planListLoaded: true }));
|
||||||
|
};
|
||||||
|
if (!state.init) {
|
||||||
|
initPlans();
|
||||||
|
}
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return [state, setState];
|
||||||
|
};
|
||||||
|
|
||||||
|
//Хук для таблицы маршрутных листов
|
||||||
|
const useCostRouteLists = task => {
|
||||||
|
//Собственное состояние - таблица данных
|
||||||
|
const [costRouteLists, setCostRouteLists] = useState({
|
||||||
|
dataLoaded: false,
|
||||||
|
columnsDef: [],
|
||||||
|
orders: null,
|
||||||
|
rows: [],
|
||||||
|
reload: true,
|
||||||
|
pageNumber: 1,
|
||||||
|
morePages: true,
|
||||||
|
editPriorNRN: null
|
||||||
|
});
|
||||||
|
|
||||||
|
//Подключение к контексту взаимодействия с сервером
|
||||||
|
const { executeStored, SERV_DATA_TYPE_CLOB } = useContext(BackEndСtx);
|
||||||
|
|
||||||
|
//При необходимости обновить данные таблицы
|
||||||
|
useEffect(() => {
|
||||||
|
const loadData = async () => {
|
||||||
|
const data = await executeStored({
|
||||||
|
stored: "PKG_P8PANELS_MECHREC.FCROUTLST_DEPT_DG_GET",
|
||||||
|
args: {
|
||||||
|
NFCPRODPLANSP: task,
|
||||||
|
CORDERS: { VALUE: object2Base64XML(costRouteLists.orders, { arrayNodeName: "orders" }), SDATA_TYPE: SERV_DATA_TYPE_CLOB },
|
||||||
|
NPAGE_NUMBER: costRouteLists.pageNumber,
|
||||||
|
NPAGE_SIZE: DATA_GRID_PAGE_SIZE_SMALL,
|
||||||
|
NINCLUDE_DEF: costRouteLists.dataLoaded ? 0 : 1
|
||||||
|
},
|
||||||
|
respArg: "COUT"
|
||||||
|
});
|
||||||
|
setCostRouteLists(pv => ({
|
||||||
|
...pv,
|
||||||
|
columnsDef: data.XCOLUMNS_DEF ? [...data.XCOLUMNS_DEF] : pv.columnsDef,
|
||||||
|
rows: pv.pageNumber == 1 ? [...(data.XROWS || [])] : [...pv.rows, ...(data.XROWS || [])],
|
||||||
|
dataLoaded: true,
|
||||||
|
reload: false,
|
||||||
|
morePages: (data.XROWS || []).length >= DATA_GRID_PAGE_SIZE_SMALL
|
||||||
|
}));
|
||||||
|
};
|
||||||
|
if (costRouteLists.reload && task) {
|
||||||
|
loadData();
|
||||||
|
}
|
||||||
|
}, [
|
||||||
|
SERV_DATA_TYPE_CLOB,
|
||||||
|
costRouteLists.dataLoaded,
|
||||||
|
costRouteLists.orders,
|
||||||
|
costRouteLists.pageNumber,
|
||||||
|
costRouteLists.reload,
|
||||||
|
executeStored,
|
||||||
|
task
|
||||||
|
]);
|
||||||
|
|
||||||
|
return [costRouteLists, setCostRouteLists];
|
||||||
|
};
|
||||||
|
|
||||||
|
//Хук для таблицы строк маршрутного листа
|
||||||
|
const useCostRouteListsSpecs = mainRowRN => {
|
||||||
|
//Собственное состояние - таблица данных
|
||||||
|
const [costRouteListsSpecs, setCostRouteListsSpecs] = useState({
|
||||||
|
dataLoaded: false,
|
||||||
|
columnsDef: [],
|
||||||
|
orders: null,
|
||||||
|
rows: [],
|
||||||
|
reload: true,
|
||||||
|
pageNumber: 1,
|
||||||
|
morePages: true
|
||||||
|
});
|
||||||
|
|
||||||
|
//Подключение к контексту взаимодействия с сервером
|
||||||
|
const { executeStored, SERV_DATA_TYPE_CLOB } = useContext(BackEndСtx);
|
||||||
|
|
||||||
|
//При необходимости обновить данные таблицы
|
||||||
|
useEffect(() => {
|
||||||
|
const loadData = async () => {
|
||||||
|
const data = await executeStored({
|
||||||
|
stored: "PKG_P8PANELS_MECHREC.FCROUTLSTSP_DEPT_DG_GET",
|
||||||
|
args: {
|
||||||
|
NFCROUTLST: mainRowRN,
|
||||||
|
CORDERS: {
|
||||||
|
VALUE: object2Base64XML(costRouteListsSpecs.orders, { arrayNodeName: "orders" }),
|
||||||
|
SDATA_TYPE: SERV_DATA_TYPE_CLOB
|
||||||
|
},
|
||||||
|
NPAGE_NUMBER: costRouteListsSpecs.pageNumber,
|
||||||
|
NPAGE_SIZE: DATA_GRID_PAGE_SIZE_LARGE,
|
||||||
|
NINCLUDE_DEF: costRouteListsSpecs.dataLoaded ? 0 : 1
|
||||||
|
},
|
||||||
|
respArg: "COUT"
|
||||||
|
});
|
||||||
|
setCostRouteListsSpecs(pv => ({
|
||||||
|
...pv,
|
||||||
|
columnsDef: data.XCOLUMNS_DEF ? [...data.XCOLUMNS_DEF] : pv.columnsDef,
|
||||||
|
rows: pv.pageNumber == 1 ? [...(data.XROWS || [])] : [...pv.rows, ...(data.XROWS || [])],
|
||||||
|
dataLoaded: true,
|
||||||
|
reload: false,
|
||||||
|
morePages: (data.XROWS || []).length >= DATA_GRID_PAGE_SIZE_LARGE
|
||||||
|
}));
|
||||||
|
};
|
||||||
|
if (costRouteListsSpecs.reload) {
|
||||||
|
loadData();
|
||||||
|
}
|
||||||
|
}, [
|
||||||
|
SERV_DATA_TYPE_CLOB,
|
||||||
|
costRouteListsSpecs.dataLoaded,
|
||||||
|
costRouteListsSpecs.orders,
|
||||||
|
costRouteListsSpecs.pageNumber,
|
||||||
|
costRouteListsSpecs.reload,
|
||||||
|
executeStored,
|
||||||
|
mainRowRN
|
||||||
|
]);
|
||||||
|
|
||||||
|
return [costRouteListsSpecs, setCostRouteListsSpecs];
|
||||||
|
};
|
||||||
|
|
||||||
|
//Хук для таблицы сдачи продукции
|
||||||
|
const useIncomFromDeps = task => {
|
||||||
|
//Собственное состояние - таблица данных
|
||||||
|
const [incomFromDeps, setIncomFromDeps] = useState({
|
||||||
|
dataLoaded: false,
|
||||||
|
columnsDef: [],
|
||||||
|
orders: null,
|
||||||
|
rows: [],
|
||||||
|
reload: true,
|
||||||
|
pageNumber: 1,
|
||||||
|
morePages: true
|
||||||
|
});
|
||||||
|
|
||||||
|
//Подключение к контексту взаимодействия с сервером
|
||||||
|
const { executeStored, SERV_DATA_TYPE_CLOB } = useContext(BackEndСtx);
|
||||||
|
|
||||||
|
//При необходимости обновить данные таблицы
|
||||||
|
useEffect(() => {
|
||||||
|
const loadData = async () => {
|
||||||
|
const data = await executeStored({
|
||||||
|
stored: "PKG_P8PANELS_MECHREC.INCOMEFROMDEPS_DEPT_DG_GET",
|
||||||
|
args: {
|
||||||
|
NFCPRODPLANSP: task,
|
||||||
|
CORDERS: { VALUE: object2Base64XML(incomFromDeps.orders, { arrayNodeName: "orders" }), SDATA_TYPE: SERV_DATA_TYPE_CLOB },
|
||||||
|
NPAGE_NUMBER: incomFromDeps.pageNumber,
|
||||||
|
NPAGE_SIZE: DATA_GRID_PAGE_SIZE_LARGE,
|
||||||
|
NINCLUDE_DEF: incomFromDeps.dataLoaded ? 0 : 1
|
||||||
|
},
|
||||||
|
attributeValueProcessor: (name, val) => (["DDUE_DATE"].includes(name) ? formatDateRF(val) : val),
|
||||||
|
respArg: "COUT"
|
||||||
|
});
|
||||||
|
setIncomFromDeps(pv => ({
|
||||||
|
...pv,
|
||||||
|
columnsDef: data.XCOLUMNS_DEF ? [...data.XCOLUMNS_DEF] : pv.columnsDef,
|
||||||
|
rows: pv.pageNumber == 1 ? [...(data.XROWS || [])] : [...pv.rows, ...(data.XROWS || [])],
|
||||||
|
dataLoaded: true,
|
||||||
|
reload: false,
|
||||||
|
morePages: (data.XROWS || []).length >= DATA_GRID_PAGE_SIZE_LARGE
|
||||||
|
}));
|
||||||
|
};
|
||||||
|
if (incomFromDeps.reload) {
|
||||||
|
loadData();
|
||||||
|
}
|
||||||
|
}, [SERV_DATA_TYPE_CLOB, executeStored, incomFromDeps.dataLoaded, incomFromDeps.orders, incomFromDeps.pageNumber, incomFromDeps.reload, task]);
|
||||||
|
|
||||||
|
return [incomFromDeps, setIncomFromDeps];
|
||||||
|
};
|
||||||
|
|
||||||
|
export { useDeptCostProdPlans, useCostRouteLists, useCostRouteListsSpecs, useIncomFromDeps };
|
||||||
|
@ -7,13 +7,12 @@
|
|||||||
//Подключение библиотек
|
//Подключение библиотек
|
||||||
//---------------------
|
//---------------------
|
||||||
|
|
||||||
import React, { useState, useCallback, useEffect, useContext } from "react"; //Классы React
|
import React from "react"; //Классы React
|
||||||
import PropTypes from "prop-types"; //Контроль свойств компонента
|
import PropTypes from "prop-types"; //Контроль свойств компонента
|
||||||
import { Typography, Box, Dialog, DialogContent, DialogActions, Button } from "@mui/material"; //Интерфейсные элементы
|
import { Typography, Box, Dialog, DialogContent, DialogActions, Button } from "@mui/material"; //Интерфейсные элементы
|
||||||
import { P8PDataGrid, P8P_DATA_GRID_SIZE } from "../../components/p8p_data_grid"; //Таблица данных
|
import { P8PDataGrid, P8P_DATA_GRID_SIZE } from "../../components/p8p_data_grid"; //Таблица данных
|
||||||
import { P8P_DATA_GRID_CONFIG_PROPS } from "../../config_wrapper"; //Подключение компонентов к настройкам приложения
|
import { P8P_DATA_GRID_CONFIG_PROPS } from "../../config_wrapper"; //Подключение компонентов к настройкам приложения
|
||||||
import { BackEndСtx } from "../../context/backend"; //Контекст взаимодействия с сервером
|
import { useIncomFromDeps } from "./hooks"; //Хук состояния таблицы сдача продукции
|
||||||
import { object2Base64XML, formatDateRF } from "../../core/utils"; //Вспомогательные функции
|
|
||||||
|
|
||||||
//---------
|
//---------
|
||||||
//Константы
|
//Константы
|
||||||
@ -32,53 +31,7 @@ const STYLES = {
|
|||||||
//Таблица сдачи продукции
|
//Таблица сдачи продукции
|
||||||
const IncomFromDepsDataGrid = ({ task }) => {
|
const IncomFromDepsDataGrid = ({ task }) => {
|
||||||
//Собственное состояние - таблица данных
|
//Собственное состояние - таблица данных
|
||||||
const [incomFromDeps, setIncomFromDeps] = useState({
|
const [incomFromDeps, setIncomFromDeps] = useIncomFromDeps(task);
|
||||||
dataLoaded: false,
|
|
||||||
columnsDef: [],
|
|
||||||
orders: null,
|
|
||||||
rows: [],
|
|
||||||
reload: true,
|
|
||||||
pageNumber: 1,
|
|
||||||
morePages: true
|
|
||||||
});
|
|
||||||
|
|
||||||
//Размер страницы данных
|
|
||||||
const DATA_GRID_PAGE_SIZE = 10;
|
|
||||||
|
|
||||||
//Подключение к контексту взаимодействия с сервером
|
|
||||||
const { executeStored, SERV_DATA_TYPE_CLOB } = useContext(BackEndСtx);
|
|
||||||
|
|
||||||
//Загрузка данных таблицы с сервера
|
|
||||||
const loadData = useCallback(async () => {
|
|
||||||
if (incomFromDeps.reload) {
|
|
||||||
const data = await executeStored({
|
|
||||||
stored: "PKG_P8PANELS_MECHREC.INCOMEFROMDEPS_DEPT_DG_GET",
|
|
||||||
args: {
|
|
||||||
NFCPRODPLANSP: task,
|
|
||||||
CORDERS: { VALUE: object2Base64XML(incomFromDeps.orders, { arrayNodeName: "orders" }), SDATA_TYPE: SERV_DATA_TYPE_CLOB },
|
|
||||||
NPAGE_NUMBER: incomFromDeps.pageNumber,
|
|
||||||
NPAGE_SIZE: DATA_GRID_PAGE_SIZE,
|
|
||||||
NINCLUDE_DEF: incomFromDeps.dataLoaded ? 0 : 1
|
|
||||||
},
|
|
||||||
attributeValueProcessor: (name, val) => (["DDUE_DATE"].includes(name) ? formatDateRF(val) : val),
|
|
||||||
respArg: "COUT"
|
|
||||||
});
|
|
||||||
setIncomFromDeps(pv => ({
|
|
||||||
...pv,
|
|
||||||
columnsDef: data.XCOLUMNS_DEF ? [...data.XCOLUMNS_DEF] : pv.columnsDef,
|
|
||||||
rows: pv.pageNumber == 1 ? [...(data.XROWS || [])] : [...pv.rows, ...(data.XROWS || [])],
|
|
||||||
dataLoaded: true,
|
|
||||||
reload: false,
|
|
||||||
morePages: (data.XROWS || []).length >= DATA_GRID_PAGE_SIZE
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
||||||
}, [incomFromDeps.reload, incomFromDeps.orders, incomFromDeps.dataLoaded, incomFromDeps.pageNumber, executeStored, SERV_DATA_TYPE_CLOB]);
|
|
||||||
|
|
||||||
//При необходимости обновить данные таблицы
|
|
||||||
useEffect(() => {
|
|
||||||
loadData();
|
|
||||||
}, [incomFromDeps.reload, loadData]);
|
|
||||||
|
|
||||||
//При изменении состояния сортировки
|
//При изменении состояния сортировки
|
||||||
const handleOrderChanged = ({ orders }) => setIncomFromDeps(pv => ({ ...pv, orders: [...orders], pageNumber: 1, reload: true }));
|
const handleOrderChanged = ({ orders }) => setIncomFromDeps(pv => ({ ...pv, orders: [...orders], pageNumber: 1, reload: true }));
|
||||||
|
@ -7,12 +7,10 @@
|
|||||||
//Подключение библиотек
|
//Подключение библиотек
|
||||||
//---------------------
|
//---------------------
|
||||||
|
|
||||||
import React, { useContext, useState, useCallback, useEffect } from "react"; //Классы React
|
import React, { useContext, useState } from "react"; //Классы React
|
||||||
import PropTypes from "prop-types"; //Контроль свойств компонента
|
import PropTypes from "prop-types"; //Контроль свойств компонента
|
||||||
import { Drawer, Fab, Box, List, ListItemButton, ListItemText, Typography, TextField, Link, Grid } from "@mui/material"; //Интерфейсные элементы
|
import { Drawer, Fab, Box, List, ListItemButton, ListItemText, Typography, TextField, Link, Grid } from "@mui/material"; //Интерфейсные элементы
|
||||||
import { BackEndСtx } from "../../context/backend"; //Контекст взаимодействия с сервером
|
import { useDeptCostProdPlans, useFilteredPlans } from "./hooks"; //Вспомогательные хуки
|
||||||
import { useFilteredPlans } from "./hooks"; //Вспомогательные хуки
|
|
||||||
import { object2Base64XML } from "../../core/utils"; //Вспомогательные функции
|
|
||||||
import { P8PDataGrid, P8P_DATA_GRID_SIZE } from "../../components/p8p_data_grid"; //Таблица данных
|
import { P8PDataGrid, P8P_DATA_GRID_SIZE } from "../../components/p8p_data_grid"; //Таблица данных
|
||||||
import { P8P_DATA_GRID_CONFIG_PROPS } from "../../config_wrapper"; //Подключение компонентов к настройкам приложения
|
import { P8P_DATA_GRID_CONFIG_PROPS } from "../../config_wrapper"; //Подключение компонентов к настройкам приложения
|
||||||
import { MessagingСtx } from "../../context/messaging"; //Контекст сообщений
|
import { MessagingСtx } from "../../context/messaging"; //Контекст сообщений
|
||||||
@ -27,14 +25,14 @@ import { CostRouteListsDataGridDialog } from "./fcroutlst"; //Диалог ма
|
|||||||
const STYLES = {
|
const STYLES = {
|
||||||
PLANS_FINDER: { marginTop: "10px", marginLeft: "10px", width: "93%" },
|
PLANS_FINDER: { marginTop: "10px", marginLeft: "10px", width: "93%" },
|
||||||
PLANS_LIST_ITEM_PRIMARY: { wordWrap: "break-word" },
|
PLANS_LIST_ITEM_PRIMARY: { wordWrap: "break-word" },
|
||||||
PLANS_BUTTON: { position: "absolute", marginTop: "10px", marginLeft: "10px" },
|
PLANS_BUTTON: { position: "absolute" },
|
||||||
PLANS_DRAWER: {
|
PLANS_DRAWER: {
|
||||||
width: "350px",
|
width: "350px",
|
||||||
display: "inline-block",
|
display: "inline-block",
|
||||||
flexShrink: 0,
|
flexShrink: 0,
|
||||||
[`& .MuiDrawer-paper`]: { width: "350px", display: "inline-block", boxSizing: "border-box" }
|
[`& .MuiDrawer-paper`]: { width: "350px", display: "inline-block", boxSizing: "border-box" }
|
||||||
},
|
},
|
||||||
CONTAINER: { paddingTop: "40px", margin: "5px 0px", textAlign: "center" },
|
CONTAINER: { textAlign: "center" },
|
||||||
DATA_GRID_CONTAINER: { minWidth: "95vw", maxWidth: "95vw", minHeight: "80vh", maxHeight: "80vh" },
|
DATA_GRID_CONTAINER: { minWidth: "95vw", maxWidth: "95vw", minHeight: "80vh", maxHeight: "80vh" },
|
||||||
DATA_GRID_GROUP_CELL: { padding: "2px" },
|
DATA_GRID_GROUP_CELL: { padding: "2px" },
|
||||||
DATA_GRID_CELL: { padding: "8px", maxWidth: "300px", textOverflow: "ellipsis", overflow: "hidden", whiteSpace: "pre" },
|
DATA_GRID_CELL: { padding: "8px", maxWidth: "300px", textOverflow: "ellipsis", overflow: "hidden", whiteSpace: "pre" },
|
||||||
@ -177,24 +175,7 @@ PlanList.propTypes = {
|
|||||||
//Корневая панель производственного плана цеха
|
//Корневая панель производственного плана цеха
|
||||||
const MechRecDeptCostProdPlans = () => {
|
const MechRecDeptCostProdPlans = () => {
|
||||||
//Собственное состояние - таблица данных
|
//Собственное состояние - таблица данных
|
||||||
const [state, setState] = useState({
|
const [state, setState] = useDeptCostProdPlans();
|
||||||
init: false,
|
|
||||||
showPlanList: false,
|
|
||||||
showIncomeFromDeps: null,
|
|
||||||
showFcroutelst: null,
|
|
||||||
planList: [],
|
|
||||||
planListLoaded: false,
|
|
||||||
selectedPlan: {},
|
|
||||||
dataLoaded: false,
|
|
||||||
columnsDef: [],
|
|
||||||
orders: null,
|
|
||||||
rows: [],
|
|
||||||
reload: true,
|
|
||||||
pageNumber: 1,
|
|
||||||
morePages: true,
|
|
||||||
fixedHeader: false,
|
|
||||||
fixedColumns: 0
|
|
||||||
});
|
|
||||||
|
|
||||||
//Состояние для фильтра каталогов
|
//Состояние для фильтра каталогов
|
||||||
const [filter, setFilter] = useState({ planName: "" });
|
const [filter, setFilter] = useState({ planName: "" });
|
||||||
@ -202,77 +183,9 @@ const MechRecDeptCostProdPlans = () => {
|
|||||||
//Массив отфильтрованных каталогов
|
//Массив отфильтрованных каталогов
|
||||||
const filteredPlanCtgls = useFilteredPlans(state.planList, filter);
|
const filteredPlanCtgls = useFilteredPlans(state.planList, filter);
|
||||||
|
|
||||||
//Размер страницы данных
|
|
||||||
const DATA_GRID_PAGE_SIZE = 10;
|
|
||||||
|
|
||||||
//Подключение к контексту взаимодействия с сервером
|
|
||||||
const { executeStored, SERV_DATA_TYPE_CLOB } = useContext(BackEndСtx);
|
|
||||||
|
|
||||||
//Подключение к контексту сообщений
|
//Подключение к контексту сообщений
|
||||||
const { InlineMsgInfo } = useContext(MessagingСtx);
|
const { InlineMsgInfo } = useContext(MessagingСtx);
|
||||||
|
|
||||||
// Инициализация каталогов планов
|
|
||||||
const initPlans = useCallback(async () => {
|
|
||||||
if (!state.init) {
|
|
||||||
const data = await executeStored({
|
|
||||||
stored: "PKG_P8PANELS_MECHREC.FCPRODPLAN_DEPT_INIT",
|
|
||||||
args: {},
|
|
||||||
respArg: "COUT",
|
|
||||||
isArray: name => name === "XFCPRODPLANS",
|
|
||||||
attributeValueProcessor: (name, val) => (name === "SPERIOD" ? undefined : val)
|
|
||||||
});
|
|
||||||
setState(pv => ({ ...pv, init: true, planList: [...(data?.XFCPRODPLANS || [])], planListLoaded: true }));
|
|
||||||
}
|
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
||||||
}, [state.init, executeStored]);
|
|
||||||
|
|
||||||
//Загрузка данных таблицы с сервера
|
|
||||||
const loadData = useCallback(
|
|
||||||
async NRN => {
|
|
||||||
if (state.reload && NRN) {
|
|
||||||
const data = await executeStored({
|
|
||||||
stored: "PKG_P8PANELS_MECHREC.FCPRODPLANSP_DEPT_DG_GET",
|
|
||||||
args: {
|
|
||||||
NFCPRODPLAN: NRN,
|
|
||||||
CORDERS: { VALUE: object2Base64XML(state.orders, { arrayNodeName: "orders" }), SDATA_TYPE: SERV_DATA_TYPE_CLOB },
|
|
||||||
NPAGE_NUMBER: state.pageNumber,
|
|
||||||
NPAGE_SIZE: DATA_GRID_PAGE_SIZE,
|
|
||||||
NINCLUDE_DEF: state.dataLoaded ? 0 : 1
|
|
||||||
},
|
|
||||||
respArg: "COUT",
|
|
||||||
attributeValueProcessor: (name, val) => (name === "caption" ? undefined : val)
|
|
||||||
});
|
|
||||||
setState(pv => ({
|
|
||||||
...pv,
|
|
||||||
fixedHeader: data.XDATA_GRID.fixedHeader,
|
|
||||||
fixedColumns: data.XDATA_GRID.fixedColumns,
|
|
||||||
columnsDef: data.XCOLUMNS_DEF ? [...data.XCOLUMNS_DEF] : pv.columnsDef,
|
|
||||||
rows: pv.pageNumber == 1 ? [...(data.XROWS || [])] : [...pv.rows, ...(data.XROWS || [])],
|
|
||||||
dataLoaded: true,
|
|
||||||
reload: false,
|
|
||||||
morePages: (data.XROWS || []).length >= DATA_GRID_PAGE_SIZE
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
},
|
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
||||||
[state.reload, state.orders, state.dataLoaded, state.pageNumber, executeStored, SERV_DATA_TYPE_CLOB]
|
|
||||||
);
|
|
||||||
|
|
||||||
//При необходимости обновить данные таблицы
|
|
||||||
useEffect(() => {
|
|
||||||
if (state.selectedPlan.NRN) {
|
|
||||||
loadData(state.selectedPlan.NRN);
|
|
||||||
} else {
|
|
||||||
setState(pv => ({ ...pv, dataLoaded: false, columnsDef: [], orders: null, rows: [], reload: true, pageNumber: 1, morePages: true }));
|
|
||||||
}
|
|
||||||
}, [state.selectedPlan, state.reload, loadData]);
|
|
||||||
|
|
||||||
//При подключении компонента к странице
|
|
||||||
useEffect(() => {
|
|
||||||
initPlans();
|
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
//Выбор плана
|
//Выбор плана
|
||||||
const selectPlan = plan => {
|
const selectPlan = plan => {
|
||||||
setState(pv => ({
|
setState(pv => ({
|
||||||
@ -332,7 +245,7 @@ const MechRecDeptCostProdPlans = () => {
|
|||||||
|
|
||||||
//Генерация содержимого
|
//Генерация содержимого
|
||||||
return (
|
return (
|
||||||
<>
|
<Box p={2}>
|
||||||
<Fab variant="extended" sx={STYLES.PLANS_BUTTON} onClick={() => setState(pv => ({ ...pv, showPlanList: !pv.showPlanList }))}>
|
<Fab variant="extended" sx={STYLES.PLANS_BUTTON} onClick={() => setState(pv => ({ ...pv, showPlanList: !pv.showPlanList }))}>
|
||||||
Планы
|
Планы
|
||||||
</Fab>
|
</Fab>
|
||||||
@ -350,16 +263,18 @@ const MechRecDeptCostProdPlans = () => {
|
|||||||
onClick={handlePlanClick}
|
onClick={handlePlanClick}
|
||||||
/>
|
/>
|
||||||
</Drawer>
|
</Drawer>
|
||||||
<div style={STYLES.CONTAINER}>
|
|
||||||
{state.dataLoaded ? (
|
|
||||||
<Typography variant={"h6"}>
|
|
||||||
{`Производственный план цеха №${state.selectedPlan.SSUBDIV} на ${state.selectedPlan.SPERIOD}`}
|
|
||||||
</Typography>
|
|
||||||
) : null}
|
|
||||||
<Grid container spacing={1}>
|
<Grid container spacing={1}>
|
||||||
<Grid item xs={12}>
|
<Grid item xs={12}>
|
||||||
<Box pt={1} display="flex" justifyContent="center" alignItems="center">
|
<Box display="flex" justifyContent="center" alignItems="center">
|
||||||
{state.dataLoaded ? (
|
{state.dataLoaded ? (
|
||||||
|
state.rows.length === 0 ? (
|
||||||
|
<InlineMsgInfo okBtn={false} text={"В плане отсутствуют записи спецификации"} />
|
||||||
|
) : (
|
||||||
|
<Box sx={STYLES.CONTAINER}>
|
||||||
|
<Typography pt={1} variant={"h6"}>
|
||||||
|
{`Производственный план цеха №${state.selectedPlan.SSUBDIV} на ${state.selectedPlan.SPERIOD}`}
|
||||||
|
</Typography>
|
||||||
|
<Box pt={2.5}>
|
||||||
<P8PDataGrid
|
<P8PDataGrid
|
||||||
{...P8P_DATA_GRID_CONFIG_PROPS}
|
{...P8P_DATA_GRID_CONFIG_PROPS}
|
||||||
containerComponentProps={{ elevation: 6, style: STYLES.DATA_GRID_CONTAINER }}
|
containerComponentProps={{ elevation: 6, style: STYLES.DATA_GRID_CONTAINER }}
|
||||||
@ -375,8 +290,11 @@ const MechRecDeptCostProdPlans = () => {
|
|||||||
dataCellRender={prms => dataCellRender({ ...prms, handleProdOrderClick, handleMatresCodeClick })}
|
dataCellRender={prms => dataCellRender({ ...prms, handleProdOrderClick, handleMatresCodeClick })}
|
||||||
groupCellRender={groupCellRender}
|
groupCellRender={groupCellRender}
|
||||||
/>
|
/>
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
)
|
||||||
) : !state.selectedPlan.NRN ? (
|
) : !state.selectedPlan.NRN ? (
|
||||||
<InlineMsgInfo okBtn={false} text={"Укажите план для отображения его спецификаций"} />
|
<InlineMsgInfo okBtn={false} text={"Укажите план для отображения спецификаций"} />
|
||||||
) : null}
|
) : null}
|
||||||
</Box>
|
</Box>
|
||||||
</Grid>
|
</Grid>
|
||||||
@ -384,11 +302,8 @@ const MechRecDeptCostProdPlans = () => {
|
|||||||
{state.showIncomeFromDeps ? (
|
{state.showIncomeFromDeps ? (
|
||||||
<IncomFromDepsDataGridDialog task={state.showIncomeFromDeps} onClose={() => handleProdOrderClick(null)} />
|
<IncomFromDepsDataGridDialog task={state.showIncomeFromDeps} onClose={() => handleProdOrderClick(null)} />
|
||||||
) : null}
|
) : null}
|
||||||
{state.showFcroutelst ? (
|
{state.showFcroutelst ? <CostRouteListsDataGridDialog task={state.showFcroutelst} onClose={() => handleMatresCodeClick(null)} /> : null}
|
||||||
<CostRouteListsDataGridDialog task={state.showFcroutelst} onClose={() => handleMatresCodeClick(null)} />
|
</Box>
|
||||||
) : null}
|
|
||||||
</div>
|
|
||||||
</>
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user