ЦИТК-802 - Изменения блока выбора каталога

This commit is contained in:
Dollerino 2024-02-16 17:24:08 +03:00
parent ab30b92d9a
commit a0e9be4c4b
3 changed files with 118 additions and 15 deletions

View File

@ -13,10 +13,14 @@ import React from "react"; //Классы React
//Тело модуля //Тело модуля
//----------- //-----------
//Клиентский отбор загруженных планов по поисковой фразе //Клиентский отбор каталогов по поисковой фразе и наличию планов
export const useFilteredPlanCtlgs = (planCtlgs, filter) => { export const useFilteredPlanCtlgs = (planCtlgs, filter) => {
const filteredPlanCtlgs = React.useMemo(() => { const filteredPlanCtlgs = React.useMemo(() => {
return planCtlgs.filter(catalog => catalog.SNAME.toString().toLowerCase().includes(filter)); return planCtlgs.filter(
catalog =>
catalog.SNAME.toString().toLowerCase().includes(filter.ctlgName) &&
(filter.haveDocs ? catalog.NCOUNT_DOCS > 0 : catalog.NCOUNT_DOCS >= 0)
);
}, [planCtlgs, filter]); }, [planCtlgs, filter]);
return filteredPlanCtlgs; return filteredPlanCtlgs;

View File

@ -9,7 +9,23 @@
import React, { useContext, useState, useCallback, useEffect } from "react"; //Классы React import React, { useContext, useState, useCallback, useEffect } from "react"; //Классы React
import PropTypes from "prop-types"; //Контроль свойств компонента import PropTypes from "prop-types"; //Контроль свойств компонента
import { Drawer, Fab, Box, List, ListItemButton, ListItemText, Typography, Grid, TextField, Select, MenuItem, InputLabel } from "@mui/material"; //Интерфейсные элементы import {
Drawer,
Fab,
Box,
List,
ListItemButton,
ListItemText,
Typography,
Grid,
TextField,
Select,
MenuItem,
InputLabel,
FormGroup,
FormControlLabel,
Checkbox
} from "@mui/material"; //Интерфейсные элементы
import { BackEndСtx } from "../../context/backend"; //Контекст взаимодействия с сервером import { BackEndСtx } from "../../context/backend"; //Контекст взаимодействия с сервером
import { MessagingСtx } from "../../context/messaging"; //Контекст сообщений import { MessagingСtx } from "../../context/messaging"; //Контекст сообщений
import { P8P_GANTT_CONFIG_PROPS } from "../../config_wrapper"; //Подключение компонентов к настройкам приложения import { P8P_GANTT_CONFIG_PROPS } from "../../config_wrapper"; //Подключение компонентов к настройкам приложения
@ -21,6 +37,9 @@ import { useFilteredPlanCtlgs } from "./hooks"; //Вспомогательные
//Константы //Константы
//--------- //---------
//Склонения для документов
const DECLINATIONS = ["план", "плана", "планов"];
//Поля сортировки //Поля сортировки
const SORT_REP_DATE = "DREP_DATE"; const SORT_REP_DATE = "DREP_DATE";
const SORT_REP_DATE_TO = "DREP_DATE_TO"; const SORT_REP_DATE_TO = "DREP_DATE_TO";
@ -34,13 +53,16 @@ const GANTT_WIDTH = "98vw";
//Стили //Стили
const STYLES = { const STYLES = {
PLANS_FINDER: { marginTop: "10px", marginLeft: "10px", width: "93%" }, 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_PRIMARY: { wordWrap: "break-word" },
PLANS_LIST_ITEM_SECONDARY: { wordWrap: "break-word", fontSize: "0.6rem", textTransform: "uppercase" },
PLANS_BUTTON: { position: "absolute" }, PLANS_BUTTON: { position: "absolute" },
PLANS_DRAWER: { PLANS_DRAWER: {
minWidth: "250px", width: "350px",
display: "inline-block", display: "inline-block",
flexShrink: 0, flexShrink: 0,
[`& .MuiDrawer-paper`]: { minWidth: "250px", display: "inline-block", boxSizing: "border-box" } [`& .MuiDrawer-paper`]: { width: "350px", display: "inline-block", boxSizing: "border-box" }
}, },
GANTT_CONTAINER: { height: GANTT_HEIGHT, width: GANTT_WIDTH }, GANTT_CONTAINER: { height: GANTT_HEIGHT, width: GANTT_WIDTH },
GANTT_TITLE: { paddingLeft: "100px", paddingRight: "120px" } GANTT_TITLE: { paddingLeft: "100px", paddingRight: "120px" }
@ -59,6 +81,26 @@ const parseProdPlanSpXML = async xmlDoc => {
return data.XDATA; return data.XDATA;
}; };
//Форматирование для отображения количества документов
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 } = {}) => { const PlanCtlgsList = ({ planCtlgs = [], selectedPlanCtlg, filter, setFilter, onClick } = {}) => {
//Генерация содержимого //Генерация содержимого
@ -67,18 +109,48 @@ const PlanCtlgsList = ({ planCtlgs = [], selectedPlanCtlg, filter, setFilter, on
<TextField <TextField
sx={STYLES.PLANS_FINDER} sx={STYLES.PLANS_FINDER}
name="planFilter" name="planFilter"
label="План" label="Каталог"
value={filter} value={filter.ctlgName}
variant="standard" variant="standard"
fullWidth fullWidth
onChange={event => { onChange={event => {
setFilter(event.target.value); setFilter(pv => ({ ...pv, ctlgName: event.target.value }));
}} }}
></TextField> ></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> <List>
{planCtlgs.map(p => ( {planCtlgs.map(p => (
<ListItemButton key={p.NRN} selected={p.NRN === selectedPlanCtlg} onClick={() => (onClick ? onClick(p) : null)}> <ListItemButton
<ListItemText primary={<Typography sx={STYLES.PLANS_LIST_ITEM_PRIMARY}>{p.SNAME}</Typography>} /> sx={p.NCOUNT_DOCS == 0 ? STYLES.PLANS_LIST_ITEM_ZERODOCS : null}
key={p.NRN}
selected={p.NRN === selectedPlanCtlg}
onClick={() => (onClick ? onClick(p) : 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> </ListItemButton>
))} ))}
</List> </List>
@ -116,9 +188,10 @@ const MechRecCostProdPlans = () => {
selectedPlanCtlgGanttDef: {}, selectedPlanCtlgGanttDef: {},
selectedPlanCtlgSpecs: [] selectedPlanCtlgSpecs: []
}); });
//Состояние для фильтра каталогов
const [filter, setFilter] = useState({ ctlgName: "", haveLinks: false });
const [filter, setFilter] = useState(""); //Массив отфильтрованных каталогов
const filteredPlanCtgls = useFilteredPlanCtlgs(state.planCtlgs, filter); const filteredPlanCtgls = useFilteredPlanCtlgs(state.planCtlgs, filter);
//Подключение к контексту сообщений //Подключение к контексту сообщений

View File

@ -557,7 +557,32 @@ create or replace package body PKG_P8PANELS_MECHREC as
PKG_XFAST.DOWN_NODE(SNAME => 'XDATA'); PKG_XFAST.DOWN_NODE(SNAME => 'XDATA');
/* Цикл по планам и отчетам производства изделий */ /* Цикл по планам и отчетам производства изделий */
for REC in (select T.RN as NRN, for REC in (select T.RN as NRN,
T.NAME as SNAME T.NAME as SNAME,
(select count(P.RN)
from FCPRODPLAN P,
FINSTATE FS
where P.CRN = T.RN
and P.CATEGORY = NFCPRODPLAN_CATEGORY
and P.STATUS = NFCPRODPLAN_STATUS
and FS.RN = P.TYPE
and FS.CODE = SFCPRODPLAN_TYPE
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)) as NCOUNT_DOCS
from ACATALOG T, from ACATALOG T,
UNITLIST UL UNITLIST UL
where T.DOCNAME = 'CostProductPlans' where T.DOCNAME = 'CostProductPlans'
@ -577,6 +602,7 @@ create or replace package body PKG_P8PANELS_MECHREC as
/* Описываем план */ /* Описываем план */
PKG_XFAST.ATTR(SNAME => 'NRN', NVALUE => REC.NRN); PKG_XFAST.ATTR(SNAME => 'NRN', NVALUE => REC.NRN);
PKG_XFAST.ATTR(SNAME => 'SNAME', SVALUE => REC.SNAME); PKG_XFAST.ATTR(SNAME => 'SNAME', SVALUE => REC.SNAME);
PKG_XFAST.ATTR(SNAME => 'NCOUNT_DOCS', NVALUE => REC.NCOUNT_DOCS);
/* Закрываем план */ /* Закрываем план */
PKG_XFAST.UP(); PKG_XFAST.UP();
end loop; end loop;