ЦИТК-902 - вызов панели "Производственная программа" из контекстного меню

This commit is contained in:
Mikhail Chechnev 2024-09-20 14:58:41 +03:00
parent 17b4c55d53
commit 79eea7f38f
2 changed files with 122 additions and 58 deletions

View File

@ -40,7 +40,9 @@ import {
} from "@mui/material"; //Интерфейсные элементы
import { BackEndСtx } from "../../context/backend"; //Контекст взаимодействия с сервером
import { MessagingСtx } from "../../context/messaging"; //Контекст сообщений
import { NavigationCtx } from "../../context/navigation"; //Контекст навигации
import { P8P_GANTT_CONFIG_PROPS } from "../../config_wrapper"; //Подключение компонентов к настройкам приложения
import { APP_BAR_HEIGHT } from "../../components/p8p_app_workspace"; //Заголовок страницы
import { P8PGantt, taskLegendDesc } from "../../components/p8p_gantt"; //Диаграмма Ганта
import { xml2JSON, formatDateJSONDateOnly, formatDateRF, hasValue } from "../../core/utils"; //Вспомогательные функции
import { useFilteredPlanCtlgs } from "./hooks"; //Вспомогательные хуки
@ -58,12 +60,6 @@ const DECLINATIONS = ["план", "плана", "планов"];
const SORT_REP_DATE = "DREP_DATE";
const SORT_REP_DATE_TO = "DREP_DATE_TO";
//Высота диаграммы Ганта
const GANTT_HEIGHT = "75vh";
//Ширина диаграммы Ганта
const GANTT_WIDTH = "98vw";
//Стили
const STYLES = {
PLANS_FINDER: { marginTop: "10px", marginLeft: "10px", width: "93%" },
@ -71,20 +67,23 @@ const STYLES = {
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_BUTTON: { position: "absolute", top: `calc(${APP_BAR_HEIGHT} + 16px)`, left: "16px" },
PLANS_DRAWER: {
width: "350px",
display: "inline-block",
flexShrink: 0,
[`& .MuiDrawer-paper`]: { width: "350px", display: "inline-block", boxSizing: "border-box" }
},
GANTT_CONTAINER: { height: GANTT_HEIGHT, width: GANTT_WIDTH },
GANTT_TITLE: { paddingLeft: "100px", paddingRight: "120px" },
GANTT_CONTAINER: { height: `calc(100vh - ${APP_BAR_HEIGHT})`, width: "100vw", paddingTop: "24px" },
GANTT_TITLE: { paddingLeft: "250px", paddingRight: "250px" },
SECOND_TABLE: { paddingTop: "30px" },
TASK_DIALOG_CARD_CONTAINER: { padding: "0px" },
TASK_DIALOG_LIST_ITEM_ICON: { justifyContent: "center" },
TASK_DIALOG_ICON: { fontSize: "2rem" },
TASK_DIALOG_ACTION_CONTAINER: { border: 1, borderColor: "text.primary", borderRadius: "5px", width: "100%" }
TASK_DIALOG_ACTION_CONTAINER: { border: 1, borderColor: "text.primary", borderRadius: "5px", width: "100%" },
FILTERS: { display: "table", float: "right" },
FILTERS_DATE: { display: "table-cell", verticalAlign: "middle" },
FILTERS_LEVEL: { display: "table-cell", verticalAlign: "middle", paddingLeft: "15px" }
};
//------------------------------------
@ -148,7 +147,7 @@ const PlanCtlgsList = ({ planCtlgs = [], selectedPlanCtlg, filter, setFilter, on
>
<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>}
secondary={<Typography sx={STYLES.PLANS_LIST_ITEM_SECONDARY}>{formatCountDocs(p.NCOUNT_DOCS)}</Typography>}
/>
</ListItemButton>
))}
@ -210,7 +209,9 @@ const taskDialogRenderer = ({ task, taskColors, close, handleTaskDetailOpen }) =
{task["detail_list"]}
</Button>
) : (
<Typography color="textSecondary">{`Анализ отклонений недоступен: ${task["detail_list"]}`}</Typography>
<Typography color="textSecondary">{`Анализ отклонений недоступен${
task["detail_list"] ? `: ${task["detail_list"]}` : ""
}`}</Typography>
)}
</Box>
</CardActions>
@ -239,7 +240,8 @@ const MechRecCostProdPlans = () => {
selectedPlanCtlgGanttDef: {},
selectedPlanCtlgSpecs: [],
selectedTaskDetail: null,
selectedTaskDetailType: null
selectedTaskDetailType: null,
planSpec: null
});
//Состояние для фильтра каталогов
const [filter, setFilter] = useState({ ctlgName: "", haveDocs: false });
@ -253,7 +255,10 @@ const MechRecCostProdPlans = () => {
//Подключение к контексту взаимодействия с сервером
const { executeStored } = useContext(BackEndСtx);
// Инициализация каталогов планов
//Подключение к контексту навигации
const { getNavigationSearch } = useContext(NavigationCtx);
//Инициализация каталогов планов
const initPlanCtlgs = useCallback(async () => {
if (!state.init) {
const data = await executeStored({
@ -307,7 +312,7 @@ const MechRecCostProdPlans = () => {
async (level = null, sort = null) => {
const data = await executeStored({
stored: "PKG_P8PANELS_MECHREC.FCPRODPLANSP_GET",
args: { NCRN: state.selectedPlanCtlg, NLEVEL: level, SSORT_FIELD: sort }
args: { NCRN: state.selectedPlanCtlg, NLEVEL: level, SSORT_FIELD: sort, NFCPRODPLANSP: state.planSpec }
});
let doc = await parseProdPlanSpXML(data.COUT);
setState(pv => ({
@ -324,7 +329,7 @@ const MechRecCostProdPlans = () => {
}));
},
// eslint-disable-next-line react-hooks/exhaustive-deps
[executeStored, state.ident, state.selectedPlanCtlg]
[executeStored, state.ident, state.selectedPlanCtlg, state.planSpec]
);
//Обработка нажатия на элемент в списке каталогов планов
@ -335,14 +340,16 @@ const MechRecCostProdPlans = () => {
//При подключении компонента к странице
useEffect(() => {
initPlanCtlgs();
const actionPrms = getNavigationSearch();
if (actionPrms.NSPRN) setState(pv => ({ ...pv, planSpec: parseInt(actionPrms.NSPRN), init: true }));
else initPlanCtlgs();
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
//При смене выбранного каталога плана
//При смене выбранного каталога плана или при явном указании позиции спецификации плана
useEffect(() => {
if (state.selectedPlanCtlg) loadPlanCtglSpecs(null, SORT_REP_DATE_TO);
}, [state.selectedPlanCtlg, loadPlanCtglSpecs]);
if (state.selectedPlanCtlg || state.planSpec) loadPlanCtglSpecs(null, SORT_REP_DATE_TO);
}, [state.selectedPlanCtlg, state.planSpec, loadPlanCtglSpecs]);
//Выбор уровня
const handleChangeSelectLevel = selectedLevel => {
@ -368,35 +375,48 @@ const MechRecCostProdPlans = () => {
//Генерация содержимого
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}
>
<PlanCtlgsList
planCtlgs={filteredPlanCtgls}
selectedPlanCtlg={state.selectedPlanCtlg}
filter={filter}
setFilter={setFilter}
onClick={handleProjectClick}
/>
</Drawer>
<Box>
{!state.planSpec ? (
<>
<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}
filter={filter}
setFilter={setFilter}
onClick={handleProjectClick}
/>
</Drawer>
</>
) : null}
{state.init == true ? (
<Grid container spacing={1}>
<Grid container>
<Grid item xs={12}>
{state.selectedPlanCtlgSpecsLoaded ? (
state.selectedPlanCtlgSpecs.length === 0 ? (
<InlineMsgInfo okBtn={false} text={"В каталоге планов отсутствуют записи спецификации"} />
<Box pt={3}>
<InlineMsgInfo
okBtn={false}
text={
state.planSpec
? "Не найдено данных для выбранной позиции плана"
: "В каталоге планов отсутствуют записи спецификации"
}
/>
</Box>
) : (
<Box sx={STYLES.GANTT_CONTAINER} p={1}>
<Box>
{state.selectedPlanCtlgMaxLevel ? (
<Box sx={{ display: "table", float: "right" }}>
<Box sx={{ display: "table-cell", verticalAlign: "middle" }}>
<Box sx={STYLES.FILTERS} p={1}>
<Box sx={STYLES.FILTERS_DATE}>
<InputLabel id="select-label-sort">Сортировка</InputLabel>
<Select
labelId="select-label-sort"
@ -416,7 +436,7 @@ const MechRecCostProdPlans = () => {
</MenuItem>
</Select>
</Box>
<Box sx={{ display: "table-cell", verticalAlign: "middle", paddingLeft: "15px" }}>
<Box sx={STYLES.FILTERS_LEVEL}>
<InputLabel id="select-label-level">До уровня</InputLabel>
<Select
labelId="select-label-level"
@ -440,7 +460,7 @@ const MechRecCostProdPlans = () => {
<P8PGantt
{...P8P_GANTT_CONFIG_PROPS}
{...state.selectedPlanCtlgGanttDef}
height={GANTT_HEIGHT}
containerStyle={STYLES.GANTT_CONTAINER}
titleStyle={STYLES.GANTT_TITLE}
tasks={state.selectedPlanCtlgSpecs}
taskDialogRenderer={prms => taskDialogRenderer({ ...prms, handleTaskDetailOpen })}
@ -448,7 +468,16 @@ const MechRecCostProdPlans = () => {
</Box>
)
) : !state.selectedPlanCtlg ? (
<InlineMsgInfo okBtn={false} text={"Укажите каталог планов для отображения их спецификаций"} />
<Box pt={3}>
<InlineMsgInfo
okBtn={false}
text={
state.planSpec
? "Загружаю график для выбранной позиции плана..."
: "Укажите каталог планов для отображения их спецификаций"
}
/>
</Box>
) : null}
</Grid>
</Grid>

View File

@ -81,6 +81,7 @@ create or replace package PKG_P8PANELS_MECHREC as
procedure FCPRODPLANSP_GET
(
NCRN in number, -- Рег. номер каталога
NFCPRODPLANSP in number, -- Рег. номер позиции спецификации
NLEVEL in number := null, -- Уровень отбора
SSORT_FIELD in varchar2 := 'DREP_DATE_TO', -- Поле сортировки
COUT out clob, -- Список задач
@ -2164,6 +2165,7 @@ create or replace package body PKG_P8PANELS_MECHREC as
procedure FCPRODPLANSP_GET
(
NCRN in number, -- Рег. номер каталога
NFCPRODPLANSP in number, -- Рег. номер позиции спецификации
NLEVEL in number := null, -- Уровень отбора
SSORT_FIELD in varchar2 := 'DREP_DATE_TO', -- Поле сортировки
COUT out clob, -- Список задач
@ -2210,7 +2212,8 @@ create or replace package body PKG_P8PANELS_MECHREC as
/* Считывание максимального уровня иерархии плана по каталогу */
function PRODPLAN_MAX_LEVEL_GET
(
NCRN in number -- Рег. номер каталога планов
NCRN in number, -- Рег. номер каталога планов
NFCPRODPLANSP in number -- Рег. номер позиции спецификации
) return number -- Максимальный уровень иерархии
is
NRESULT PKG_STD.TNUMBER := 1; -- Максимальный уровень иерархии
@ -2224,7 +2227,10 @@ create or replace package body PKG_P8PANELS_MECHREC as
from FCPRODPLAN P,
FCPRODPLANSP T,
FINSTATE FS
where P.CRN = NCRN
where ((NCRN is null) or ((NCRN is not null) and (P.CRN = NCRN)))
and ((NFCPRODPLANSP is null) or
((NFCPRODPLANSP is not null) and
(P.RN = (select PRN from FCPRODPLANSP where RN = NFCPRODPLANSP))))
and P.CATEGORY = NFCPRODPLAN_CATEGORY
and P.STATUS = NFCPRODPLAN_STATUS
and FS.RN = P.TYPE
@ -2248,7 +2254,8 @@ create or replace package body PKG_P8PANELS_MECHREC as
and T.PRN = P.RN
and T.MAIN_QUANT > 0) TMP
connect by prior TMP.RN = TMP.UP_LEVEL
start with TMP.UP_LEVEL is null
start with (((NCRN is not null) and (TMP.UP_LEVEL is null)) or
((NCRN is null) and (TMP.RN = NFCPRODPLANSP)))
group by level
order by level)
loop
@ -2603,12 +2610,36 @@ create or replace package body PKG_P8PANELS_MECHREC as
end GET_TASK_COLORS;
begin
/* Определяем заголовок плана */
FIND_ACATALOG_RN(NFLAG_SMART => 0,
NCOMPANY => NCOMPANY,
NVERSION => null,
SUNITCODE => 'CostProductPlans',
NRN => NCRN,
SNAME => SPLAN_TITLE);
if (NCRN is not null) then
FIND_ACATALOG_RN(NFLAG_SMART => 0,
NCOMPANY => NCOMPANY,
NVERSION => null,
SUNITCODE => 'CostProductPlans',
NRN => NCRN,
SNAME => SPLAN_TITLE);
else
if (NFCPRODPLANSP is not null) then
begin
select MR.CODE || ' - ' || MR.NAME || ', ' || T.REL_FACT || ' ' || DM.MEAS_MNEMO || ', ' ||
COALESCE(TO_CHAR(T.REP_DATE_TO, 'dd.mm.yyyy'), '<ДАТА ВЫПУСКА НЕ УКАЗА>')
into SPLAN_TITLE
from FCPRODPLANSP T,
FCMATRESOURCE MR,
DICNOMNS DN,
DICMUNTS DM
where T.RN = NFCPRODPLANSP
and T.MATRES = MR.RN
and MR.NOMENCLATURE = DN.RN
and DN.UMEAS_MAIN = DM.RN;
exception
when NO_DATA_FOUND then
PKG_MSG.RECORD_NOT_FOUND(NFLAG_SMART => 0, NDOCUMENT => NFCPRODPLANSP, SUNIT_TABLE => 'FCPRODPLANSP');
end;
else
P_EXCEPTION(0,
'Не указан каталог размещения или позиция спецификации плана.');
end if;
end if;
/* Инициализируем диаграмму Ганта */
RG := PKG_P8PANELS_VISUAL.TGANTT_MAKE(STITLE => SPLAN_TITLE,
NZOOM => PKG_P8PANELS_VISUAL.NGANTT_ZOOM_DAY,
@ -2619,7 +2650,7 @@ create or replace package body PKG_P8PANELS_MECHREC as
/* Инициализируем описания цветов */
TASK_COLORS_INIT(RG => RG);
/* Определяем максимальный уровень иерархии */
NMAX_LEVEL := PRODPLAN_MAX_LEVEL_GET(NCRN => NCRN);
NMAX_LEVEL := PRODPLAN_MAX_LEVEL_GET(NCRN => NCRN, NFCPRODPLANSP => NFCPRODPLANSP);
/* Определяем уровень фильтра */
NLEVEL_FILTER := COALESCE(NLEVEL, NMAX_LEVEL);
/* Обходим данные */
@ -2662,7 +2693,10 @@ create or replace package body PKG_P8PANELS_MECHREC as
FCMATRESOURCE FM,
DICNOMNS D,
DICMUNTS DM
where P.CRN = NCRN
where ((NCRN is null) or ((NCRN is not null) and (P.CRN = NCRN)))
and ((NFCPRODPLANSP is null) or
((NFCPRODPLANSP is not null) and
(P.RN = (select PRN from FCPRODPLANSP where RN = NFCPRODPLANSP))))
and P.CATEGORY = NFCPRODPLAN_CATEGORY
and P.STATUS = NFCPRODPLAN_STATUS
and FS.RN = P.TYPE
@ -2692,7 +2726,8 @@ create or replace package body PKG_P8PANELS_MECHREC as
and D.UMEAS_MAIN = DM.RN) TMP
where level <= NLEVEL_FILTER
connect by prior TMP.NRN = TMP.NUP_LEVEL
start with TMP.NUP_LEVEL is null
start with (((NCRN is not null) and (TMP.NUP_LEVEL is null)) or
((NCRN is null) and (TMP.NRN = NFCPRODPLANSP)))
order siblings by TMP.DORDER_DATE asc)
loop
/* Формируем описание задачи в Ганте */