forked from CITKParus/P8-Panels
ЦИТК-826, ЦИТК-827, ЦИТК-828, ЦИТК-841 - Добавление новых панелей
This commit is contained in:
parent
852a083a3b
commit
140e255904
341
app/panels/mech_rec_assembly_mon/backend.js
Normal file
341
app/panels/mech_rec_assembly_mon/backend.js
Normal file
@ -0,0 +1,341 @@
|
|||||||
|
//---------------------
|
||||||
|
//Подключение библиотек
|
||||||
|
//---------------------
|
||||||
|
|
||||||
|
import { useState, useCallback, useEffect, useContext } from "react"; //Классы React
|
||||||
|
import { BackEndСtx } from "../../context/backend"; //Контекст взаимодействия с сервером
|
||||||
|
import { object2Base64XML } from "../../core/utils"; //Вспомогательные функции
|
||||||
|
|
||||||
|
//---------
|
||||||
|
//Константы
|
||||||
|
//---------
|
||||||
|
|
||||||
|
//Размер страницы данных
|
||||||
|
const DATA_GRID_PAGE_SIZE = 10;
|
||||||
|
|
||||||
|
//-----------
|
||||||
|
//Тело модуля
|
||||||
|
//-----------
|
||||||
|
|
||||||
|
//Хук для основной таблицы панели
|
||||||
|
const useMechRecAssemblyMon = () => {
|
||||||
|
//Собственное состояние
|
||||||
|
let [state, setState] = useState({
|
||||||
|
init: false,
|
||||||
|
showPlanList: false,
|
||||||
|
planCtlgs: [],
|
||||||
|
planCtlgsLoaded: false,
|
||||||
|
selectedPlanCtlg: { NRN: null, SNAME: null, NMIN_YEAR: null, NMAX_YEAR: null },
|
||||||
|
plans: [],
|
||||||
|
plansLoaded: false,
|
||||||
|
selectedPlan: { NRN: null, SNUMB: null, NPROGRESS: null, SDETAIL: null, NYEAR: null }
|
||||||
|
});
|
||||||
|
|
||||||
|
//Подключение к контексту взаимодействия с сервером
|
||||||
|
const { executeStored } = useContext(BackEndСtx);
|
||||||
|
|
||||||
|
//Инициализация каталогов планов
|
||||||
|
const initPlanCtlgs = useCallback(async () => {
|
||||||
|
if (!state.init) {
|
||||||
|
const data = await executeStored({
|
||||||
|
stored: "PKG_P8PANELS_MECHREC.FCPRODPLAN_CTLG_INIT",
|
||||||
|
args: {},
|
||||||
|
respArg: "COUT",
|
||||||
|
isArray: name => name === "XFCPRODPLAN_CRNS"
|
||||||
|
});
|
||||||
|
setState(pv => ({ ...pv, init: true, planCtlgs: [...(data?.XFCPRODPLAN_CRNS || [])], planCtlgsLoaded: true }));
|
||||||
|
}
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
|
}, [state.init, executeStored]);
|
||||||
|
|
||||||
|
//Получение информации о планах каталога
|
||||||
|
const loadPlans = useCallback(
|
||||||
|
async NCRN => {
|
||||||
|
if (NCRN) {
|
||||||
|
const data = await executeStored({
|
||||||
|
stored: "PKG_P8PANELS_MECHREC.FCPRODPLAN_GET",
|
||||||
|
args: { NCRN: NCRN },
|
||||||
|
respArg: "COUT",
|
||||||
|
isArray: name => name === "XFCPRODPLAN_INFO"
|
||||||
|
});
|
||||||
|
setState(pv => ({ ...pv, init: true, plans: [...(data?.XFCPRODPLAN_INFO || [])], plansLoaded: true }));
|
||||||
|
}
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
|
},
|
||||||
|
[executeStored]
|
||||||
|
);
|
||||||
|
|
||||||
|
//Выбор каталога планов
|
||||||
|
const selectPlan = project => {
|
||||||
|
setState(pv => ({
|
||||||
|
...pv,
|
||||||
|
selectedPlanCtlg: project,
|
||||||
|
showPlanList: false
|
||||||
|
}));
|
||||||
|
};
|
||||||
|
|
||||||
|
//Сброс выбора каталога планов
|
||||||
|
const unselectPlan = () =>
|
||||||
|
setState(pv => ({
|
||||||
|
...pv,
|
||||||
|
selectedPlanCtlg: { NRN: null, SNAME: null, NMIN_YEAR: null, NMAX_YEAR: null },
|
||||||
|
showPlanList: false
|
||||||
|
}));
|
||||||
|
|
||||||
|
//При подключении компонента к странице
|
||||||
|
useEffect(() => {
|
||||||
|
initPlanCtlgs();
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
//При изменении каталога
|
||||||
|
useEffect(() => {
|
||||||
|
//Если каталог выбран
|
||||||
|
if (state.selectedPlanCtlg) {
|
||||||
|
loadPlans(state.selectedPlanCtlg.NRN);
|
||||||
|
} else {
|
||||||
|
setState(pv => ({ ...pv, plans: [], plansLoaded: false }));
|
||||||
|
}
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
|
}, [state.selectedPlanCtlg]);
|
||||||
|
|
||||||
|
return [state, setState, selectPlan, unselectPlan];
|
||||||
|
};
|
||||||
|
|
||||||
|
//Хук для информации по производственным составам
|
||||||
|
const useCostProductComposition = nProdPlan => {
|
||||||
|
//Собственное состояние
|
||||||
|
let [costProductComposition, setCostProductComposition] = useState({
|
||||||
|
init: false,
|
||||||
|
showPlanList: false,
|
||||||
|
products: [],
|
||||||
|
selectedProduct: null
|
||||||
|
});
|
||||||
|
|
||||||
|
//Подключение к контексту взаимодействия с сервером
|
||||||
|
const { executeStored } = useContext(BackEndСtx);
|
||||||
|
|
||||||
|
//Инициализация производственных составов
|
||||||
|
const initCostProductComposition = useCallback(async () => {
|
||||||
|
if (!costProductComposition.init) {
|
||||||
|
const data = await executeStored({
|
||||||
|
stored: "PKG_P8PANELS_MECHREC.FCPRODCMP_DETAILS_GET",
|
||||||
|
args: { NFCPRODPLAN: nProdPlan },
|
||||||
|
respArg: "COUT",
|
||||||
|
isArray: name => name === "XFCPRODCMP"
|
||||||
|
});
|
||||||
|
setCostProductComposition(pv => ({ ...pv, init: true, products: [...(data?.XFCPRODCMP || [])], productsLoaded: true }));
|
||||||
|
}
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
|
}, [costProductComposition.init, executeStored]);
|
||||||
|
|
||||||
|
//При подключении компонента к странице
|
||||||
|
useEffect(() => {
|
||||||
|
initCostProductComposition();
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return [costProductComposition, setCostProductComposition];
|
||||||
|
};
|
||||||
|
|
||||||
|
//Хук для таблицы маршрутных листов
|
||||||
|
const useCostRouteLists = (plan, product) => {
|
||||||
|
//Собственное состояние - таблица данных
|
||||||
|
const [costRouteLists, setCostRouteLists] = 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 (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
|
||||||
|
}));
|
||||||
|
//Загружаем данные с учетом выбранного продукта
|
||||||
|
loadData();
|
||||||
|
}
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
|
}, [product]);
|
||||||
|
|
||||||
|
//При необходимости обновить данные таблицы
|
||||||
|
useEffect(() => {
|
||||||
|
//Если продукт указан и необходимо стандартное обновление
|
||||||
|
if (product) {
|
||||||
|
loadData();
|
||||||
|
}
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
|
}, [costDeliverySheets.reload, loadData]);
|
||||||
|
|
||||||
|
//При изменении плана
|
||||||
|
useEffect(() => {
|
||||||
|
setCostDeliverySheets(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 [costDeliverySheets, setCostDeliverySheets];
|
||||||
|
};
|
||||||
|
|
||||||
|
export { useMechRecAssemblyMon, useCostProductComposition, useCostRouteLists, useCostDeliverySheets };
|
102
app/panels/mech_rec_assembly_mon/blocks/cardBlock.js
Normal file
102
app/panels/mech_rec_assembly_mon/blocks/cardBlock.js
Normal file
@ -0,0 +1,102 @@
|
|||||||
|
/*
|
||||||
|
Парус 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 };
|
289
app/panels/mech_rec_assembly_mon/blocks/cardDetail.js
Normal file
289
app/panels/mech_rec_assembly_mon/blocks/cardDetail.js
Normal file
@ -0,0 +1,289 @@
|
|||||||
|
/*
|
||||||
|
Парус 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 };
|
76
app/panels/mech_rec_assembly_mon/elements/progressBox.js
Normal file
76
app/panels/mech_rec_assembly_mon/elements/progressBox.js
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
/*
|
||||||
|
Парус 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 };
|
27
app/panels/mech_rec_assembly_mon/hooks.js
Normal file
27
app/panels/mech_rec_assembly_mon/hooks.js
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
/*
|
||||||
|
Парус 8 - Панели мониторинга - ПУП - Мониторинг сборки изделий
|
||||||
|
Кастомные хуки
|
||||||
|
*/
|
||||||
|
|
||||||
|
//---------------------
|
||||||
|
//Подключение библиотек
|
||||||
|
//---------------------
|
||||||
|
|
||||||
|
import React from "react"; //Классы React
|
||||||
|
|
||||||
|
//-----------
|
||||||
|
//Тело модуля
|
||||||
|
//-----------
|
||||||
|
|
||||||
|
//Клиентский отбор каталогов по поисковой фразе и наличию планов
|
||||||
|
export const useFilteredPlanCtlgs = (planCtlgs, filter) => {
|
||||||
|
const filteredPlanCtlgs = React.useMemo(() => {
|
||||||
|
return planCtlgs.filter(
|
||||||
|
catalog =>
|
||||||
|
catalog.SNAME.toString().toLowerCase().includes(filter.ctlgName) &&
|
||||||
|
(filter.haveDocs ? catalog.NCOUNT_DOCS > 0 : catalog.NCOUNT_DOCS >= 0)
|
||||||
|
);
|
||||||
|
}, [planCtlgs, filter]);
|
||||||
|
|
||||||
|
return filteredPlanCtlgs;
|
||||||
|
};
|
16
app/panels/mech_rec_assembly_mon/index.js
Normal file
16
app/panels/mech_rec_assembly_mon/index.js
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
/*
|
||||||
|
Парус 8 - Панели мониторинга - ПУП - Мониторинг сборки изделий
|
||||||
|
Панель мониторинга: Точка входа
|
||||||
|
*/
|
||||||
|
|
||||||
|
//---------------------
|
||||||
|
//Подключение библиотек
|
||||||
|
//---------------------
|
||||||
|
|
||||||
|
import { MechRecAssemblyMon } from "./mech_rec_assembly_mon"; //Корневая панель мониторинга сборки изделий
|
||||||
|
|
||||||
|
//----------------
|
||||||
|
//Интерфейс модуля
|
||||||
|
//----------------
|
||||||
|
|
||||||
|
export const RootClass = MechRecAssemblyMon;
|
226
app/panels/mech_rec_assembly_mon/mech_rec_assembly_mon.js
Normal file
226
app/panels/mech_rec_assembly_mon/mech_rec_assembly_mon.js
Normal file
@ -0,0 +1,226 @@
|
|||||||
|
/*
|
||||||
|
Парус 8 - Панели мониторинга - ПУП - Мониторинг сборки изделий
|
||||||
|
Панель мониторинга: Корневая панель мониторинга сборки изделий
|
||||||
|
*/
|
||||||
|
|
||||||
|
//---------------------
|
||||||
|
//Подключение библиотек
|
||||||
|
//---------------------
|
||||||
|
|
||||||
|
import React, { useState, useContext } from "react"; //Классы React
|
||||||
|
import PropTypes from "prop-types"; //Контроль свойств компонента
|
||||||
|
import {
|
||||||
|
Drawer,
|
||||||
|
Fab,
|
||||||
|
Box,
|
||||||
|
List,
|
||||||
|
ListItemButton,
|
||||||
|
ListItemText,
|
||||||
|
Typography,
|
||||||
|
Grid,
|
||||||
|
TextField,
|
||||||
|
FormGroup,
|
||||||
|
FormControlLabel,
|
||||||
|
Checkbox,
|
||||||
|
Container
|
||||||
|
} from "@mui/material"; //Интерфейсные элементы
|
||||||
|
import { ThemeProvider } from "@mui/material/styles"; //Подключение темы
|
||||||
|
import { MessagingСtx } from "../../context/messaging"; //Контекст сообщений
|
||||||
|
import { CardBlock } from "./blocks/cardBlock"; //Информация об объекте
|
||||||
|
import { CardDetail } from "./blocks/cardDetail"; //Детализация по объекту
|
||||||
|
import { theme } from "./styles/themes.js"; //Стиль темы
|
||||||
|
import { useFilteredPlanCtlgs } from "./hooks"; //Вспомогательные хуки
|
||||||
|
import { useMechRecAssemblyMon } from "./backend"; //Хук корневой панели мониторинга сборки изделий
|
||||||
|
|
||||||
|
//---------
|
||||||
|
//Константы
|
||||||
|
//---------
|
||||||
|
|
||||||
|
//Стили
|
||||||
|
const STYLES = {
|
||||||
|
PLANS_FINDER: { marginTop: "10px", marginLeft: "10px", width: "93%" },
|
||||||
|
PLANS_CHECKBOX_HAVEDOCS: { alignContent: "space-around" },
|
||||||
|
PLANS_LIST_ITEM_ZERODOCS: { backgroundColor: "#ebecec" },
|
||||||
|
PLANS_LIST_ITEM_PRIMARY: { wordWrap: "break-word" },
|
||||||
|
PLANS_LIST_ITEM_SECONDARY: { wordWrap: "break-word", fontSize: "0.6rem", textTransform: "uppercase" },
|
||||||
|
PLANS_BUTTON: { position: "absolute" },
|
||||||
|
PLANS_DRAWER: {
|
||||||
|
width: "350px",
|
||||||
|
display: "inline-block",
|
||||||
|
flexShrink: 0,
|
||||||
|
[`& .MuiDrawer-paper`]: { width: "350px", display: "inline-block", boxSizing: "border-box" }
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
//------------------------------------
|
||||||
|
//Вспомогательные функции и компоненты
|
||||||
|
//------------------------------------
|
||||||
|
|
||||||
|
//Склонения для документов
|
||||||
|
const DECLINATIONS = ["план", "плана", "планов"];
|
||||||
|
|
||||||
|
//Форматирование для отображения количества документов
|
||||||
|
const formatCountDocs = nCountDocs => {
|
||||||
|
//Получаем последнюю цифру в значении
|
||||||
|
let num = (nCountDocs % 100) % 10;
|
||||||
|
//Документов
|
||||||
|
if (nCountDocs > 10 && nCountDocs < 20) return `${nCountDocs} ${DECLINATIONS[2]}`;
|
||||||
|
//Документа
|
||||||
|
if (num > 1 && num < 5) return `${nCountDocs} ${DECLINATIONS[1]}`;
|
||||||
|
//Документ
|
||||||
|
if (num == 1) return `${nCountDocs} ${DECLINATIONS[0]}`;
|
||||||
|
//Документов
|
||||||
|
return `${nCountDocs} ${DECLINATIONS[2]}`;
|
||||||
|
};
|
||||||
|
|
||||||
|
//Список каталогов планов
|
||||||
|
const PlanCtlgsList = ({ planCtlgs = [], selectedPlanCtlg, filter, setFilter, onClick } = {}) => {
|
||||||
|
//Генерация содержимого
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<TextField
|
||||||
|
sx={STYLES.PLANS_FINDER}
|
||||||
|
name="planFilter"
|
||||||
|
label="Каталог"
|
||||||
|
value={filter.ctlgName}
|
||||||
|
variant="standard"
|
||||||
|
fullWidth
|
||||||
|
onChange={event => {
|
||||||
|
setFilter(pv => ({ ...pv, ctlgName: event.target.value }));
|
||||||
|
}}
|
||||||
|
></TextField>
|
||||||
|
<FormGroup sx={STYLES.PLANS_CHECKBOX_HAVEDOCS}>
|
||||||
|
<FormControlLabel
|
||||||
|
control={<Checkbox checked={filter.haveDocs} onChange={event => setFilter(pv => ({ ...pv, haveDocs: event.target.checked }))} />}
|
||||||
|
label="Только с планами"
|
||||||
|
labelPlacement="end"
|
||||||
|
/>
|
||||||
|
</FormGroup>
|
||||||
|
<List>
|
||||||
|
{planCtlgs.map(p => (
|
||||||
|
<ListItemButton
|
||||||
|
sx={p.NCOUNT_DOCS == 0 ? STYLES.PLANS_LIST_ITEM_ZERODOCS : null}
|
||||||
|
key={p.NRN}
|
||||||
|
selected={p.NRN === selectedPlanCtlg}
|
||||||
|
onClick={() => (onClick ? onClick({ NRN: p.NRN, SNAME: p.SNAME, NMIN_YEAR: p.NMIN_YEAR, NMAX_YEAR: p.NMAX_YEAR }) : null)}
|
||||||
|
>
|
||||||
|
<ListItemText
|
||||||
|
primary={<Typography sx={STYLES.PLANS_LIST_ITEM_PRIMARY}>{p.SNAME}</Typography>}
|
||||||
|
secondary={<Typography sx={{ ...STYLES.PLANS_LIST_ITEM_SECONDARY }}>{formatCountDocs(p.NCOUNT_DOCS)}</Typography>}
|
||||||
|
/>
|
||||||
|
</ListItemButton>
|
||||||
|
))}
|
||||||
|
</List>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
//Контроль свойств - Список каталогов планов
|
||||||
|
PlanCtlgsList.propTypes = {
|
||||||
|
planCtlgs: PropTypes.array,
|
||||||
|
selectedPlanCtlg: PropTypes.number,
|
||||||
|
onClick: PropTypes.func,
|
||||||
|
filter: PropTypes.object,
|
||||||
|
setFilter: PropTypes.func
|
||||||
|
};
|
||||||
|
|
||||||
|
//-----------
|
||||||
|
//Тело модуля
|
||||||
|
//-----------
|
||||||
|
|
||||||
|
//Корневая панель мониторинга сборки изделий
|
||||||
|
const MechRecAssemblyMon = () => {
|
||||||
|
//Собственное состояние
|
||||||
|
const [state, setState, selectPlan, unselectPlan] = useMechRecAssemblyMon();
|
||||||
|
|
||||||
|
//Состояние для фильтра каталогов
|
||||||
|
const [filter, setFilter] = useState({ ctlgName: "", haveDocs: false });
|
||||||
|
|
||||||
|
//Массив отфильтрованных каталогов
|
||||||
|
const filteredPlanCtgls = useFilteredPlanCtlgs(state.planCtlgs, filter);
|
||||||
|
|
||||||
|
//Подключение к контексту сообщений
|
||||||
|
const { InlineMsgInfo } = useContext(MessagingСtx);
|
||||||
|
|
||||||
|
//Обработка нажатия на элемент в списке каталогов планов
|
||||||
|
const handleProjectClick = project => {
|
||||||
|
if (state.selectedPlanCtlg.NRN != project.NRN) selectPlan(project);
|
||||||
|
else unselectPlan();
|
||||||
|
};
|
||||||
|
|
||||||
|
//Обработка нажатия на карточку объекта
|
||||||
|
const handleCardClick = plan => {
|
||||||
|
setState(pv => ({
|
||||||
|
...pv,
|
||||||
|
selectedPlan: { NRN: plan.NRN, SNUMB: plan.SNUMB, NPROGRESS: plan.NPROGRESS, SDETAIL: plan.SDETAIL, NYEAR: plan.NYEAR }
|
||||||
|
}));
|
||||||
|
};
|
||||||
|
|
||||||
|
//Обработка нажатия на кнопку "Назад"
|
||||||
|
const handleBackClick = () => {
|
||||||
|
setState(pv => ({ ...pv, selectedPlan: { NRN: null, SNUMB: null, NPROGRESS: null, SDETAIL: null, NYEAR: null } }));
|
||||||
|
};
|
||||||
|
|
||||||
|
//Генерация содержимого
|
||||||
|
return (
|
||||||
|
<Box p={2}>
|
||||||
|
<ThemeProvider theme={theme}>
|
||||||
|
<Fab variant="extended" sx={STYLES.PLANS_BUTTON} onClick={() => setState(pv => ({ ...pv, showPlanList: !pv.showPlanList }))}>
|
||||||
|
Программы
|
||||||
|
</Fab>
|
||||||
|
<Drawer
|
||||||
|
anchor={"left"}
|
||||||
|
open={state.showPlanList}
|
||||||
|
onClose={() => setState(pv => ({ ...pv, showPlanList: false }))}
|
||||||
|
sx={STYLES.PLANS_DRAWER}
|
||||||
|
>
|
||||||
|
<PlanCtlgsList
|
||||||
|
planCtlgs={filteredPlanCtgls}
|
||||||
|
selectedPlanCtlg={state.selectedPlanCtlg.NRN}
|
||||||
|
filter={filter}
|
||||||
|
setFilter={setFilter}
|
||||||
|
onClick={handleProjectClick}
|
||||||
|
/>
|
||||||
|
</Drawer>
|
||||||
|
{state.init == true ? (
|
||||||
|
state.selectedPlanCtlg.NRN ? (
|
||||||
|
<>
|
||||||
|
<Typography variant="h1" align="center" py={3}>
|
||||||
|
{`${state.selectedPlanCtlg.SNAME} на ${state.selectedPlanCtlg.NMIN_YEAR}г. - ${state.selectedPlanCtlg.NMAX_YEAR}г.`}
|
||||||
|
</Typography>
|
||||||
|
{state.plansLoaded == true ? (
|
||||||
|
state.selectedPlan.NRN ? (
|
||||||
|
<CardDetail card={state.selectedPlan} handleBackClick={handleBackClick} />
|
||||||
|
) : (
|
||||||
|
<Container>
|
||||||
|
<Grid container spacing={5}>
|
||||||
|
{state.plans.map(el => (
|
||||||
|
<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}
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
<InlineMsgInfo okBtn={false} text={"Укажите каталог планов для отображения его спецификаций"} />
|
||||||
|
)
|
||||||
|
) : null}
|
||||||
|
</ThemeProvider>
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
//----------------
|
||||||
|
//Интерфейс модуля
|
||||||
|
//----------------
|
||||||
|
|
||||||
|
export { MechRecAssemblyMon };
|
66
app/panels/mech_rec_assembly_mon/styles/themes.js
Normal file
66
app/panels/mech_rec_assembly_mon/styles/themes.js
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
import { createTheme } from "@mui/material/styles"; //Интерфейсные элементы
|
||||||
|
|
||||||
|
//Описание темы
|
||||||
|
const theme = createTheme({
|
||||||
|
palette: {
|
||||||
|
text: {
|
||||||
|
secondary: { fontColor: "rgba(0, 0, 0, 0.298)" }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
typography: {
|
||||||
|
h1: {
|
||||||
|
fontSize: "40px",
|
||||||
|
fontWeight: 400,
|
||||||
|
textAlign: "center"
|
||||||
|
},
|
||||||
|
h2: {
|
||||||
|
fontSize: "40px",
|
||||||
|
fontWeight: 700,
|
||||||
|
textAlign: "center"
|
||||||
|
},
|
||||||
|
h3: {
|
||||||
|
fontSize: "30px",
|
||||||
|
fontWeight: 700,
|
||||||
|
textAlign: "center"
|
||||||
|
},
|
||||||
|
h4: {
|
||||||
|
fontSize: "16px",
|
||||||
|
fontWeight: 400,
|
||||||
|
textAlign: "center"
|
||||||
|
},
|
||||||
|
subtitle1: {
|
||||||
|
fontSize: "30px",
|
||||||
|
fontWeight: 400,
|
||||||
|
textAlign: "center"
|
||||||
|
},
|
||||||
|
subtitle2: {
|
||||||
|
fontSize: "20px",
|
||||||
|
fontWeight: 700,
|
||||||
|
textAlign: "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: {
|
||||||
|
fontSize: "9px",
|
||||||
|
whiteSpace: "pre-line",
|
||||||
|
textAlign: "center"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
export { theme };
|
337
app/panels/mech_rec_cost_jobs_manage/backend.js
Normal file
337
app/panels/mech_rec_cost_jobs_manage/backend.js
Normal file
@ -0,0 +1,337 @@
|
|||||||
|
//---------------------
|
||||||
|
//Подключение библиотек
|
||||||
|
//---------------------
|
||||||
|
|
||||||
|
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 };
|
422
app/panels/mech_rec_cost_jobs_manage/fcjobssp.js
Normal file
422
app/panels/mech_rec_cost_jobs_manage/fcjobssp.js
Normal file
@ -0,0 +1,422 @@
|
|||||||
|
/*
|
||||||
|
Парус 8 - Панели мониторинга - ПУП - Выдача сменного задания
|
||||||
|
Компонент панели: Таблица информации об операциях сменного задания
|
||||||
|
*/
|
||||||
|
|
||||||
|
//---------------------
|
||||||
|
//Подключение библиотек
|
||||||
|
//---------------------
|
||||||
|
|
||||||
|
import React from "react"; //Классы React
|
||||||
|
import PropTypes from "prop-types"; //Контроль свойств компонента
|
||||||
|
import { Typography, Box, Checkbox, Grid, Icon, Button } from "@mui/material"; //Интерфейсные элементы
|
||||||
|
import { P8PDataGrid, P8P_DATA_GRID_SIZE } from "../../components/p8p_data_grid"; //Таблица данных
|
||||||
|
import { P8P_DATA_GRID_CONFIG_PROPS } from "../../config_wrapper"; //Подключение компонентов к настройкам приложения
|
||||||
|
import { useCostRouteLists, useCostJobsSpecs, useCostEquipment } from "./backend"; //Собственные хуки таблиц
|
||||||
|
|
||||||
|
//---------
|
||||||
|
//Константы
|
||||||
|
//---------
|
||||||
|
|
||||||
|
const sUnitCostRouteLists = "CostRouteLists"; //Мнемокод раздела маршрутных листов
|
||||||
|
const sUnitCostJobsSpecs = "CostJobsSpecs"; //Мнемокод раздела операций
|
||||||
|
const sUnitCostEquipment = "CostEquipment"; //Мнемокод раздела рабочих центров
|
||||||
|
|
||||||
|
//Стили
|
||||||
|
const STYLES = {
|
||||||
|
CONTAINER: { textAlign: "center" },
|
||||||
|
TABLE: { paddingTop: "15px" },
|
||||||
|
TABLE_SUM: { textAlign: "right", paddingTop: "5px", paddingRight: "15px" },
|
||||||
|
TABLE_BUTTONS: { display: "flex", justifyContent: "flex-end" },
|
||||||
|
CHECK_BOX: { textAlign: "center" },
|
||||||
|
OPERATIONS_SEPARATOR: { padding: "3px 0px", backgroundColor: "lightblue" },
|
||||||
|
INFORMATION_HALF: { minWidth: "50%", maxWidth: "50%", textAlign: "center" }
|
||||||
|
};
|
||||||
|
|
||||||
|
//---------------------------------------------
|
||||||
|
//Вспомогательные функции форматирования данных
|
||||||
|
//---------------------------------------------
|
||||||
|
|
||||||
|
//Формирование списка отмеченных записей
|
||||||
|
function selectedReducer(accumulator, current) {
|
||||||
|
if (current.NSELECT == 1) {
|
||||||
|
accumulator.push(current.NRN);
|
||||||
|
}
|
||||||
|
return accumulator;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Форматирование значения ячейки
|
||||||
|
const dataCellRender = ({ row, columnDef, handleSelectChange, sUnit, selectedEquip }) => {
|
||||||
|
//Инициализируем доступность выбора
|
||||||
|
let disabled = false;
|
||||||
|
//Если это рабочие центры
|
||||||
|
if (sUnit === sUnitCostEquipment) {
|
||||||
|
//Для колонки выбора
|
||||||
|
if (columnDef.name === "NSELECT") {
|
||||||
|
return {
|
||||||
|
data: (
|
||||||
|
<Box sx={STYLES.CHECK_BOX}>
|
||||||
|
<Checkbox
|
||||||
|
disabled={selectedEquip.length === 1 && selectedEquip[0] !== row["NRN"]}
|
||||||
|
checked={row[columnDef.name]}
|
||||||
|
//checked={row[columnDef.name] === 1}
|
||||||
|
onChange={() => handleSelectChange(row["NRN"], sUnit, row["NCOEFF"] <= row["NLOADING"])}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
//Если оборудование загружено
|
||||||
|
if (row["NCOEFF"] <= row["NLOADING"]) {
|
||||||
|
//Если поле не поле выбора
|
||||||
|
if (columnDef.name !== "NSELECT") {
|
||||||
|
return {
|
||||||
|
cellStyle: { color: "lightgrey" },
|
||||||
|
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") {
|
||||||
|
return {
|
||||||
|
data: (
|
||||||
|
<Box sx={STYLES.CHECK_BOX}>
|
||||||
|
<Checkbox
|
||||||
|
disabled={disabled}
|
||||||
|
checked={row[columnDef.name]}
|
||||||
|
//checked={row[columnDef.name] === 1}
|
||||||
|
onChange={() => handleSelectChange(row["NRN"], sUnit)}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
data: row[columnDef.name]
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
//Генерация представления ячейки заголовка группы
|
||||||
|
export const headCellRender = ({ columnDef }) => {
|
||||||
|
if (columnDef.name === "NSELECT") {
|
||||||
|
return {
|
||||||
|
stackStyle: { padding: "2px", justifyContent: "space-around" },
|
||||||
|
data: <Icon>done</Icon>
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
return {
|
||||||
|
stackStyle: { padding: "2px" },
|
||||||
|
data: columnDef.caption
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
//-----------
|
||||||
|
//Тело модуля
|
||||||
|
//-----------
|
||||||
|
|
||||||
|
//Таблица информации об операциях сменного задания
|
||||||
|
const CostJobsSpecsDataGrid = ({ task, processIdent, clearSelectlist }) => {
|
||||||
|
//Собственное состояние - таблица данных маршрутных листов
|
||||||
|
const [costRouteLists, setCostRouteLists, modifySelectList] = useCostRouteLists(task, processIdent);
|
||||||
|
|
||||||
|
//Собственное состояние - таблица данных операций
|
||||||
|
const [costJobsSpecs, setCostJobsSpecs, issueCostJobsSpecs] = useCostJobsSpecs(task, costRouteLists.selectedRows, processIdent);
|
||||||
|
|
||||||
|
//Собственное состояние - таблица рабочих центров
|
||||||
|
const [costEquipment, setCostEquipment, includeCostEquipment, excludeCostEquipment] = useCostEquipment();
|
||||||
|
|
||||||
|
//При изменении состояния сортировки маршрутных листов
|
||||||
|
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 costJobsSpecPagesCountChanged = () => setCostJobsSpecs(pv => ({ ...pv, pageNumber: pv.pageNumber + 1, reload: true }));
|
||||||
|
|
||||||
|
//При изменении состояния сортировки рабочих центров
|
||||||
|
const costEquipmentOrderChanged = ({ orders }) => setCostEquipment(pv => ({ ...pv, orders: [...orders], pageNumber: 1, reload: true }));
|
||||||
|
|
||||||
|
//При изменении количества отображаемых страниц рабочих центров
|
||||||
|
const costEquipmentPagesCountChanged = () => setCostEquipment(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 excludeAsync = async () => {
|
||||||
|
//Включаем оборудование в операции
|
||||||
|
try {
|
||||||
|
await excludeCostEquipment({
|
||||||
|
NFCEQUIPMENT: costEquipment.selectedRows[0],
|
||||||
|
NFCJOBS: task,
|
||||||
|
SFCJOBSSP_LIST: costJobsSpecs.selectedRows.join(";")
|
||||||
|
});
|
||||||
|
//Необходимо обновить данные о маршрутных листах и оборудовании
|
||||||
|
setCostJobsSpecs(pv => ({ ...pv, selectedRows: [], reload: true }));
|
||||||
|
setCostEquipment(pv => ({ ...pv, selectedRows: [], reload: true }));
|
||||||
|
} catch (e) {
|
||||||
|
throw new Error(e.message);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
//Исключаем операции асинхронно
|
||||||
|
excludeAsync();
|
||||||
|
};
|
||||||
|
|
||||||
|
//Выдача задания операции
|
||||||
|
const costJobsSpecIssue = () => {
|
||||||
|
//Делаем асинхронно, чтобы при ошибке ничего не обновлять
|
||||||
|
const issueAsync = async () => {
|
||||||
|
//Включаем оборудование в операции
|
||||||
|
try {
|
||||||
|
await issueCostJobsSpecs({
|
||||||
|
NFCJOBS: task,
|
||||||
|
SFCJOBSSP_LIST: costJobsSpecs.selectedRows.join(";")
|
||||||
|
});
|
||||||
|
//Необходимо обновить данные о маршрутных листах и оборудовании
|
||||||
|
clearSelectlist(processIdent);
|
||||||
|
setCostRouteLists(pv => ({ ...pv, selectedRows: [], reload: true }));
|
||||||
|
setCostEquipment(pv => ({ ...pv, selectedRows: [], reload: true }));
|
||||||
|
} catch (e) {
|
||||||
|
throw new Error(e.message);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
//Выдаем задание асинхронно
|
||||||
|
issueAsync();
|
||||||
|
};
|
||||||
|
|
||||||
|
//При изменение состояния выбора
|
||||||
|
const handleSelectChange = (NRN, sUnit, selectedLoaded) => {
|
||||||
|
//Инициализируем строки таблицы
|
||||||
|
let rows = [];
|
||||||
|
//Индекс элемента в массиве
|
||||||
|
let indexRow = null;
|
||||||
|
//Исходим от раздела
|
||||||
|
switch (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:
|
||||||
|
//Инициализируем операциями
|
||||||
|
rows = costJobsSpecs.rows;
|
||||||
|
//Определяем индекс элемента в массиве
|
||||||
|
indexRow = rows.findIndex(obj => obj.NRN == NRN);
|
||||||
|
//Изменяем значение выбора
|
||||||
|
rows[indexRow].NSELECT = !rows[indexRow].NSELECT;
|
||||||
|
//Актуализируем строки
|
||||||
|
setCostJobsSpecs(pv => ({ ...pv, rows: rows, selectedRows: rows.reduce(selectedReducer, []) }));
|
||||||
|
//Выходим
|
||||||
|
break;
|
||||||
|
//Рабочие центры
|
||||||
|
case sUnitCostEquipment:
|
||||||
|
//Инициализируем рабочими центрами
|
||||||
|
rows = costEquipment.rows;
|
||||||
|
//Определяем индекс элемента в массиве
|
||||||
|
indexRow = rows.findIndex(obj => obj.NRN == NRN);
|
||||||
|
//Изменяем значение выбора
|
||||||
|
rows[indexRow].NSELECT = !rows[indexRow].NSELECT;
|
||||||
|
//Актуализируем строки
|
||||||
|
setCostEquipment(pv => ({ ...pv, rows: rows, selectedRows: rows.reduce(selectedReducer, []), selectedLoaded: selectedLoaded }));
|
||||||
|
//Выходим
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
//Генерация содержимого
|
||||||
|
return (
|
||||||
|
<div style={STYLES.CONTAINER}>
|
||||||
|
<Grid container spacing={2}>
|
||||||
|
<Grid item sx={STYLES.INFORMATION_HALF}>
|
||||||
|
<Typography variant={"h6"}>Маршрутные листы</Typography>
|
||||||
|
{costRouteLists.dataLoaded ? (
|
||||||
|
<>
|
||||||
|
<Box sx={STYLES.TABLE_BUTTONS}>
|
||||||
|
<Button
|
||||||
|
variant="contained"
|
||||||
|
size="small"
|
||||||
|
disabled={costJobsSpecs.selectedRows.length === 0}
|
||||||
|
onClick={costJobsSpecIssue}
|
||||||
|
>
|
||||||
|
Выдать задания
|
||||||
|
</Button>
|
||||||
|
</Box>
|
||||||
|
<Box sx={STYLES.TABLE}>
|
||||||
|
<P8PDataGrid
|
||||||
|
{...P8P_DATA_GRID_CONFIG_PROPS}
|
||||||
|
columnsDef={costRouteLists.columnsDef}
|
||||||
|
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}
|
||||||
|
rows={costJobsSpecs.rows}
|
||||||
|
size={P8P_DATA_GRID_SIZE.SMALL}
|
||||||
|
morePages={costJobsSpecs.morePages}
|
||||||
|
reloading={costJobsSpecs.reload}
|
||||||
|
onOrderChanged={costJobsSpecOrderChanged}
|
||||||
|
onPagesCountChanged={costJobsSpecPagesCountChanged}
|
||||||
|
dataCellRender={prms =>
|
||||||
|
dataCellRender({
|
||||||
|
...prms,
|
||||||
|
handleSelectChange,
|
||||||
|
sUnit: sUnitCostJobsSpecs,
|
||||||
|
selectedEquip: costEquipment.selectedRows
|
||||||
|
})
|
||||||
|
}
|
||||||
|
headCellRender={prms => headCellRender({ ...prms })}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
) : null}
|
||||||
|
</Box>
|
||||||
|
</>
|
||||||
|
) : null}
|
||||||
|
</Grid>
|
||||||
|
<Grid item sx={STYLES.INFORMATION_HALF}>
|
||||||
|
<Typography variant={"h6"}>Рабочие центры</Typography>
|
||||||
|
{costEquipment.dataLoaded ? (
|
||||||
|
<>
|
||||||
|
<Box sx={STYLES.TABLE_BUTTONS}>
|
||||||
|
<Button
|
||||||
|
variant="contained"
|
||||||
|
size="small"
|
||||||
|
disabled={
|
||||||
|
costEquipment.selectedRows.length !== 1 ||
|
||||||
|
(costEquipment.selectedRows.length === 1 && costJobsSpecs.selectedRows.length === 0) ||
|
||||||
|
costEquipment.selectedLoaded
|
||||||
|
}
|
||||||
|
onClick={costJobsSpecIncludeCostEquipment}
|
||||||
|
>
|
||||||
|
Включить в задание
|
||||||
|
</Button>
|
||||||
|
<Box ml={1}>
|
||||||
|
<Button
|
||||||
|
variant="contained"
|
||||||
|
size="small"
|
||||||
|
disabled={
|
||||||
|
costEquipment.selectedRows.length !== 1 ||
|
||||||
|
(costEquipment.selectedRows.length === 1 && costJobsSpecs.selectedRows.length === 0)
|
||||||
|
}
|
||||||
|
onClick={costJobsSpecExcludeCostEquipment}
|
||||||
|
>
|
||||||
|
Исключить из задания
|
||||||
|
</Button>
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
<Box sx={STYLES.TABLE}>
|
||||||
|
<P8PDataGrid
|
||||||
|
{...P8P_DATA_GRID_CONFIG_PROPS}
|
||||||
|
columnsDef={costEquipment.columnsDef}
|
||||||
|
rows={costEquipment.rows}
|
||||||
|
size={P8P_DATA_GRID_SIZE.SMALL}
|
||||||
|
morePages={costEquipment.morePages}
|
||||||
|
reloading={costEquipment.reload}
|
||||||
|
onOrderChanged={costEquipmentOrderChanged}
|
||||||
|
onPagesCountChanged={costEquipmentPagesCountChanged}
|
||||||
|
dataCellRender={prms =>
|
||||||
|
dataCellRender({
|
||||||
|
...prms,
|
||||||
|
handleSelectChange,
|
||||||
|
sUnit: sUnitCostEquipment,
|
||||||
|
selectedEquip: costEquipment.selectedRows
|
||||||
|
})
|
||||||
|
}
|
||||||
|
headCellRender={prms => headCellRender({ ...prms })}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
</>
|
||||||
|
) : null}
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
//Контроль свойств - Таблица информации об операциях сменного задания
|
||||||
|
CostJobsSpecsDataGrid.propTypes = {
|
||||||
|
task: PropTypes.number.isRequired,
|
||||||
|
processIdent: PropTypes.number,
|
||||||
|
clearSelectlist: PropTypes.func
|
||||||
|
};
|
||||||
|
|
||||||
|
//----------------
|
||||||
|
//Интерфейс модуля
|
||||||
|
//----------------
|
||||||
|
|
||||||
|
export { CostJobsSpecsDataGrid };
|
23
app/panels/mech_rec_cost_jobs_manage/hooks.js
Normal file
23
app/panels/mech_rec_cost_jobs_manage/hooks.js
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
/*
|
||||||
|
Парус 8 - Панели мониторинга - ПУП - Выдача сменного задания
|
||||||
|
Кастомные хуки
|
||||||
|
*/
|
||||||
|
|
||||||
|
//---------------------
|
||||||
|
//Подключение библиотек
|
||||||
|
//---------------------
|
||||||
|
|
||||||
|
import React from "react"; //Классы React
|
||||||
|
|
||||||
|
//-----------
|
||||||
|
//Тело модуля
|
||||||
|
//-----------
|
||||||
|
|
||||||
|
//Клиентский отбор сменных заданий по поисковой фразе
|
||||||
|
export const useFilteredFcjobs = (jobs, filter) => {
|
||||||
|
const filteredJobs = React.useMemo(() => {
|
||||||
|
return jobs.filter(catalog => catalog.SDOC_INFO.toString().toLowerCase().includes(filter.jobName));
|
||||||
|
}, [jobs, filter]);
|
||||||
|
|
||||||
|
return filteredJobs;
|
||||||
|
};
|
16
app/panels/mech_rec_cost_jobs_manage/index.js
Normal file
16
app/panels/mech_rec_cost_jobs_manage/index.js
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
/*
|
||||||
|
Парус 8 - Панели мониторинга - ПУП - Выдача сменного задания
|
||||||
|
Панель мониторинга: Точка входа
|
||||||
|
*/
|
||||||
|
|
||||||
|
//---------------------
|
||||||
|
//Подключение библиотек
|
||||||
|
//---------------------
|
||||||
|
|
||||||
|
import { MechRecCostJobs } from "./mech_rec_cost_jobs_manage"; //Корневая панель выдачи сменного задания
|
||||||
|
|
||||||
|
//----------------
|
||||||
|
//Интерфейс модуля
|
||||||
|
//----------------
|
||||||
|
|
||||||
|
export const RootClass = MechRecCostJobs;
|
@ -0,0 +1,206 @@
|
|||||||
|
/*
|
||||||
|
Парус 8 - Панели мониторинга - ПУП - Выдача сменного задания
|
||||||
|
Панель мониторинга: Корневая панель выдачи сменного задания
|
||||||
|
*/
|
||||||
|
|
||||||
|
//---------------------
|
||||||
|
//Подключение библиотек
|
||||||
|
//---------------------
|
||||||
|
|
||||||
|
import React, { useContext, useState, useCallback, useEffect } from "react"; //Классы React
|
||||||
|
import PropTypes from "prop-types"; //Контроль свойств компонента
|
||||||
|
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 { useFilteredFcjobs } from "./hooks"; //Вспомогательные хуки
|
||||||
|
import { CostJobsSpecsDataGrid } from "./fcjobssp"; //Собственные хуки таблиц
|
||||||
|
|
||||||
|
//---------
|
||||||
|
//Константы
|
||||||
|
//---------
|
||||||
|
|
||||||
|
//Стили
|
||||||
|
const STYLES = {
|
||||||
|
JOBS_FINDER: { marginTop: "10px", marginLeft: "10px", width: "93%" },
|
||||||
|
JOBS_LIST_ITEM_PRIMARY: { wordWrap: "break-word" },
|
||||||
|
JOBS_BUTTON: { position: "absolute" },
|
||||||
|
JOBS_DRAWER: {
|
||||||
|
width: "350px",
|
||||||
|
display: "inline-block",
|
||||||
|
flexShrink: 0,
|
||||||
|
[`& .MuiDrawer-paper`]: { width: "350px", display: "inline-block", boxSizing: "border-box" }
|
||||||
|
},
|
||||||
|
CONTAINER: { margin: "5px 0px", textAlign: "center" }
|
||||||
|
};
|
||||||
|
|
||||||
|
//------------------------------------
|
||||||
|
//Вспомогательные функции и компоненты
|
||||||
|
//------------------------------------
|
||||||
|
|
||||||
|
//Список сменных заданий
|
||||||
|
const JobList = ({ jobs = [], selectedJob, filter, setFilter, onClick } = {}) => {
|
||||||
|
//Генерация содержимого
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<TextField
|
||||||
|
sx={STYLES.JOBS_FINDER}
|
||||||
|
name="jobFilter"
|
||||||
|
label="Сменное задание"
|
||||||
|
value={filter.jobName}
|
||||||
|
variant="standard"
|
||||||
|
fullWidth
|
||||||
|
onChange={event => {
|
||||||
|
setFilter(pv => ({ ...pv, jobName: event.target.value }));
|
||||||
|
}}
|
||||||
|
></TextField>
|
||||||
|
<List>
|
||||||
|
{jobs.map(p => (
|
||||||
|
<ListItemButton key={p.NRN} selected={p.NRN === selectedJob.NRN} onClick={() => (onClick ? onClick(p) : null)}>
|
||||||
|
<ListItemText primary={<Typography sx={STYLES.JOBS_LIST_ITEM_PRIMARY}>{p.SDOC_INFO}</Typography>} />
|
||||||
|
</ListItemButton>
|
||||||
|
))}
|
||||||
|
</List>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
//Контроль свойств - Список каталогов планов
|
||||||
|
JobList.propTypes = {
|
||||||
|
jobs: PropTypes.array,
|
||||||
|
selectedJob: PropTypes.object,
|
||||||
|
onClick: PropTypes.func,
|
||||||
|
filter: PropTypes.object,
|
||||||
|
setFilter: PropTypes.func
|
||||||
|
};
|
||||||
|
|
||||||
|
//-----------
|
||||||
|
//Тело модуля
|
||||||
|
//-----------
|
||||||
|
|
||||||
|
//Корневая панель выдачи сменного задания
|
||||||
|
const MechRecCostJobs = () => {
|
||||||
|
//Собственное состояние - таблица данных
|
||||||
|
const [state, setState] = useState({
|
||||||
|
init: false,
|
||||||
|
showJobList: false,
|
||||||
|
jobList: [],
|
||||||
|
jobListLoaded: false,
|
||||||
|
selectedJob: {},
|
||||||
|
processIdent: null,
|
||||||
|
dataLoaded: false
|
||||||
|
});
|
||||||
|
|
||||||
|
//Состояние для фильтра каталогов
|
||||||
|
const [filter, setFilter] = useState({ jobName: "" });
|
||||||
|
|
||||||
|
//Массив отфильтрованных каталогов
|
||||||
|
const filteredJobs = useFilteredFcjobs(state.jobList, filter);
|
||||||
|
|
||||||
|
//Подключение к контексту взаимодействия с сервером
|
||||||
|
const { executeStored } = useContext(BackEndС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 => {
|
||||||
|
console.log(NIDENT);
|
||||||
|
try {
|
||||||
|
await executeStored({
|
||||||
|
stored: "P_SELECTLIST_CLEAR",
|
||||||
|
args: { NIDENT: NIDENT }
|
||||||
|
});
|
||||||
|
} catch (e) {
|
||||||
|
throw new Error(e.message);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[executeStored]
|
||||||
|
);
|
||||||
|
|
||||||
|
//Выбор плана
|
||||||
|
const selectJob = job => {
|
||||||
|
//Очищаем селектлист
|
||||||
|
clearSelectlist(state.processIdent);
|
||||||
|
//Обновляем состояние
|
||||||
|
setState(pv => ({
|
||||||
|
...pv,
|
||||||
|
selectedJob: job,
|
||||||
|
showJobList: false,
|
||||||
|
dataLoaded: false
|
||||||
|
}));
|
||||||
|
};
|
||||||
|
|
||||||
|
//Сброс выбора плана
|
||||||
|
const unselectJob = () => {
|
||||||
|
//Очищаем селектлист
|
||||||
|
clearSelectlist(state.processIdent);
|
||||||
|
//Обновляем состояние
|
||||||
|
setState(pv => ({
|
||||||
|
...pv,
|
||||||
|
selectedJob: {},
|
||||||
|
showJobList: false,
|
||||||
|
dataLoaded: false
|
||||||
|
}));
|
||||||
|
};
|
||||||
|
|
||||||
|
//Обработка нажатия на элемент в списке планов
|
||||||
|
const handleJobClick = job => {
|
||||||
|
if (state.selectedJob.NRN != job.NRN) selectJob(job);
|
||||||
|
else unselectJob();
|
||||||
|
};
|
||||||
|
|
||||||
|
//Генерация содержимого
|
||||||
|
return (
|
||||||
|
<Box p={2}>
|
||||||
|
<Fab variant="extended" sx={STYLES.JOBS_BUTTON} onClick={() => setState(pv => ({ ...pv, showJobList: !pv.showJobList }))}>
|
||||||
|
Сменные задания
|
||||||
|
</Fab>
|
||||||
|
<Drawer anchor={"left"} open={state.showJobList} onClose={() => setState(pv => ({ ...pv, showJobList: false }))} sx={STYLES.JOBS_DRAWER}>
|
||||||
|
<JobList jobs={filteredJobs} selectedJob={state.selectedJob} filter={filter} setFilter={setFilter} onClick={handleJobClick} />
|
||||||
|
</Drawer>
|
||||||
|
<div style={STYLES.CONTAINER}>
|
||||||
|
{state.selectedJob.NRN ? (
|
||||||
|
<>
|
||||||
|
<Typography variant={"h6"}>{`Сменное задание "${state.selectedJob.SSUBDIV}" на ${state.selectedJob.SPERIOD}`}</Typography>
|
||||||
|
<CostJobsSpecsDataGrid task={state.selectedJob.NRN} processIdent={state.processIdent} clearSelectlist={clearSelectlist} />
|
||||||
|
</>
|
||||||
|
) : !state.selectedJob.NRN ? (
|
||||||
|
<InlineMsgInfo okBtn={false} text={"Укажите сменное задание"} />
|
||||||
|
) : null}
|
||||||
|
</div>
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
//----------------
|
||||||
|
//Интерфейс модуля
|
||||||
|
//----------------
|
||||||
|
|
||||||
|
export { MechRecCostJobs };
|
16
app/panels/mech_rec_dept_cost_jobs/index.js
Normal file
16
app/panels/mech_rec_dept_cost_jobs/index.js
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
/*
|
||||||
|
Парус 8 - Панели мониторинга - ПУП - Загрузка цеха
|
||||||
|
Панель мониторинга: Точка входа
|
||||||
|
*/
|
||||||
|
|
||||||
|
//---------------------
|
||||||
|
//Подключение библиотек
|
||||||
|
//---------------------
|
||||||
|
|
||||||
|
import { MechRecDeptCostJobs } from "./mech_rec_dept_cost_jobs"; //Корневая панель загрузки цеха
|
||||||
|
|
||||||
|
//----------------
|
||||||
|
//Интерфейс модуля
|
||||||
|
//----------------
|
||||||
|
|
||||||
|
export const RootClass = MechRecDeptCostJobs;
|
153
app/panels/mech_rec_dept_cost_jobs/mech_rec_dept_cost_jobs.js
Normal file
153
app/panels/mech_rec_dept_cost_jobs/mech_rec_dept_cost_jobs.js
Normal file
@ -0,0 +1,153 @@
|
|||||||
|
/*
|
||||||
|
Парус 8 - Панели мониторинга - ПУП - Загрузка цеха
|
||||||
|
Панель мониторинга: Корневая панель загрузки цеха
|
||||||
|
*/
|
||||||
|
|
||||||
|
//---------------------
|
||||||
|
//Подключение библиотек
|
||||||
|
//---------------------
|
||||||
|
|
||||||
|
import React, { useState, useContext, useCallback, useEffect } from "react"; //Классы React
|
||||||
|
import { Typography, Box } from "@mui/material"; //Интерфейсные элементы
|
||||||
|
import { object2Base64XML } from "../../core/utils"; //Вспомогательные процедуры и функции
|
||||||
|
import { P8PDataGrid, P8P_DATA_GRID_SIZE } from "../../components/p8p_data_grid"; //Таблица данных
|
||||||
|
import { P8P_DATA_GRID_CONFIG_PROPS } from "../../config_wrapper"; //Подключение компонентов к настройкам приложения
|
||||||
|
import { BackEndСtx } from "../../context/backend"; //Контекст взаимодействия с сервером
|
||||||
|
|
||||||
|
//---------
|
||||||
|
//Константы
|
||||||
|
//---------
|
||||||
|
|
||||||
|
//Размер страницы данных
|
||||||
|
const DATA_GRID_PAGE_SIZE = 5;
|
||||||
|
|
||||||
|
//Стили
|
||||||
|
const STYLES = {
|
||||||
|
CONTAINER: { textAlign: "center", paddingTop: "20px" },
|
||||||
|
TITLE: { paddingBottom: "15px" }
|
||||||
|
};
|
||||||
|
|
||||||
|
//------------------------------------
|
||||||
|
//Вспомогательные функции и компоненты
|
||||||
|
//------------------------------------
|
||||||
|
|
||||||
|
//Генерация заливки строки исходя от значений
|
||||||
|
const dataCellRender = ({ row, columnDef }) => {
|
||||||
|
//Описываем общие свойства
|
||||||
|
let cellProps = { title: row[columnDef.name] };
|
||||||
|
//Описываем общий стиль
|
||||||
|
let cellStyle = { padding: "8px", maxWidth: "300px", textOverflow: "ellipsis", overflow: "hidden", whiteSpace: "pre" };
|
||||||
|
//
|
||||||
|
if (columnDef.name.match(/N.*_VALUE/) && row[columnDef.name]) {
|
||||||
|
if (row[`${columnDef.name.substring(0, 12)}_TYPE`] === 0) {
|
||||||
|
cellStyle = { ...cellStyle, backgroundColor: "lightgrey" };
|
||||||
|
} else {
|
||||||
|
cellStyle = { ...cellStyle, backgroundColor: "lightgreen" };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
cellProps,
|
||||||
|
cellStyle,
|
||||||
|
data: row[columnDef]
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
//-----------
|
||||||
|
//Тело модуля
|
||||||
|
//-----------
|
||||||
|
|
||||||
|
//Корневая панель загрузки цеха
|
||||||
|
const MechRecDeptCostJobs = () => {
|
||||||
|
//Собственное состояние - таблица данных
|
||||||
|
const [costJobs, setCostJobs] = useState({
|
||||||
|
subdiv: null,
|
||||||
|
dataLoaded: false,
|
||||||
|
columnsDef: [],
|
||||||
|
filters: [],
|
||||||
|
orders: null,
|
||||||
|
rows: [],
|
||||||
|
reload: true,
|
||||||
|
pageNumber: 1,
|
||||||
|
morePages: true
|
||||||
|
});
|
||||||
|
|
||||||
|
//Подключение к контексту взаимодействия с сервером
|
||||||
|
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",
|
||||||
|
isArray: name => name === "XCOLUMNS_DEF" || name === "XROWS",
|
||||||
|
attributeValueProcessor: (name, val) => (name === "caption" ? undefined : val)
|
||||||
|
});
|
||||||
|
setCostJobs(pv => ({
|
||||||
|
...pv,
|
||||||
|
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 handlePagesCountChanged = () => setCostJobs(pv => ({ ...pv, pageNumber: pv.pageNumber + 1, reload: true }));
|
||||||
|
|
||||||
|
//При необходимости обновить данные таблицы
|
||||||
|
useEffect(() => {
|
||||||
|
loadData();
|
||||||
|
}, [costJobs.reload, loadData]);
|
||||||
|
|
||||||
|
//Генерация содержимого
|
||||||
|
return (
|
||||||
|
<div style={STYLES.CONTAINER}>
|
||||||
|
<Box>
|
||||||
|
{costJobs.dataLoaded ? (
|
||||||
|
<>
|
||||||
|
<Typography sx={STYLES.TITLE} variant={"h6"}>
|
||||||
|
{`Загрузка станков "${costJobs.subdiv}"`}
|
||||||
|
</Typography>
|
||||||
|
<Box px={1}>
|
||||||
|
<P8PDataGrid
|
||||||
|
{...P8P_DATA_GRID_CONFIG_PROPS}
|
||||||
|
columnsDef={costJobs.columnsDef}
|
||||||
|
rows={costJobs.rows}
|
||||||
|
size={P8P_DATA_GRID_SIZE.LARGE}
|
||||||
|
morePages={costJobs.morePages}
|
||||||
|
reloading={costJobs.reload}
|
||||||
|
onOrderChanged={handleOrderChanged}
|
||||||
|
onFilterChanged={handleFilterChanged}
|
||||||
|
onPagesCountChanged={handlePagesCountChanged}
|
||||||
|
dataCellRender={prms => dataCellRender({ ...prms })}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
</>
|
||||||
|
) : null}
|
||||||
|
</Box>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
//----------------
|
||||||
|
//Интерфейс модуля
|
||||||
|
//----------------
|
||||||
|
|
||||||
|
export { MechRecDeptCostJobs };
|
328
app/panels/mech_rec_dept_cost_prod_plans/fcroutlst.js
Normal file
328
app/panels/mech_rec_dept_cost_prod_plans/fcroutlst.js
Normal file
@ -0,0 +1,328 @@
|
|||||||
|
/*
|
||||||
|
Парус 8 - Панели мониторинга - ПУП - Производственный план цеха
|
||||||
|
Компонент панели: Таблица маршрутных листов
|
||||||
|
*/
|
||||||
|
|
||||||
|
//---------------------
|
||||||
|
//Подключение библиотек
|
||||||
|
//---------------------
|
||||||
|
|
||||||
|
import React, { useState, useCallback, useEffect, useContext } from "react"; //Классы React
|
||||||
|
import PropTypes from "prop-types"; //Контроль свойств компонента
|
||||||
|
import { Typography, Box, Paper, IconButton, Icon, Dialog, DialogContent, DialogActions, Button, TextField } from "@mui/material"; //Интерфейсные элементы
|
||||||
|
import { P8PDataGrid, P8P_DATA_GRID_SIZE } from "../../components/p8p_data_grid"; //Таблица данных
|
||||||
|
import { P8P_DATA_GRID_CONFIG_PROPS } from "../../config_wrapper"; //Подключение компонентов к настройкам приложения
|
||||||
|
import { BackEndСtx } from "../../context/backend"; //Контекст взаимодействия с сервером
|
||||||
|
import { object2Base64XML } from "../../core/utils"; //Вспомогательные функции
|
||||||
|
import { CostRouteListsOrdDataGrid } from "./fcroutlstord"; //Состояние таблицы заказов маршрутных листов
|
||||||
|
import { ApplicationСtx } from "../../context/application"; //Контекст приложения
|
||||||
|
|
||||||
|
//---------
|
||||||
|
//Константы
|
||||||
|
//---------
|
||||||
|
|
||||||
|
//Стили
|
||||||
|
const STYLES = {
|
||||||
|
CONTAINER: { textAlign: "center" },
|
||||||
|
TABLE: { paddingTop: "15px" },
|
||||||
|
TABLE_SUM: { textAlign: "right", paddingTop: "5px", paddingRight: "15px" },
|
||||||
|
DIALOG_EDITOR: { maxWidth: "250px" },
|
||||||
|
DIALOG_BUTTONS: { marginTop: "10px", width: "240px" }
|
||||||
|
};
|
||||||
|
|
||||||
|
//---------------------------------------------
|
||||||
|
//Вспомогательные функции форматирования данных
|
||||||
|
//---------------------------------------------
|
||||||
|
|
||||||
|
//Генерация представления расширения строки
|
||||||
|
export const rowExpandRender = ({ row }) => {
|
||||||
|
return (
|
||||||
|
<Paper elevation={4}>
|
||||||
|
<CostRouteListsOrdDataGrid mainRowRN={row.NRN} />
|
||||||
|
</Paper>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
//Форматирование значений колонок
|
||||||
|
const dataCellRender = ({ row, columnDef, handlePriorEditOpen, handleOrderEditOpen }) => {
|
||||||
|
//!!! Пока отключено - не удалять
|
||||||
|
// switch (columnDef.name) {
|
||||||
|
// case "NPRIOR_PARTY":
|
||||||
|
// return {
|
||||||
|
// data: (
|
||||||
|
// <>
|
||||||
|
// {row["NPRIOR_PARTY"]}
|
||||||
|
// <IconButton edge="end" title="Изменить приоритет" onClick={() => handlePriorEditOpen(row["NRN"], row["NPRIOR_PARTY"])}>
|
||||||
|
// <Icon>edit</Icon>
|
||||||
|
// </IconButton>
|
||||||
|
// </>
|
||||||
|
// )
|
||||||
|
// };
|
||||||
|
// case "NCHANGE_FACEACC":
|
||||||
|
// return {
|
||||||
|
// data: (
|
||||||
|
// <Box sx={{ textAlign: "center" }}>
|
||||||
|
// <IconButton title="Изменить заказ" onClick={() => handleOrderEditOpen(row["NRN"], row["SPROD_ORDER"])}>
|
||||||
|
// <Icon>inventory</Icon>
|
||||||
|
// </IconButton>
|
||||||
|
// </Box>
|
||||||
|
// )
|
||||||
|
// };
|
||||||
|
// }
|
||||||
|
return {
|
||||||
|
data: row[columnDef]
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
//-----------
|
||||||
|
//Тело модуля
|
||||||
|
//-----------
|
||||||
|
|
||||||
|
//Таблица маршрутных листов
|
||||||
|
const CostRouteListsDataGrid = ({ task }) => {
|
||||||
|
//Собственное состояние - таблица данных
|
||||||
|
const [costRouteLists, setCostRouteLists] = useState({
|
||||||
|
dataLoaded: false,
|
||||||
|
columnsDef: [],
|
||||||
|
orders: null,
|
||||||
|
rows: [],
|
||||||
|
reload: true,
|
||||||
|
pageNumber: 1,
|
||||||
|
morePages: true,
|
||||||
|
editPriorNRN: null,
|
||||||
|
editPriorValue: null,
|
||||||
|
editOrderNRN: null,
|
||||||
|
editOrderValue: null
|
||||||
|
});
|
||||||
|
|
||||||
|
//Подключение к контексту взаимодействия с сервером
|
||||||
|
const { executeStored, SERV_DATA_TYPE_CLOB } = useContext(BackEndСtx);
|
||||||
|
|
||||||
|
//Подключение к контексту приложения
|
||||||
|
const { pOnlineShowDictionary } = useContext(ApplicationС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 = () => {
|
||||||
|
setCostRouteLists(pv => ({ ...pv, editPriorNRN: null, editPriorValue: null }));
|
||||||
|
};
|
||||||
|
|
||||||
|
//При изменении значения приоритета партии
|
||||||
|
const handlePriorFormChanged = e => {
|
||||||
|
setCostRouteLists(pv => ({ ...pv, editPriorValue: e.target.value }));
|
||||||
|
};
|
||||||
|
|
||||||
|
//Изменение приоритета
|
||||||
|
const priorChange = useCallback(
|
||||||
|
async (NRN, PriorValue, rows) => {
|
||||||
|
try {
|
||||||
|
await executeStored({
|
||||||
|
stored: "PKG_P8PANELS_MECHREC.FCROUTLST_PRIOR_PARTY_UPDATE",
|
||||||
|
args: { NFCROUTLST: NRN, SPRIOR_PARTY: PriorValue }
|
||||||
|
});
|
||||||
|
//Изменяем значение приоритета у нужного
|
||||||
|
rows[rows.findIndex(obj => obj.NRN == NRN)].NPRIOR_PARTY = PriorValue;
|
||||||
|
//Актуализируем строки таблицы
|
||||||
|
setCostRouteLists(pv => ({ ...pv, rows: rows }));
|
||||||
|
//Закрываем окно
|
||||||
|
handlePriorEditClose();
|
||||||
|
} catch (e) {
|
||||||
|
throw new Error(e.message);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[executeStored]
|
||||||
|
);
|
||||||
|
|
||||||
|
//При нажатии на изменение приоритета партии
|
||||||
|
const handlePriorChange = () => {
|
||||||
|
//Изменяем значение
|
||||||
|
priorChange(costRouteLists.editPriorNRN, costRouteLists.editPriorValue, costRouteLists.rows);
|
||||||
|
};
|
||||||
|
|
||||||
|
//При открытии изменения заказа
|
||||||
|
const handleOrderEditOpen = (NRN, sProdOrderValue) => {
|
||||||
|
setCostRouteLists(pv => ({ ...pv, editOrderNRN: NRN, editOrderValue: sProdOrderValue }));
|
||||||
|
};
|
||||||
|
|
||||||
|
//При закрытии изменения заказа
|
||||||
|
const handleOrderEditClose = () => {
|
||||||
|
setCostRouteLists(pv => ({ ...pv, editOrderNRN: null, editOrderValue: null }));
|
||||||
|
};
|
||||||
|
|
||||||
|
//Изменение заказа
|
||||||
|
const setEditOrderValue = value => {
|
||||||
|
console.log(value);
|
||||||
|
setCostRouteLists(pv => ({ ...pv, editOrderValue: value }));
|
||||||
|
};
|
||||||
|
|
||||||
|
//При изменении значения заказа
|
||||||
|
const handleOrderFormChanged = e => {
|
||||||
|
setEditOrderValue(e.target.value);
|
||||||
|
};
|
||||||
|
|
||||||
|
//При нажатии на изменение заказа
|
||||||
|
const handleOrderChange = () => {
|
||||||
|
//Изменяем значение
|
||||||
|
//priorChange(costRouteLists.editPriorNRN, costRouteLists.editPriorValue);
|
||||||
|
//Закрываем окно
|
||||||
|
handleOrderEditClose();
|
||||||
|
};
|
||||||
|
|
||||||
|
//Генерация содержимого
|
||||||
|
return (
|
||||||
|
<div style={STYLES.CONTAINER}>
|
||||||
|
<Typography variant={"h6"}>Маршрутные листы</Typography>
|
||||||
|
{costRouteLists.dataLoaded ? (
|
||||||
|
<>
|
||||||
|
<Box sx={STYLES.TABLE}>
|
||||||
|
<P8PDataGrid
|
||||||
|
{...P8P_DATA_GRID_CONFIG_PROPS}
|
||||||
|
columnsDef={costRouteLists.columnsDef}
|
||||||
|
rows={costRouteLists.rows}
|
||||||
|
size={P8P_DATA_GRID_SIZE.LARGE}
|
||||||
|
morePages={costRouteLists.morePages}
|
||||||
|
reloading={costRouteLists.reload}
|
||||||
|
expandable={true}
|
||||||
|
rowExpandRender={rowExpandRender}
|
||||||
|
onOrderChanged={handleOrderChanged}
|
||||||
|
onPagesCountChanged={handlePagesCountChanged}
|
||||||
|
dataCellRender={prms => dataCellRender({ ...prms, handlePriorEditOpen, handleOrderEditOpen })}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
</>
|
||||||
|
) : null}
|
||||||
|
{costRouteLists.editPriorNRN ? (
|
||||||
|
<Dialog open onClose={() => handlePriorEditClose(null)} sx={STYLES.DIALOG_EDITOR}>
|
||||||
|
<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}
|
||||||
|
{costRouteLists.editOrderNRN ? (
|
||||||
|
<Dialog open onClose={() => handleOrderEditClose(null)} sx={STYLES.DIALOG_EDITOR}>
|
||||||
|
<DialogContent>
|
||||||
|
<Box>
|
||||||
|
<TextField
|
||||||
|
name="editOrderValue"
|
||||||
|
label="Заказ"
|
||||||
|
variant="standard"
|
||||||
|
fullWidth
|
||||||
|
value={costRouteLists.editOrderValue}
|
||||||
|
onChange={handleOrderFormChanged}
|
||||||
|
/>
|
||||||
|
<Box>
|
||||||
|
<Button
|
||||||
|
sx={STYLES.DIALOG_BUTTONS}
|
||||||
|
variant="contained"
|
||||||
|
onClick={() => {
|
||||||
|
pOnlineShowDictionary({
|
||||||
|
unitCode: "FaceAccounts",
|
||||||
|
inputParameters: [
|
||||||
|
{
|
||||||
|
name: "in_NUMB",
|
||||||
|
value: costRouteLists.editOrderValue
|
||||||
|
}
|
||||||
|
],
|
||||||
|
callBack: res => (res.success === true ? setEditOrderValue(res.outParameters.out_NUMB) : null)
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Лицевые счета
|
||||||
|
</Button>
|
||||||
|
<Box>
|
||||||
|
<Button sx={STYLES.DIALOG_BUTTONS} onClick={handleOrderChange} variant="contained">
|
||||||
|
Изменить
|
||||||
|
</Button>
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
</DialogContent>
|
||||||
|
<DialogActions>
|
||||||
|
<Button onClick={() => handleOrderEditClose(null)}>Закрыть</Button>
|
||||||
|
</DialogActions>
|
||||||
|
</Dialog>
|
||||||
|
) : null}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
//Контроль свойств - Таблица маршрутных листов
|
||||||
|
CostRouteListsDataGrid.propTypes = {
|
||||||
|
task: PropTypes.number.isRequired
|
||||||
|
};
|
||||||
|
|
||||||
|
//----------------
|
||||||
|
//Интерфейс модуля
|
||||||
|
//----------------
|
||||||
|
|
||||||
|
export { CostRouteListsDataGrid };
|
124
app/panels/mech_rec_dept_cost_prod_plans/fcroutlstord.js
Normal file
124
app/panels/mech_rec_dept_cost_prod_plans/fcroutlstord.js
Normal file
@ -0,0 +1,124 @@
|
|||||||
|
/*
|
||||||
|
Парус 8 - Панели мониторинга - ПУП - Производственный план цеха
|
||||||
|
Компонент панели: Таблица заказов маршрутного листа
|
||||||
|
*/
|
||||||
|
|
||||||
|
//---------------------
|
||||||
|
//Подключение библиотек
|
||||||
|
//---------------------
|
||||||
|
|
||||||
|
import React, { useState, useCallback, useEffect, useContext } 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 { BackEndСtx } from "../../context/backend"; //Контекст взаимодействия с сервером
|
||||||
|
import { object2Base64XML } from "../../core/utils"; //Вспомогательные функции
|
||||||
|
|
||||||
|
//---------
|
||||||
|
//Константы
|
||||||
|
//---------
|
||||||
|
|
||||||
|
//Стили
|
||||||
|
const STYLES = {
|
||||||
|
CONTAINER: { margin: "5px 0px", textAlign: "center" }
|
||||||
|
};
|
||||||
|
|
||||||
|
//-----------
|
||||||
|
//Тело модуля
|
||||||
|
//-----------
|
||||||
|
|
||||||
|
//Таблица заказов маршрутного листа
|
||||||
|
const CostRouteListsOrdDataGrid = ({ mainRowRN }) => {
|
||||||
|
//Собственное состояние - таблица данных
|
||||||
|
const [costRouteListsOrd, setCostRouteListsOrd] = useState({
|
||||||
|
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 (costRouteListsOrd.reload) {
|
||||||
|
const data = await executeStored({
|
||||||
|
stored: "PKG_P8PANELS_MECHREC.FCROUTLSTORD_DEPT_DG_GET",
|
||||||
|
args: {
|
||||||
|
NFCROUTLST: mainRowRN,
|
||||||
|
CORDERS: { VALUE: object2Base64XML(costRouteListsOrd.orders, { arrayNodeName: "orders" }), SDATA_TYPE: SERV_DATA_TYPE_CLOB },
|
||||||
|
NPAGE_NUMBER: costRouteListsOrd.pageNumber,
|
||||||
|
NPAGE_SIZE: DATA_GRID_PAGE_SIZE,
|
||||||
|
NINCLUDE_DEF: costRouteListsOrd.dataLoaded ? 0 : 1
|
||||||
|
},
|
||||||
|
respArg: "COUT"
|
||||||
|
});
|
||||||
|
setCostRouteListsOrd(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
|
||||||
|
}, [
|
||||||
|
costRouteListsOrd.reload,
|
||||||
|
costRouteListsOrd.filters,
|
||||||
|
costRouteListsOrd.orders,
|
||||||
|
costRouteListsOrd.dataLoaded,
|
||||||
|
costRouteListsOrd.pageNumber,
|
||||||
|
executeStored,
|
||||||
|
SERV_DATA_TYPE_CLOB
|
||||||
|
]);
|
||||||
|
|
||||||
|
//При необходимости обновить данные таблицы
|
||||||
|
useEffect(() => {
|
||||||
|
loadData();
|
||||||
|
}, [costRouteListsOrd.reload, loadData]);
|
||||||
|
|
||||||
|
//При изменении состояния сортировки
|
||||||
|
const handleOrderChanged = ({ orders }) => setCostRouteListsOrd(pv => ({ ...pv, orders: [...orders], pageNumber: 1, reload: true }));
|
||||||
|
|
||||||
|
//При изменении количества отображаемых страниц
|
||||||
|
const handlePagesCountChanged = () => setCostRouteListsOrd(pv => ({ ...pv, pageNumber: pv.pageNumber + 1, reload: true }));
|
||||||
|
|
||||||
|
//Генерация содержимого
|
||||||
|
return (
|
||||||
|
<div style={STYLES.CONTAINER}>
|
||||||
|
<Typography variant={"subtitle2"}>Заказы</Typography>
|
||||||
|
{costRouteListsOrd.dataLoaded ? (
|
||||||
|
<P8PDataGrid
|
||||||
|
{...P8P_DATA_GRID_CONFIG_PROPS}
|
||||||
|
columnsDef={costRouteListsOrd.columnsDef}
|
||||||
|
rows={costRouteListsOrd.rows}
|
||||||
|
size={P8P_DATA_GRID_SIZE.SMALL}
|
||||||
|
morePages={costRouteListsOrd.morePages}
|
||||||
|
reloading={costRouteListsOrd.reload}
|
||||||
|
onOrderChanged={handleOrderChanged}
|
||||||
|
onPagesCountChanged={handlePagesCountChanged}
|
||||||
|
/>
|
||||||
|
) : null}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
//Контроль свойств - Таблица заказов маршрутного листа
|
||||||
|
CostRouteListsOrdDataGrid.propTypes = {
|
||||||
|
mainRowRN: PropTypes.number.isRequired
|
||||||
|
};
|
||||||
|
|
||||||
|
//----------------
|
||||||
|
//Интерфейс модуля
|
||||||
|
//----------------
|
||||||
|
|
||||||
|
export { CostRouteListsOrdDataGrid };
|
23
app/panels/mech_rec_dept_cost_prod_plans/hooks.js
Normal file
23
app/panels/mech_rec_dept_cost_prod_plans/hooks.js
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
/*
|
||||||
|
Парус 8 - Панели мониторинга - ПУП - Производственный план цеха
|
||||||
|
Кастомные хуки
|
||||||
|
*/
|
||||||
|
|
||||||
|
//---------------------
|
||||||
|
//Подключение библиотек
|
||||||
|
//---------------------
|
||||||
|
|
||||||
|
import React from "react"; //Классы React
|
||||||
|
|
||||||
|
//-----------
|
||||||
|
//Тело модуля
|
||||||
|
//-----------
|
||||||
|
|
||||||
|
//Клиентский отбор каталогов по поисковой фразе и наличию планов
|
||||||
|
export const useFilteredPlans = (plans, filter) => {
|
||||||
|
const filteredPlans = React.useMemo(() => {
|
||||||
|
return plans.filter(catalog => catalog.SDOC_INFO.toString().toLowerCase().includes(filter.planName));
|
||||||
|
}, [plans, filter]);
|
||||||
|
|
||||||
|
return filteredPlans;
|
||||||
|
};
|
120
app/panels/mech_rec_dept_cost_prod_plans/incomefromdeps.js
Normal file
120
app/panels/mech_rec_dept_cost_prod_plans/incomefromdeps.js
Normal file
@ -0,0 +1,120 @@
|
|||||||
|
/*
|
||||||
|
Парус 8 - Панели мониторинга - ПУП - Производственный план цеха
|
||||||
|
Компонент панели: Таблица сдачи продукции
|
||||||
|
*/
|
||||||
|
|
||||||
|
//---------------------
|
||||||
|
//Подключение библиотек
|
||||||
|
//---------------------
|
||||||
|
|
||||||
|
import React, { useState, useCallback, useEffect, useContext } from "react"; //Классы React
|
||||||
|
import PropTypes from "prop-types"; //Контроль свойств компонента
|
||||||
|
import { Typography, Box } from "@mui/material"; //Интерфейсные элементы
|
||||||
|
import { P8PDataGrid, P8P_DATA_GRID_SIZE } from "../../components/p8p_data_grid"; //Таблица данных
|
||||||
|
import { P8P_DATA_GRID_CONFIG_PROPS } from "../../config_wrapper"; //Подключение компонентов к настройкам приложения
|
||||||
|
import { BackEndСtx } from "../../context/backend"; //Контекст взаимодействия с сервером
|
||||||
|
import { object2Base64XML, formatDateRF } from "../../core/utils"; //Вспомогательные функции
|
||||||
|
|
||||||
|
//---------
|
||||||
|
//Константы
|
||||||
|
//---------
|
||||||
|
|
||||||
|
//Стили
|
||||||
|
const STYLES = {
|
||||||
|
CONTAINER: { textAlign: "center" },
|
||||||
|
TABLE: { paddingTop: "15px" }
|
||||||
|
};
|
||||||
|
|
||||||
|
//-----------
|
||||||
|
//Тело модуля
|
||||||
|
//-----------
|
||||||
|
|
||||||
|
//Таблица сдачи продукции
|
||||||
|
const IncomFromDepsDataGrid = ({ task }) => {
|
||||||
|
//Собственное состояние - таблица данных
|
||||||
|
const [incomFromDeps, setIncomFromDeps] = useState({
|
||||||
|
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 handlePagesCountChanged = () => setIncomFromDeps(pv => ({ ...pv, pageNumber: pv.pageNumber + 1, reload: true }));
|
||||||
|
|
||||||
|
//Генерация содержимого
|
||||||
|
return (
|
||||||
|
<div style={STYLES.CONTAINER}>
|
||||||
|
<Typography variant={"h6"}>Сдача продукции</Typography>
|
||||||
|
<Box sx={STYLES.TABLE}>
|
||||||
|
{incomFromDeps.dataLoaded ? (
|
||||||
|
<P8PDataGrid
|
||||||
|
{...P8P_DATA_GRID_CONFIG_PROPS}
|
||||||
|
columnsDef={incomFromDeps.columnsDef}
|
||||||
|
rows={incomFromDeps.rows}
|
||||||
|
size={P8P_DATA_GRID_SIZE.LARGE}
|
||||||
|
morePages={incomFromDeps.morePages}
|
||||||
|
reloading={incomFromDeps.reload}
|
||||||
|
onOrderChanged={handleOrderChanged}
|
||||||
|
onPagesCountChanged={handlePagesCountChanged}
|
||||||
|
/>
|
||||||
|
) : null}
|
||||||
|
</Box>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
//Контроль свойств - Таблица сдачи продукции
|
||||||
|
IncomFromDepsDataGrid.propTypes = {
|
||||||
|
task: PropTypes.number.isRequired
|
||||||
|
};
|
||||||
|
|
||||||
|
//----------------
|
||||||
|
//Интерфейс модуля
|
||||||
|
//----------------
|
||||||
|
|
||||||
|
export { IncomFromDepsDataGrid };
|
16
app/panels/mech_rec_dept_cost_prod_plans/index.js
Normal file
16
app/panels/mech_rec_dept_cost_prod_plans/index.js
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
/*
|
||||||
|
Парус 8 - Панели мониторинга - ПУДП - Производственный план цеха
|
||||||
|
Панель мониторинга: Точка входа
|
||||||
|
*/
|
||||||
|
|
||||||
|
//---------------------
|
||||||
|
//Подключение библиотек
|
||||||
|
//---------------------
|
||||||
|
|
||||||
|
import { MechRecDeptCostProdPlans } from "./mech_rec_dept_cost_prod_plans"; //Корневая панель производственного плана цеха
|
||||||
|
|
||||||
|
//----------------
|
||||||
|
//Интерфейс модуля
|
||||||
|
//----------------
|
||||||
|
|
||||||
|
export const RootClass = MechRecDeptCostProdPlans;
|
@ -0,0 +1,445 @@
|
|||||||
|
/*
|
||||||
|
Парус 8 - Панели мониторинга - ПУП - Производственный план цеха
|
||||||
|
Панель мониторинга: Корневая панель производственного плана цеха
|
||||||
|
*/
|
||||||
|
|
||||||
|
//---------------------
|
||||||
|
//Подключение библиотек
|
||||||
|
//---------------------
|
||||||
|
|
||||||
|
import React, { useContext, useState, useCallback, useEffect } from "react"; //Классы React
|
||||||
|
import PropTypes from "prop-types"; //Контроль свойств компонента
|
||||||
|
import {
|
||||||
|
Drawer,
|
||||||
|
Fab,
|
||||||
|
Box,
|
||||||
|
List,
|
||||||
|
ListItemButton,
|
||||||
|
ListItemText,
|
||||||
|
Typography,
|
||||||
|
TextField,
|
||||||
|
Link,
|
||||||
|
Dialog,
|
||||||
|
DialogContent,
|
||||||
|
DialogActions,
|
||||||
|
Button
|
||||||
|
} from "@mui/material"; //Интерфейсные элементы
|
||||||
|
import { BackEndСtx } from "../../context/backend"; //Контекст взаимодействия с сервером
|
||||||
|
import { useFilteredPlans } from "./hooks"; //Вспомогательные хуки
|
||||||
|
import { object2Base64XML } from "../../core/utils"; //Вспомогательные функции
|
||||||
|
import { P8PDataGrid, P8P_DATA_GRID_SIZE } from "../../components/p8p_data_grid"; //Таблица данных
|
||||||
|
import { P8P_DATA_GRID_CONFIG_PROPS } from "../../config_wrapper"; //Подключение компонентов к настройкам приложения
|
||||||
|
import { MessagingСtx } from "../../context/messaging"; //Контекст сообщений
|
||||||
|
import { IncomFromDepsDataGrid } from "./incomefromdeps"; //Таблица сдачи продукции
|
||||||
|
import { CostRouteListsDataGrid } from "./fcroutlst"; //Таблица маршрутных листов
|
||||||
|
|
||||||
|
//---------
|
||||||
|
//Константы
|
||||||
|
//---------
|
||||||
|
|
||||||
|
//Стили
|
||||||
|
const STYLES = {
|
||||||
|
PLANS_FINDER: { marginTop: "10px", marginLeft: "10px", width: "93%" },
|
||||||
|
PLANS_LIST_ITEM_PRIMARY: { wordWrap: "break-word" },
|
||||||
|
PLANS_BUTTON: { position: "absolute" },
|
||||||
|
PLANS_DRAWER: {
|
||||||
|
width: "350px",
|
||||||
|
display: "inline-block",
|
||||||
|
flexShrink: 0,
|
||||||
|
[`& .MuiDrawer-paper`]: { width: "350px", display: "inline-block", boxSizing: "border-box" }
|
||||||
|
},
|
||||||
|
CONTAINER: { paddingTop: "40px", margin: "5px 0px", textAlign: "center" },
|
||||||
|
PLAN_FACT_VALUE: { textAlign: "center", display: "flex", justifyContent: "center" },
|
||||||
|
PLAN_FACT_DELIMITER: { padding: "0px 5px" },
|
||||||
|
FACT_VALUE: { color: "blue" }
|
||||||
|
};
|
||||||
|
|
||||||
|
//------------------------------------
|
||||||
|
//Вспомогательные функции и компоненты
|
||||||
|
//------------------------------------
|
||||||
|
|
||||||
|
//Генерация представления ячейки заголовка группы
|
||||||
|
export const groupCellRender = ({ group }) => ({
|
||||||
|
cellStyle: { padding: "2px" },
|
||||||
|
data: group.caption
|
||||||
|
});
|
||||||
|
|
||||||
|
//Генерация заливки строки исходя от значений
|
||||||
|
const dataCellRender = ({ row, columnDef, handleProdOrderClick, handleMatresCodeClick }) => {
|
||||||
|
//Описываем общие свойства
|
||||||
|
let cellProps = { title: row[columnDef.name] };
|
||||||
|
//Описываем общий стиль
|
||||||
|
let cellStyle = { padding: "8px", maxWidth: "300px", textOverflow: "ellipsis", overflow: "hidden", whiteSpace: "pre" };
|
||||||
|
//Для колонки "Статус"
|
||||||
|
if (columnDef.name === "SSTATUS") {
|
||||||
|
//Факт === План
|
||||||
|
if (row["NMAIN_QUANT"] === row["NREL_FACT"]) {
|
||||||
|
return {
|
||||||
|
cellProps,
|
||||||
|
cellStyle: { backgroundColor: "lightgreen", ...cellStyle },
|
||||||
|
data: row[columnDef]
|
||||||
|
};
|
||||||
|
}
|
||||||
|
//План <= (Факт + Запущено)
|
||||||
|
if (row["NMAIN_QUANT"] <= row["NREL_FACT"] + row["NFCROUTLST_QUANT"]) {
|
||||||
|
return {
|
||||||
|
cellProps,
|
||||||
|
cellStyle: { backgroundColor: "lightblue", ...cellStyle },
|
||||||
|
data: row[columnDef]
|
||||||
|
};
|
||||||
|
}
|
||||||
|
//Сумма "Количество план" = 0 или < "План"
|
||||||
|
if (row["NSUM_PLAN"] === 0 || (row["NSUM_PLAN"] !== 0 && row["NSUM_PLAN"] < row["NMAIN_QUANT"])) {
|
||||||
|
//"Факт" >= "План"
|
||||||
|
if (row["NREL_FACT"] >= row["NMAIN_QUANT"]) {
|
||||||
|
return {
|
||||||
|
cellProps,
|
||||||
|
cellStyle: { backgroundColor: "#F0E68C", ...cellStyle },
|
||||||
|
data: row[columnDef]
|
||||||
|
};
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
//Сумма "Количество факт" >= сумма "Количество план"
|
||||||
|
if (row["NSUM_FACT"] >= row["NSUM_PLAN"]) {
|
||||||
|
return {
|
||||||
|
cellProps,
|
||||||
|
cellStyle: { backgroundColor: "#F0E68C", ...cellStyle },
|
||||||
|
data: row[columnDef]
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
cellProps,
|
||||||
|
cellStyle: { backgroundColor: "lightcoral", ...cellStyle },
|
||||||
|
data: row[columnDef]
|
||||||
|
};
|
||||||
|
}
|
||||||
|
//Для колонки даты
|
||||||
|
if (columnDef.name.indexOf("PLAN_FACT") >= 0) {
|
||||||
|
//Получаем текущий день
|
||||||
|
let curDay = new Date().getDate().toString().padStart(2, "0");
|
||||||
|
//Формируем regex для проверки
|
||||||
|
let regex = new RegExp(`N_${curDay}.*`, "g");
|
||||||
|
//Если это значение текущего дня
|
||||||
|
if (columnDef.name.match(regex)) {
|
||||||
|
cellStyle = { ...cellStyle, backgroundColor: "lightgrey" };
|
||||||
|
}
|
||||||
|
//Если в колонке есть значени
|
||||||
|
if (row[columnDef.name]) {
|
||||||
|
//Разбиваем его на план/факт
|
||||||
|
let values = row[columnDef.name].split("/");
|
||||||
|
//Разбиваем значения на блоки
|
||||||
|
return {
|
||||||
|
cellProps,
|
||||||
|
cellStyle,
|
||||||
|
data: (
|
||||||
|
<Box sx={STYLES.PLAN_FACT_VALUE}>
|
||||||
|
<Box>{values[0]}</Box>
|
||||||
|
<Box sx={STYLES.PLAN_FACT_DELIMITER}>/</Box>
|
||||||
|
<Box sx={STYLES.FACT_VALUE}>{values[1]}</Box>
|
||||||
|
</Box>
|
||||||
|
)
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
//Если значения нет
|
||||||
|
return {
|
||||||
|
cellProps,
|
||||||
|
cellStyle,
|
||||||
|
data: row[columnDef]
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//Для колонки "Заказ"
|
||||||
|
if (columnDef.name === "SPROD_ORDER") {
|
||||||
|
return {
|
||||||
|
cellProps,
|
||||||
|
cellStyle,
|
||||||
|
data: (
|
||||||
|
<Link component="button" variant="body2" align="left" underline="hover" onClick={() => handleProdOrderClick(row["NRN"])}>
|
||||||
|
{row[columnDef.name]}
|
||||||
|
</Link>
|
||||||
|
)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
//Для колонки "Обозначение"
|
||||||
|
if (columnDef.name === "SMATRES_CODE") {
|
||||||
|
return {
|
||||||
|
cellProps,
|
||||||
|
cellStyle,
|
||||||
|
data: (
|
||||||
|
<Link component="button" variant="body2" align="left" underline="hover" onClick={() => handleMatresCodeClick(row["NRN"])}>
|
||||||
|
{row[columnDef.name]}
|
||||||
|
</Link>
|
||||||
|
)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
cellProps,
|
||||||
|
cellStyle,
|
||||||
|
data: row[columnDef]
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
//Список каталогов планов
|
||||||
|
const PlanList = ({ plans = [], selectedPlan, filter, setFilter, onClick } = {}) => {
|
||||||
|
//Генерация содержимого
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<TextField
|
||||||
|
sx={STYLES.PLANS_FINDER}
|
||||||
|
name="planFilter"
|
||||||
|
label="План"
|
||||||
|
value={filter.planName}
|
||||||
|
variant="standard"
|
||||||
|
fullWidth
|
||||||
|
onChange={event => {
|
||||||
|
setFilter(pv => ({ ...pv, planName: event.target.value }));
|
||||||
|
}}
|
||||||
|
></TextField>
|
||||||
|
<List>
|
||||||
|
{plans.map(p => (
|
||||||
|
<ListItemButton key={p.NRN} selected={p.NRN === selectedPlan.NRN} onClick={() => (onClick ? onClick(p) : null)}>
|
||||||
|
<ListItemText primary={<Typography sx={STYLES.PLANS_LIST_ITEM_PRIMARY}>{p.SDOC_INFO}</Typography>} />
|
||||||
|
</ListItemButton>
|
||||||
|
))}
|
||||||
|
</List>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
//Контроль свойств - Список каталогов планов
|
||||||
|
PlanList.propTypes = {
|
||||||
|
plans: PropTypes.array,
|
||||||
|
selectedPlan: PropTypes.object,
|
||||||
|
onClick: PropTypes.func,
|
||||||
|
filter: PropTypes.object,
|
||||||
|
setFilter: PropTypes.func
|
||||||
|
};
|
||||||
|
|
||||||
|
//-----------
|
||||||
|
//Тело модуля
|
||||||
|
//-----------
|
||||||
|
|
||||||
|
//Корневая панель производственного плана цеха
|
||||||
|
const MechRecDeptCostProdPlans = () => {
|
||||||
|
//Собственное состояние - таблица данных
|
||||||
|
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
|
||||||
|
});
|
||||||
|
|
||||||
|
//Состояние для фильтра каталогов
|
||||||
|
const [filter, setFilter] = useState({ planName: "" });
|
||||||
|
|
||||||
|
//Массив отфильтрованных каталогов
|
||||||
|
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 initPlans = useCallback(async () => {
|
||||||
|
if (!state.init) {
|
||||||
|
const data = await executeStored({
|
||||||
|
stored: "PKG_P8PANELS_MECHREC.FCPRODPLAN_DEPT_INIT",
|
||||||
|
args: {},
|
||||||
|
respArg: "COUT",
|
||||||
|
isArray: name => name === "XFCPRODPLANS"
|
||||||
|
});
|
||||||
|
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,
|
||||||
|
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 => {
|
||||||
|
setState(pv => ({
|
||||||
|
...pv,
|
||||||
|
showIncomeFromDeps: null,
|
||||||
|
showFcroutelst: null,
|
||||||
|
selectedPlan: plan,
|
||||||
|
showPlanList: false,
|
||||||
|
dataLoaded: false,
|
||||||
|
columnsDef: [],
|
||||||
|
orders: null,
|
||||||
|
rows: [],
|
||||||
|
reload: true,
|
||||||
|
pageNumber: 1,
|
||||||
|
morePages: true
|
||||||
|
}));
|
||||||
|
};
|
||||||
|
|
||||||
|
//Сброс выбора плана
|
||||||
|
const unselectPlan = () =>
|
||||||
|
setState(pv => ({
|
||||||
|
...pv,
|
||||||
|
showIncomeFromDeps: null,
|
||||||
|
showFcroutelst: null,
|
||||||
|
selectedPlan: {},
|
||||||
|
showPlanList: false,
|
||||||
|
dataLoaded: false,
|
||||||
|
columnsDef: [],
|
||||||
|
orders: null,
|
||||||
|
rows: [],
|
||||||
|
reload: true,
|
||||||
|
pageNumber: 1,
|
||||||
|
morePages: true
|
||||||
|
}));
|
||||||
|
|
||||||
|
//Обработка нажатия на элемент в списке планов
|
||||||
|
const handlePlanClick = plan => {
|
||||||
|
if (state.selectedPlan.NRN != plan.NRN) selectPlan(plan);
|
||||||
|
else unselectPlan();
|
||||||
|
};
|
||||||
|
|
||||||
|
//При изменении состояния сортировки
|
||||||
|
const handleOrderChanged = ({ orders }) => setState(pv => ({ ...pv, orders: [...orders], pageNumber: 1, reload: true }));
|
||||||
|
|
||||||
|
//При изменении количества отображаемых страниц
|
||||||
|
const handlePagesCountChanged = () => setState(pv => ({ ...pv, pageNumber: pv.pageNumber + 1, reload: true }));
|
||||||
|
|
||||||
|
//При нажатии на "Заказ"
|
||||||
|
const handleProdOrderClick = planSp => {
|
||||||
|
setState(pv => ({ ...pv, showIncomeFromDeps: planSp }));
|
||||||
|
};
|
||||||
|
|
||||||
|
//При нажатии на "Обозначение"
|
||||||
|
const handleMatresCodeClick = planSp => {
|
||||||
|
setState(pv => ({ ...pv, showFcroutelst: planSp }));
|
||||||
|
};
|
||||||
|
|
||||||
|
//Генерация содержимого
|
||||||
|
return (
|
||||||
|
<Box p={2}>
|
||||||
|
<Fab variant="extended" sx={STYLES.PLANS_BUTTON} onClick={() => setState(pv => ({ ...pv, showPlanList: !pv.showPlanList }))}>
|
||||||
|
Планы
|
||||||
|
</Fab>
|
||||||
|
<Drawer
|
||||||
|
anchor={"left"}
|
||||||
|
open={state.showPlanList}
|
||||||
|
onClose={() => setState(pv => ({ ...pv, showPlanList: false }))}
|
||||||
|
sx={STYLES.PLANS_DRAWER}
|
||||||
|
>
|
||||||
|
<PlanList
|
||||||
|
plans={filteredPlanCtgls}
|
||||||
|
selectedPlan={state.selectedPlan}
|
||||||
|
filter={filter}
|
||||||
|
setFilter={setFilter}
|
||||||
|
onClick={handlePlanClick}
|
||||||
|
/>
|
||||||
|
</Drawer>
|
||||||
|
<div style={STYLES.CONTAINER}>
|
||||||
|
{state.dataLoaded ? (
|
||||||
|
<>
|
||||||
|
<Typography
|
||||||
|
variant={"h6"}
|
||||||
|
>{`Производственный план цеха "${state.selectedPlan.SSUBDIV}" на ${state.selectedPlan.SPERIOD}`}</Typography>
|
||||||
|
<P8PDataGrid
|
||||||
|
{...P8P_DATA_GRID_CONFIG_PROPS}
|
||||||
|
columnsDef={state.columnsDef}
|
||||||
|
rows={state.rows}
|
||||||
|
size={P8P_DATA_GRID_SIZE.MEDIUM}
|
||||||
|
morePages={state.morePages}
|
||||||
|
reloading={state.reload}
|
||||||
|
onOrderChanged={handleOrderChanged}
|
||||||
|
onPagesCountChanged={handlePagesCountChanged}
|
||||||
|
dataCellRender={prms => dataCellRender({ ...prms, handleProdOrderClick, handleMatresCodeClick })}
|
||||||
|
groupCellRender={groupCellRender}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
) : !state.selectedPlan.NRN ? (
|
||||||
|
<InlineMsgInfo okBtn={false} text={"Укажите план для отображения его спецификаций"} />
|
||||||
|
) : null}
|
||||||
|
</div>
|
||||||
|
{state.showIncomeFromDeps ? (
|
||||||
|
<Dialog open onClose={() => handleProdOrderClick(null)} fullWidth maxWidth="xl">
|
||||||
|
<DialogContent>
|
||||||
|
<IncomFromDepsDataGrid task={state.showIncomeFromDeps} />
|
||||||
|
</DialogContent>
|
||||||
|
<DialogActions>
|
||||||
|
<Button onClick={() => handleProdOrderClick(null)}>Закрыть</Button>
|
||||||
|
</DialogActions>
|
||||||
|
</Dialog>
|
||||||
|
) : null}
|
||||||
|
{state.showFcroutelst ? (
|
||||||
|
<Dialog open onClose={() => handleMatresCodeClick(null)} fullWidth maxWidth="xl">
|
||||||
|
<DialogContent>
|
||||||
|
<CostRouteListsDataGrid task={state.showFcroutelst} />
|
||||||
|
</DialogContent>
|
||||||
|
<DialogActions>
|
||||||
|
<Button onClick={() => handleMatresCodeClick(null)}>Закрыть</Button>
|
||||||
|
</DialogActions>
|
||||||
|
</Dialog>
|
||||||
|
) : null}
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
//----------------
|
||||||
|
//Интерфейс модуля
|
||||||
|
//----------------
|
||||||
|
|
||||||
|
export { MechRecDeptCostProdPlans };
|
@ -62,6 +62,50 @@ create or replace package PKG_P8PANELS_MECHREC as
|
|||||||
COUT out clob -- Список каталогов раздела "Планы и отчеты производства изделий"
|
COUT out clob -- Список каталогов раздела "Планы и отчеты производства изделий"
|
||||||
);
|
);
|
||||||
|
|
||||||
|
/* Получение таблицы маршрутных листов, связанных с производственным составом */
|
||||||
|
procedure FCROUTLST_MON_DG_GET
|
||||||
|
(
|
||||||
|
NPRODCMPSP in number, -- Рег. номер производственного состава
|
||||||
|
NFCPRODPLAN in number, -- Рег. номер план
|
||||||
|
NPAGE_NUMBER in number, -- Номер страницы (игнорируется при NPAGE_SIZE=0)
|
||||||
|
NPAGE_SIZE in number, -- Количество записей на странице (0 - все)
|
||||||
|
CORDERS in clob, -- Сортировки
|
||||||
|
NINCLUDE_DEF in number, -- Признак включения описания колонок таблицы в ответ
|
||||||
|
COUT out clob -- Сериализованная таблица данных
|
||||||
|
);
|
||||||
|
|
||||||
|
/* Получение таблицы комплектовочных ведомостей, связанных с производственным составом */
|
||||||
|
procedure FCDELIVSH_DG_GET
|
||||||
|
(
|
||||||
|
NPRODCMPSP in number, -- Рег. номер производственного состава
|
||||||
|
NFCPRODPLAN in number, -- Рег. номер план
|
||||||
|
NPAGE_NUMBER in number, -- Номер страницы (игнорируется при NPAGE_SIZE=0)
|
||||||
|
NPAGE_SIZE in number, -- Количество записей на странице (0 - все)
|
||||||
|
CORDERS in clob, -- Сортировки
|
||||||
|
NINCLUDE_DEF in number, -- Признак включения описания колонок таблицы в ответ
|
||||||
|
COUT out clob -- Сериализованная таблица данных
|
||||||
|
);
|
||||||
|
|
||||||
|
/* Считывание деталий для выбора SVG */
|
||||||
|
procedure FCPRODCMP_DETAILS_GET
|
||||||
|
(
|
||||||
|
NFCPRODPLAN in number, -- Рег. номер плана
|
||||||
|
COUT out clob -- Сериализованная таблица данных
|
||||||
|
);
|
||||||
|
|
||||||
|
/* Получение таблицы записей "Планы и отчеты производства изделий" */
|
||||||
|
procedure FCPRODPLAN_GET
|
||||||
|
(
|
||||||
|
NCRN in number, -- Рег. номер каталога
|
||||||
|
COUT out clob -- Сериализованная таблица данных
|
||||||
|
);
|
||||||
|
|
||||||
|
/* Инициализация каталогов раздела "Планы и отчеты производства изделий" */
|
||||||
|
procedure FCPRODPLAN_CTLG_INIT
|
||||||
|
(
|
||||||
|
COUT out clob -- Список каталогов раздела "Планы и отчеты производства изделий"
|
||||||
|
);
|
||||||
|
|
||||||
end PKG_P8PANELS_MECHREC;
|
end PKG_P8PANELS_MECHREC;
|
||||||
/
|
/
|
||||||
create or replace package body PKG_P8PANELS_MECHREC as
|
create or replace package body PKG_P8PANELS_MECHREC as
|
||||||
@ -75,7 +119,7 @@ create or replace package body PKG_P8PANELS_MECHREC as
|
|||||||
STEXT_COLOR_ORANGE constant PKG_STD.TSTRING := '#FF8C00'; -- Цвет текста оранжевый
|
STEXT_COLOR_ORANGE constant PKG_STD.TSTRING := '#FF8C00'; -- Цвет текста оранжевый
|
||||||
STEXT_COLOR_GREY constant PKG_STD.TSTRING := '#555'; -- Цвет текста серый
|
STEXT_COLOR_GREY constant PKG_STD.TSTRING := '#555'; -- Цвет текста серый
|
||||||
|
|
||||||
/* Константы - параметры отборов планов */
|
/* Константы - параметры отборов планов ("Производственная программа") */
|
||||||
NFCPRODPLAN_CATEGORY constant PKG_STD.TNUMBER := 1; -- Категория планов "Производственная программа"
|
NFCPRODPLAN_CATEGORY constant PKG_STD.TNUMBER := 1; -- Категория планов "Производственная программа"
|
||||||
NFCPRODPLAN_STATUS constant PKG_STD.TNUMBER := 2; -- Статус планов "Утвержден"
|
NFCPRODPLAN_STATUS constant PKG_STD.TNUMBER := 2; -- Статус планов "Утвержден"
|
||||||
SFCPRODPLAN_TYPE constant PKG_STD.TSTRING := 'План'; -- Тип планов (мнемокод состояния)
|
SFCPRODPLAN_TYPE constant PKG_STD.TSTRING := 'План'; -- Тип планов (мнемокод состояния)
|
||||||
@ -97,6 +141,16 @@ create or replace package body PKG_P8PANELS_MECHREC as
|
|||||||
NTASK_TYPE_RL constant PKG_STD.TNUMBER := 4; -- Маршрутные листы
|
NTASK_TYPE_RL constant PKG_STD.TNUMBER := 4; -- Маршрутные листы
|
||||||
NTASK_TYPE_EMPTY constant PKG_STD.TNUMBER := null; -- Нет детализации
|
NTASK_TYPE_EMPTY constant PKG_STD.TNUMBER := null; -- Нет детализации
|
||||||
|
|
||||||
|
/* Константы - параметры отборов планов ("Мониторинг сборки изделий") */
|
||||||
|
NFCPRODPLAN_CATEGORY_MON constant PKG_STD.TNUMBER := 0; -- Категория планов "Первичный документ"
|
||||||
|
NFCPRODPLAN_STATUS_MON constant PKG_STD.TNUMBER := 2; -- Статус планов "Утвержден"
|
||||||
|
SFCPRODPLAN_TYPE_MON constant PKG_STD.TSTRING := 'План'; -- Тип планов (мнемокод состояния)
|
||||||
|
|
||||||
|
/* Константы - параметры отборов ("Загрузка цеха") */
|
||||||
|
SDICMUNTS_WD constant PKG_STD.TSTRING := 'н/ч'; -- Мнемокод ед. измерения нормочасов
|
||||||
|
SDICMUNTS_HOUR constant PKG_STD.TSTRING := 'час'; -- Мнемокод ед. измерения часов
|
||||||
|
|
||||||
|
|
||||||
/* Константы - дополнительные атрибуты */
|
/* Константы - дополнительные атрибуты */
|
||||||
STASK_ATTR_START_FACT constant PKG_STD.TSTRING := 'start_fact'; -- Запущено
|
STASK_ATTR_START_FACT constant PKG_STD.TSTRING := 'start_fact'; -- Запущено
|
||||||
STASK_ATTR_MAIN_QUANT constant PKG_STD.TSTRING := 'main_quant'; -- Количество план
|
STASK_ATTR_MAIN_QUANT constant PKG_STD.TSTRING := 'main_quant'; -- Количество план
|
||||||
@ -2211,5 +2265,638 @@ create or replace package body PKG_P8PANELS_MECHREC as
|
|||||||
P_EXCEPTION(0, PKG_STATE.SQL_ERRM());
|
P_EXCEPTION(0, PKG_STATE.SQL_ERRM());
|
||||||
end ACATALOG_INIT;
|
end ACATALOG_INIT;
|
||||||
|
|
||||||
|
/* Считывание рег. номера спецификации связанного плана */
|
||||||
|
function FCPRODPLANSP_LINKED_GET
|
||||||
|
(
|
||||||
|
NPRODCMPSP in number, -- Рег. номер производственного состава
|
||||||
|
NFCPRODPLAN in number -- Рег. номер план
|
||||||
|
) return number -- Рег. номер спецификации связанного плана
|
||||||
|
is
|
||||||
|
NRESULT PKG_STD.TREF; -- Рег. номер спецификации связанного плана
|
||||||
|
begin
|
||||||
|
/* Считываем запись */
|
||||||
|
begin
|
||||||
|
select S.RN
|
||||||
|
into NRESULT
|
||||||
|
from FCPRODPLAN T,
|
||||||
|
FCPRODPLANSP S
|
||||||
|
where T.RN = (select P.RN
|
||||||
|
from DOCLINKS L,
|
||||||
|
FCPRODPLAN P
|
||||||
|
where L.IN_DOCUMENT = NFCPRODPLAN
|
||||||
|
and L.IN_UNITCODE = 'CostProductPlans'
|
||||||
|
and L.OUT_UNITCODE = 'CostProductPlans'
|
||||||
|
and P.RN = L.OUT_DOCUMENT
|
||||||
|
and P.CATEGORY = 1
|
||||||
|
and ROWNUM = 1)
|
||||||
|
and S.PRN = T.RN
|
||||||
|
and S.PRODCMPSP = NPRODCMPSP;
|
||||||
|
exception
|
||||||
|
when others then
|
||||||
|
NRESULT := null;
|
||||||
|
end;
|
||||||
|
/* Возвращаем результат */
|
||||||
|
return NRESULT;
|
||||||
|
end FCPRODPLANSP_LINKED_GET;
|
||||||
|
|
||||||
|
/* Получение таблицы маршрутных листов, связанных с производственным составом */
|
||||||
|
procedure FCROUTLST_MON_DG_GET
|
||||||
|
(
|
||||||
|
NPRODCMPSP in number, -- Рег. номер производственного состава
|
||||||
|
NFCPRODPLAN in number, -- Рег. номер план
|
||||||
|
NPAGE_NUMBER in number, -- Номер страницы (игнорируется при NPAGE_SIZE=0)
|
||||||
|
NPAGE_SIZE in number, -- Количество записей на странице (0 - все)
|
||||||
|
CORDERS in clob, -- Сортировки
|
||||||
|
NINCLUDE_DEF in number, -- Признак включения описания колонок таблицы в ответ
|
||||||
|
COUT out clob -- Сериализованная таблица данных
|
||||||
|
)
|
||||||
|
is
|
||||||
|
NCOMPANY PKG_STD.TREF := GET_SESSION_COMPANY(); -- Организация сеанса
|
||||||
|
RO PKG_P8PANELS_VISUAL.TORDERS; -- Сортировки
|
||||||
|
RDG PKG_P8PANELS_VISUAL.TDATA_GRID; -- Описание таблицы
|
||||||
|
RDG_ROW PKG_P8PANELS_VISUAL.TROW; -- Строка таблицы
|
||||||
|
NROW_FROM PKG_STD.TREF; -- Номер строки с
|
||||||
|
NROW_TO PKG_STD.TREF; -- Номер строки по
|
||||||
|
CSQL clob; -- Буфер для запроса
|
||||||
|
ICURSOR integer; -- Курсор для исполнения запроса
|
||||||
|
NFCPRODPLANSP PKG_STD.TREF; -- Рег. номер спецификации связанного плана
|
||||||
|
NFCROUTLST_IDENT PKG_STD.TREF; -- Рег. номер идентификатора отмеченных записей маршрутных листов
|
||||||
|
NDICMUNTS_WD PKG_STD.TREF; -- Рег. номер ед. измерения нормочасов
|
||||||
|
begin
|
||||||
|
/* Читем сортировки */
|
||||||
|
RO := PKG_P8PANELS_VISUAL.TORDERS_FROM_XML(CORDERS => CORDERS);
|
||||||
|
/* Преобразуем номер и размер страницы в номер строк с и по */
|
||||||
|
PKG_P8PANELS_VISUAL.UTL_ROWS_LIMITS_CALC(NPAGE_NUMBER => NPAGE_NUMBER,
|
||||||
|
NPAGE_SIZE => NPAGE_SIZE,
|
||||||
|
NROW_FROM => NROW_FROM,
|
||||||
|
NROW_TO => NROW_TO);
|
||||||
|
/* Инициализируем таблицу данных */
|
||||||
|
RDG := PKG_P8PANELS_VISUAL.TDATA_GRID_MAKE();
|
||||||
|
/* Описываем колонки таблицы данных */
|
||||||
|
PKG_P8PANELS_VISUAL.TDATA_GRID_ADD_COL_DEF(RDATA_GRID => RDG,
|
||||||
|
SNAME => 'NRN',
|
||||||
|
SCAPTION => 'Рег. номер',
|
||||||
|
SDATA_TYPE => PKG_P8PANELS_VISUAL.SDATA_TYPE_NUMB,
|
||||||
|
BVISIBLE => false);
|
||||||
|
PKG_P8PANELS_VISUAL.TDATA_GRID_ADD_COL_DEF(RDATA_GRID => RDG,
|
||||||
|
SNAME => 'SNUMB',
|
||||||
|
SCAPTION => '% п/п',
|
||||||
|
SDATA_TYPE => PKG_P8PANELS_VISUAL.SDATA_TYPE_STR,
|
||||||
|
BVISIBLE => true);
|
||||||
|
PKG_P8PANELS_VISUAL.TDATA_GRID_ADD_COL_DEF(RDATA_GRID => RDG,
|
||||||
|
SNAME => 'SOPERATION',
|
||||||
|
SCAPTION => 'Содержание работ',
|
||||||
|
SDATA_TYPE => PKG_P8PANELS_VISUAL.SDATA_TYPE_STR,
|
||||||
|
BVISIBLE => true);
|
||||||
|
PKG_P8PANELS_VISUAL.TDATA_GRID_ADD_COL_DEF(RDATA_GRID => RDG,
|
||||||
|
SNAME => 'SEXECUTOR',
|
||||||
|
SCAPTION => 'Исполнитель',
|
||||||
|
SDATA_TYPE => PKG_P8PANELS_VISUAL.SDATA_TYPE_STR,
|
||||||
|
BVISIBLE => true);
|
||||||
|
PKG_P8PANELS_VISUAL.TDATA_GRID_ADD_COL_DEF(RDATA_GRID => RDG,
|
||||||
|
SNAME => 'NREMN_LABOUR',
|
||||||
|
SCAPTION => 'Остаточная трудоемкость, в н/ч',
|
||||||
|
SDATA_TYPE => PKG_P8PANELS_VISUAL.SDATA_TYPE_NUMB,
|
||||||
|
BVISIBLE => true);
|
||||||
|
/* Считываем рег. номер спецификации связанного плана */
|
||||||
|
NFCPRODPLANSP := FCPRODPLANSP_LINKED_GET(NPRODCMPSP => NPRODCMPSP, NFCPRODPLAN => NFCPRODPLAN);
|
||||||
|
/* Если спецификация считалась */
|
||||||
|
if (NFCPRODPLANSP is not null) then
|
||||||
|
/* Инициализируем список маршрутных листов */
|
||||||
|
UTL_FCROUTLST_IDENT_INIT(NFCPRODPLANSP => NFCPRODPLANSP, NIDENT => NFCROUTLST_IDENT);
|
||||||
|
/* Считываем единицу измерения нормочасов */
|
||||||
|
FIND_DICMUNTS_CODE(NFLAG_SMART => 0,
|
||||||
|
NFLAG_OPTION => 0,
|
||||||
|
NCOMPANY => NCOMPANY,
|
||||||
|
SMEAS_MNEMO => SDICMUNTS_WD,
|
||||||
|
NRN => NDICMUNTS_WD);
|
||||||
|
begin
|
||||||
|
/* Добавляем подсказку совместимости */
|
||||||
|
CSQL := PKG_SQL_BUILD.COMPATIBLE(SSQL => CSQL);
|
||||||
|
/* Формируем запрос */
|
||||||
|
PKG_SQL_BUILD.APPEND(SSQL => CSQL, SELEMENT1 => 'select *');
|
||||||
|
PKG_SQL_BUILD.APPEND(SSQL => CSQL, SELEMENT1 => ' from (select D.*,');
|
||||||
|
PKG_SQL_BUILD.APPEND(SSQL => CSQL, SELEMENT1 => PKG_SQL_BUILD.SQLROWNUM() || ' NROW');
|
||||||
|
PKG_SQL_BUILD.APPEND(SSQL => CSQL, SELEMENT1 => ' from (select SF.RN NRN,');
|
||||||
|
PKG_SQL_BUILD.APPEND(SSQL => CSQL, SELEMENT1 => ' TRIM(SH.NUMB) SNUMB,');
|
||||||
|
PKG_SQL_BUILD.APPEND(SSQL => CSQL, SELEMENT1 => ' COALESCE(SH.OPER_UK, FT.NAME) SOPERATION,');
|
||||||
|
PKG_SQL_BUILD.APPEND(SSQL => CSQL, SELEMENT1 => ' (select I.CODE from INS_DEPARTMENT I where SF.SUBDIV = I.RN) SEXECUTOR,');
|
||||||
|
PKG_SQL_BUILD.APPEND(SSQL => CSQL, SELEMENT1 => ' F_DICMUNTS_BASE_RECALC_QUANT(' || PKG_SQL_BUILD.WRAP_NUM(NVALUE => 0) || ',');
|
||||||
|
PKG_SQL_BUILD.APPEND(SSQL => CSQL, SELEMENT1 => ' :NCOMPANY,');
|
||||||
|
PKG_SQL_BUILD.APPEND(SSQL => CSQL, SELEMENT1 => ' SF.MUNIT,');
|
||||||
|
PKG_SQL_BUILD.APPEND(SSQL => CSQL, SELEMENT1 => ' SF.T_SHT_PLAN - SF.LABOUR_FACT,');
|
||||||
|
PKG_SQL_BUILD.APPEND(SSQL => CSQL, SELEMENT1 => ' :NDICMUNTS_WD) NREMN_LABOUR');
|
||||||
|
PKG_SQL_BUILD.APPEND(SSQL => CSQL, SELEMENT1 => ' from FCROUTLST F,');
|
||||||
|
PKG_SQL_BUILD.APPEND(SSQL => CSQL, SELEMENT1 => ' FCROUTLSTSP SF,');
|
||||||
|
PKG_SQL_BUILD.APPEND(SSQL => CSQL, SELEMENT1 => ' FCROUTSHTSP SH left outer join FCOPERTYPES FT on SH.OPER_TPS = FT.RN');
|
||||||
|
PKG_SQL_BUILD.APPEND(SSQL => CSQL, SELEMENT1 => ' where F.RN in (select SL."DOCUMENT"');
|
||||||
|
PKG_SQL_BUILD.APPEND(SSQL => CSQL, SELEMENT1 => ' from SELECTLIST SL');
|
||||||
|
PKG_SQL_BUILD.APPEND(SSQL => CSQL, SELEMENT1 => ' where SL.IDENT = :NFCROUTLST_IDENT');
|
||||||
|
PKG_SQL_BUILD.APPEND(SSQL => CSQL, SELEMENT1 => ' and SL.UNITCODE = ' || PKG_SQL_BUILD.WRAP_STR(SVALUE => 'CostRouteLists') || ')');
|
||||||
|
PKG_SQL_BUILD.APPEND(SSQL => CSQL, SELEMENT1 => ' and SF.PRN = F.RN');
|
||||||
|
PKG_SQL_BUILD.APPEND(SSQL => CSQL, SELEMENT1 => ' and SH.RN = SF.FCROUTSHTSP');
|
||||||
|
PKG_SQL_BUILD.APPEND(SSQL => CSQL, SELEMENT1 => ' and F.COMPANY = :NCOMPANY');
|
||||||
|
PKG_SQL_BUILD.APPEND(SSQL => CSQL, SELEMENT1 => ' %ORDER_BY%) D) F');
|
||||||
|
PKG_SQL_BUILD.APPEND(SSQL => CSQL, SELEMENT1 => ' where F.NROW between :NROW_FROM and :NROW_TO');
|
||||||
|
/* Учтём сортировки */
|
||||||
|
PKG_P8PANELS_VISUAL.TORDERS_SET_QUERY(RDATA_GRID => RDG, RORDERS => RO, SPATTERN => '%ORDER_BY%', CSQL => CSQL);
|
||||||
|
/* Разбираем его */
|
||||||
|
ICURSOR := PKG_SQL_DML.OPEN_CURSOR(SWHAT => 'SELECT');
|
||||||
|
PKG_SQL_DML.PARSE(ICURSOR => ICURSOR, SQUERY => CSQL);
|
||||||
|
/* Делаем подстановку параметров */
|
||||||
|
PKG_SQL_DML.BIND_VARIABLE_NUM(ICURSOR => ICURSOR, SNAME => 'NCOMPANY', NVALUE => NCOMPANY);
|
||||||
|
PKG_SQL_DML.BIND_VARIABLE_NUM(ICURSOR => ICURSOR, SNAME => 'NROW_FROM', NVALUE => NROW_FROM);
|
||||||
|
PKG_SQL_DML.BIND_VARIABLE_NUM(ICURSOR => ICURSOR, SNAME => 'NROW_TO', NVALUE => NROW_TO);
|
||||||
|
PKG_SQL_DML.BIND_VARIABLE_NUM(ICURSOR => ICURSOR, SNAME => 'NDICMUNTS_WD', NVALUE => NDICMUNTS_WD);
|
||||||
|
PKG_SQL_DML.BIND_VARIABLE_NUM(ICURSOR => ICURSOR, SNAME => 'NFCROUTLST_IDENT', NVALUE => NFCROUTLST_IDENT);
|
||||||
|
/* Описываем структуру записи курсора */
|
||||||
|
PKG_SQL_DML.DEFINE_COLUMN_NUM(ICURSOR => ICURSOR, IPOSITION => 1);
|
||||||
|
PKG_SQL_DML.DEFINE_COLUMN_STR(ICURSOR => ICURSOR, IPOSITION => 2);
|
||||||
|
PKG_SQL_DML.DEFINE_COLUMN_STR(ICURSOR => ICURSOR, IPOSITION => 3);
|
||||||
|
PKG_SQL_DML.DEFINE_COLUMN_STR(ICURSOR => ICURSOR, IPOSITION => 4);
|
||||||
|
PKG_SQL_DML.DEFINE_COLUMN_NUM(ICURSOR => ICURSOR, IPOSITION => 5);
|
||||||
|
PKG_SQL_DML.DEFINE_COLUMN_NUM(ICURSOR => ICURSOR, IPOSITION => 6);
|
||||||
|
/* Делаем выборку */
|
||||||
|
if (PKG_SQL_DML.EXECUTE(ICURSOR => ICURSOR) = 0) then
|
||||||
|
null;
|
||||||
|
end if;
|
||||||
|
/* Обходим выбранные записи */
|
||||||
|
while (PKG_SQL_DML.FETCH_ROWS(ICURSOR => ICURSOR) > 0)
|
||||||
|
loop
|
||||||
|
/* Добавляем колонки с данными */
|
||||||
|
PKG_P8PANELS_VISUAL.TROW_ADD_CUR_COLN(RROW => RDG_ROW,
|
||||||
|
SNAME => 'NRN',
|
||||||
|
ICURSOR => ICURSOR,
|
||||||
|
NPOSITION => 1,
|
||||||
|
BCLEAR => true);
|
||||||
|
PKG_P8PANELS_VISUAL.TROW_ADD_CUR_COLS(RROW => RDG_ROW,
|
||||||
|
SNAME => 'SNUMB',
|
||||||
|
ICURSOR => ICURSOR,
|
||||||
|
NPOSITION => 2);
|
||||||
|
PKG_P8PANELS_VISUAL.TROW_ADD_CUR_COLS(RROW => RDG_ROW,
|
||||||
|
SNAME => 'SOPERATION',
|
||||||
|
ICURSOR => ICURSOR,
|
||||||
|
NPOSITION => 3);
|
||||||
|
PKG_P8PANELS_VISUAL.TROW_ADD_CUR_COLS(RROW => RDG_ROW,
|
||||||
|
SNAME => 'SEXECUTOR',
|
||||||
|
ICURSOR => ICURSOR,
|
||||||
|
NPOSITION => 4);
|
||||||
|
PKG_P8PANELS_VISUAL.TROW_ADD_CUR_COLN(RROW => RDG_ROW,
|
||||||
|
SNAME => 'NREMN_LABOUR',
|
||||||
|
ICURSOR => ICURSOR,
|
||||||
|
NPOSITION => 5);
|
||||||
|
/* Добавляем строку в таблицу */
|
||||||
|
PKG_P8PANELS_VISUAL.TDATA_GRID_ADD_ROW(RDATA_GRID => RDG, RROW => RDG_ROW);
|
||||||
|
end loop;
|
||||||
|
exception
|
||||||
|
when others then
|
||||||
|
PKG_SQL_DML.CLOSE_CURSOR(ICURSOR => ICURSOR);
|
||||||
|
raise;
|
||||||
|
end;
|
||||||
|
end if;
|
||||||
|
/* Очищаем отмеченные маршрутные листы */
|
||||||
|
P_SELECTLIST_CLEAR(NIDENT => NFCROUTLST_IDENT);
|
||||||
|
/* Сериализуем описание */
|
||||||
|
COUT := PKG_P8PANELS_VISUAL.TDATA_GRID_TO_XML(RDATA_GRID => RDG, NINCLUDE_DEF => NINCLUDE_DEF);
|
||||||
|
exception
|
||||||
|
when others then
|
||||||
|
/* Очищаем отмеченные маршрутные листы */
|
||||||
|
P_SELECTLIST_CLEAR(NIDENT => NFCROUTLST_IDENT);
|
||||||
|
raise;
|
||||||
|
end FCROUTLST_MON_DG_GET;
|
||||||
|
|
||||||
|
/* Получение таблицы комплектовочных ведомостей, связанных с производственным составом */
|
||||||
|
procedure FCDELIVSH_DG_GET
|
||||||
|
(
|
||||||
|
NPRODCMPSP in number, -- Рег. номер производственного состава
|
||||||
|
NFCPRODPLAN in number, -- Рег. номер план
|
||||||
|
NPAGE_NUMBER in number, -- Номер страницы (игнорируется при NPAGE_SIZE=0)
|
||||||
|
NPAGE_SIZE in number, -- Количество записей на странице (0 - все)
|
||||||
|
CORDERS in clob, -- Сортировки
|
||||||
|
NINCLUDE_DEF in number, -- Признак включения описания колонок таблицы в ответ
|
||||||
|
COUT out clob -- Сериализованная таблица данных
|
||||||
|
)
|
||||||
|
is
|
||||||
|
NCOMPANY PKG_STD.TREF := GET_SESSION_COMPANY(); -- Организация сеанса
|
||||||
|
RO PKG_P8PANELS_VISUAL.TORDERS; -- Сортировки
|
||||||
|
RDG PKG_P8PANELS_VISUAL.TDATA_GRID; -- Описание таблицы
|
||||||
|
RDG_ROW PKG_P8PANELS_VISUAL.TROW; -- Строка таблицы
|
||||||
|
NROW_FROM PKG_STD.TREF; -- Номер строки с
|
||||||
|
NROW_TO PKG_STD.TREF; -- Номер строки по
|
||||||
|
CSQL clob; -- Буфер для запроса
|
||||||
|
ICURSOR integer; -- Курсор для исполнения запроса
|
||||||
|
NFCPRODPLANSP PKG_STD.TREF; -- Рег. номер спецификации связанного плана
|
||||||
|
begin
|
||||||
|
/* Читем сортировки */
|
||||||
|
RO := PKG_P8PANELS_VISUAL.TORDERS_FROM_XML(CORDERS => CORDERS);
|
||||||
|
/* Преобразуем номер и размер страницы в номер строк с и по */
|
||||||
|
PKG_P8PANELS_VISUAL.UTL_ROWS_LIMITS_CALC(NPAGE_NUMBER => NPAGE_NUMBER,
|
||||||
|
NPAGE_SIZE => NPAGE_SIZE,
|
||||||
|
NROW_FROM => NROW_FROM,
|
||||||
|
NROW_TO => NROW_TO);
|
||||||
|
/* Инициализируем таблицу данных */
|
||||||
|
RDG := PKG_P8PANELS_VISUAL.TDATA_GRID_MAKE();
|
||||||
|
/* Описываем колонки таблицы данных */
|
||||||
|
PKG_P8PANELS_VISUAL.TDATA_GRID_ADD_COL_DEF(RDATA_GRID => RDG,
|
||||||
|
SNAME => 'NRN',
|
||||||
|
SCAPTION => 'Рег. номер',
|
||||||
|
SDATA_TYPE => PKG_P8PANELS_VISUAL.SDATA_TYPE_NUMB,
|
||||||
|
BVISIBLE => false);
|
||||||
|
PKG_P8PANELS_VISUAL.TDATA_GRID_ADD_COL_DEF(RDATA_GRID => RDG,
|
||||||
|
SNAME => 'SSUBDIV',
|
||||||
|
SCAPTION => 'Цех',
|
||||||
|
SDATA_TYPE => PKG_P8PANELS_VISUAL.SDATA_TYPE_STR,
|
||||||
|
BVISIBLE => true);
|
||||||
|
PKG_P8PANELS_VISUAL.TDATA_GRID_ADD_COL_DEF(RDATA_GRID => RDG,
|
||||||
|
SNAME => 'SNOMEN',
|
||||||
|
SCAPTION => 'Номенклатура',
|
||||||
|
SDATA_TYPE => PKG_P8PANELS_VISUAL.SDATA_TYPE_STR,
|
||||||
|
BVISIBLE => true);
|
||||||
|
PKG_P8PANELS_VISUAL.TDATA_GRID_ADD_COL_DEF(RDATA_GRID => RDG,
|
||||||
|
SNAME => 'NQUANT_PROD',
|
||||||
|
SCAPTION => 'Применяемость на одно ВС',
|
||||||
|
SDATA_TYPE => PKG_P8PANELS_VISUAL.SDATA_TYPE_NUMB,
|
||||||
|
BVISIBLE => true);
|
||||||
|
PKG_P8PANELS_VISUAL.TDATA_GRID_ADD_COL_DEF(RDATA_GRID => RDG,
|
||||||
|
SNAME => 'SPROVIDER',
|
||||||
|
SCAPTION => 'Поставщик',
|
||||||
|
SDATA_TYPE => PKG_P8PANELS_VISUAL.SDATA_TYPE_STR,
|
||||||
|
BVISIBLE => true);
|
||||||
|
PKG_P8PANELS_VISUAL.TDATA_GRID_ADD_COL_DEF(RDATA_GRID => RDG,
|
||||||
|
SNAME => 'NDEFICIT',
|
||||||
|
SCAPTION => 'Дефицит',
|
||||||
|
SDATA_TYPE => PKG_P8PANELS_VISUAL.SDATA_TYPE_NUMB,
|
||||||
|
BVISIBLE => true);
|
||||||
|
/* Считываем рег. номер спецификации связанного плана */
|
||||||
|
NFCPRODPLANSP := FCPRODPLANSP_LINKED_GET(NPRODCMPSP => NPRODCMPSP, NFCPRODPLAN => NFCPRODPLAN);
|
||||||
|
/* Если спецификация считалась */
|
||||||
|
if (NFCPRODPLANSP is not null) then
|
||||||
|
begin
|
||||||
|
/* Добавляем подсказку совместимости */
|
||||||
|
CSQL := PKG_SQL_BUILD.COMPATIBLE(SSQL => CSQL);
|
||||||
|
/* Формируем запрос */
|
||||||
|
PKG_SQL_BUILD.APPEND(SSQL => CSQL, SELEMENT1 => 'select *');
|
||||||
|
PKG_SQL_BUILD.APPEND(SSQL => CSQL, SELEMENT1 => ' from (select D.*,');
|
||||||
|
PKG_SQL_BUILD.APPEND(SSQL => CSQL, SELEMENT1 => PKG_SQL_BUILD.SQLROWNUM() || ' NROW');
|
||||||
|
PKG_SQL_BUILD.APPEND(SSQL => CSQL, SELEMENT1 => ' from (select T.RN NRN,');
|
||||||
|
PKG_SQL_BUILD.APPEND(SSQL => CSQL, SELEMENT1 => ' (select I.CODE from INS_DEPARTMENT I where T.SUBDIV = I.RN) SSUBDIV,');
|
||||||
|
PKG_SQL_BUILD.APPEND(SSQL => CSQL, SELEMENT1 => ' NM.NOMEN_NAME SNOMEN,');
|
||||||
|
PKG_SQL_BUILD.APPEND(SSQL => CSQL, SELEMENT1 => ' T.QUANT_PROD NQUANT_PROD,');
|
||||||
|
PKG_SQL_BUILD.APPEND(SSQL => CSQL, SELEMENT1 => ' (select I2.CODE from INS_DEPARTMENT I2 where T.PR_SUBDIV = I2.RN) SPROVIDER,');
|
||||||
|
PKG_SQL_BUILD.APPEND(SSQL => CSQL, SELEMENT1 => ' T.DEFICIT NDEFICIT');
|
||||||
|
PKG_SQL_BUILD.APPEND(SSQL => CSQL, SELEMENT1 => ' from DOCLINKS D,');
|
||||||
|
PKG_SQL_BUILD.APPEND(SSQL => CSQL, SELEMENT1 => ' FCDELIVSHSP T,');
|
||||||
|
PKG_SQL_BUILD.APPEND(SSQL => CSQL, SELEMENT1 => ' FCMATRESOURCE F,');
|
||||||
|
PKG_SQL_BUILD.APPEND(SSQL => CSQL, SELEMENT1 => ' DICNOMNS NM');
|
||||||
|
PKG_SQL_BUILD.APPEND(SSQL => CSQL, SELEMENT1 => ' where D.IN_DOCUMENT = :NFCPRODPLANSP');
|
||||||
|
PKG_SQL_BUILD.APPEND(SSQL => CSQL, SELEMENT1 => ' and D.IN_UNITCODE = ' || PKG_SQL_BUILD.WRAP_STR(SVALUE => 'CostProductPlansSpecs'));
|
||||||
|
PKG_SQL_BUILD.APPEND(SSQL => CSQL, SELEMENT1 => ' and D.OUT_UNITCODE = ' || PKG_SQL_BUILD.WRAP_STR(SVALUE => 'CostDeliverySheets'));
|
||||||
|
PKG_SQL_BUILD.APPEND(SSQL => CSQL, SELEMENT1 => ' and T.PRN = D.OUT_DOCUMENT');
|
||||||
|
PKG_SQL_BUILD.APPEND(SSQL => CSQL, SELEMENT1 => ' and T.COMPANY = :NCOMPANY');
|
||||||
|
PKG_SQL_BUILD.APPEND(SSQL => CSQL, SELEMENT1 => ' and T.MATRES = F.RN');
|
||||||
|
PKG_SQL_BUILD.APPEND(SSQL => CSQL, SELEMENT1 => ' and F.NOMENCLATURE = NM.RN');
|
||||||
|
PKG_SQL_BUILD.APPEND(SSQL => CSQL, SELEMENT1 => ' %ORDER_BY%) D) F');
|
||||||
|
PKG_SQL_BUILD.APPEND(SSQL => CSQL, SELEMENT1 => ' where F.NROW between :NROW_FROM and :NROW_TO');
|
||||||
|
/* Учтём сортировки */
|
||||||
|
PKG_P8PANELS_VISUAL.TORDERS_SET_QUERY(RDATA_GRID => RDG, RORDERS => RO, SPATTERN => '%ORDER_BY%', CSQL => CSQL);
|
||||||
|
/* Разбираем его */
|
||||||
|
ICURSOR := PKG_SQL_DML.OPEN_CURSOR(SWHAT => 'SELECT');
|
||||||
|
PKG_SQL_DML.PARSE(ICURSOR => ICURSOR, SQUERY => CSQL);
|
||||||
|
/* Делаем подстановку параметров */
|
||||||
|
PKG_SQL_DML.BIND_VARIABLE_NUM(ICURSOR => ICURSOR, SNAME => 'NCOMPANY', NVALUE => NCOMPANY);
|
||||||
|
PKG_SQL_DML.BIND_VARIABLE_NUM(ICURSOR => ICURSOR, SNAME => 'NROW_FROM', NVALUE => NROW_FROM);
|
||||||
|
PKG_SQL_DML.BIND_VARIABLE_NUM(ICURSOR => ICURSOR, SNAME => 'NROW_TO', NVALUE => NROW_TO);
|
||||||
|
PKG_SQL_DML.BIND_VARIABLE_NUM(ICURSOR => ICURSOR, SNAME => 'NFCPRODPLANSP', NVALUE => NFCPRODPLANSP);
|
||||||
|
/* Описываем структуру записи курсора */
|
||||||
|
PKG_SQL_DML.DEFINE_COLUMN_NUM(ICURSOR => ICURSOR, IPOSITION => 1);
|
||||||
|
PKG_SQL_DML.DEFINE_COLUMN_STR(ICURSOR => ICURSOR, IPOSITION => 2);
|
||||||
|
PKG_SQL_DML.DEFINE_COLUMN_STR(ICURSOR => ICURSOR, IPOSITION => 3);
|
||||||
|
PKG_SQL_DML.DEFINE_COLUMN_NUM(ICURSOR => ICURSOR, IPOSITION => 4);
|
||||||
|
PKG_SQL_DML.DEFINE_COLUMN_STR(ICURSOR => ICURSOR, IPOSITION => 5);
|
||||||
|
PKG_SQL_DML.DEFINE_COLUMN_NUM(ICURSOR => ICURSOR, IPOSITION => 6);
|
||||||
|
PKG_SQL_DML.DEFINE_COLUMN_NUM(ICURSOR => ICURSOR, IPOSITION => 7);
|
||||||
|
/* Делаем выборку */
|
||||||
|
if (PKG_SQL_DML.EXECUTE(ICURSOR => ICURSOR) = 0) then
|
||||||
|
null;
|
||||||
|
end if;
|
||||||
|
/* Обходим выбранные записи */
|
||||||
|
while (PKG_SQL_DML.FETCH_ROWS(ICURSOR => ICURSOR) > 0)
|
||||||
|
loop
|
||||||
|
/* Добавляем колонки с данными */
|
||||||
|
PKG_P8PANELS_VISUAL.TROW_ADD_CUR_COLN(RROW => RDG_ROW,
|
||||||
|
SNAME => 'NRN',
|
||||||
|
ICURSOR => ICURSOR,
|
||||||
|
NPOSITION => 1,
|
||||||
|
BCLEAR => true);
|
||||||
|
PKG_P8PANELS_VISUAL.TROW_ADD_CUR_COLS(RROW => RDG_ROW,
|
||||||
|
SNAME => 'SSUBDIV',
|
||||||
|
ICURSOR => ICURSOR,
|
||||||
|
NPOSITION => 2);
|
||||||
|
PKG_P8PANELS_VISUAL.TROW_ADD_CUR_COLS(RROW => RDG_ROW,
|
||||||
|
SNAME => 'SNOMEN',
|
||||||
|
ICURSOR => ICURSOR,
|
||||||
|
NPOSITION => 3);
|
||||||
|
PKG_P8PANELS_VISUAL.TROW_ADD_CUR_COLN(RROW => RDG_ROW,
|
||||||
|
SNAME => 'NQUANT_PROD',
|
||||||
|
ICURSOR => ICURSOR,
|
||||||
|
NPOSITION => 4);
|
||||||
|
PKG_P8PANELS_VISUAL.TROW_ADD_CUR_COLS(RROW => RDG_ROW,
|
||||||
|
SNAME => 'SPROVIDER',
|
||||||
|
ICURSOR => ICURSOR,
|
||||||
|
NPOSITION => 5);
|
||||||
|
PKG_P8PANELS_VISUAL.TROW_ADD_CUR_COLS(RROW => RDG_ROW,
|
||||||
|
SNAME => 'NDEFICIT',
|
||||||
|
ICURSOR => ICURSOR,
|
||||||
|
NPOSITION => 6);
|
||||||
|
/* Добавляем строку в таблицу */
|
||||||
|
PKG_P8PANELS_VISUAL.TDATA_GRID_ADD_ROW(RDATA_GRID => RDG, RROW => RDG_ROW);
|
||||||
|
end loop;
|
||||||
|
exception
|
||||||
|
when others then
|
||||||
|
PKG_SQL_DML.CLOSE_CURSOR(ICURSOR => ICURSOR);
|
||||||
|
raise;
|
||||||
|
end;
|
||||||
|
end if;
|
||||||
|
/* Сериализуем описание */
|
||||||
|
COUT := PKG_P8PANELS_VISUAL.TDATA_GRID_TO_XML(RDATA_GRID => RDG, NINCLUDE_DEF => NINCLUDE_DEF);
|
||||||
|
end FCDELIVSH_DG_GET;
|
||||||
|
|
||||||
|
/* Считывание деталий для выбора SVG */
|
||||||
|
procedure FCPRODCMP_DETAILS_GET
|
||||||
|
(
|
||||||
|
NFCPRODPLAN in number, -- Рег. номер плана
|
||||||
|
COUT out clob -- Сериализованная таблица данных
|
||||||
|
)
|
||||||
|
is
|
||||||
|
NCOMPANY PKG_STD.TREF := GET_SESSION_COMPANY(); -- Организация сеанса
|
||||||
|
NDOC_PROP PKG_STD.TREF; -- Рег. номер свойства "ID"
|
||||||
|
NFCPRODPLANSP PKG_STD.TREF; -- Рег. номер связанной спецификации плана
|
||||||
|
begin
|
||||||
|
/* Начинаем формирование XML */
|
||||||
|
PKG_XFAST.PROLOGUE(ITYPE => PKG_XFAST.CONTENT_);
|
||||||
|
/* Считываем свойство документа */
|
||||||
|
FIND_DOCS_PROPS_CODE_EX(NFLAG_SMART => 0,
|
||||||
|
NCOMPVERS => NCOMPANY,
|
||||||
|
SUNITCODE => 'CostProductCompositionSpec',
|
||||||
|
SPROPCODE => 'ID',
|
||||||
|
NRN => NDOC_PROP);
|
||||||
|
/* Открываем корень */
|
||||||
|
PKG_XFAST.DOWN_NODE(SNAME => 'XDATA');
|
||||||
|
/* Цикл по планам и отчетам производства изделий */
|
||||||
|
for REC in (select S.RN NRN,
|
||||||
|
(select F.NAME from FCMATRESOURCE F where F.RN = S.MTR_RES) SNAME,
|
||||||
|
PV.NUM_VALUE NID
|
||||||
|
from FCPRODPLANSP T,
|
||||||
|
FCPRODCMPSP S,
|
||||||
|
DOCS_PROPS_VALS PV
|
||||||
|
where T.PRN = NFCPRODPLAN
|
||||||
|
and S.PRN = T.PRODCMP
|
||||||
|
and PV.DOCS_PROP_RN = NDOC_PROP
|
||||||
|
and PV.UNIT_RN = S.RN)
|
||||||
|
loop
|
||||||
|
/* Получаем рег. номер связанной спецификации плана */
|
||||||
|
NFCPRODPLANSP := FCPRODPLANSP_LINKED_GET(NPRODCMPSP => REC.NRN, NFCPRODPLAN => NFCPRODPLAN);
|
||||||
|
/* Открываем план */
|
||||||
|
PKG_XFAST.DOWN_NODE(SNAME => 'XFCPRODCMP');
|
||||||
|
/* Описываем план */
|
||||||
|
PKG_XFAST.ATTR(SNAME => 'NRN', NVALUE => REC.NRN);
|
||||||
|
PKG_XFAST.ATTR(SNAME => 'SNAME', SVALUE => REC.SNAME);
|
||||||
|
PKG_XFAST.ATTR(SNAME => 'NID', NVALUE => REC.NID);
|
||||||
|
PKG_XFAST.ATTR(SNAME => 'NFCPRODPLANSP', NVALUE => NFCPRODPLANSP);
|
||||||
|
/* Закрываем план */
|
||||||
|
PKG_XFAST.UP();
|
||||||
|
end loop;
|
||||||
|
/* Закрываем корень */
|
||||||
|
PKG_XFAST.UP();
|
||||||
|
/* Сериализуем */
|
||||||
|
COUT := PKG_XFAST.SERIALIZE_TO_CLOB();
|
||||||
|
/* Завершаем формирование XML */
|
||||||
|
PKG_XFAST.EPILOGUE();
|
||||||
|
exception
|
||||||
|
when others then
|
||||||
|
/* Завершаем формирование XML */
|
||||||
|
PKG_XFAST.EPILOGUE();
|
||||||
|
/* Вернем ошибку */
|
||||||
|
PKG_STATE.DIAGNOSTICS_STACKED();
|
||||||
|
P_EXCEPTION(0, PKG_STATE.SQL_ERRM());
|
||||||
|
end FCPRODCMP_DETAILS_GET;
|
||||||
|
|
||||||
|
/* Получение таблицы записей "Планы и отчеты производства изделий" */
|
||||||
|
procedure FCPRODPLAN_GET
|
||||||
|
(
|
||||||
|
NCRN in number, -- Рег. номер каталога
|
||||||
|
COUT out clob -- Сериализованная таблица данных
|
||||||
|
)
|
||||||
|
is
|
||||||
|
NCOMPANY PKG_STD.TREF := GET_SESSION_COMPANY(); -- Организация сеанса
|
||||||
|
NPROGRESS PKG_STD.TNUMBER; -- Прогресс плана
|
||||||
|
|
||||||
|
/* Получение номера плана из примечания */
|
||||||
|
function NUMB_BY_NOTE_GET
|
||||||
|
(
|
||||||
|
SNOTE in varchar2 -- Примечание
|
||||||
|
) return varchar2 -- Номер плана
|
||||||
|
is
|
||||||
|
begin
|
||||||
|
/* Возвращаем результат */
|
||||||
|
return TRIM(SUBSTR(SNOTE, INSTR(SNOTE, '№')+1, length(SNOTE)));
|
||||||
|
end NUMB_BY_NOTE_GET;
|
||||||
|
|
||||||
|
/* Получение детализации по прогрессу */
|
||||||
|
function DETAIL_BY_PROGRESS_GET
|
||||||
|
(
|
||||||
|
NPROGRESS in number -- Прогресс
|
||||||
|
) return varchar2 -- Детализация по прогрессу
|
||||||
|
is
|
||||||
|
SRESULT PKG_STD.TSTRING; -- Детализация по прогрессу
|
||||||
|
begin
|
||||||
|
/* Определяем детализацию по прогрессу */
|
||||||
|
case
|
||||||
|
when (NPROGRESS >= 70) then
|
||||||
|
SRESULT := 'Основная сборка: Стыковка агрегатов выполнена';
|
||||||
|
when (NPROGRESS >= 40) then
|
||||||
|
SRESULT := 'Изготовление агрегатов: Фюзеляж и ОЧК не переданы в цех ОС';
|
||||||
|
when (NPROGRESS >= 10) then
|
||||||
|
SRESULT := 'Изготовление ДСЕ: Фюзеляж и ОЧК не укомлектованы ДСЕ';
|
||||||
|
else
|
||||||
|
SRESULT := 'Изготовление ДСЕ не начато';
|
||||||
|
end case;
|
||||||
|
/* Возвращаем результат */
|
||||||
|
return SRESULT;
|
||||||
|
end DETAIL_BY_PROGRESS_GET;
|
||||||
|
begin
|
||||||
|
/* Начинаем формирование XML */
|
||||||
|
PKG_XFAST.PROLOGUE(ITYPE => PKG_XFAST.CONTENT_);
|
||||||
|
/* Открываем корень */
|
||||||
|
PKG_XFAST.DOWN_NODE(SNAME => 'XDATA');
|
||||||
|
/* Цикл по планам и отчетам производства изделий */
|
||||||
|
for REC in (select P.RN NRN,
|
||||||
|
P.NOTE SNOTE,
|
||||||
|
D_YEAR(EN.STARTDATE) NYEAR,
|
||||||
|
COALESCE(SUM(SP.LABOUR_FACT), 0) NLABOUR_FACT,
|
||||||
|
COALESCE(SUM(SP.LABOUR_NORM), 0) NLABOUR_NORM,
|
||||||
|
(select M.BDATA
|
||||||
|
from FILELINKS M,
|
||||||
|
FILELINKSUNITS U
|
||||||
|
where M.COMPANY = NCOMPANY
|
||||||
|
and U.TABLE_PRN = P.RN
|
||||||
|
and U.UNITCODE = 'CostProductPlans'
|
||||||
|
and M.RN = U.FILELINKS_PRN
|
||||||
|
and M.BDATA is not null
|
||||||
|
and rownum = 1) BIMAGE
|
||||||
|
from FCPRODPLAN P left outer join FCPRODPLANSP SP on P.RN = SP.PRN and ((SP.LABOUR_NORM is not null) or (SP.LABOUR_FACT is not null)),
|
||||||
|
FINSTATE FS,
|
||||||
|
ENPERIOD EN
|
||||||
|
where P.CRN = NCRN
|
||||||
|
and P.CATEGORY = NFCPRODPLAN_CATEGORY_MON
|
||||||
|
and P.STATUS = NFCPRODPLAN_STATUS_MON
|
||||||
|
and FS.RN = P.TYPE
|
||||||
|
and FS.CODE = SFCPRODPLAN_TYPE_MON
|
||||||
|
and EN.RN = P.CALC_PERIOD
|
||||||
|
and exists (select /*+ INDEX(UP I_USERPRIV_JUR_PERS_ROLEID) */
|
||||||
|
null
|
||||||
|
from USERPRIV UP
|
||||||
|
where UP.JUR_PERS = P.JUR_PERS
|
||||||
|
and UP.UNITCODE = 'CostProductPlans'
|
||||||
|
and UP.ROLEID in (select /*+ INDEX(UR I_USERROLES_AUTHID_FK) */
|
||||||
|
UR.ROLEID
|
||||||
|
from USERROLES UR
|
||||||
|
where UR.AUTHID = UTILIZER())
|
||||||
|
union all
|
||||||
|
select /*+ INDEX(UP I_USERPRIV_JUR_PERS_AUTHID) */
|
||||||
|
null
|
||||||
|
from USERPRIV UP
|
||||||
|
where UP.JUR_PERS = P.JUR_PERS
|
||||||
|
and UP.UNITCODE = 'CostProductPlans'
|
||||||
|
and UP.AUTHID = UTILIZER())
|
||||||
|
group by P.RN, P.NOTE, EN.STARTDATE
|
||||||
|
order by EN.STARTDATE asc)
|
||||||
|
loop
|
||||||
|
/* Открываем план */
|
||||||
|
PKG_XFAST.DOWN_NODE(SNAME => 'XFCPRODPLAN_INFO');
|
||||||
|
/* Описываем план */
|
||||||
|
PKG_XFAST.ATTR(SNAME => 'NRN', NVALUE => REC.NRN);
|
||||||
|
PKG_XFAST.ATTR(SNAME => 'SNUMB', SVALUE => NUMB_BY_NOTE_GET(SNOTE => REC.SNOTE));
|
||||||
|
/* Определяем прогресс */
|
||||||
|
if (REC.NLABOUR_NORM = 0) then
|
||||||
|
/* Не можем определить прогресс */
|
||||||
|
NPROGRESS := 0;
|
||||||
|
else
|
||||||
|
/* Если факта нет */
|
||||||
|
if (REC.NLABOUR_FACT = 0) then
|
||||||
|
/* Не можем определить прогресс */
|
||||||
|
NPROGRESS := 0;
|
||||||
|
else
|
||||||
|
/* Не можем определить прогресс */
|
||||||
|
NPROGRESS := REC.NLABOUR_FACT / REC.NLABOUR_NORM;
|
||||||
|
end if;
|
||||||
|
end if;
|
||||||
|
PKG_XFAST.ATTR(SNAME => 'NPROGRESS', NVALUE => NPROGRESS);
|
||||||
|
PKG_XFAST.ATTR(SNAME => 'SDETAIL', SVALUE => DETAIL_BY_PROGRESS_GET(NPROGRESS => NPROGRESS));
|
||||||
|
PKG_XFAST.ATTR(SNAME => 'NYEAR', NVALUE => REC.NYEAR);
|
||||||
|
PKG_XFAST.VALUE(lbVALUE => REC.BIMAGE);
|
||||||
|
/* Закрываем план */
|
||||||
|
PKG_XFAST.UP();
|
||||||
|
end loop;
|
||||||
|
/* Закрываем корень */
|
||||||
|
PKG_XFAST.UP();
|
||||||
|
/* Сериализуем */
|
||||||
|
COUT := PKG_XFAST.SERIALIZE_TO_CLOB();
|
||||||
|
/* Завершаем формирование XML */
|
||||||
|
PKG_XFAST.EPILOGUE();
|
||||||
|
exception
|
||||||
|
when others then
|
||||||
|
/* Завершаем формирование XML */
|
||||||
|
PKG_XFAST.EPILOGUE();
|
||||||
|
/* Вернем ошибку */
|
||||||
|
PKG_STATE.DIAGNOSTICS_STACKED();
|
||||||
|
P_EXCEPTION(0, PKG_STATE.SQL_ERRM());
|
||||||
|
end FCPRODPLAN_GET;
|
||||||
|
|
||||||
|
/* Инициализация каталогов раздела "Планы и отчеты производства изделий" */
|
||||||
|
procedure FCPRODPLAN_CTLG_INIT
|
||||||
|
(
|
||||||
|
COUT out clob -- Список каталогов раздела "Планы и отчеты производства изделий"
|
||||||
|
)
|
||||||
|
is
|
||||||
|
begin
|
||||||
|
/* Начинаем формирование XML */
|
||||||
|
PKG_XFAST.PROLOGUE(ITYPE => PKG_XFAST.CONTENT_);
|
||||||
|
/* Открываем корень */
|
||||||
|
PKG_XFAST.DOWN_NODE(SNAME => 'XDATA');
|
||||||
|
/* Цикл по планам и отчетам производства изделий */
|
||||||
|
for REC in (select TMP.NRN,
|
||||||
|
TMP.SNAME,
|
||||||
|
count(P.RN) NCOUNT_DOCS,
|
||||||
|
min(D_YEAR(P.DOCDATE)) NMIN_YEAR,
|
||||||
|
max(D_YEAR(P.DOCDATE)) NMAX_YEAR
|
||||||
|
from (select T.RN as NRN,
|
||||||
|
T.NAME as SNAME
|
||||||
|
from ACATALOG T,
|
||||||
|
UNITLIST UL
|
||||||
|
where T.DOCNAME = 'CostProductPlans'
|
||||||
|
and T.SIGNS = 1
|
||||||
|
and T.DOCNAME = UL.UNITCODE
|
||||||
|
and (UL.SHOW_INACCESS_CTLG = 1 or exists
|
||||||
|
(select null from V_USERPRIV UP where UP.CATALOG = T.RN) or exists
|
||||||
|
(select null
|
||||||
|
from ACATALOG T1
|
||||||
|
where exists (select null from V_USERPRIV UP where UP.CATALOG = T1.RN)
|
||||||
|
connect by prior T1.RN = T1.CRN
|
||||||
|
start with T1.CRN = T.RN))
|
||||||
|
order by T.NAME asc) TMP
|
||||||
|
left outer join FCPRODPLAN P
|
||||||
|
on TMP.NRN = P.CRN
|
||||||
|
and P.CATEGORY = NFCPRODPLAN_CATEGORY_MON
|
||||||
|
and P.STATUS = NFCPRODPLAN_STATUS_MON
|
||||||
|
and exists (select /*+ INDEX(UP I_USERPRIV_JUR_PERS_ROLEID) */
|
||||||
|
null
|
||||||
|
from USERPRIV UP
|
||||||
|
where UP.JUR_PERS = P.JUR_PERS
|
||||||
|
and UP.UNITCODE = 'CostProductPlans'
|
||||||
|
and UP.ROLEID in (select /*+ INDEX(UR I_USERROLES_AUTHID_FK) */
|
||||||
|
UR.ROLEID
|
||||||
|
from USERROLES UR
|
||||||
|
where UR.AUTHID = UTILIZER())
|
||||||
|
union all
|
||||||
|
select /*+ INDEX(UP I_USERPRIV_JUR_PERS_AUTHID) */
|
||||||
|
null
|
||||||
|
from USERPRIV UP
|
||||||
|
where UP.JUR_PERS = P.JUR_PERS
|
||||||
|
and UP.UNITCODE = 'CostProductPlans'
|
||||||
|
and UP.AUTHID = UTILIZER())
|
||||||
|
left outer join FINSTATE FS
|
||||||
|
on P.TYPE = FS.RN
|
||||||
|
and FS.CODE = SFCPRODPLAN_TYPE_MON
|
||||||
|
group by TMP.NRN,
|
||||||
|
TMP.SNAME
|
||||||
|
order by TMP.SNAME asc)
|
||||||
|
loop
|
||||||
|
/* Открываем план */
|
||||||
|
PKG_XFAST.DOWN_NODE(SNAME => 'XFCPRODPLAN_CRNS');
|
||||||
|
/* Описываем план */
|
||||||
|
PKG_XFAST.ATTR(SNAME => 'NRN', NVALUE => REC.NRN);
|
||||||
|
PKG_XFAST.ATTR(SNAME => 'SNAME', SVALUE => REC.SNAME);
|
||||||
|
PKG_XFAST.ATTR(SNAME => 'NCOUNT_DOCS', NVALUE => REC.NCOUNT_DOCS);
|
||||||
|
PKG_XFAST.ATTR(SNAME => 'NMIN_YEAR', NVALUE => REC.NMIN_YEAR);
|
||||||
|
PKG_XFAST.ATTR(SNAME => 'NMAX_YEAR', NVALUE => REC.NMAX_YEAR);
|
||||||
|
/* Закрываем план */
|
||||||
|
PKG_XFAST.UP();
|
||||||
|
end loop;
|
||||||
|
/* Закрываем корень */
|
||||||
|
PKG_XFAST.UP();
|
||||||
|
/* Сериализуем */
|
||||||
|
COUT := PKG_XFAST.SERIALIZE_TO_CLOB();
|
||||||
|
/* Завершаем формирование XML */
|
||||||
|
PKG_XFAST.EPILOGUE();
|
||||||
|
exception
|
||||||
|
when others then
|
||||||
|
/* Завершаем формирование XML */
|
||||||
|
PKG_XFAST.EPILOGUE();
|
||||||
|
/* Вернем ошибку */
|
||||||
|
PKG_STATE.DIAGNOSTICS_STACKED();
|
||||||
|
P_EXCEPTION(0, PKG_STATE.SQL_ERRM());
|
||||||
|
end FCPRODPLAN_CTLG_INIT;
|
||||||
|
|
||||||
end PKG_P8PANELS_MECHREC;
|
end PKG_P8PANELS_MECHREC;
|
||||||
/
|
/
|
||||||
|
@ -21,6 +21,10 @@
|
|||||||
<MenuItem parent="{BA073333-DFBC-4BA3-8EA7-172F3F6B4FEE}" name="ShowMechRecPanelsRoot" caption="Панели мониторинга" url="Modules/P8-Panels/"/>
|
<MenuItem parent="{BA073333-DFBC-4BA3-8EA7-172F3F6B4FEE}" name="ShowMechRecPanelsRoot" caption="Панели мониторинга" url="Modules/P8-Panels/"/>
|
||||||
<MenuItem parent="{BA073333-DFBC-4BA3-8EA7-172F3F6B4FEE}" separator="true"/>
|
<MenuItem parent="{BA073333-DFBC-4BA3-8EA7-172F3F6B4FEE}" separator="true"/>
|
||||||
<MenuItem parent="{BA073333-DFBC-4BA3-8EA7-172F3F6B4FEE}" name="ShowMechRecPanelCostProdPlans" caption="Производственная программа" panelName="MechRecCostProdPlans"/>
|
<MenuItem parent="{BA073333-DFBC-4BA3-8EA7-172F3F6B4FEE}" name="ShowMechRecPanelCostProdPlans" caption="Производственная программа" panelName="MechRecCostProdPlans"/>
|
||||||
|
<MenuItem parent="{BA073333-DFBC-4BA3-8EA7-172F3F6B4FEE}" name="ShowMechRecPanelDeptCostProdPlans" caption="Производственный план цеха" panelName="MechRecDeptCostProdPlans"/>
|
||||||
|
<MenuItem parent="{BA073333-DFBC-4BA3-8EA7-172F3F6B4FEE}" name="ShowMechRecPanelDeptCostJobsManage" caption="Выдача сменного задания" panelName="MechRecCostJobsManage"/>
|
||||||
|
<MenuItem parent="{BA073333-DFBC-4BA3-8EA7-172F3F6B4FEE}" name="ShowMechRecPanelDeptCostJobs" caption="Загрузка цеха" panelName="MechRecDeptCostJobs"/>
|
||||||
|
<MenuItem parent="{BA073333-DFBC-4BA3-8EA7-172F3F6B4FEE}" name="ShowMechRecPanelAssemblyMon" caption=" Мониторинг сборки изделий" panelName="MechRecAssemblyMon"/>
|
||||||
</App>
|
</App>
|
||||||
</MenuItems>
|
</MenuItems>
|
||||||
<Panels urlBase="Modules/p8-panels/#/">
|
<Panels urlBase="Modules/p8-panels/#/">
|
||||||
@ -84,6 +88,46 @@
|
|||||||
icon="calendar_month"
|
icon="calendar_month"
|
||||||
showInPanelsList="true"
|
showInPanelsList="true"
|
||||||
preview="./img/mech_rec_cost_prod_plans.jpg"/>
|
preview="./img/mech_rec_cost_prod_plans.jpg"/>
|
||||||
|
<Panel
|
||||||
|
name="MechRecDeptCostProdPlans"
|
||||||
|
group="Планирование и учёт в дискретном производстве"
|
||||||
|
caption="Производственный план цеха"
|
||||||
|
desc="Мониторинг и управление (установка приоритетов партий, заказов) производственным планом цеха"
|
||||||
|
url="mech_rec_dept_cost_prod_plans"
|
||||||
|
path="mech_rec_dept_cost_prod_plans"
|
||||||
|
icon="free_cancellation"
|
||||||
|
showInPanelsList="true"
|
||||||
|
preview="./img/mech_rec_cost_prod_plans.jpg"/>
|
||||||
|
<Panel
|
||||||
|
name="MechRecCostJobsManage"
|
||||||
|
group="Планирование и учёт в дискретном производстве"
|
||||||
|
caption="Выдача сменного задания"
|
||||||
|
desc="Управление составом сменных заданий цеха/участка"
|
||||||
|
url="mech_rec_cost_jobs_manage"
|
||||||
|
path="mech_rec_cost_jobs_manage"
|
||||||
|
icon="free_cancellation"
|
||||||
|
showInPanelsList="true"
|
||||||
|
preview="./img/mech_rec_cost_prod_plans.jpg"/>
|
||||||
|
<Panel
|
||||||
|
name="MechRecDeptCostJobs"
|
||||||
|
group="Планирование и учёт в дискретном производстве"
|
||||||
|
caption="Загрузка цеха"
|
||||||
|
desc="Просмотр сведений о производственной загрузке цеха/участка"
|
||||||
|
url="mech_rec_dept_cost_jobs"
|
||||||
|
path="mech_rec_dept_cost_jobs"
|
||||||
|
icon="insert_invitation"
|
||||||
|
showInPanelsList="true"
|
||||||
|
preview="./img/mech_rec_cost_prod_plans.jpg"/>
|
||||||
|
<Panel
|
||||||
|
name="MechRecAssemblyMon"
|
||||||
|
group="Планирование и учёт в дискретном производстве"
|
||||||
|
caption="Мониторинг сборки изделий"
|
||||||
|
desc="Отображение текущего состояния комплектации и сборки изделий производственными подразделениями"
|
||||||
|
url="mech_rec_assembly_mon"
|
||||||
|
path="mech_rec_assembly_mon"
|
||||||
|
icon="insert_invitation"
|
||||||
|
showInPanelsList="true"
|
||||||
|
preview="./img/mech_rec_cost_prod_plans.jpg"/>
|
||||||
<Panel
|
<Panel
|
||||||
name="Samples"
|
name="Samples"
|
||||||
group=""
|
group=""
|
||||||
|
Loading…
x
Reference in New Issue
Block a user