forked from CITKParus/P8-Panels
WEB APP: ЦИТК-841 панель "Мониторинг сборки изделий" - добавлена SVG-модель и проведён первый этап рефакторинга
This commit is contained in:
parent
46d078219f
commit
dea0f3643d
@ -11,7 +11,7 @@ import { object2Base64XML } from "../../core/utils"; //Вспомогатель
|
|||||||
//---------
|
//---------
|
||||||
|
|
||||||
//Размер страницы данных
|
//Размер страницы данных
|
||||||
const DATA_GRID_PAGE_SIZE = 10;
|
const DATA_GRID_PAGE_SIZE = 0;
|
||||||
|
|
||||||
//-----------
|
//-----------
|
||||||
//Тело модуля
|
//Тело модуля
|
||||||
@ -25,10 +25,10 @@ const useMechRecAssemblyMon = () => {
|
|||||||
showPlanList: false,
|
showPlanList: false,
|
||||||
planCtlgs: [],
|
planCtlgs: [],
|
||||||
planCtlgsLoaded: false,
|
planCtlgsLoaded: false,
|
||||||
selectedPlanCtlg: { NRN: null, SNAME: null, NMIN_YEAR: null, NMAX_YEAR: null },
|
selectedPlanCtlg: {},
|
||||||
plans: [],
|
plans: [],
|
||||||
plansLoaded: false,
|
plansLoaded: false,
|
||||||
selectedPlan: { NRN: null, SNUMB: null, NPROGRESS: null, SDETAIL: null, NYEAR: null }
|
selectedPlan: {}
|
||||||
});
|
});
|
||||||
|
|
||||||
//Подключение к контексту взаимодействия с сервером
|
//Подключение к контексту взаимодействия с сервером
|
||||||
@ -66,19 +66,21 @@ const useMechRecAssemblyMon = () => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
//Выбор каталога планов
|
//Выбор каталога планов
|
||||||
const selectPlan = project => {
|
const selectPlanCtlg = planCtlg => {
|
||||||
setState(pv => ({
|
setState(pv => ({
|
||||||
...pv,
|
...pv,
|
||||||
selectedPlanCtlg: project,
|
selectedPlanCtlg: { ...planCtlg },
|
||||||
|
selectedPlan: {},
|
||||||
showPlanList: false
|
showPlanList: false
|
||||||
}));
|
}));
|
||||||
};
|
};
|
||||||
|
|
||||||
//Сброс выбора каталога планов
|
//Сброс выбора каталога планов
|
||||||
const unselectPlan = () =>
|
const unselectPlanCtlg = () =>
|
||||||
setState(pv => ({
|
setState(pv => ({
|
||||||
...pv,
|
...pv,
|
||||||
selectedPlanCtlg: { NRN: null, SNAME: null, NMIN_YEAR: null, NMAX_YEAR: null },
|
selectedPlanCtlg: {},
|
||||||
|
selectedPlan: {},
|
||||||
showPlanList: false
|
showPlanList: false
|
||||||
}));
|
}));
|
||||||
|
|
||||||
@ -99,7 +101,7 @@ const useMechRecAssemblyMon = () => {
|
|||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, [state.selectedPlanCtlg]);
|
}, [state.selectedPlanCtlg]);
|
||||||
|
|
||||||
return [state, setState, selectPlan, unselectPlan];
|
return [state, setState, selectPlanCtlg, unselectPlanCtlg];
|
||||||
};
|
};
|
||||||
|
|
||||||
//Хук для информации по производственным составам
|
//Хук для информации по производственным составам
|
||||||
@ -109,6 +111,8 @@ const useCostProductComposition = nProdPlan => {
|
|||||||
init: false,
|
init: false,
|
||||||
showPlanList: false,
|
showPlanList: false,
|
||||||
products: [],
|
products: [],
|
||||||
|
productsLoaded: false,
|
||||||
|
model: null,
|
||||||
selectedProduct: null
|
selectedProduct: null
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -124,7 +128,13 @@ const useCostProductComposition = nProdPlan => {
|
|||||||
respArg: "COUT",
|
respArg: "COUT",
|
||||||
isArray: name => name === "XFCPRODCMP"
|
isArray: name => name === "XFCPRODCMP"
|
||||||
});
|
});
|
||||||
setCostProductComposition(pv => ({ ...pv, init: true, products: [...(data?.XFCPRODCMP || [])], productsLoaded: true }));
|
setCostProductComposition(pv => ({
|
||||||
|
...pv,
|
||||||
|
init: true,
|
||||||
|
products: [...(data?.XFCPRODCMP || [])],
|
||||||
|
productsLoaded: true,
|
||||||
|
model: data?.BMODEL
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, [costProductComposition.init, executeStored]);
|
}, [costProductComposition.init, executeStored]);
|
||||||
@ -138,204 +148,53 @@ const useCostProductComposition = nProdPlan => {
|
|||||||
return [costProductComposition, setCostProductComposition];
|
return [costProductComposition, setCostProductComposition];
|
||||||
};
|
};
|
||||||
|
|
||||||
//Хук для таблицы маршрутных листов
|
//Хук для таблицы детализации изделия
|
||||||
const useCostRouteLists = (plan, product) => {
|
const useProductDetailsTable = (plan, product, orders, pageNumber, stored) => {
|
||||||
|
//Собственное состояние - флаг загрузки
|
||||||
|
const [isLoading, setLoading] = useState(true);
|
||||||
|
|
||||||
//Собственное состояние - таблица данных
|
//Собственное состояние - таблица данных
|
||||||
const [costRouteLists, setCostRouteLists] = useState({
|
const [data, setData] = useState({
|
||||||
dataLoaded: false,
|
|
||||||
columnsDef: [],
|
columnsDef: [],
|
||||||
orders: null,
|
|
||||||
rows: [],
|
rows: [],
|
||||||
reload: true,
|
|
||||||
pageNumber: 1,
|
|
||||||
morePages: true,
|
|
||||||
selectedProduct: null
|
|
||||||
});
|
|
||||||
|
|
||||||
//Подключение к контексту взаимодействия с сервером
|
|
||||||
const { executeStored, SERV_DATA_TYPE_CLOB } = useContext(BackEndСtx);
|
|
||||||
|
|
||||||
//Загрузка данных таблицы с сервера
|
|
||||||
const loadData = useCallback(
|
|
||||||
async () => {
|
|
||||||
if (costRouteLists.reload) {
|
|
||||||
const data = await executeStored({
|
|
||||||
stored: "PKG_P8PANELS_MECHREC.FCROUTLST_MON_DG_GET",
|
|
||||||
args: {
|
|
||||||
NPRODCMPSP: product,
|
|
||||||
NFCPRODPLAN: plan,
|
|
||||||
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.orders, costRouteLists.dataLoaded, costRouteLists.pageNumber, executeStored, SERV_DATA_TYPE_CLOB]
|
|
||||||
);
|
|
||||||
|
|
||||||
//При изменении продукта
|
|
||||||
useEffect(() => {
|
|
||||||
//Если продукт указан
|
|
||||||
if (product) {
|
|
||||||
//Принудительно обновляем состояние
|
|
||||||
setCostRouteLists(pv => ({
|
|
||||||
...pv,
|
|
||||||
dataLoaded: false,
|
|
||||||
columnsDef: [],
|
|
||||||
orders: null,
|
|
||||||
rows: [],
|
|
||||||
reload: true,
|
|
||||||
pageNumber: 1,
|
|
||||||
morePages: true,
|
|
||||||
selectedProduct: null
|
|
||||||
}));
|
|
||||||
//Загружаем данные с учетом выбранного продукта
|
|
||||||
loadData();
|
|
||||||
}
|
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
||||||
}, [product]);
|
|
||||||
|
|
||||||
//При необходимости обновить данные таблицы
|
|
||||||
useEffect(() => {
|
|
||||||
//Если продукт указан и необходимо стандартное обновление
|
|
||||||
if (product) {
|
|
||||||
loadData();
|
|
||||||
}
|
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
||||||
}, [costRouteLists.reload, loadData]);
|
|
||||||
|
|
||||||
//При изменении плана
|
|
||||||
useEffect(() => {
|
|
||||||
setCostRouteLists(pv => ({
|
|
||||||
...pv,
|
|
||||||
dataLoaded: false,
|
|
||||||
columnsDef: [],
|
|
||||||
orders: null,
|
|
||||||
rows: [],
|
|
||||||
reload: true,
|
|
||||||
pageNumber: 1,
|
|
||||||
morePages: true,
|
|
||||||
selectedProduct: null
|
|
||||||
}));
|
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
||||||
}, [plan]);
|
|
||||||
|
|
||||||
return [costRouteLists, setCostRouteLists];
|
|
||||||
};
|
|
||||||
|
|
||||||
//Хук для таблицы комплектовочных ведомостей
|
|
||||||
const useCostDeliverySheets = (plan, product) => {
|
|
||||||
//Собственное состояние - таблица данных
|
|
||||||
const [costDeliverySheets, setCostDeliverySheets] = useState({
|
|
||||||
dataLoaded: false,
|
|
||||||
columnsDef: [],
|
|
||||||
orders: null,
|
|
||||||
rows: [],
|
|
||||||
reload: true,
|
|
||||||
pageNumber: 1,
|
|
||||||
morePages: true,
|
|
||||||
selectedProduct: null
|
|
||||||
});
|
|
||||||
|
|
||||||
//Подключение к контексту взаимодействия с сервером
|
|
||||||
const { executeStored, SERV_DATA_TYPE_CLOB } = useContext(BackEndСtx);
|
|
||||||
|
|
||||||
//Загрузка данных таблицы с сервера
|
|
||||||
const loadData = useCallback(
|
|
||||||
async () => {
|
|
||||||
if (costDeliverySheets.reload) {
|
|
||||||
const data = await executeStored({
|
|
||||||
stored: "PKG_P8PANELS_MECHREC.FCDELIVSH_DG_GET",
|
|
||||||
args: {
|
|
||||||
NPRODCMPSP: product,
|
|
||||||
NFCPRODPLAN: plan,
|
|
||||||
CORDERS: { VALUE: object2Base64XML(costDeliverySheets.orders, { arrayNodeName: "orders" }), SDATA_TYPE: SERV_DATA_TYPE_CLOB },
|
|
||||||
NPAGE_NUMBER: costDeliverySheets.pageNumber,
|
|
||||||
NPAGE_SIZE: DATA_GRID_PAGE_SIZE,
|
|
||||||
NINCLUDE_DEF: costDeliverySheets.dataLoaded ? 0 : 1
|
|
||||||
},
|
|
||||||
respArg: "COUT"
|
|
||||||
});
|
|
||||||
setCostDeliverySheets(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
|
|
||||||
[
|
|
||||||
costDeliverySheets.reload,
|
|
||||||
costDeliverySheets.orders,
|
|
||||||
costDeliverySheets.dataLoaded,
|
|
||||||
costDeliverySheets.pageNumber,
|
|
||||||
executeStored,
|
|
||||||
SERV_DATA_TYPE_CLOB
|
|
||||||
]
|
|
||||||
);
|
|
||||||
|
|
||||||
//При изменении продукта
|
|
||||||
useEffect(() => {
|
|
||||||
//Если продукт указан
|
|
||||||
if (product) {
|
|
||||||
//Принудительно обновляем состояние
|
|
||||||
setCostDeliverySheets(pv => ({
|
|
||||||
...pv,
|
|
||||||
dataLoaded: false,
|
|
||||||
columnsDef: [],
|
|
||||||
orders: null,
|
|
||||||
rows: [],
|
|
||||||
reload: true,
|
|
||||||
pageNumber: 1,
|
|
||||||
morePages: true
|
morePages: true
|
||||||
}));
|
});
|
||||||
//Загружаем данные с учетом выбранного продукта
|
|
||||||
loadData();
|
|
||||||
}
|
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
||||||
}, [product]);
|
|
||||||
|
|
||||||
//При необходимости обновить данные таблицы
|
//Подключение к контексту взаимодействия с сервером
|
||||||
useEffect(() => {
|
const { executeStored, SERV_DATA_TYPE_CLOB } = useContext(BackEndСtx);
|
||||||
//Если продукт указан и необходимо стандартное обновление
|
|
||||||
if (product) {
|
|
||||||
loadData();
|
|
||||||
}
|
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
||||||
}, [costDeliverySheets.reload, loadData]);
|
|
||||||
|
|
||||||
//При изменении плана
|
//Загрузка данных при изменении зависимостей
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setCostDeliverySheets(pv => ({
|
const loadData = async () => {
|
||||||
|
try {
|
||||||
|
setLoading(true);
|
||||||
|
const data = await executeStored({
|
||||||
|
stored,
|
||||||
|
args: {
|
||||||
|
NPRODCMPSP: product,
|
||||||
|
NFCPRODPLAN: plan,
|
||||||
|
CORDERS: { VALUE: object2Base64XML(orders, { arrayNodeName: "orders" }), SDATA_TYPE: SERV_DATA_TYPE_CLOB },
|
||||||
|
NPAGE_NUMBER: pageNumber,
|
||||||
|
NPAGE_SIZE: DATA_GRID_PAGE_SIZE,
|
||||||
|
NINCLUDE_DEF: 1
|
||||||
|
},
|
||||||
|
respArg: "COUT"
|
||||||
|
});
|
||||||
|
setData(pv => ({
|
||||||
...pv,
|
...pv,
|
||||||
dataLoaded: false,
|
columnsDef: data.XCOLUMNS_DEF ? [...data.XCOLUMNS_DEF] : pv.columnsDef,
|
||||||
columnsDef: [],
|
rows: pageNumber == 1 ? [...(data.XROWS || [])] : [...pv.rows, ...(data.XROWS || [])],
|
||||||
orders: null,
|
morePages: DATA_GRID_PAGE_SIZE == 0 ? false : (data.XROWS || []).length >= DATA_GRID_PAGE_SIZE
|
||||||
rows: [],
|
|
||||||
reload: true,
|
|
||||||
pageNumber: 1,
|
|
||||||
morePages: true,
|
|
||||||
selectedProduct: null
|
|
||||||
}));
|
}));
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
} finally {
|
||||||
}, [plan]);
|
setLoading(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if (plan && product) loadData();
|
||||||
|
}, [plan, product, orders, pageNumber, stored, executeStored, SERV_DATA_TYPE_CLOB]);
|
||||||
|
|
||||||
return [costDeliverySheets, setCostDeliverySheets];
|
//Вернём данные
|
||||||
|
return { data, isLoading };
|
||||||
};
|
};
|
||||||
|
|
||||||
export { useMechRecAssemblyMon, useCostProductComposition, useCostRouteLists, useCostDeliverySheets };
|
export { useMechRecAssemblyMon, useCostProductComposition, useProductDetailsTable };
|
||||||
|
@ -1,102 +0,0 @@
|
|||||||
/*
|
|
||||||
Парус 8 - Панели мониторинга - ПУП - Мониторинг сборки изделий
|
|
||||||
Панель мониторинга: Информация об объекте
|
|
||||||
*/
|
|
||||||
|
|
||||||
//---------------------
|
|
||||||
//Подключение библиотек
|
|
||||||
//---------------------
|
|
||||||
|
|
||||||
import React from "react"; //Классы React
|
|
||||||
import PropTypes from "prop-types"; //Контроль свойств компонента
|
|
||||||
import { Typography, Box, ImageList, ImageListItem } from "@mui/material"; //Интерфейсные элементы
|
|
||||||
import { ProgressBox } from "../elements/progressBox"; //Блок информации по прогрессу объекта
|
|
||||||
|
|
||||||
//---------
|
|
||||||
//Константы
|
|
||||||
//---------
|
|
||||||
|
|
||||||
//Стили
|
|
||||||
const STYLES = {
|
|
||||||
PLAN_INFO: {
|
|
||||||
display: "flex",
|
|
||||||
justifyContent: "center",
|
|
||||||
alignItems: "center",
|
|
||||||
flexDirection: "column",
|
|
||||||
gap: "24px",
|
|
||||||
border: "1px solid",
|
|
||||||
borderRadius: "25px"
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
//------------------------------------
|
|
||||||
//Вспомогательные функции и компоненты
|
|
||||||
//------------------------------------
|
|
||||||
|
|
||||||
//Картинка объекта
|
|
||||||
const CardImage = ({ card }) => {
|
|
||||||
return (
|
|
||||||
<Box width={180} height={180}>
|
|
||||||
<ImageList variant="masonry" cols={1} gap={8}>
|
|
||||||
<ImageListItem key={1}>
|
|
||||||
<img src={`data:image/png;base64,${card["#text"]}`} alt={"Image not loaded."} loading="lazy" width={180} />
|
|
||||||
{/* <img src={`./${airplaneImg}`} alt={"Image not loaded."} loading="lazy" width={180} /> */}
|
|
||||||
</ImageListItem>
|
|
||||||
</ImageList>
|
|
||||||
</Box>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
//Контроль свойств - Заголовок первого уровня
|
|
||||||
CardImage.propTypes = {
|
|
||||||
card: PropTypes.object
|
|
||||||
};
|
|
||||||
|
|
||||||
//-----------
|
|
||||||
//Тело модуля
|
|
||||||
//-----------
|
|
||||||
|
|
||||||
//Информация об объекте
|
|
||||||
const CardBlock = ({ card, handleCardClick }) => {
|
|
||||||
return (
|
|
||||||
<Box sx={STYLES.PLAN_INFO} onClick={() => handleCardClick(card)}>
|
|
||||||
<CardImage card={card} />
|
|
||||||
<Box textAlign="center">
|
|
||||||
<Typography variant="UDO_body1" color="text.secondary.fontColor">
|
|
||||||
Номер борта
|
|
||||||
</Typography>
|
|
||||||
<Typography variant="h2">{card.SNUMB}</Typography>
|
|
||||||
</Box>
|
|
||||||
<ProgressBox
|
|
||||||
prms={{
|
|
||||||
NPROGRESS: card.NPROGRESS,
|
|
||||||
SDETAIL: card.SDETAIL,
|
|
||||||
width: "155px",
|
|
||||||
height: "155px",
|
|
||||||
progressVariant: "h3",
|
|
||||||
detailVariant: "UDO_body2"
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
<Box>
|
|
||||||
<Typography variant="UDO_body1" color="text.secondary.fontColor">
|
|
||||||
Год выпуска:
|
|
||||||
</Typography>
|
|
||||||
<Typography variant="subtitle1" mt={-1}>
|
|
||||||
{card.NYEAR}
|
|
||||||
</Typography>
|
|
||||||
</Box>
|
|
||||||
</Box>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
//Контроль свойств - Заголовок первого уровня
|
|
||||||
CardBlock.propTypes = {
|
|
||||||
card: PropTypes.object,
|
|
||||||
handleCardClick: PropTypes.func
|
|
||||||
};
|
|
||||||
|
|
||||||
//----------------
|
|
||||||
//Интерфейс модуля
|
|
||||||
//----------------
|
|
||||||
|
|
||||||
export { CardBlock };
|
|
@ -1,289 +0,0 @@
|
|||||||
/*
|
|
||||||
Парус 8 - Панели мониторинга - ПУП - Мониторинг сборки изделий
|
|
||||||
Панель мониторинга: Детализация по объекту
|
|
||||||
*/
|
|
||||||
|
|
||||||
//---------------------
|
|
||||||
//Подключение библиотек
|
|
||||||
//---------------------
|
|
||||||
|
|
||||||
import React from "react"; //Классы React
|
|
||||||
import PropTypes from "prop-types"; //Контроль свойств компонента
|
|
||||||
import { Box, Grid, Container, Button, Typography } from "@mui/material"; //Интерфейсные элементы
|
|
||||||
import { ProgressBox } from "../elements/progressBox"; //Блок информации по прогрессу объекта
|
|
||||||
import { P8PDataGrid, P8P_DATA_GRID_SIZE } from "../../../components/p8p_data_grid"; //Таблица данных
|
|
||||||
import { P8P_DATA_GRID_CONFIG_PROPS } from "../../../config_wrapper"; //Подключение компонентов к настройкам приложения
|
|
||||||
import { useCostProductComposition, useCostRouteLists, useCostDeliverySheets } from "../backend"; //Компоненты панели
|
|
||||||
|
|
||||||
//---------
|
|
||||||
//Константы
|
|
||||||
//---------
|
|
||||||
|
|
||||||
//Стили
|
|
||||||
const STYLES = {
|
|
||||||
TABLE_INFO_MAIN: {
|
|
||||||
display: "flex",
|
|
||||||
justifyContent: "center",
|
|
||||||
alignItems: "center",
|
|
||||||
flexDirection: "column",
|
|
||||||
border: "1px solid",
|
|
||||||
borderRadius: "25px",
|
|
||||||
height: "35vh"
|
|
||||||
},
|
|
||||||
TABLE_INFO_SUB: {
|
|
||||||
margin: "21.6px 0px",
|
|
||||||
maxHeight: "100%",
|
|
||||||
overflow: "auto",
|
|
||||||
textAlign: "center",
|
|
||||||
width: "100%"
|
|
||||||
},
|
|
||||||
DETAIL_INFO: {
|
|
||||||
display: "flex",
|
|
||||||
justifyContent: "space-around",
|
|
||||||
alignItems: "center",
|
|
||||||
border: "1px solid",
|
|
||||||
borderRadius: "25px",
|
|
||||||
height: "17vh"
|
|
||||||
},
|
|
||||||
PRODUCT_SELECTOR: {
|
|
||||||
display: "flex",
|
|
||||||
justifyContent: "center",
|
|
||||||
alignItems: "center",
|
|
||||||
flexDirection: "column",
|
|
||||||
border: "1px solid",
|
|
||||||
borderRadius: "25px",
|
|
||||||
height: "53vh",
|
|
||||||
marginTop: "16px"
|
|
||||||
},
|
|
||||||
PLAN_INFO_MAIN: {
|
|
||||||
display: "flex",
|
|
||||||
flexDirection: "column",
|
|
||||||
gap: "16px"
|
|
||||||
},
|
|
||||||
PLAN_INFO_SUB: {
|
|
||||||
display: "flex",
|
|
||||||
justifyContent: "space-between",
|
|
||||||
width: "280px",
|
|
||||||
borderBottom: "1px solid"
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
//------------------------------------
|
|
||||||
//Вспомогательные функции и компоненты
|
|
||||||
//------------------------------------
|
|
||||||
|
|
||||||
//Информация об объекте
|
|
||||||
const CardDetailInfo = ({ cardInfo }) => {
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<Box sx={STYLES.PLAN_INFO_MAIN}>
|
|
||||||
<Box sx={STYLES.PLAN_INFO_SUB}>
|
|
||||||
<Typography variant="UDO_body1" mt={1}>
|
|
||||||
Номер борта:
|
|
||||||
</Typography>
|
|
||||||
<Typography variant="subtitle2">{cardInfo.SNUMB}</Typography>
|
|
||||||
</Box>
|
|
||||||
<Box sx={STYLES.PLAN_INFO_SUB}>
|
|
||||||
<Typography variant="UDO_body1" mt={1}>
|
|
||||||
Год выпуска:
|
|
||||||
</Typography>
|
|
||||||
<Typography variant="subtitle2">{cardInfo.NYEAR}</Typography>
|
|
||||||
</Box>
|
|
||||||
</Box>
|
|
||||||
<ProgressBox
|
|
||||||
prms={{
|
|
||||||
NPROGRESS: cardInfo.NPROGRESS,
|
|
||||||
SDETAIL: cardInfo.SDETAIL,
|
|
||||||
width: "110px",
|
|
||||||
height: "110px",
|
|
||||||
progressVariant: "subtitle2",
|
|
||||||
detailVariant: "body3"
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
//Контроль свойств - Информация об объекте
|
|
||||||
CardDetailInfo.propTypes = {
|
|
||||||
cardInfo: PropTypes.object
|
|
||||||
};
|
|
||||||
|
|
||||||
//Детали объекта
|
|
||||||
const CardSelector = ({ products, setCostProductComposition }) => {
|
|
||||||
//При выборе детали в SVG
|
|
||||||
const handleProductClick = product => {
|
|
||||||
setCostProductComposition(pv => ({ ...pv, selectedProduct: product }));
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<Box sx={STYLES.PLAN_INFO_MAIN}>
|
|
||||||
{products.map(el => (
|
|
||||||
<Button key={el.NRN} onClick={() => handleProductClick(el.NRN)}>{`${el.SNAME}`}</Button>
|
|
||||||
))}
|
|
||||||
</Box>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
//Контроль свойств - Детали объекта
|
|
||||||
CardSelector.propTypes = {
|
|
||||||
products: PropTypes.array,
|
|
||||||
setCostProductComposition: PropTypes.func
|
|
||||||
};
|
|
||||||
|
|
||||||
//Генерация представления ячейки заголовка
|
|
||||||
const headCellRender = ({ columnDef }) => {
|
|
||||||
//Описываем общий стиль
|
|
||||||
let cellStyle = { padding: "2px 5px", fontSize: "12px", textAlign: "center", lineHeight: "1rem" };
|
|
||||||
let stackProps = { justifyContent: "center" };
|
|
||||||
//Дополнительные свойства
|
|
||||||
switch (columnDef.name) {
|
|
||||||
case "NREMN_LABOUR":
|
|
||||||
//Добавляем максимальную ширину
|
|
||||||
cellStyle = { ...cellStyle, maxWidth: "90px" };
|
|
||||||
break;
|
|
||||||
case "NDEFICIT":
|
|
||||||
//Добавляем максимальную ширину
|
|
||||||
cellStyle = { ...cellStyle, maxWidth: "55px" };
|
|
||||||
break;
|
|
||||||
case "NAPPLICABILITY":
|
|
||||||
//Добавляем максимальную ширину
|
|
||||||
cellStyle = { ...cellStyle, maxWidth: "90px" };
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
stackProps,
|
|
||||||
cellStyle
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
//Генерация заливки строки исходя от значений
|
|
||||||
const dataCellRender = ({ row, columnDef }) => {
|
|
||||||
//Описываем общий стиль
|
|
||||||
let cellStyle = { padding: "2px 5px", fontSize: "12px" };
|
|
||||||
//Для всех кроме содержания и номенклатуры добавляем выравнивание
|
|
||||||
switch (columnDef.name) {
|
|
||||||
case "SOPERATION":
|
|
||||||
break;
|
|
||||||
case "SNOMEN":
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
//Добавляем выравнивание
|
|
||||||
cellStyle = { ...cellStyle, textAlign: "center" };
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
cellStyle,
|
|
||||||
data: row[columnDef]
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
//-----------
|
|
||||||
//Тело модуля
|
|
||||||
//-----------
|
|
||||||
|
|
||||||
//Детализация по объекту
|
|
||||||
const CardDetail = ({ card, handleBackClick }) => {
|
|
||||||
//Собственное состояние - данные производственных составов SVG
|
|
||||||
const [costProductComposition, setCostProductComposition] = useCostProductComposition(card.NRN);
|
|
||||||
//Собственное состояние - таблица данных маршрутных листов
|
|
||||||
const [costRouteLists, setCostRouteLists] = useCostRouteLists(card.NRN, costProductComposition.selectedProduct);
|
|
||||||
//Собственное состояние - таблица данных комплектовочных ведомостей
|
|
||||||
const [сostDeliverySheets, setСostDeliverySheets] = useCostDeliverySheets(card.NRN, costProductComposition.selectedProduct);
|
|
||||||
|
|
||||||
//При изменении состояния сортировки маршрутных листов
|
|
||||||
const costRouteListsOrderChanged = ({ orders }) => setCostRouteLists(pv => ({ ...pv, orders: [...orders], pageNumber: 1, reload: true }));
|
|
||||||
|
|
||||||
//При изменении количества отображаемых страниц маршрутных листов
|
|
||||||
const costRouteListsPagesCountChanged = () => setCostRouteLists(pv => ({ ...pv, pageNumber: pv.pageNumber + 1, reload: true }));
|
|
||||||
|
|
||||||
//При изменении состояния сортировки комплектовочных ведомостей
|
|
||||||
const СostDeliverySheetsOrderChanged = ({ orders }) => setСostDeliverySheets(pv => ({ ...pv, orders: [...orders], pageNumber: 1, reload: true }));
|
|
||||||
|
|
||||||
//При изменении количества отображаемых страниц комплектовочных ведомостей
|
|
||||||
const СostDeliverySheetsPagesCountChanged = () => setСostDeliverySheets(pv => ({ ...pv, pageNumber: pv.pageNumber + 1, reload: true }));
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Container>
|
|
||||||
<Button onClick={() => handleBackClick()}>Назад</Button>
|
|
||||||
<Grid container spacing={2}>
|
|
||||||
<Grid item xs={5}>
|
|
||||||
<Box sx={STYLES.TABLE_INFO_MAIN}>
|
|
||||||
<Box sx={STYLES.TABLE_INFO_SUB}>
|
|
||||||
{!costRouteLists.dataLoaded ? (
|
|
||||||
<Typography variant="UDO_body2">Выберите агрегат самолёта, чтобы увидеть информацию</Typography>
|
|
||||||
) : costRouteLists.rows.length === 0 ? (
|
|
||||||
<Typography variant="subtitle2">Нет данных по МК</Typography>
|
|
||||||
) : (
|
|
||||||
<>
|
|
||||||
<Typography variant="h4">Маршрутная карта</Typography>
|
|
||||||
<P8PDataGrid
|
|
||||||
{...P8P_DATA_GRID_CONFIG_PROPS}
|
|
||||||
columnsDef={costRouteLists.columnsDef}
|
|
||||||
rows={costRouteLists.rows}
|
|
||||||
size={P8P_DATA_GRID_SIZE.SMALL}
|
|
||||||
morePages={costRouteLists.morePages}
|
|
||||||
reloading={costRouteLists.reload}
|
|
||||||
dataCellRender={dataCellRender}
|
|
||||||
headCellRender={headCellRender}
|
|
||||||
onOrderChanged={costRouteListsOrderChanged}
|
|
||||||
onPagesCountChanged={costRouteListsPagesCountChanged}
|
|
||||||
/>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</Box>
|
|
||||||
</Box>
|
|
||||||
<Box sx={STYLES.TABLE_INFO_MAIN} mt={2}>
|
|
||||||
<Box sx={STYLES.TABLE_INFO_SUB}>
|
|
||||||
{!сostDeliverySheets.dataLoaded ? (
|
|
||||||
<Typography variant="UDO_body2">Выберите агрегат самолёта, чтобы увидеть информацию</Typography>
|
|
||||||
) : сostDeliverySheets.rows.length === 0 ? (
|
|
||||||
<Typography variant="subtitle2">Нет данных по КВ</Typography>
|
|
||||||
) : (
|
|
||||||
<>
|
|
||||||
<Typography variant="h4">Дефицит по КВ</Typography>
|
|
||||||
<P8PDataGrid
|
|
||||||
{...P8P_DATA_GRID_CONFIG_PROPS}
|
|
||||||
columnsDef={сostDeliverySheets.columnsDef}
|
|
||||||
rows={сostDeliverySheets.rows}
|
|
||||||
size={P8P_DATA_GRID_SIZE.SMALL}
|
|
||||||
morePages={сostDeliverySheets.morePages}
|
|
||||||
reloading={сostDeliverySheets.reload}
|
|
||||||
dataCellRender={dataCellRender}
|
|
||||||
headCellRender={headCellRender}
|
|
||||||
onOrderChanged={СostDeliverySheetsOrderChanged}
|
|
||||||
onPagesCountChanged={СostDeliverySheetsPagesCountChanged}
|
|
||||||
/>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</Box>
|
|
||||||
</Box>
|
|
||||||
</Grid>
|
|
||||||
<Grid item xs={7}>
|
|
||||||
<Box sx={STYLES.DETAIL_INFO}>
|
|
||||||
<CardDetailInfo cardInfo={card} />
|
|
||||||
</Box>
|
|
||||||
<Box sx={STYLES.PRODUCT_SELECTOR}>
|
|
||||||
<CardSelector products={costProductComposition.products} setCostProductComposition={setCostProductComposition} />
|
|
||||||
</Box>
|
|
||||||
</Grid>
|
|
||||||
</Grid>
|
|
||||||
</Container>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
//Контроль свойств - Детализация по объекту
|
|
||||||
CardDetail.propTypes = {
|
|
||||||
card: PropTypes.object,
|
|
||||||
handleBackClick: PropTypes.func
|
|
||||||
};
|
|
||||||
|
|
||||||
//----------------
|
|
||||||
//Интерфейс модуля
|
|
||||||
//----------------
|
|
||||||
|
|
||||||
export { CardDetail };
|
|
324
app/panels/mech_rec_assembly_mon/components/plan_detail.js
Normal file
324
app/panels/mech_rec_assembly_mon/components/plan_detail.js
Normal file
@ -0,0 +1,324 @@
|
|||||||
|
/*
|
||||||
|
Парус 8 - Панели мониторинга - ПУП - Мониторинг сборки изделий
|
||||||
|
Панель мониторинга: Детализация по объекту
|
||||||
|
*/
|
||||||
|
|
||||||
|
//---------------------
|
||||||
|
//Подключение библиотек
|
||||||
|
//---------------------
|
||||||
|
|
||||||
|
import React, { useEffect, useState } from "react"; //Классы React
|
||||||
|
import PropTypes from "prop-types"; //Контроль свойств компонента
|
||||||
|
import { Box, Grid, Container, Button, Typography, Icon, Stack, IconButton } from "@mui/material"; //Интерфейсные элементы
|
||||||
|
import { P8PDataGrid, P8P_DATA_GRID_SIZE } from "../../../components/p8p_data_grid"; //Таблица данных
|
||||||
|
import { P8PSVG } from "../../../components/p8p_svg"; //Интерактивные изображения
|
||||||
|
import { P8P_DATA_GRID_CONFIG_PROPS } from "../../../config_wrapper"; //Подключение компонентов к настройкам приложения
|
||||||
|
import { useCostProductComposition, useProductDetailsTable } from "../backend"; //Взаимодействие с сервером
|
||||||
|
import { ProgressBox } from "./progress_box"; //Информация по прогрессу объекта
|
||||||
|
|
||||||
|
//---------
|
||||||
|
//Константы
|
||||||
|
//---------
|
||||||
|
|
||||||
|
//Стили
|
||||||
|
const STYLES = {
|
||||||
|
BOX_INFO_MAIN: {
|
||||||
|
border: "1px solid",
|
||||||
|
borderRadius: "25px",
|
||||||
|
height: "35vh"
|
||||||
|
},
|
||||||
|
BOX_INFO_SUB: isMessage => ({
|
||||||
|
overflow: "hidden",
|
||||||
|
textAlign: "center",
|
||||||
|
width: "100%",
|
||||||
|
height: "100%",
|
||||||
|
display: "flex",
|
||||||
|
flexDirection: "column",
|
||||||
|
justifyContent: isMessage ? "center" : "flex-start",
|
||||||
|
paddingLeft: "5px",
|
||||||
|
paddingRight: "5px",
|
||||||
|
...(isMessage ? { padding: "5px" } : { paddingTop: "10px" })
|
||||||
|
}),
|
||||||
|
DETAIL_INFO: {
|
||||||
|
display: "flex",
|
||||||
|
justifyContent: "space-around",
|
||||||
|
alignItems: "center",
|
||||||
|
border: "1px solid",
|
||||||
|
borderRadius: "25px",
|
||||||
|
height: "17vh"
|
||||||
|
},
|
||||||
|
PRODUCT_SELECTOR_CONTAINER: {
|
||||||
|
display: "flex",
|
||||||
|
justifyContent: "center",
|
||||||
|
alignItems: "center",
|
||||||
|
flexDirection: "column",
|
||||||
|
border: "1px solid",
|
||||||
|
borderRadius: "25px",
|
||||||
|
height: "53vh",
|
||||||
|
marginTop: "16px"
|
||||||
|
},
|
||||||
|
PRODUCT_SELECTOR_MODEL: { width: "70%" },
|
||||||
|
PLAN_INFO_MAIN: {
|
||||||
|
display: "flex",
|
||||||
|
flexDirection: "column",
|
||||||
|
gap: "16px"
|
||||||
|
},
|
||||||
|
PLAN_INFO_SUB: {
|
||||||
|
display: "flex",
|
||||||
|
justifyContent: "space-between",
|
||||||
|
width: "280px",
|
||||||
|
borderBottom: "1px solid"
|
||||||
|
},
|
||||||
|
TABLE_DETAILS: { height: "260px" },
|
||||||
|
TABLE_DETAILS_HEADER_CELL: maxWidth => ({
|
||||||
|
padding: "2px 2px",
|
||||||
|
fontSize: "11px",
|
||||||
|
textAlign: "center",
|
||||||
|
lineHeight: "1rem",
|
||||||
|
...(maxWidth ? { maxWidth } : {})
|
||||||
|
}),
|
||||||
|
TABLE_DETAILS_DATA_CELL: textAlign => ({ padding: "2px 2px", fontSize: "11px", ...(textAlign ? { textAlign } : {}) }),
|
||||||
|
CARD_DETAILS_CONTAINER: { minWidth: "1200px", maxWidth: "1400px" },
|
||||||
|
CARD_DETAILS_NAVIGATION_STACK: { width: "100%" }
|
||||||
|
};
|
||||||
|
|
||||||
|
//------------------------------------
|
||||||
|
//Вспомогательные функции и компоненты
|
||||||
|
//------------------------------------
|
||||||
|
|
||||||
|
//Информация о плане
|
||||||
|
const PlanInfo = ({ plan }) => {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Box sx={STYLES.PLAN_INFO_MAIN}>
|
||||||
|
<Box sx={STYLES.PLAN_INFO_SUB}>
|
||||||
|
<Typography variant="UDO_body1" mt={1}>
|
||||||
|
Номер борта:
|
||||||
|
</Typography>
|
||||||
|
<Typography variant="subtitle2">{plan.SNUMB}</Typography>
|
||||||
|
</Box>
|
||||||
|
<Box sx={STYLES.PLAN_INFO_SUB}>
|
||||||
|
<Typography variant="UDO_body1" mt={1}>
|
||||||
|
Год выпуска:
|
||||||
|
</Typography>
|
||||||
|
<Typography variant="subtitle2">{plan.NYEAR}</Typography>
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
<ProgressBox
|
||||||
|
progress={plan.NPROGRESS}
|
||||||
|
detail={plan.SDETAIL}
|
||||||
|
width={"110px"}
|
||||||
|
height={"110px"}
|
||||||
|
progressVariant={"subtitle2"}
|
||||||
|
detailVariant={"body3"}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
//Контроль свойств - Информация о плане
|
||||||
|
PlanInfo.propTypes = {
|
||||||
|
plan: PropTypes.object
|
||||||
|
};
|
||||||
|
|
||||||
|
//Модель выпуска плана
|
||||||
|
const PlanProductCompositionModel = ({ model, products, setCostProductComposition }) => {
|
||||||
|
//При выборе детали на модели
|
||||||
|
const handleProductClick = ({ item }) => {
|
||||||
|
const product = products.find(p => p.SMODEL_ID == item.id);
|
||||||
|
if (product) setCostProductComposition(pv => ({ ...pv, selectedProduct: { ...product } }));
|
||||||
|
};
|
||||||
|
|
||||||
|
//Генерация содержимого
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Box sx={STYLES.PRODUCT_SELECTOR_MODEL}>
|
||||||
|
{model ? (
|
||||||
|
<P8PSVG
|
||||||
|
data={atob(model)}
|
||||||
|
items={products.map(p => ({ id: p.SMODEL_ID, backgroundColor: p.SMODEL_BG_COLOR || "red", desc: p.SNAME, title: p.SNAME }))}
|
||||||
|
fillOpacity={"0.3"}
|
||||||
|
onItemClick={handleProductClick}
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<Typography variant="subtitle2">Модель изделия не загружена</Typography>
|
||||||
|
)}
|
||||||
|
</Box>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
//Контроль свойств - Модель выпуска плана
|
||||||
|
PlanProductCompositionModel.propTypes = {
|
||||||
|
model: PropTypes.any,
|
||||||
|
products: PropTypes.array,
|
||||||
|
setCostProductComposition: PropTypes.func
|
||||||
|
};
|
||||||
|
|
||||||
|
//Генерация представления ячейки заголовка
|
||||||
|
const headCellRender = ({ columnDef }) => ({
|
||||||
|
stackProps: { justifyContent: "center" },
|
||||||
|
cellStyle: STYLES.TABLE_DETAILS_HEADER_CELL(
|
||||||
|
["NREMN_LABOUR", "NAPPLICABILITY"].includes(columnDef.name) ? "90px" : ["NDEFICIT"].includes(columnDef.name) ? "55px" : null
|
||||||
|
)
|
||||||
|
});
|
||||||
|
|
||||||
|
//Генерация заливки строки исходя от значений
|
||||||
|
const dataCellRender = ({ row, columnDef }) => ({
|
||||||
|
cellStyle: STYLES.TABLE_DETAILS_DATA_CELL(["SOPERATION", "SNOMEN"].includes(columnDef.name) ? null : "center"),
|
||||||
|
data: row[columnDef]
|
||||||
|
});
|
||||||
|
|
||||||
|
//Таблица детализации изделия
|
||||||
|
const ProductDetailsTable = ({ plan, product, stored, noProductMessage, noDataFoundMessage, title }) => {
|
||||||
|
//Собственное состояние
|
||||||
|
const [state, setState] = useState({ plan: null, product: null, orders: null, pageNumber: 1 });
|
||||||
|
|
||||||
|
//Собственное состояние - данные таблицы
|
||||||
|
const { data, isLoading } = useProductDetailsTable(state.plan, state.product, state.orders, state.pageNumber, stored);
|
||||||
|
|
||||||
|
//При изменении состояния сортировки
|
||||||
|
const handleOrderChanged = ({ orders }) => setState(pv => ({ ...pv, orders: [...orders], pageNumber: 1 }));
|
||||||
|
|
||||||
|
//При изменении количества отображаемых страниц
|
||||||
|
const handlePagesCountChanged = () => setState(pv => ({ ...pv, pageNumber: pv.pageNumber + 1 }));
|
||||||
|
|
||||||
|
//При изменении изделия
|
||||||
|
useEffect(() => {
|
||||||
|
setState(pv => ({ ...pv, plan, product, orders: null, pageNumber: 1 }));
|
||||||
|
}, [product, plan]);
|
||||||
|
|
||||||
|
//Генерация содержимого
|
||||||
|
return (
|
||||||
|
<Box sx={STYLES.BOX_INFO_SUB(!product || data.rows.length === 0)}>
|
||||||
|
{!product ? (
|
||||||
|
<Typography variant="UDO_body2">{noProductMessage}</Typography>
|
||||||
|
) : isLoading ? null : data.rows.length === 0 ? (
|
||||||
|
<Typography variant="subtitle2">{noDataFoundMessage}</Typography>
|
||||||
|
) : (
|
||||||
|
<>
|
||||||
|
<Typography variant="h4">
|
||||||
|
<b>{title}</b>
|
||||||
|
</Typography>
|
||||||
|
<P8PDataGrid
|
||||||
|
{...P8P_DATA_GRID_CONFIG_PROPS}
|
||||||
|
containerComponentProps={{ sx: STYLES.TABLE_DETAILS, elevation: 0 }}
|
||||||
|
columnsDef={data.columnsDef}
|
||||||
|
rows={data.rows}
|
||||||
|
size={P8P_DATA_GRID_SIZE.SMALL}
|
||||||
|
morePages={data.morePages}
|
||||||
|
fixedHeader={true}
|
||||||
|
reloading={false}
|
||||||
|
dataCellRender={dataCellRender}
|
||||||
|
headCellRender={headCellRender}
|
||||||
|
onOrderChanged={handleOrderChanged}
|
||||||
|
onPagesCountChanged={handlePagesCountChanged}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
//Контроль свойств - Таблица детализации изделия
|
||||||
|
ProductDetailsTable.propTypes = {
|
||||||
|
plan: PropTypes.number.isRequired,
|
||||||
|
product: PropTypes.number,
|
||||||
|
stored: PropTypes.string.isRequired,
|
||||||
|
noProductMessage: PropTypes.string.isRequired,
|
||||||
|
noDataFoundMessage: PropTypes.string.isRequired,
|
||||||
|
title: PropTypes.string.isRequired
|
||||||
|
};
|
||||||
|
|
||||||
|
//-----------
|
||||||
|
//Тело модуля
|
||||||
|
//-----------
|
||||||
|
|
||||||
|
//Детализация по объекту
|
||||||
|
const PlanDetail = ({ plan, disableNavigatePrev = false, disableNavigateNext = false, onNavigate, onBack }) => {
|
||||||
|
//Собственное состояние - данные производственных составов SVG
|
||||||
|
const [costProductComposition, setCostProductComposition] = useCostProductComposition(plan.NRN);
|
||||||
|
|
||||||
|
//Формируем представление
|
||||||
|
return (
|
||||||
|
<Container maxWidth={false} sx={STYLES.CARD_DETAILS_CONTAINER}>
|
||||||
|
<Grid container direction="row" justifyContent="center" alignItems="center" spacing={0}>
|
||||||
|
<Grid item display="flex" justifyContent="center" xs={1}>
|
||||||
|
<Stack display="flex" direction="row" justifyContent="flex-end" alignItems="center" sx={STYLES.CARD_DETAILS_NAVIGATION_STACK}>
|
||||||
|
<IconButton disabled={disableNavigatePrev} onClick={() => (onNavigate ? onNavigate(-1) : null)}>
|
||||||
|
<Icon>navigate_before</Icon>
|
||||||
|
</IconButton>
|
||||||
|
</Stack>
|
||||||
|
</Grid>
|
||||||
|
<Grid item xs={10}>
|
||||||
|
<Container maxWidth={false}>
|
||||||
|
<Button onClick={() => (onBack ? onBack() : null)}>
|
||||||
|
<Stack direction="row">
|
||||||
|
<Icon>chevron_left</Icon>Назад
|
||||||
|
</Stack>
|
||||||
|
</Button>
|
||||||
|
|
||||||
|
<Grid container spacing={2} sx={{ paddingTop: "5px" }}>
|
||||||
|
<Grid item xs={5}>
|
||||||
|
<Box sx={STYLES.BOX_INFO_MAIN}>
|
||||||
|
<ProductDetailsTable
|
||||||
|
plan={plan.NRN}
|
||||||
|
product={costProductComposition.selectedProduct?.NRN}
|
||||||
|
stored={"PKG_P8PANELS_MECHREC.FCROUTLST_DG_BY_PRDCMPSP_GET"}
|
||||||
|
noProductMessage={"Укажите элемент модели, чтобы увидеть информацию о маршрутных картах"}
|
||||||
|
noDataFoundMessage={"Маршрутные карты не найдены"}
|
||||||
|
title={"Маршрутные карты"}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
<Box sx={STYLES.BOX_INFO_MAIN} mt={2}>
|
||||||
|
<ProductDetailsTable
|
||||||
|
plan={plan.NRN}
|
||||||
|
product={costProductComposition.selectedProduct?.NRN}
|
||||||
|
stored={"PKG_P8PANELS_MECHREC.FCDELIVSH_DG_BY_PRDCMPSP_GET"}
|
||||||
|
noProductMessage={"Укажите элемент модели, чтобы увидеть информацию о комплектовочных ведомостях"}
|
||||||
|
noDataFoundMessage={"Комплектовочные ведомости не найдены"}
|
||||||
|
title={"Дефицит комплектации"}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
</Grid>
|
||||||
|
<Grid item xs={7}>
|
||||||
|
<Box sx={STYLES.DETAIL_INFO}>
|
||||||
|
<PlanInfo plan={plan} />
|
||||||
|
</Box>
|
||||||
|
<Box sx={STYLES.PRODUCT_SELECTOR_CONTAINER}>
|
||||||
|
<PlanProductCompositionModel
|
||||||
|
model={costProductComposition.model}
|
||||||
|
products={costProductComposition.products}
|
||||||
|
setCostProductComposition={setCostProductComposition}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
</Container>
|
||||||
|
</Grid>
|
||||||
|
<Grid item display="flex" justifyContent="center" xs={1}>
|
||||||
|
<Stack display="flex" direction="row" justifyContent="flex-start" alignItems="center" sx={STYLES.CARD_DETAILS_NAVIGATION_STACK}>
|
||||||
|
<IconButton disabled={disableNavigateNext} onClick={() => (onNavigate ? onNavigate(1) : null)}>
|
||||||
|
<Icon>navigate_next</Icon>
|
||||||
|
</IconButton>
|
||||||
|
</Stack>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
</Container>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
//Контроль свойств - Детализация по объекту
|
||||||
|
PlanDetail.propTypes = {
|
||||||
|
plan: PropTypes.object,
|
||||||
|
disableNavigatePrev: PropTypes.bool,
|
||||||
|
disableNavigateNext: PropTypes.bool,
|
||||||
|
onNavigate: PropTypes.func,
|
||||||
|
onBack: PropTypes.func
|
||||||
|
};
|
||||||
|
|
||||||
|
//----------------
|
||||||
|
//Интерфейс модуля
|
||||||
|
//----------------
|
||||||
|
|
||||||
|
export { PlanDetail };
|
83
app/panels/mech_rec_assembly_mon/components/plans_list.js
Normal file
83
app/panels/mech_rec_assembly_mon/components/plans_list.js
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
/*
|
||||||
|
Парус 8 - Панели мониторинга - ПУП - Мониторинг сборки изделий
|
||||||
|
Компонент: Список планов
|
||||||
|
*/
|
||||||
|
|
||||||
|
//---------------------
|
||||||
|
//Подключение библиотек
|
||||||
|
//---------------------
|
||||||
|
|
||||||
|
import React, { useState } from "react"; //Классы React
|
||||||
|
import { Container, Grid, IconButton, Icon } from "@mui/material"; //Интерфейсные элементы
|
||||||
|
import PropTypes from "prop-types"; //Контроль свойств компонента
|
||||||
|
import { PlansListItem } from "./plans_list_item"; //Элемент списка планов
|
||||||
|
|
||||||
|
//---------
|
||||||
|
//Константы
|
||||||
|
//---------
|
||||||
|
|
||||||
|
//Количество одновременно отображаемых элементов списка по умолчанию
|
||||||
|
const DEFAULT_PAGE_SIZE = 5;
|
||||||
|
|
||||||
|
//Стили
|
||||||
|
const STYLES = {
|
||||||
|
PLAN_DOCUMENTS_LIST: { minWidth: "1024px" }
|
||||||
|
};
|
||||||
|
|
||||||
|
//-----------
|
||||||
|
//Тело модуля
|
||||||
|
//-----------
|
||||||
|
|
||||||
|
//Список планов
|
||||||
|
const PlansList = ({ plans, pageSize = DEFAULT_PAGE_SIZE, onItemClick }) => {
|
||||||
|
//Состояние прокрутки списка отображаемых планов
|
||||||
|
const [scroll, setScroll] = useState(0);
|
||||||
|
|
||||||
|
//Отработка нажатия на прокрутку списка планов влево
|
||||||
|
const handleScrollLeft = () => setScroll(pv => (pv <= 1 ? 0 : pv - 1));
|
||||||
|
|
||||||
|
//Отработка нажатия на прокрутку списка планов вправо
|
||||||
|
const handleScrollRight = () => setScroll(pv => (pv + pageSize >= plans.length ? pv : pv + 1));
|
||||||
|
|
||||||
|
//Сборка представления
|
||||||
|
return (
|
||||||
|
<Container>
|
||||||
|
<Grid container direction="row" justifyContent="center" alignItems="center" spacing={2} sx={STYLES.PLAN_DOCUMENTS_LIST}>
|
||||||
|
<Grid item display="flex" justifyContent="center" xs={1}>
|
||||||
|
<IconButton onClick={handleScrollLeft} disabled={scroll <= 0}>
|
||||||
|
<Icon>navigate_before</Icon>
|
||||||
|
</IconButton>
|
||||||
|
</Grid>
|
||||||
|
{plans.map((el, i) =>
|
||||||
|
i >= scroll && i < scroll + pageSize ? (
|
||||||
|
<Grid item key={`${el.NRN}_${i}`} xs={2}>
|
||||||
|
<PlansListItem
|
||||||
|
card={el}
|
||||||
|
cardIndex={i}
|
||||||
|
onClick={(card, cardIndex) => (onItemClick ? onItemClick(card, cardIndex) : null)}
|
||||||
|
/>
|
||||||
|
</Grid>
|
||||||
|
) : null
|
||||||
|
)}
|
||||||
|
<Grid item display="flex" justifyContent="center" xs={1}>
|
||||||
|
<IconButton onClick={handleScrollRight} disabled={scroll + pageSize >= plans.length}>
|
||||||
|
<Icon>navigate_next</Icon>
|
||||||
|
</IconButton>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
</Container>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
//Контроль свойств - Список планов
|
||||||
|
PlansList.propTypes = {
|
||||||
|
plans: PropTypes.arrayOf(PropTypes.object),
|
||||||
|
pageSize: PropTypes.number,
|
||||||
|
onItemClick: PropTypes.func
|
||||||
|
};
|
||||||
|
|
||||||
|
//----------------
|
||||||
|
//Интерфейс модуля
|
||||||
|
//----------------
|
||||||
|
|
||||||
|
export { PlansList };
|
108
app/panels/mech_rec_assembly_mon/components/plans_list_item.js
Normal file
108
app/panels/mech_rec_assembly_mon/components/plans_list_item.js
Normal file
@ -0,0 +1,108 @@
|
|||||||
|
/*
|
||||||
|
Парус 8 - Панели мониторинга - ПУП - Мониторинг сборки изделий
|
||||||
|
Компонент: Элемент списка планов
|
||||||
|
*/
|
||||||
|
|
||||||
|
//---------------------
|
||||||
|
//Подключение библиотек
|
||||||
|
//---------------------
|
||||||
|
|
||||||
|
import React from "react"; //Классы React
|
||||||
|
import PropTypes from "prop-types"; //Контроль свойств компонента
|
||||||
|
import { Typography, Box, ImageList, ImageListItem, Icon } from "@mui/material"; //Интерфейсные элементы
|
||||||
|
import { ProgressBox } from "./progress_box"; //Информация по прогрессу объекта
|
||||||
|
|
||||||
|
//---------
|
||||||
|
//Константы
|
||||||
|
//---------
|
||||||
|
|
||||||
|
//Стили
|
||||||
|
const STYLES = {
|
||||||
|
CONTAINER: {
|
||||||
|
display: "flex",
|
||||||
|
justifyContent: "center",
|
||||||
|
alignItems: "center",
|
||||||
|
flexDirection: "column",
|
||||||
|
gap: "24px",
|
||||||
|
border: "1px solid",
|
||||||
|
borderRadius: "25px",
|
||||||
|
cursor: "pointer"
|
||||||
|
},
|
||||||
|
IMAGE_BOX: { width: "180px", height: "180px", alignItems: "center", justifyContent: "center", display: "flex" },
|
||||||
|
IMAGE_LIST_ITEM: { textAlign: "center" },
|
||||||
|
IMAGE_IMG: { width: "160px" }
|
||||||
|
};
|
||||||
|
|
||||||
|
//------------------------------------
|
||||||
|
//Вспомогательные функции и компоненты
|
||||||
|
//------------------------------------
|
||||||
|
|
||||||
|
//Изображение для элемента
|
||||||
|
const PlansListItemImage = ({ card }) => {
|
||||||
|
return (
|
||||||
|
<Box sx={STYLES.IMAGE_BOX}>
|
||||||
|
<ImageList variant="masonry" cols={1} gap={8}>
|
||||||
|
<ImageListItem key={1} sx={STYLES.IMAGE_LIST_ITEM}>
|
||||||
|
{card["BIMAGE"] ? (
|
||||||
|
<img src={`data:image/png;base64,${card["BIMAGE"]}`} loading="lazy" style={STYLES.IMAGE_IMG} />
|
||||||
|
) : (
|
||||||
|
<Icon sx={{ fontSize: "5rem" }}>construction</Icon>
|
||||||
|
)}
|
||||||
|
</ImageListItem>
|
||||||
|
</ImageList>
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
//Контроль свойств - Изображение для элемента
|
||||||
|
PlansListItemImage.propTypes = {
|
||||||
|
card: PropTypes.object
|
||||||
|
};
|
||||||
|
|
||||||
|
//-----------
|
||||||
|
//Тело модуля
|
||||||
|
//-----------
|
||||||
|
|
||||||
|
//Элемент списка планов
|
||||||
|
const PlansListItem = ({ card, cardIndex, onClick }) => {
|
||||||
|
return (
|
||||||
|
<Box sx={STYLES.CONTAINER} onClick={() => (onClick ? onClick(card, cardIndex) : null)}>
|
||||||
|
<PlansListItemImage card={card} />
|
||||||
|
<Box textAlign="center">
|
||||||
|
<Typography variant="UDO_body1" color="text.secondary.fontColor">
|
||||||
|
Номер борта
|
||||||
|
</Typography>
|
||||||
|
<Typography variant="h2">{card.SNUMB}</Typography>
|
||||||
|
</Box>
|
||||||
|
<ProgressBox
|
||||||
|
progress={card.NPROGRESS}
|
||||||
|
detail={card.SDETAIL}
|
||||||
|
width={"155px"}
|
||||||
|
height={"155px"}
|
||||||
|
progressVariant={"h3"}
|
||||||
|
detailVariant={"UDO_body2"}
|
||||||
|
/>
|
||||||
|
<Box>
|
||||||
|
<Typography variant="UDO_body1" color="text.secondary.fontColor">
|
||||||
|
Год выпуска:
|
||||||
|
</Typography>
|
||||||
|
<Typography variant="subtitle1" mt={-1}>
|
||||||
|
{card.NYEAR}
|
||||||
|
</Typography>
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
//Контроль свойств - Элемент списка планов
|
||||||
|
PlansListItem.propTypes = {
|
||||||
|
card: PropTypes.object,
|
||||||
|
cardIndex: PropTypes.number,
|
||||||
|
onClick: PropTypes.func
|
||||||
|
};
|
||||||
|
|
||||||
|
//----------------
|
||||||
|
//Интерфейс модуля
|
||||||
|
//----------------
|
||||||
|
|
||||||
|
export { PlansListItem };
|
75
app/panels/mech_rec_assembly_mon/components/progress_box.js
Normal file
75
app/panels/mech_rec_assembly_mon/components/progress_box.js
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
/*
|
||||||
|
Парус 8 - Панели мониторинга - ПУП - Мониторинг сборки изделий
|
||||||
|
Компонент: Информация по прогрессу объекта
|
||||||
|
*/
|
||||||
|
|
||||||
|
//---------------------
|
||||||
|
//Подключение библиотек
|
||||||
|
//---------------------
|
||||||
|
|
||||||
|
import React from "react"; //Классы React
|
||||||
|
import PropTypes from "prop-types"; //Контроль свойств компонента
|
||||||
|
import { Typography, Box } from "@mui/material"; //Интерфейсные элементы
|
||||||
|
|
||||||
|
//---------
|
||||||
|
//Константы
|
||||||
|
//---------
|
||||||
|
|
||||||
|
//Стили
|
||||||
|
const STYLES = {
|
||||||
|
PROGRESS_BOX: (width, height) => ({
|
||||||
|
display: "flex",
|
||||||
|
justifyContent: "center",
|
||||||
|
alignItems: "center",
|
||||||
|
flexDirection: "column",
|
||||||
|
margin: "0px 32px",
|
||||||
|
borderRadius: "50%",
|
||||||
|
...(width ? { width } : {}),
|
||||||
|
...(height ? { height } : {})
|
||||||
|
})
|
||||||
|
};
|
||||||
|
|
||||||
|
//-----------
|
||||||
|
//Тело модуля
|
||||||
|
//-----------
|
||||||
|
|
||||||
|
//Информация по прогрессу объекта
|
||||||
|
const ProgressBox = ({ progress, detail, width, height, progressVariant, detailVariant }) => {
|
||||||
|
//Определяем цвет тени
|
||||||
|
let boxShadow = "0 0 30px #d3d3d3";
|
||||||
|
switch (true) {
|
||||||
|
case progress >= 70:
|
||||||
|
boxShadow = "0 0 30px #21d21e66";
|
||||||
|
break;
|
||||||
|
case progress >= 40:
|
||||||
|
boxShadow = "0 0 30px #fddd3566";
|
||||||
|
break;
|
||||||
|
case progress >= 10:
|
||||||
|
boxShadow = "0 0 30px #ea5c4966";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Возвращаем содержимое
|
||||||
|
return (
|
||||||
|
<Box sx={STYLES.PROGRESS_BOX(width, height)} boxShadow={boxShadow}>
|
||||||
|
<Typography variant={progressVariant}>{`${progress}%`}</Typography>
|
||||||
|
<Typography variant={detailVariant}>{detail}</Typography>
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
//Контроль свойств - Информация по прогрессу объекта
|
||||||
|
ProgressBox.propTypes = {
|
||||||
|
progress: PropTypes.number,
|
||||||
|
detail: PropTypes.string,
|
||||||
|
width: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
|
||||||
|
height: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
|
||||||
|
progressVariant: PropTypes.string,
|
||||||
|
detailVariant: PropTypes.string
|
||||||
|
};
|
||||||
|
|
||||||
|
//----------------
|
||||||
|
//Интерфейс модуля
|
||||||
|
//----------------
|
||||||
|
|
||||||
|
export { ProgressBox };
|
@ -1,76 +0,0 @@
|
|||||||
/*
|
|
||||||
Парус 8 - Панели мониторинга - ПУП - Мониторинг сборки изделий
|
|
||||||
Панель мониторинга: Блок информации по прогрессу объекта
|
|
||||||
*/
|
|
||||||
|
|
||||||
//---------------------
|
|
||||||
//Подключение библиотек
|
|
||||||
//---------------------
|
|
||||||
|
|
||||||
import React from "react"; //Классы React
|
|
||||||
import PropTypes from "prop-types"; //Контроль свойств компонента
|
|
||||||
import { Typography, Box } from "@mui/material"; //Интерфейсные элементы
|
|
||||||
|
|
||||||
//---------
|
|
||||||
//Константы
|
|
||||||
//---------
|
|
||||||
|
|
||||||
//Стили
|
|
||||||
const STYLES = {
|
|
||||||
PROGRESS_INFO: {
|
|
||||||
display: "flex",
|
|
||||||
justifyContent: "center",
|
|
||||||
alignItems: "center",
|
|
||||||
flexDirection: "column",
|
|
||||||
margin: "0px 32px",
|
|
||||||
borderRadius: "50%"
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
//------------------------------------
|
|
||||||
//Вспомогательные функции и компоненты
|
|
||||||
//------------------------------------
|
|
||||||
|
|
||||||
//-----------
|
|
||||||
//Тело модуля
|
|
||||||
//-----------
|
|
||||||
|
|
||||||
//Детализация по объекту
|
|
||||||
|
|
||||||
//Блок информации по прогрессу объекта
|
|
||||||
const ProgressBox = ({ prms }) => {
|
|
||||||
//Инициализируем цвет тени
|
|
||||||
let boxShadow = null;
|
|
||||||
//Определяем цвет тени
|
|
||||||
switch (true) {
|
|
||||||
case prms.NPROGRESS >= 70:
|
|
||||||
boxShadow = "0 0 30px #21d21e66";
|
|
||||||
break;
|
|
||||||
case prms.NPROGRESS >= 40:
|
|
||||||
boxShadow = "0 0 30px #fddd3566";
|
|
||||||
break;
|
|
||||||
case prms.NPROGRESS >= 10:
|
|
||||||
boxShadow = "0 0 30px #ea5c4966";
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
boxShadow = "0 0 30px #d3d3d3";
|
|
||||||
}
|
|
||||||
//Возвращаем блок
|
|
||||||
return (
|
|
||||||
<Box sx={{ ...STYLES.PROGRESS_INFO, width: prms.width, height: prms.height }} boxShadow={boxShadow}>
|
|
||||||
<Typography variant={prms.progressVariant}>{`${prms.NPROGRESS}%`}</Typography>
|
|
||||||
<Typography variant={prms.detailVariant}>{prms.SDETAIL}</Typography>
|
|
||||||
</Box>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
//Контроль свойств - Блок информации по прогрессу объекта
|
|
||||||
ProgressBox.propTypes = {
|
|
||||||
prms: PropTypes.object
|
|
||||||
};
|
|
||||||
|
|
||||||
//----------------
|
|
||||||
//Интерфейс модуля
|
|
||||||
//----------------
|
|
||||||
|
|
||||||
export { ProgressBox };
|
|
@ -9,26 +9,12 @@
|
|||||||
|
|
||||||
import React, { useState, useContext } from "react"; //Классы React
|
import React, { useState, useContext } from "react"; //Классы React
|
||||||
import PropTypes from "prop-types"; //Контроль свойств компонента
|
import PropTypes from "prop-types"; //Контроль свойств компонента
|
||||||
import {
|
import { Drawer, Fab, Box, List, ListItemButton, ListItemText, Typography, TextField, FormGroup, FormControlLabel, Checkbox } from "@mui/material"; //Интерфейсные элементы
|
||||||
Drawer,
|
|
||||||
Fab,
|
|
||||||
Box,
|
|
||||||
List,
|
|
||||||
ListItemButton,
|
|
||||||
ListItemText,
|
|
||||||
Typography,
|
|
||||||
Grid,
|
|
||||||
TextField,
|
|
||||||
FormGroup,
|
|
||||||
FormControlLabel,
|
|
||||||
Checkbox,
|
|
||||||
Container
|
|
||||||
} from "@mui/material"; //Интерфейсные элементы
|
|
||||||
import { ThemeProvider } from "@mui/material/styles"; //Подключение темы
|
import { ThemeProvider } from "@mui/material/styles"; //Подключение темы
|
||||||
import { MessagingСtx } from "../../context/messaging"; //Контекст сообщений
|
import { MessagingСtx } from "../../context/messaging"; //Контекст сообщений
|
||||||
import { CardBlock } from "./blocks/cardBlock"; //Информация об объекте
|
import { PlansList } from "./components/plans_list"; //Список планов
|
||||||
import { CardDetail } from "./blocks/cardDetail"; //Детализация по объекту
|
import { PlanDetail } from "./components/plan_detail"; //Детали плана
|
||||||
import { theme } from "./styles/themes.js"; //Стиль темы
|
import { theme } from "./styles/themes"; //Стиль темы
|
||||||
import { useFilteredPlanCtlgs } from "./hooks"; //Вспомогательные хуки
|
import { useFilteredPlanCtlgs } from "./hooks"; //Вспомогательные хуки
|
||||||
import { useMechRecAssemblyMon } from "./backend"; //Хук корневой панели мониторинга сборки изделий
|
import { useMechRecAssemblyMon } from "./backend"; //Хук корневой панели мониторинга сборки изделий
|
||||||
|
|
||||||
@ -49,7 +35,8 @@ const STYLES = {
|
|||||||
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" }
|
||||||
}
|
},
|
||||||
|
PLANS_LIST_BOX: { paddingTop: "20px" }
|
||||||
};
|
};
|
||||||
|
|
||||||
//------------------------------------
|
//------------------------------------
|
||||||
@ -131,11 +118,18 @@ PlanCtlgsList.propTypes = {
|
|||||||
//Корневая панель мониторинга сборки изделий
|
//Корневая панель мониторинга сборки изделий
|
||||||
const MechRecAssemblyMon = () => {
|
const MechRecAssemblyMon = () => {
|
||||||
//Собственное состояние
|
//Собственное состояние
|
||||||
const [state, setState, selectPlan, unselectPlan] = useMechRecAssemblyMon();
|
const [state, setState, selectPlanCtlg, unselectPlanCtlg] = useMechRecAssemblyMon();
|
||||||
|
|
||||||
//Состояние для фильтра каталогов
|
//Состояние фильтра каталогов
|
||||||
const [filter, setFilter] = useState({ ctlgName: "", haveDocs: false });
|
const [filter, setFilter] = useState({ ctlgName: "", haveDocs: false });
|
||||||
|
|
||||||
|
//Состояние навигации по карточкам детализации
|
||||||
|
const [planDetailNavigation, setPlanDetailNavigation] = useState({
|
||||||
|
disableNavigatePrev: false,
|
||||||
|
disableNavigateNext: false,
|
||||||
|
currentPlanIndex: 0
|
||||||
|
});
|
||||||
|
|
||||||
//Массив отфильтрованных каталогов
|
//Массив отфильтрованных каталогов
|
||||||
const filteredPlanCtgls = useFilteredPlanCtlgs(state.planCtlgs, filter);
|
const filteredPlanCtgls = useFilteredPlanCtlgs(state.planCtlgs, filter);
|
||||||
|
|
||||||
@ -143,24 +137,38 @@ const MechRecAssemblyMon = () => {
|
|||||||
const { InlineMsgInfo } = useContext(MessagingСtx);
|
const { InlineMsgInfo } = useContext(MessagingСtx);
|
||||||
|
|
||||||
//Обработка нажатия на элемент в списке каталогов планов
|
//Обработка нажатия на элемент в списке каталогов планов
|
||||||
const handleProjectClick = project => {
|
const handlePlanCtlgClick = planCtlg => {
|
||||||
if (state.selectedPlanCtlg.NRN != project.NRN) selectPlan(project);
|
if (state.selectedPlanCtlg.NRN != planCtlg.NRN) selectPlanCtlg(planCtlg);
|
||||||
else unselectPlan();
|
else unselectPlanCtlg();
|
||||||
};
|
};
|
||||||
|
|
||||||
//Обработка нажатия на карточку объекта
|
//Перемещение к нужному плану
|
||||||
const handleCardClick = plan => {
|
const navigateToPlan = planIndex => {
|
||||||
|
if (planIndex < 0) planIndex = 0;
|
||||||
|
if (planIndex > state.plans.length - 1) planIndex = state.plans.length - 1;
|
||||||
setState(pv => ({
|
setState(pv => ({
|
||||||
...pv,
|
...pv,
|
||||||
selectedPlan: { NRN: plan.NRN, SNUMB: plan.SNUMB, NPROGRESS: plan.NPROGRESS, SDETAIL: plan.SDETAIL, NYEAR: plan.NYEAR }
|
selectedPlan: { ...state.plans[planIndex] }
|
||||||
|
}));
|
||||||
|
setPlanDetailNavigation(pv => ({
|
||||||
|
...pv,
|
||||||
|
disableNavigatePrev: planIndex == 0 ? true : false,
|
||||||
|
disableNavigateNext: planIndex == state.plans.length - 1 ? true : false,
|
||||||
|
currentPlanIndex: planIndex
|
||||||
}));
|
}));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
//Обработка нажатия на документ плана
|
||||||
|
const handlePlanClick = (plan, planIndex) => navigateToPlan(planIndex);
|
||||||
|
|
||||||
//Обработка нажатия на кнопку "Назад"
|
//Обработка нажатия на кнопку "Назад"
|
||||||
const handleBackClick = () => {
|
const handlePlanDetailBackClick = () => {
|
||||||
setState(pv => ({ ...pv, selectedPlan: { NRN: null, SNUMB: null, NPROGRESS: null, SDETAIL: null, NYEAR: null } }));
|
setState(pv => ({ ...pv, selectedPlan: {} }));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
//Обработка навигации из карточки с деталями плана
|
||||||
|
const handlePlanDetailNavigateClick = direction => navigateToPlan(planDetailNavigation.currentPlanIndex + direction);
|
||||||
|
|
||||||
//Генерация содержимого
|
//Генерация содержимого
|
||||||
return (
|
return (
|
||||||
<Box p={2}>
|
<Box p={2}>
|
||||||
@ -179,34 +187,30 @@ const MechRecAssemblyMon = () => {
|
|||||||
selectedPlanCtlg={state.selectedPlanCtlg.NRN}
|
selectedPlanCtlg={state.selectedPlanCtlg.NRN}
|
||||||
filter={filter}
|
filter={filter}
|
||||||
setFilter={setFilter}
|
setFilter={setFilter}
|
||||||
onClick={handleProjectClick}
|
onClick={handlePlanCtlgClick}
|
||||||
/>
|
/>
|
||||||
</Drawer>
|
</Drawer>
|
||||||
{state.init == true ? (
|
{state.init == true ? (
|
||||||
state.selectedPlanCtlg.NRN ? (
|
state.selectedPlanCtlg.NRN ? (
|
||||||
<>
|
<>
|
||||||
<Typography variant="h1" align="center" py={3}>
|
<Typography variant="h3" align="center" color="text.title.fontColor" py={2}>
|
||||||
{`${state.selectedPlanCtlg.SNAME} на ${state.selectedPlanCtlg.NMIN_YEAR}г. - ${state.selectedPlanCtlg.NMAX_YEAR}г.`}
|
{`${state.selectedPlanCtlg.SNAME} ${
|
||||||
|
state.selectedPlanCtlg.NMIN_YEAR ? `с ${state.selectedPlanCtlg.NMIN_YEAR} г` : ""
|
||||||
|
} ${state.selectedPlanCtlg.NMAX_YEAR ? `по ${state.selectedPlanCtlg.NMAX_YEAR}` : ""}`}
|
||||||
</Typography>
|
</Typography>
|
||||||
{state.plansLoaded == true ? (
|
{state.plansLoaded == true ? (
|
||||||
state.selectedPlan.NRN ? (
|
state.selectedPlan.NRN ? (
|
||||||
<CardDetail card={state.selectedPlan} handleBackClick={handleBackClick} />
|
<PlanDetail
|
||||||
|
plan={state.selectedPlan}
|
||||||
|
disableNavigatePrev={planDetailNavigation.disableNavigatePrev}
|
||||||
|
disableNavigateNext={planDetailNavigation.disableNavigateNext}
|
||||||
|
onNavigate={handlePlanDetailNavigateClick}
|
||||||
|
onBack={handlePlanDetailBackClick}
|
||||||
|
/>
|
||||||
) : (
|
) : (
|
||||||
<Container>
|
<Box sx={STYLES.PLANS_LIST_BOX}>
|
||||||
<Grid container spacing={5}>
|
<PlansList plans={state.plans} onItemClick={handlePlanClick} />
|
||||||
{state.plans.map(el => (
|
</Box>
|
||||||
<Grid
|
|
||||||
item
|
|
||||||
xs={state.plans.length >= 5 ? 2.4 : 12 / state.plans.length}
|
|
||||||
key={el.NRN}
|
|
||||||
display="flex"
|
|
||||||
justifyContent="center"
|
|
||||||
>
|
|
||||||
<CardBlock card={el} handleCardClick={handleCardClick} />
|
|
||||||
</Grid>
|
|
||||||
))}
|
|
||||||
</Grid>
|
|
||||||
</Container>
|
|
||||||
)
|
)
|
||||||
) : null}
|
) : null}
|
||||||
</>
|
</>
|
||||||
|
@ -4,6 +4,7 @@ import { createTheme } from "@mui/material/styles"; //Интерфейсные
|
|||||||
const theme = createTheme({
|
const theme = createTheme({
|
||||||
palette: {
|
palette: {
|
||||||
text: {
|
text: {
|
||||||
|
title: { fontColor: "rgba(0, 0, 0, 0.65)" },
|
||||||
secondary: { fontColor: "rgba(0, 0, 0, 0.298)" }
|
secondary: { fontColor: "rgba(0, 0, 0, 0.298)" }
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
Loading…
x
Reference in New Issue
Block a user