forked from CITKParus/P8-Panels
ЦИТК-968 - Доработка панели "Производственная программа"
This commit is contained in:
parent
11f29bcf0c
commit
47d6b0cdb1
@ -36,7 +36,8 @@ import {
|
||||
Card,
|
||||
CardHeader,
|
||||
CardContent,
|
||||
CardActions
|
||||
CardActions,
|
||||
Tooltip
|
||||
} from "@mui/material"; //Интерфейсные элементы
|
||||
import { BackEndСtx } from "../../context/backend"; //Контекст взаимодействия с сервером
|
||||
import { MessagingСtx } from "../../context/messaging"; //Контекст сообщений
|
||||
@ -55,19 +56,34 @@ import { IncomFromDepsDataGrid } from "./datagrids/incomefromdeps"; //Табли
|
||||
//---------
|
||||
|
||||
//Склонения для документов
|
||||
const DECLINATIONS = ["план", "плана", "планов"];
|
||||
const PLANS_DECLINATIONS = ["план", "плана", "планов"];
|
||||
const SPEC_DECLINATIONS = ["элемент", "элемента", "элементов"];
|
||||
|
||||
//Поля сортировки
|
||||
const SORT_REP_DATE = "DREP_DATE";
|
||||
const SORT_REP_DATE_TO = "DREP_DATE_TO";
|
||||
|
||||
//Максимальное количество элементов
|
||||
const MAX_TASKS = 10000;
|
||||
|
||||
//Стили
|
||||
const STYLES = {
|
||||
PLANS_FINDER: { marginTop: "10px", marginLeft: "10px", width: "93%" },
|
||||
PLANS_CHECKBOX_HAVEDOCS: { alignContent: "space-around" },
|
||||
PLANS_LIST_CONTAINER: { height: "100%", display: "flex", flexDirection: "column", justifyContent: "space-between" },
|
||||
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_LIST_ITEM_PLAN: {
|
||||
backgroundColor: "#c7e7f1",
|
||||
"&:hover": { backgroundColor: `#c7e7f1`, filter: "brightness(0.92) !important" }
|
||||
},
|
||||
PLANS_LIST_ITEM_PLAN_FIELD: {
|
||||
marginLeft: "15px"
|
||||
},
|
||||
PLANS_LIST_FILTER_CONTAINER: { height: "calc(100% - 55px)", overflowY: "auto" },
|
||||
PLANS_LIST_BUTTONS_CONTAINER: { display: "flex", justifyContent: "space-around", paddingBottom: "10px", height: "45px" },
|
||||
PLANS_LIST_BUTTON: { minWidth: "125px", height: "35px" },
|
||||
PLANS_BUTTON: { position: "absolute", top: `calc(${APP_BAR_HEIGHT} + 16px)`, left: "16px" },
|
||||
PLANS_DRAWER: {
|
||||
width: "350px",
|
||||
@ -121,7 +137,9 @@ const parseProdPlanSpXML = async xmlDoc => {
|
||||
};
|
||||
|
||||
//Форматирование для отображения количества документов
|
||||
const formatCountDocs = nCountDocs => {
|
||||
const formatCountDocs = (nCountDocs, nType = 0) => {
|
||||
//Склонение документов
|
||||
let DECLINATIONS = nType === 0 ? PLANS_DECLINATIONS : SPEC_DECLINATIONS;
|
||||
//Получаем последнюю цифру в значении
|
||||
let num = (nCountDocs % 100) % 10;
|
||||
//Документов
|
||||
@ -134,55 +152,146 @@ const formatCountDocs = nCountDocs => {
|
||||
return `${nCountDocs} ${DECLINATIONS[2]}`;
|
||||
};
|
||||
|
||||
//Изменение информации об отмеченных планах
|
||||
const updateCtlgPlanInfo = (selectedPlans, plan) => {
|
||||
//Результат изменений
|
||||
let res = { selectedPlans: [...selectedPlans] || [], selectedPlansElements: plan.NCOUNT_DOCS };
|
||||
//Определяем наличие в отмеченных планах
|
||||
let selectedIndex = res.selectedPlans.indexOf(plan.NRN);
|
||||
//Если уже есть в отмеченных - удаляем, нет - добавляем
|
||||
if (selectedIndex > -1) {
|
||||
//Удаляем план из выбранных
|
||||
res.selectedPlans.splice(selectedIndex, 1);
|
||||
//Переворачиваем сумму документов
|
||||
res.selectedPlansElements = res.selectedPlansElements * -1;
|
||||
} else {
|
||||
//Добавляем план в выбранные
|
||||
res.selectedPlans.push(plan.NRN);
|
||||
}
|
||||
//Возвращаем результат
|
||||
return res;
|
||||
};
|
||||
|
||||
//Список каталогов планов
|
||||
const PlanCtlgsList = ({ planCtlgs = [], selectedPlanCtlg, filter, setFilter, onClick } = {}) => {
|
||||
const PlanCtlgsList = ({
|
||||
planCtlgs = [],
|
||||
selectedPlans = [],
|
||||
selectedPlanCtlg,
|
||||
selectedPlansElements,
|
||||
filter,
|
||||
setFilter,
|
||||
onCtlgClick,
|
||||
onCtlgPlanClick,
|
||||
onCtlgPlansOk,
|
||||
onCtlgPlansCancel
|
||||
} = {}) => {
|
||||
//Генерация содержимого
|
||||
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(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>
|
||||
))}
|
||||
</List>
|
||||
</div>
|
||||
<Box sx={STYLES.PLANS_LIST_CONTAINER}>
|
||||
<Box sx={STYLES.PLANS_LIST_FILTER_CONTAINER}>
|
||||
<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(ctlg => (
|
||||
<Box key={ctlg.NRN}>
|
||||
<ListItemButton
|
||||
sx={ctlg.NCOUNT_DOCS == 0 ? STYLES.PLANS_LIST_ITEM_ZERODOCS : null}
|
||||
key={ctlg.NRN}
|
||||
selected={ctlg.NRN === selectedPlanCtlg}
|
||||
onClick={() => (onCtlgClick ? onCtlgClick(ctlg) : null)}
|
||||
disabled={ctlg.NCOUNT_DOCS == 0}
|
||||
>
|
||||
<ListItemText
|
||||
primary={<Typography sx={STYLES.PLANS_LIST_ITEM_PRIMARY}>{ctlg.SNAME}</Typography>}
|
||||
secondary={<Typography sx={STYLES.PLANS_LIST_ITEM_SECONDARY}>{formatCountDocs(ctlg.NCOUNT_DOCS, 0)}</Typography>}
|
||||
/>
|
||||
</ListItemButton>
|
||||
{ctlg.NRN === selectedPlanCtlg && ctlg.XCRN_PLANS.length > 1
|
||||
? ctlg.XCRN_PLANS.map(plan => (
|
||||
<ListItemButton
|
||||
sx={plan.NCOUNT_DOCS == 0 ? STYLES.PLANS_LIST_ITEM_ZERODOCS : STYLES.PLANS_LIST_ITEM_PLAN}
|
||||
key={plan.NRN}
|
||||
disabled={plan.NCOUNT_DOCS == 0}
|
||||
onClick={() => (onCtlgPlanClick ? onCtlgPlanClick(plan) : null)}
|
||||
>
|
||||
<ListItemText
|
||||
sx={STYLES.PLANS_LIST_ITEM_PLAN_FIELD}
|
||||
primary={<Typography sx={STYLES.PLANS_LIST_ITEM_PRIMARY}>{plan.SNAME}</Typography>}
|
||||
secondary={
|
||||
<Typography sx={STYLES.PLANS_LIST_ITEM_SECONDARY}>
|
||||
{formatCountDocs(plan.NCOUNT_DOCS, 1)}
|
||||
</Typography>
|
||||
}
|
||||
/>
|
||||
{plan.NCOUNT_DOCS !== 0 ? <Checkbox checked={selectedPlans.includes(plan.NRN)} /> : null}
|
||||
</ListItemButton>
|
||||
))
|
||||
: null}
|
||||
</Box>
|
||||
))}
|
||||
</List>
|
||||
</Box>
|
||||
<Box sx={STYLES.PLANS_LIST_BUTTONS_CONTAINER}>
|
||||
<Tooltip
|
||||
title={
|
||||
!selectedPlanCtlg
|
||||
? "Не выбран каталог планов"
|
||||
: selectedPlans.length === 0
|
||||
? "Не выбраны планы каталога"
|
||||
: selectedPlansElements > MAX_TASKS
|
||||
? `Выбранные планы превышают максимум элементов (выбрано: ${selectedPlansElements}, максимум: ${MAX_TASKS})`
|
||||
: null
|
||||
}
|
||||
>
|
||||
<Box>
|
||||
<Button
|
||||
sx={STYLES.PLANS_LIST_BUTTON}
|
||||
variant="contained"
|
||||
disabled={selectedPlans.length === 0 || selectedPlansElements > MAX_TASKS}
|
||||
onClick={onCtlgPlansOk}
|
||||
>
|
||||
Применить
|
||||
</Button>
|
||||
</Box>
|
||||
</Tooltip>
|
||||
<Button sx={STYLES.PLANS_LIST_BUTTON} variant="contained" onClick={onCtlgPlansCancel}>
|
||||
Отмена
|
||||
</Button>
|
||||
</Box>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
//Контроль свойств - Список каталогов планов
|
||||
PlanCtlgsList.propTypes = {
|
||||
planCtlgs: PropTypes.array,
|
||||
selectedPlans: PropTypes.array,
|
||||
selectedPlanCtlg: PropTypes.number,
|
||||
onClick: PropTypes.func,
|
||||
selectedPlansElements: PropTypes.number,
|
||||
onCtlgClick: PropTypes.func,
|
||||
onCtlgPlanClick: PropTypes.func,
|
||||
filter: PropTypes.object,
|
||||
setFilter: PropTypes.func
|
||||
setFilter: PropTypes.func,
|
||||
onCtlgPlansOk: PropTypes.func,
|
||||
onCtlgPlansCancel: PropTypes.func
|
||||
};
|
||||
|
||||
//Генерация диалога задачи
|
||||
@ -251,6 +360,8 @@ const MechRecCostProdPlans = () => {
|
||||
showPlanList: false,
|
||||
planCtlgs: [],
|
||||
planCtlgsLoaded: false,
|
||||
selectedPlans: [],
|
||||
selectedPlansElements: 0,
|
||||
selectedPlanCtlgSpecsLoaded: false,
|
||||
selectedPlanCtlg: null,
|
||||
selectedPlanCtlgMaxLevel: null,
|
||||
@ -258,6 +369,9 @@ const MechRecCostProdPlans = () => {
|
||||
selectedPlanCtlgOutOfLimit: 0,
|
||||
selectedPlanCtlgSort: null,
|
||||
selectedPlanCtlgMenuItems: null,
|
||||
loadedCtlg: null,
|
||||
loadedPlans: [],
|
||||
loadedElements: 0,
|
||||
gantt: {},
|
||||
selectedTaskDetail: null,
|
||||
selectedTaskDetailType: null,
|
||||
@ -273,7 +387,7 @@ const MechRecCostProdPlans = () => {
|
||||
const { InlineMsgInfo } = useContext(MessagingСtx);
|
||||
|
||||
//Подключение к контексту взаимодействия с сервером
|
||||
const { executeStored } = useContext(BackEndСtx);
|
||||
const { executeStored, SERV_DATA_TYPE_CLOB } = useContext(BackEndСtx);
|
||||
|
||||
//Подключение к контексту навигации
|
||||
const { getNavigationSearch } = useContext(NavigationCtx);
|
||||
@ -288,54 +402,28 @@ const MechRecCostProdPlans = () => {
|
||||
stored: "PKG_P8PANELS_MECHREC.FCPRODPLAN_PP_CTLG_INIT",
|
||||
args: {},
|
||||
respArg: "COUT",
|
||||
isArray: name => name === "XFCPRODPLAN_CRNS"
|
||||
isArray: name => ["XFCPRODPLAN_CRNS", "XCRN_PLANS"].includes(name)
|
||||
});
|
||||
setState(pv => ({ ...pv, init: true, planCtlgs: [...(data?.XFCPRODPLAN_CRNS || [])], planCtlgsLoaded: true }));
|
||||
}
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [state.init, executeStored]);
|
||||
|
||||
//Выбор каталога планов
|
||||
const selectPlan = project => {
|
||||
setState(pv => ({
|
||||
...pv,
|
||||
selectedPlanCtlg: project,
|
||||
selectedPlanCtlgSpecsLoaded: false,
|
||||
selectedPlanCtlgMaxLevel: null,
|
||||
selectedPlanCtlgLevel: null,
|
||||
selectedPlanCtlgOutOfLimit: 0,
|
||||
selectedPlanCtlgSort: null,
|
||||
selectedPlanCtlgMenuItems: null,
|
||||
gantt: {},
|
||||
showPlanList: false,
|
||||
selectedTaskDetail: null,
|
||||
selectedTaskDetailType: null
|
||||
}));
|
||||
};
|
||||
|
||||
//Сброс выбора каталога планов
|
||||
const unselectPlan = () =>
|
||||
setState(pv => ({
|
||||
...pv,
|
||||
selectedPlanCtlgSpecsLoaded: false,
|
||||
selectedPlanCtlg: null,
|
||||
selectedPlanCtlgMaxLevel: null,
|
||||
selectedPlanCtlgLevel: null,
|
||||
selectedPlanCtlgOutOfLimit: 0,
|
||||
selectedPlanCtlgSort: null,
|
||||
selectedPlanCtlgMenuItems: null,
|
||||
gantt: {},
|
||||
showPlanList: false,
|
||||
selectedTaskDetail: null,
|
||||
selectedTaskDetailType: null
|
||||
}));
|
||||
|
||||
//Загрузка списка спецификаций каталога планов
|
||||
const loadPlanCtglSpecs = useCallback(
|
||||
async (level = null, sort = null) => {
|
||||
const data = await executeStored({
|
||||
stored: "PKG_P8PANELS_MECHREC.FCPRODPLANSP_GET",
|
||||
args: { NCRN: state.selectedPlanCtlg, NLEVEL: level, SSORT_FIELD: sort, NFCPRODPLANSP: state.planSpec }
|
||||
args: {
|
||||
NCRN: state.selectedPlanCtlg,
|
||||
CFCPRODPLANS: {
|
||||
VALUE: state.selectedPlans.length > 0 ? state.selectedPlans.join(";") : null,
|
||||
SDATA_TYPE: SERV_DATA_TYPE_CLOB
|
||||
},
|
||||
NLEVEL: level,
|
||||
SSORT_FIELD: sort,
|
||||
NFCPRODPLANSP: state.planSpec
|
||||
}
|
||||
});
|
||||
let doc = await parseProdPlanSpXML(data.COUT);
|
||||
setState(pv => ({
|
||||
@ -344,21 +432,71 @@ const MechRecCostProdPlans = () => {
|
||||
selectedPlanCtlgLevel: level || level === 0 ? level : data.NMAX_LEVEL,
|
||||
selectedPlanCtlgOutOfLimit: data.NOUT_OF_LIMIT,
|
||||
selectedPlanCtlgSort: sort,
|
||||
selectedPlanCtlgMenuItems: state.selectedPlanCtlgMenuItems
|
||||
? state.selectedPlanCtlgMenuItems
|
||||
: [...Array(data.NMAX_LEVEL).keys()].map(el => el + 1),
|
||||
selectedPlanCtlgMenuItems: [...Array(data.NMAX_LEVEL).keys()].map(el => el + 1),
|
||||
selectedPlanCtlgSpecsLoaded: true,
|
||||
gantt: { ...doc, tasks: [...(doc?.tasks || [])] }
|
||||
gantt: { ...doc, tasks: [...(doc?.tasks || [])] },
|
||||
loadedCtlg: state.selectedPlanCtlg,
|
||||
loadedPlans: [...state.selectedPlans],
|
||||
loadedElements: state.selectedPlansElements,
|
||||
showPlanList: false
|
||||
}));
|
||||
},
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
[executeStored, state.ident, state.selectedPlanCtlg, state.planSpec]
|
||||
[executeStored, state.selectedPlanCtlg, state.selectedPlans, state.planSpec]
|
||||
);
|
||||
|
||||
//Обработка нажатия на элемент в списке каталогов планов
|
||||
const handleProjectClick = project => {
|
||||
if (state.selectedPlanCtlg != project.NRN) selectPlan(project.NRN);
|
||||
else unselectPlan();
|
||||
const handleCtlgClick = project => {
|
||||
//Если этот каталог не был выбран
|
||||
if (state.selectedPlanCtlg != project.NRN) {
|
||||
//Если выбран уже загруженный - укажем информацию о том, как он загружен
|
||||
if (project.NRN === state.loadedCtlg) {
|
||||
setState(pv => ({
|
||||
...pv,
|
||||
selectedPlanCtlg: project.NRN,
|
||||
selectedPlans: [...pv.loadedPlans],
|
||||
selectedPlansElements: pv.loadedElements
|
||||
}));
|
||||
} else {
|
||||
setState(pv => ({
|
||||
...pv,
|
||||
selectedPlanCtlg: project.NRN,
|
||||
selectedPlans: project.XCRN_PLANS.length === 1 ? [project.XCRN_PLANS[0].NRN] : [],
|
||||
selectedPlansElements: 0
|
||||
}));
|
||||
}
|
||||
} else {
|
||||
setState(pv => ({ ...pv, selectedPlanCtlg: null, selectedPlans: [], selectedPlansElements: 0 }));
|
||||
}
|
||||
};
|
||||
|
||||
//Обработка нажатия на элемент в списке планов каталога
|
||||
const handleCtlgPlanClick = plan => {
|
||||
//Считываем обновленную информацию об отмеченных планах
|
||||
let newPlansInfo = updateCtlgPlanInfo(state.selectedPlans, plan);
|
||||
//Обновляем список отмеченных планов
|
||||
setState(pv => ({
|
||||
...pv,
|
||||
selectedPlans: [...newPlansInfo.selectedPlans],
|
||||
selectedPlansElements: pv.selectedPlansElements + newPlansInfo.selectedPlansElements
|
||||
}));
|
||||
};
|
||||
|
||||
//Обработка нажатия "ОК" при отборе планов
|
||||
const handleSelectedPlansOk = () => {
|
||||
//Загружаем диаграмму
|
||||
loadPlanCtglSpecs(null, SORT_REP_DATE_TO);
|
||||
};
|
||||
|
||||
//Обработка нажатия "Отмена" при отборе планов
|
||||
const handleSelectedPlansCancel = () => {
|
||||
setState(pv => ({
|
||||
...pv,
|
||||
selectedPlanCtlg: pv.loadedCtlg,
|
||||
selectedPlans: [...pv.loadedPlans] || [],
|
||||
selectedPlansElements: pv.loadedElements,
|
||||
showPlanList: false
|
||||
}));
|
||||
};
|
||||
|
||||
//При подключении компонента к странице
|
||||
@ -371,8 +509,8 @@ const MechRecCostProdPlans = () => {
|
||||
|
||||
//При смене выбранного каталога плана или при явном указании позиции спецификации плана
|
||||
useEffect(() => {
|
||||
if (state.selectedPlanCtlg || state.planSpec) loadPlanCtglSpecs(null, SORT_REP_DATE_TO);
|
||||
}, [state.selectedPlanCtlg, state.planSpec, loadPlanCtglSpecs]);
|
||||
if (state.planSpec) loadPlanCtglSpecs(null, SORT_REP_DATE_TO);
|
||||
}, [state.planSpec, loadPlanCtglSpecs]);
|
||||
|
||||
//Выбор уровня
|
||||
const handleChangeSelectLevel = selectedLevel => {
|
||||
@ -415,18 +553,18 @@ const MechRecCostProdPlans = () => {
|
||||
<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}
|
||||
>
|
||||
<Drawer anchor={"left"} open={state.showPlanList} onClose={handleSelectedPlansCancel} sx={STYLES.PLANS_DRAWER}>
|
||||
<PlanCtlgsList
|
||||
planCtlgs={filteredPlanCtgls}
|
||||
selectedPlans={state.selectedPlans}
|
||||
selectedPlanCtlg={state.selectedPlanCtlg}
|
||||
selectedPlansElements={state.selectedPlansElements}
|
||||
filter={filter}
|
||||
setFilter={setFilter}
|
||||
onClick={handleProjectClick}
|
||||
onCtlgClick={handleCtlgClick}
|
||||
onCtlgPlanClick={handleCtlgPlanClick}
|
||||
onCtlgPlansOk={handleSelectedPlansOk}
|
||||
onCtlgPlansCancel={handleSelectedPlansCancel}
|
||||
/>
|
||||
</Drawer>
|
||||
</>
|
||||
@ -508,14 +646,14 @@ const MechRecCostProdPlans = () => {
|
||||
/>
|
||||
</Box>
|
||||
)
|
||||
) : !state.selectedPlanCtlg ? (
|
||||
) : !state.loadedCtlg ? (
|
||||
<Box pt={3}>
|
||||
<InlineMsgInfo
|
||||
okBtn={false}
|
||||
text={
|
||||
state.planSpec
|
||||
? "Загружаю график для выбранной позиции плана..."
|
||||
: "Укажите каталог планов для отображения их спецификаций"
|
||||
: "Укажите каталог планов или планы для отображения их спецификаций"
|
||||
}
|
||||
/>
|
||||
</Box>
|
||||
|
@ -81,6 +81,7 @@ create or replace package PKG_P8PANELS_MECHREC as
|
||||
procedure FCPRODPLANSP_GET
|
||||
(
|
||||
NCRN in number, -- Рег. номер каталога
|
||||
CFCPRODPLANS in clob, -- Список отмеченных планов (разделитель - ";")
|
||||
NFCPRODPLANSP in number, -- Рег. номер позиции спецификации
|
||||
NLEVEL in number := null, -- Уровень отбора
|
||||
SSORT_FIELD in varchar2 := 'DREP_DATE_TO', -- Поле сортировки
|
||||
@ -513,6 +514,28 @@ create or replace package body PKG_P8PANELS_MECHREC as
|
||||
end;
|
||||
end UTL_FCROUTLST_GET;
|
||||
|
||||
/* Иницализация выбранных планов */
|
||||
procedure UTL_FCPRODPLAN_IDENT_INIT
|
||||
(
|
||||
CFCPRODPLANS in clob, -- Список отмеченных планов (разделитель - ";")
|
||||
NIDENT out number -- Идентификатор отмеченных записей
|
||||
)
|
||||
is
|
||||
NFCPRODPLAN PKG_STD.TREF; -- Рег. номер плана
|
||||
NTMP PKG_STD.TREF; -- Буфер
|
||||
begin
|
||||
/* Генерируем идентификатор */
|
||||
NIDENT := GEN_IDENT();
|
||||
/* Обходим исполнителей */
|
||||
for I in 1 .. STRCNT(source => CFCPRODPLANS, DELIMETER => ';')
|
||||
loop
|
||||
/* Считываем рег. номер плана */
|
||||
NFCPRODPLAN := TO_NUMBER(STRTOK(source => CFCPRODPLANS, DELIMETER => ';', ITEM => I));
|
||||
/* Добавляем в селектлист */
|
||||
P_SELECTLIST_INSERT(NIDENT => NIDENT, NDOCUMENT => NFCPRODPLAN, SUNITCODE => 'CostProductPlans', NRN => NTMP);
|
||||
end loop;
|
||||
end UTL_FCPRODPLAN_IDENT_INIT;
|
||||
|
||||
/* Считывания рег. номера подразделения пользователя */
|
||||
function UTL_SUBDIV_RN_GET
|
||||
(
|
||||
@ -2259,6 +2282,7 @@ create or replace package body PKG_P8PANELS_MECHREC as
|
||||
procedure FCPRODPLANSP_GET
|
||||
(
|
||||
NCRN in number, -- Рег. номер каталога
|
||||
CFCPRODPLANS in clob, -- Список отмеченных планов (разделитель - ";")
|
||||
NFCPRODPLANSP in number, -- Рег. номер позиции спецификации
|
||||
NLEVEL in number := null, -- Уровень отбора
|
||||
SSORT_FIELD in varchar2 := 'DREP_DATE_TO', -- Поле сортировки
|
||||
@ -2284,6 +2308,7 @@ create or replace package body PKG_P8PANELS_MECHREC as
|
||||
NCOMPANY PKG_STD.TREF := GET_SESSION_COMPANY(); -- Организация сеанса
|
||||
NTASK_CLASS PKG_STD.TNUMBER; -- Класс задачи (см. константы NCLASS_*)
|
||||
NLEVEL_FILTER PKG_STD.TNUMBER; -- Уровень для фильтра
|
||||
NPLANS_IDENT PKG_STD.TREF; -- Идентификатор отмеченных планов
|
||||
|
||||
/* Объединение значений в строковое представление */
|
||||
function MAKE_INFO
|
||||
@ -2308,6 +2333,7 @@ create or replace package body PKG_P8PANELS_MECHREC as
|
||||
procedure PRODPLAN_MAX_LEVEL_GET
|
||||
(
|
||||
NCRN in number, -- Рег. номер каталога планов
|
||||
NPLANS_IDENT in number, -- Идентификатор отмеченных планов
|
||||
NFCPRODPLANSP in number, -- Рег. номер позиции спецификации
|
||||
NMAX_LEVEL out number, -- Максимальный уровень иерархии
|
||||
NOUT_OF_LIMIT out number -- Признак превышения лимита (0 - нет, 1 - да)
|
||||
@ -2328,6 +2354,12 @@ create or replace package body PKG_P8PANELS_MECHREC as
|
||||
FCPRODPLANSP T,
|
||||
FINSTATE FS
|
||||
where ((NCRN is null) or ((NCRN is not null) and (P.CRN = NCRN)))
|
||||
and ((NPLANS_IDENT is null) or
|
||||
((NPLANS_IDENT is not null) and
|
||||
(P.RN in (select SL.DOCUMENT
|
||||
from SELECTLIST SL
|
||||
where SL.IDENT = NPLANS_IDENT
|
||||
and SL.UNITCODE = 'CostProductPlans'))))
|
||||
and ((NFCPRODPLANSP is null) or
|
||||
((NFCPRODPLANSP is not null) and
|
||||
(P.RN = (select PRN from FCPRODPLANSP where RN = NFCPRODPLANSP))))
|
||||
@ -2711,12 +2743,18 @@ create or replace package body PKG_P8PANELS_MECHREC as
|
||||
begin
|
||||
/* Определяем заголовок плана */
|
||||
if (NCRN is not null) then
|
||||
/* Считываем каталог */
|
||||
FIND_ACATALOG_RN(NFLAG_SMART => 0,
|
||||
NCOMPANY => NCOMPANY,
|
||||
NVERSION => null,
|
||||
SUNITCODE => 'CostProductPlans',
|
||||
NRN => NCRN,
|
||||
SNAME => SPLAN_TITLE);
|
||||
/* Если есть выбранные планы */
|
||||
if (CFCPRODPLANS is not null) then
|
||||
/* Инициализируем отмеченные планы в селектлисте */
|
||||
UTL_FCPRODPLAN_IDENT_INIT(CFCPRODPLANS => CFCPRODPLANS, NIDENT => NPLANS_IDENT);
|
||||
end if;
|
||||
else
|
||||
if (NFCPRODPLANSP is not null) then
|
||||
begin
|
||||
@ -2751,6 +2789,7 @@ create or replace package body PKG_P8PANELS_MECHREC as
|
||||
TASK_COLORS_INIT(RG => RG);
|
||||
/* Определяем максимальный уровень иерархии */
|
||||
PRODPLAN_MAX_LEVEL_GET(NCRN => NCRN,
|
||||
NPLANS_IDENT => NPLANS_IDENT,
|
||||
NFCPRODPLANSP => NFCPRODPLANSP,
|
||||
NMAX_LEVEL => NMAX_LEVEL,
|
||||
NOUT_OF_LIMIT => NOUT_OF_LIMIT);
|
||||
@ -2797,6 +2836,12 @@ create or replace package body PKG_P8PANELS_MECHREC as
|
||||
DICNOMNS D,
|
||||
DICMUNTS DM
|
||||
where ((NCRN is null) or ((NCRN is not null) and (P.CRN = NCRN)))
|
||||
and ((NPLANS_IDENT is null) or
|
||||
((NPLANS_IDENT is not null) and
|
||||
(P.RN in (select SL.DOCUMENT
|
||||
from SELECTLIST SL
|
||||
where SL.IDENT = NPLANS_IDENT
|
||||
and SL.UNITCODE = 'CostProductPlans'))))
|
||||
and ((NFCPRODPLANSP is null) or
|
||||
((NFCPRODPLANSP is not null) and
|
||||
(P.RN = (select PRN from FCPRODPLANSP where RN = NFCPRODPLANSP))))
|
||||
@ -2917,14 +2962,48 @@ create or replace package body PKG_P8PANELS_MECHREC as
|
||||
end loop;
|
||||
/* Формируем список */
|
||||
COUT := PKG_P8PANELS_VISUAL.TGANTT_TO_XML(RGANTT => RG);
|
||||
/* Очищаем отмеченные планы */
|
||||
P_SELECTLIST_CLEAR(NIDENT => NPLANS_IDENT);
|
||||
exception
|
||||
when others then
|
||||
/* Очищаем отмеченные планы */
|
||||
P_SELECTLIST_CLEAR(NIDENT => NPLANS_IDENT);
|
||||
raise;
|
||||
end FCPRODPLANSP_GET;
|
||||
|
||||
/* Инициализация каталогов раздела "Планы и отчеты производства изделий" для панели "Производственная программа" */
|
||||
procedure FCPRODPLAN_PP_CTLG_INIT
|
||||
(
|
||||
COUT out clob -- Список каталогов раздела "Планы и отчеты производства изделий"
|
||||
COUT out clob -- Список каталогов раздела "Планы и отчеты производства изделий"
|
||||
)
|
||||
is
|
||||
NCOMPANY PKG_STD.TREF := GET_SESSION_COMPANY(); -- Организация сеанса
|
||||
|
||||
/* Считывание количества спецификаций плана */
|
||||
function FCPRODPLANSP_COUNT_GET
|
||||
(
|
||||
NFCPRODPLAN in number -- Рег. номер плана
|
||||
) return number -- Количество документов спецификации плана
|
||||
is
|
||||
NRESULT PKG_STD.TNUMBER; -- Количество документов спецификации плана
|
||||
begin
|
||||
/* Считываем количество спецификаций */
|
||||
begin
|
||||
select count(T.RN)
|
||||
into NRESULT
|
||||
from FCPRODPLAN P,
|
||||
FCPRODPLANSP T,
|
||||
FINSTATE FS
|
||||
where P.RN = NFCPRODPLAN
|
||||
and T.PRN = P.RN
|
||||
and T.MAIN_QUANT > 0;
|
||||
exception
|
||||
when others then
|
||||
NRESULT := 0;
|
||||
end;
|
||||
/* Возвращаем результат */
|
||||
return NRESULT;
|
||||
end FCPRODPLANSP_COUNT_GET;
|
||||
begin
|
||||
/* Начинаем формирование XML */
|
||||
PKG_XFAST.PROLOGUE(ITYPE => PKG_XFAST.CONTENT_);
|
||||
@ -2939,7 +3018,7 @@ create or replace package body PKG_P8PANELS_MECHREC as
|
||||
where P.CRN = T.RN
|
||||
and P.CATEGORY = NFCPRODPLAN_CATEGORY
|
||||
and P.STATUS = NFCPRODPLAN_STATUS
|
||||
and P.COMPANY = GET_SESSION_COMPANY()
|
||||
and P.COMPANY = NCOMPANY
|
||||
and FS.RN = P.TYPE
|
||||
and FS.CODE = SFCPRODPLAN_TYPE
|
||||
and exists (select PSP.RN
|
||||
@ -2967,7 +3046,7 @@ create or replace package body PKG_P8PANELS_MECHREC as
|
||||
where T.DOCNAME = 'CostProductPlans'
|
||||
and T.SIGNS = 1
|
||||
and T.DOCNAME = UL.UNITCODE
|
||||
and T.COMPANY = GET_SESSION_COMPANY()
|
||||
and T.COMPANY = NCOMPANY
|
||||
and (UL.SHOW_INACCESS_CTLG = 1 or exists
|
||||
(select null from V_USERPRIV UP where UP.CATALOG = T.RN) or exists
|
||||
(select null
|
||||
@ -2977,12 +3056,56 @@ create or replace package body PKG_P8PANELS_MECHREC as
|
||||
start with T1.CRN = T.RN))
|
||||
order by T.NAME 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);
|
||||
/* Если содержит планы */
|
||||
if (REC.NCOUNT_DOCS <> 0) then
|
||||
/* Цикл по планам каталога */
|
||||
for PLN in (select T.RN NRN,
|
||||
trim(T.PREFIX) || '-' || trim(T.NUMB) SNAME
|
||||
from FCPRODPLAN T,
|
||||
FINSTATE FS
|
||||
where T.CRN = REC.NRN
|
||||
and T.CATEGORY = NFCPRODPLAN_CATEGORY
|
||||
and T.STATUS = NFCPRODPLAN_STATUS
|
||||
and T.COMPANY = NCOMPANY
|
||||
and FS.RN = T.TYPE
|
||||
and FS.CODE = SFCPRODPLAN_TYPE
|
||||
and exists (select PSP.RN
|
||||
from FCPRODPLANSP PSP
|
||||
where PSP.PRN = T.RN
|
||||
and PSP.MAIN_QUANT > 0)
|
||||
and exists (select /*+ INDEX(UP I_USERPRIV_JUR_PERS_ROLEID) */
|
||||
null
|
||||
from USERPRIV UP
|
||||
where UP.JUR_PERS = T.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 = T.JUR_PERS
|
||||
and UP.UNITCODE = 'CostProductPlans'
|
||||
and UP.AUTHID = UTILIZER()))
|
||||
loop
|
||||
/* Открываем описание документов каталога */
|
||||
PKG_XFAST.DOWN_NODE(SNAME => 'XCRN_PLANS');
|
||||
/* Описываем план */
|
||||
PKG_XFAST.ATTR(SNAME => 'NRN', NVALUE => PLN.NRN);
|
||||
PKG_XFAST.ATTR(SNAME => 'SNAME', SVALUE => PLN.SNAME);
|
||||
PKG_XFAST.ATTR(SNAME => 'NCOUNT_DOCS', NVALUE => FCPRODPLANSP_COUNT_GET(NFCPRODPLAN => PLN.NRN));
|
||||
/* Закрываем документы каталога */
|
||||
PKG_XFAST.UP();
|
||||
end loop;
|
||||
end if;
|
||||
/* Закрываем план */
|
||||
PKG_XFAST.UP();
|
||||
end loop;
|
||||
|
Loading…
x
Reference in New Issue
Block a user