forked from CITKParus/P8-Panels
ЦИТК-784 - Добавление панели "Производственная программа"
This commit is contained in:
commit
fd6e38dbcd
@ -59,7 +59,8 @@ const P8P_GANTT_TASK_SHAPE = PropTypes.shape({
|
||||
readOnlyDates: PropTypes.bool,
|
||||
readOnlyProgress: PropTypes.bool,
|
||||
bgColor: PropTypes.string,
|
||||
textColor: PropTypes.string
|
||||
textColor: PropTypes.string,
|
||||
bgProgressColor: PropTypes.string
|
||||
});
|
||||
|
||||
//Структура динамического атрибута задачи
|
||||
@ -72,6 +73,7 @@ const P8P_GANTT_TASK_ATTRIBUTE_SHAPE = PropTypes.shape({
|
||||
const P8P_GANTT_TASK_COLOR_SHAPE = PropTypes.shape({
|
||||
bgColor: PropTypes.string,
|
||||
textColor: PropTypes.string,
|
||||
bgProgressColor: PropTypes.string,
|
||||
desc: PropTypes.string.isRequired
|
||||
});
|
||||
|
||||
@ -126,14 +128,24 @@ const P8PGanttTaskEditor = ({
|
||||
//Описание легенды для задачи
|
||||
let legend = null;
|
||||
if (Array.isArray(taskColors)) {
|
||||
const colorDesc = taskColors.find(color => task.bgColor === color.bgColor && task.textColor === color.textColor);
|
||||
const colorDesc = taskColors.find(
|
||||
color => task.bgColor === color.bgColor && task.textColor === color.textColor && task.bgProgressColor === color.bgProgressColor
|
||||
);
|
||||
if (colorDesc)
|
||||
legend = (
|
||||
<ListItemText
|
||||
secondaryTypographyProps={{
|
||||
p: 1,
|
||||
sx: {
|
||||
...(colorDesc.bgColor ? { backgroundColor: colorDesc.bgColor } : {}),
|
||||
...(colorDesc.bgProgressColor
|
||||
? {
|
||||
background: `linear-gradient(to right, ${colorDesc.bgProgressColor} ,${
|
||||
colorDesc.bgColor ? colorDesc.bgColor : "transparent"
|
||||
})}`
|
||||
}
|
||||
: colorDesc.bgColor
|
||||
? { backgroundColor: colorDesc.bgColor }
|
||||
: {}),
|
||||
...(colorDesc.textColor ? { color: colorDesc.textColor } : {})
|
||||
}
|
||||
}}
|
||||
|
9
app/panels/mech_rec_cost_prod_plans/hooks.js
Normal file
9
app/panels/mech_rec_cost_prod_plans/hooks.js
Normal file
@ -0,0 +1,9 @@
|
||||
import React from "react";
|
||||
|
||||
export const useFilteredPlans = (plans, filter) => {
|
||||
const filteredPlans = React.useMemo(() => {
|
||||
return plans.filter(project => project.SDOC_INFO.toLowerCase().includes(filter));
|
||||
}, [plans, filter]);
|
||||
|
||||
return filteredPlans;
|
||||
};
|
16
app/panels/mech_rec_cost_prod_plans/index.js
Normal file
16
app/panels/mech_rec_cost_prod_plans/index.js
Normal file
@ -0,0 +1,16 @@
|
||||
/*
|
||||
Парус 8 - Панели мониторинга - ПУП - Производственная программа
|
||||
Панель мониторинга: Точка входа
|
||||
*/
|
||||
|
||||
//---------------------
|
||||
//Подключение библиотек
|
||||
//---------------------
|
||||
|
||||
import { MechRecCostProdPlans } from "./mech_rec_cost_prod_plans"; //Корневая панель производственной программы
|
||||
|
||||
//----------------
|
||||
//Интерфейс модуля
|
||||
//----------------
|
||||
|
||||
export const RootClass = MechRecCostProdPlans;
|
332
app/panels/mech_rec_cost_prod_plans/mech_rec_cost_prod_plans.js
Normal file
332
app/panels/mech_rec_cost_prod_plans/mech_rec_cost_prod_plans.js
Normal file
@ -0,0 +1,332 @@
|
||||
/*
|
||||
Парус 8 - Панели мониторинга - ПУП - Производственная программа
|
||||
Панель мониторинга: Корневая панель производственной программы
|
||||
*/
|
||||
|
||||
//---------------------
|
||||
//Подключение библиотек
|
||||
//---------------------
|
||||
|
||||
import React, { useContext, useState, useCallback, useEffect } from "react"; //Классы React
|
||||
import PropTypes from "prop-types"; //Контроль свойств компонента
|
||||
import { Drawer, Fab, Box, List, ListItemButton, ListItemText, Typography, Grid, TextField, Select, MenuItem, InputLabel } from "@mui/material"; //Интерфейсные элементы
|
||||
import { BackEndСtx } from "../../context/backend"; //Контекст взаимодействия с сервером
|
||||
import { MessagingСtx } from "../../context/messaging"; //Контекст сообщений
|
||||
import { ApplicationСtx } from "../../context/application"; //Контекст приложения
|
||||
import { P8P_GANTT_CONFIG_PROPS } from "../../config_wrapper"; //Подключение компонентов к настройкам приложения
|
||||
import { P8PGantt } from "../../components/p8p_gantt"; //Диаграмма Ганта
|
||||
import { formatDateJSONDateOnly } from "../../core/utils"; //Вспомогательные функции
|
||||
import { useFilteredPlans } from "./hooks"; //Вспомогательные хуки
|
||||
import { XMLParser } from "fast-xml-parser";
|
||||
|
||||
//---------
|
||||
//Константы
|
||||
//---------
|
||||
|
||||
//Высота диаграммы Ганта
|
||||
const GANTT_HEIGHT = "650px";
|
||||
|
||||
//Ширина диаграммы Ганта
|
||||
const GANTT_WIDTH = "98vw";
|
||||
|
||||
//Стили
|
||||
const STYLES = {
|
||||
PROJECTS_FINDER: { marginTop: "10px", marginLeft: "10px", width: "93%" },
|
||||
PROJECTS_LIST_ITEM_PRIMARY: { wordWrap: "break-word" },
|
||||
PROJECTS_LIST_ITEM_SECONDARY: { wordWrap: "break-word", fontSize: "0.5rem", textTransform: "uppercase" },
|
||||
PROJECTS_LIST_ITEM_SECONDARY_NOJOBS: { color: "red" },
|
||||
PROJECTS_LIST_ITEM_SECONDARY_NOEDIT: { color: "gray" },
|
||||
PROJECTS_LIST_ITEM_SECONDARY_CHANGED: { color: "green" },
|
||||
PROJECTS_BUTTON: { position: "absolute" },
|
||||
PROJECTS_DRAWER: {
|
||||
minWidth: "250px",
|
||||
display: "inline-block",
|
||||
flexShrink: 0,
|
||||
[`& .MuiDrawer-paper`]: { minWidth: "250px", display: "inline-block", boxSizing: "border-box" }
|
||||
},
|
||||
GANTT_CONTAINER: { height: GANTT_HEIGHT, width: GANTT_WIDTH },
|
||||
GANTT_TITLE: { paddingLeft: "100px", paddingRight: "120px" },
|
||||
PERIODS_BUTTON: { position: "absolute", right: "20px" },
|
||||
PERIODS_DRAWER: { width: "1000px", flexShrink: 0, [`& .MuiDrawer-paper`]: { width: "1000px", boxSizing: "border-box" } }
|
||||
};
|
||||
|
||||
//Список проектов
|
||||
const ProjectsList = ({ plans = [], selectedPlan, filter, setFilter, onClick } = {}) => {
|
||||
//Генерация содержимого
|
||||
return (
|
||||
<div>
|
||||
<TextField
|
||||
sx={STYLES.PROJECTS_FINDER}
|
||||
name="planFilter"
|
||||
label="План"
|
||||
value={filter}
|
||||
variant="standard"
|
||||
fullWidth
|
||||
onChange={event => {
|
||||
setFilter(event.target.value);
|
||||
}}
|
||||
></TextField>
|
||||
<List>
|
||||
{plans.map(p => (
|
||||
<ListItemButton key={p.NRN} selected={p.NRN === selectedPlan} onClick={() => (onClick ? onClick(p) : null)}>
|
||||
<ListItemText
|
||||
primary={<Typography sx={STYLES.PROJECTS_LIST_ITEM_PRIMARY}>{p.SDOC_INFO}</Typography>}
|
||||
secondary={
|
||||
<Typography
|
||||
sx={{
|
||||
...STYLES.PROJECTS_LIST_ITEM_SECONDARY,
|
||||
...(p.NJOBS == 0
|
||||
? STYLES.PROJECTS_LIST_ITEM_SECONDARY_NOJOBS
|
||||
: p.NCHANGED == 1
|
||||
? STYLES.PROJECTS_LIST_ITEM_SECONDARY_CHANGED
|
||||
: STYLES.PROJECTS_LIST_ITEM_SECONDARY_NOEDIT)
|
||||
}}
|
||||
></Typography>
|
||||
}
|
||||
/>
|
||||
</ListItemButton>
|
||||
))}
|
||||
</List>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
//Контроль свойств - Список проектов
|
||||
ProjectsList.propTypes = {
|
||||
plans: PropTypes.array,
|
||||
selectedPlan: PropTypes.number,
|
||||
onClick: PropTypes.func,
|
||||
filter: PropTypes.string,
|
||||
setFilter: PropTypes.func
|
||||
};
|
||||
|
||||
//-----------
|
||||
//Тело модуля
|
||||
//-----------
|
||||
|
||||
//Разбор XML
|
||||
const parseXML = (xmlDoc, attributeValueProcessor) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
try {
|
||||
let opts = {
|
||||
ignoreDeclaration: true,
|
||||
ignoreAttributes: false,
|
||||
parseAttributeValue: true,
|
||||
attributeNamePrefix: ""
|
||||
};
|
||||
if (attributeValueProcessor) opts.attributeValueProcessor = attributeValueProcessor;
|
||||
const parser = new XMLParser(opts);
|
||||
const data = parser.parse(xmlDoc);
|
||||
resolve(data.XDATA);
|
||||
} catch (e) {
|
||||
reject(e);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
//Корневая панель производственной программы
|
||||
const MechRecCostProdPlans = () => {
|
||||
//Собственное состояние
|
||||
let [state, setState] = useState({
|
||||
init: false,
|
||||
showPlanList: false,
|
||||
plans: [],
|
||||
plansLoaded: false,
|
||||
selectedPlanSpecsLoaded: false,
|
||||
selectedPlan: null,
|
||||
selectedPlanMaxLevel: null,
|
||||
selectedPlanLevel: null,
|
||||
selectedPlanMenuItems: null,
|
||||
selectedPlanGanttDef: {},
|
||||
selectedPlanSpecs: []
|
||||
});
|
||||
|
||||
const [filter, setFilter] = useState("");
|
||||
|
||||
const filteredPlans = useFilteredPlans(state.plans, filter);
|
||||
|
||||
//Подключение к контексту приложения
|
||||
const { pOnlineShowDocument } = useContext(ApplicationСtx);
|
||||
|
||||
//Подключение к контексту сообщений
|
||||
const { InlineMsgInfo } = useContext(MessagingСtx);
|
||||
|
||||
//Подключение к контексту взаимодействия с сервером
|
||||
const { executeStored } = useContext(BackEndСtx);
|
||||
|
||||
// Инициализация планов
|
||||
const initPlans = useCallback(async () => {
|
||||
if (!state.init) {
|
||||
const data = await executeStored({
|
||||
stored: "PKG_P8PANELS_MECHREC.PRODPLAN_INIT",
|
||||
args: {},
|
||||
respArg: "COUT"
|
||||
});
|
||||
setState(pv => ({
|
||||
...pv,
|
||||
init: true,
|
||||
plans: [...(data?.XFCPRODPLANS || [])],
|
||||
plansLoaded: true
|
||||
}));
|
||||
}
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [state.init, executeStored]);
|
||||
|
||||
//Выбор плана
|
||||
const selectPlan = project => {
|
||||
setState(pv => ({
|
||||
...pv,
|
||||
selectedPlan: project,
|
||||
selectedPlanSpecsLoaded: false,
|
||||
selectedPlanMaxLevel: null,
|
||||
selectedPlanLevel: null,
|
||||
selectedPlanMenuItems: null,
|
||||
selectedPlanSpecs: [],
|
||||
selectedPlanGanttDef: {},
|
||||
showPlanList: false
|
||||
}));
|
||||
};
|
||||
|
||||
//Сброс выбора плана
|
||||
const unselectPlan = () =>
|
||||
setState(pv => ({
|
||||
...pv,
|
||||
selectedPlanSpecsLoaded: false,
|
||||
selectedPlan: null,
|
||||
selectedPlanMaxLevel: null,
|
||||
selectedPlanLevel: null,
|
||||
selectedPlanMenuItems: null,
|
||||
selectedPlanSpecs: [],
|
||||
selectedPlanGanttDef: {},
|
||||
showPlanList: false
|
||||
}));
|
||||
|
||||
//Загрузка списка спецификаций плана
|
||||
const loadPlanSpecs = useCallback(
|
||||
async (level = null) => {
|
||||
const data = await executeStored({
|
||||
stored: "PKG_P8PANELS_MECHREC.FCPRODPLANSP_GET",
|
||||
args: { NFCPRODPLAN: state.selectedPlan, NLEVEL: level }
|
||||
});
|
||||
let doc = await parseXML(data.COUT, (name, val) =>
|
||||
name == "numb" ? undefined : ["start", "end"].includes(name) ? formatDateJSONDateOnly(val) : val
|
||||
);
|
||||
console.log(doc.XGANTT_DEF);
|
||||
console.log(doc.XGANTT_TASKS);
|
||||
setState(pv => ({
|
||||
...pv,
|
||||
selectedPlanMaxLevel: data.NMAX_LEVEL,
|
||||
selectedPlanLevel: level || level === 0 ? level : data.NMAX_LEVEL,
|
||||
selectedPlanMenuItems: state.selectedPlanMenuItems
|
||||
? state.selectedPlanMenuItems
|
||||
: [...Array(data.NMAX_LEVEL).keys()].map(el => el + 1),
|
||||
selectedPlanSpecsLoaded: true,
|
||||
selectedPlanGanttDef: doc.XGANTT_DEF ? { ...doc.XGANTT_DEF } : {},
|
||||
selectedPlanSpecs: [...(doc?.XGANTT_TASKS || [])]
|
||||
}));
|
||||
},
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
[executeStored, state.ident, state.selectedPlan]
|
||||
);
|
||||
|
||||
//Обработка нажатия на элемент в списке планов
|
||||
const handleProjectClick = project => {
|
||||
if (state.selectedPlan != project.NRN) selectPlan(project.NRN);
|
||||
else unselectPlan();
|
||||
};
|
||||
|
||||
//Отработка нажатия на заголовок плана
|
||||
const handleTitleClick = () => {
|
||||
state.selectedPlan ? pOnlineShowDocument({ unitCode: "CostProductPlans", document: state.selectedPlan }) : null;
|
||||
};
|
||||
|
||||
//При подключении компонента к странице
|
||||
useEffect(() => {
|
||||
initPlans();
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, []);
|
||||
|
||||
//При смене выбранного плана
|
||||
useEffect(() => {
|
||||
if (state.selectedPlan) loadPlanSpecs();
|
||||
}, [state.selectedPlan, loadPlanSpecs]);
|
||||
|
||||
//Выбор уровня
|
||||
const handleChangeSelectList = selectedLevel => {
|
||||
loadPlanSpecs(selectedLevel);
|
||||
setState(pv => ({ ...pv, selectedPlanLevel: selectedLevel }));
|
||||
};
|
||||
//Генерация содержимого
|
||||
return (
|
||||
<Box p={2}>
|
||||
<Fab variant="extended" sx={STYLES.PROJECTS_BUTTON} onClick={() => setState(pv => ({ ...pv, showPlanList: !pv.showPlanList }))}>
|
||||
Планы
|
||||
</Fab>
|
||||
<Drawer
|
||||
anchor={"left"}
|
||||
open={state.showPlanList}
|
||||
onClose={() => setState(pv => ({ ...pv, showPlanList: false }))}
|
||||
sx={STYLES.PROJECTS_DRAWER}
|
||||
>
|
||||
<ProjectsList
|
||||
plans={filteredPlans}
|
||||
selectedPlan={state.selectedPlan}
|
||||
filter={filter}
|
||||
setFilter={setFilter}
|
||||
onClick={handleProjectClick}
|
||||
/>
|
||||
</Drawer>
|
||||
{state.init == true ? (
|
||||
<Grid container spacing={1}>
|
||||
<Grid item xs={12}>
|
||||
{state.selectedPlanSpecsLoaded ? (
|
||||
state.selectedPlanSpecs.length === 0 ? (
|
||||
<InlineMsgInfo okBtn={false} text={"В плане отсутствуют записи спецификации"} />
|
||||
) : (
|
||||
<Box sx={STYLES.GANTT_CONTAINER} p={1}>
|
||||
{state.selectedPlanMaxLevel ? (
|
||||
<Box sx={{ float: "right" }}>
|
||||
<InputLabel id="demo-simple-select-label">Уровень</InputLabel>
|
||||
<Select
|
||||
labelId="demo-simple-select-label"
|
||||
id="demo-simple-select"
|
||||
value={state.selectedPlanLevel}
|
||||
label="Уровень"
|
||||
onChange={event => {
|
||||
handleChangeSelectList(event.target.value);
|
||||
}}
|
||||
defaultValue={state.selectedPlanLevel}
|
||||
>
|
||||
{state.selectedPlanMenuItems.map(el => (
|
||||
<MenuItem value={el} key={el}>
|
||||
{el}
|
||||
</MenuItem>
|
||||
))}
|
||||
</Select>
|
||||
</Box>
|
||||
) : null}
|
||||
<P8PGantt
|
||||
{...P8P_GANTT_CONFIG_PROPS}
|
||||
{...state.selectedPlanGanttDef}
|
||||
height={GANTT_HEIGHT}
|
||||
onTitleClick={handleTitleClick}
|
||||
titleStyle={STYLES.GANTT_TITLE}
|
||||
tasks={state.selectedPlanSpecs}
|
||||
/>
|
||||
</Box>
|
||||
)
|
||||
) : !state.selectedPlan ? (
|
||||
<InlineMsgInfo okBtn={false} text={"Укажите план для отображения его спецификации"} />
|
||||
) : null}
|
||||
</Grid>
|
||||
</Grid>
|
||||
) : null}
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
//----------------
|
||||
//Интерфейс модуля
|
||||
//----------------
|
||||
|
||||
export { MechRecCostProdPlans };
|
426
db/PKG_P8PANELS_MECHREC.pck
Normal file
426
db/PKG_P8PANELS_MECHREC.pck
Normal file
@ -0,0 +1,426 @@
|
||||
create or replace package PKG_P8PANELS_MECHREC as
|
||||
|
||||
/* Получение списка спецификаций планов и отчетов производства изделий для диаграммы Ганта */
|
||||
procedure FCPRODPLANSP_GET
|
||||
(
|
||||
NFCPRODPLAN in number, -- Рег. номер родителя
|
||||
NLEVEL in number := null, -- Уровень отбора
|
||||
COUT out clob, -- Список проектов
|
||||
NMAX_LEVEL out number -- Максимальный уровень иерархии
|
||||
);
|
||||
|
||||
/* Инициализация планов и отчетов производства изделий */
|
||||
procedure PRODPLAN_INIT
|
||||
(
|
||||
COUT out clob -- Список планов и отчетов производства изделий
|
||||
);
|
||||
|
||||
end PKG_P8PANELS_MECHREC;
|
||||
/
|
||||
create or replace package body PKG_P8PANELS_MECHREC as
|
||||
|
||||
/* Константы - цвета отображения */
|
||||
SBG_COLOR_RED constant PKG_STD.TSTRING := 'red'; -- Цвет заливки красный (Дефицит запуска != 0)
|
||||
SBG_COLOR_YELLOW constant PKG_STD.TSTRING := '#e0db44'; -- Цвет заливки желтый (Дефицит» запуска = 0 и Выпуск факт = 0)
|
||||
SBG_COLOR_GREEN constant PKG_STD.TSTRING := 'lightgreen'; -- Цвет заливки зеленый (Дефицит выпуска = 0)
|
||||
SBG_COLOR_BLACK constant PKG_STD.TSTRING := 'black'; -- Цвет заливки черный (Нет дат и связей)
|
||||
STEXT_COLOR_ORANGE constant PKG_STD.TSTRING := '#FF8C00'; -- Цвет текста для черной заливки (оранжевый)
|
||||
|
||||
/* Константы - параметры отборов планов */
|
||||
NFCPRODPLAN_CATEGORY constant PKG_STD.TNUMBER := 1; -- Категория планов "Производственная программа"
|
||||
NFCPRODPLAN_STATUS constant PKG_STD.TNUMBER := 2; -- Статус планов "Утвержден"
|
||||
SFCPRODPLAN_TYPE constant PKG_STD.TSTRING := 'План'; -- Тип планов (мнемокод состояния)
|
||||
|
||||
/* Константы - дополнительные атрибуты */
|
||||
STASK_ATTR_DEFRESLIZ constant PKG_STD.TSTRING := 'defresliz'; -- Дефицит запуска
|
||||
STASK_ATTR_REL_FACT constant PKG_STD.TSTRING := 'rel_fact'; -- Выпуск факт
|
||||
STASK_ATTR_DEFSTART constant PKG_STD.TSTRING := 'defstart'; -- Дефицит выпуска
|
||||
STASK_ATTR_LEVEL constant PKG_STD.TSTRING := 'level'; -- Уровень
|
||||
|
||||
/* Формирование характеристик спецификации в Ганте */
|
||||
procedure MAKE_GANT_ITEM
|
||||
(
|
||||
NDEFRESLIZ in number, -- Дефицит запуска
|
||||
NREL_FACT in number, -- Выпуск факт
|
||||
NDEFSTART in number, -- Дефицит выпуска
|
||||
STASK_BG_COLOR out varchar2, -- Цвет заливки спецификации
|
||||
STASK_BG_PROGRESS_COLOR out varchar2, -- Цвет заливки прогресса спецификации
|
||||
NTASK_PROGRESS out number -- Прогресс спецификации
|
||||
)
|
||||
is
|
||||
begin
|
||||
/* Если дефицит запуска <> 0 */
|
||||
if (NDEFRESLIZ <> 0) then
|
||||
/* Полностью красный */
|
||||
STASK_BG_COLOR := SBG_COLOR_RED;
|
||||
STASK_BG_PROGRESS_COLOR := null;
|
||||
NTASK_PROGRESS := null;
|
||||
else
|
||||
/* Если дефицит выпуска = 0 */
|
||||
if (NDEFSTART = 0) then
|
||||
/* Полностью зеленый */
|
||||
STASK_BG_COLOR := SBG_COLOR_GREEN;
|
||||
STASK_BG_PROGRESS_COLOR := null;
|
||||
NTASK_PROGRESS := null;
|
||||
else
|
||||
/* Если дефицит запуска = 0 и выпуск факт = 0 */
|
||||
if ((NDEFRESLIZ = 0) and (NREL_FACT = 0)) then
|
||||
/* Полностью жёлтый */
|
||||
STASK_BG_COLOR := SBG_COLOR_YELLOW;
|
||||
STASK_BG_PROGRESS_COLOR := null;
|
||||
NTASK_PROGRESS := null;
|
||||
end if;
|
||||
/* Если дефицит запуска = 0 и выпуск факт <> 0 */
|
||||
if ((NDEFRESLIZ = 0) and (NREL_FACT <> 0)) then
|
||||
/* Частично зелёный, прогресс жёлтый */
|
||||
STASK_BG_COLOR := SBG_COLOR_GREEN;
|
||||
STASK_BG_PROGRESS_COLOR := SBG_COLOR_YELLOW;
|
||||
NTASK_PROGRESS := 50;
|
||||
end if;
|
||||
end if;
|
||||
end if;
|
||||
end MAKE_GANT_ITEM;
|
||||
|
||||
/* Считывание заголовка документа */
|
||||
function TITLE_GET
|
||||
(
|
||||
NRN in number -- Рег. номер плана и отчета производства изделий
|
||||
) return varchar2 -- Заголовок для отображения
|
||||
is
|
||||
SRESULT PKG_STD.TSTRING; -- Заголовок для отображения
|
||||
SDOC_INFO PKG_STD.TSTRING; -- Информация о документе
|
||||
SJURPERSONS_CODE PKG_STD.TSTRING; -- Мнемокод принадлежности
|
||||
SINS_DEPARTMENT_CODE PKG_STD.TSTRING; -- Мнемокод подразделения
|
||||
begin
|
||||
/* Считываем информацию из плана */
|
||||
begin
|
||||
select D.DOCCODE || ', ' || trim(T.PREFIX) || '/' || trim(T.NUMB) || ', от ' || TO_CHAR(T.DOCDATE, 'dd.mm.yyyy') DOC_INFO,
|
||||
J.CODE,
|
||||
SD.CODE
|
||||
into SDOC_INFO,
|
||||
SJURPERSONS_CODE,
|
||||
SINS_DEPARTMENT_CODE
|
||||
from FCPRODPLAN T,
|
||||
DOCTYPES D,
|
||||
JURPERSONS J,
|
||||
INS_DEPARTMENT SD
|
||||
where T.RN = NRN
|
||||
and D.RN = T.DOCTYPE
|
||||
and J.RN = T.JUR_PERS
|
||||
and SD.RN = T.SUBDIV;
|
||||
exception
|
||||
when others then
|
||||
return 'Нет информации.';
|
||||
end;
|
||||
/* Формируем заголовок */
|
||||
SRESULT := 'План и отчет производства изделия "' || SDOC_INFO || '", принадлежность "' || SJURPERSONS_CODE ||
|
||||
'", подразделение "' || SINS_DEPARTMENT_CODE || '"';
|
||||
/* Возвращаем результат */
|
||||
return SRESULT;
|
||||
end TITLE_GET;
|
||||
|
||||
/* Считывание максимального уровня иерархии плана */
|
||||
function PRODPLAN_MAX_LEVEL_GET
|
||||
(
|
||||
NPRODPLAN in number -- Рег. номер плана
|
||||
) return number -- Максимальный уровень иерархии
|
||||
is
|
||||
NRESULT PKG_STD.TNUMBER; -- Максимальный уровень иерархии
|
||||
begin
|
||||
/* Считываем максимальный уровень */
|
||||
begin
|
||||
select max(level)
|
||||
into NRESULT
|
||||
from (select T.RN,
|
||||
T.UP_LEVEL
|
||||
from FCPRODPLANSP T
|
||||
where T.PRN = NPRODPLAN) TMP
|
||||
connect by prior TMP.RN = TMP.UP_LEVEL
|
||||
start with TMP.UP_LEVEL is null;
|
||||
exception
|
||||
when others then
|
||||
NRESULT := null;
|
||||
end;
|
||||
/* Возвращаем результат */
|
||||
return NRESULT;
|
||||
end PRODPLAN_MAX_LEVEL_GET;
|
||||
|
||||
/* Определение дат спецификации плана */
|
||||
procedure FCPRODPLANSP_DATES_GET
|
||||
(
|
||||
DREP_DATE in date, -- Дата запуска спецификации
|
||||
DREP_DATE_TO in date, -- Дата выпуска спецификации
|
||||
DINCL_DATE in date, -- Дата включения в план спецификации
|
||||
NHAVE_LINK in number := 0, -- Наличие связей с "Маршрутный лист" или "Приход из подразделения"
|
||||
DDATE_FROM out date, -- Итоговая дата запуска спецификации
|
||||
DDATE_TO out date, -- Итоговая дата выпуска спецификации
|
||||
STASK_BG_COLOR out varchar2, -- Цвет элемента (черный, если даты не заданы и нет связи, иначе null)
|
||||
STASK_TEXT_COLOR out varchar2, -- Цвет текста элемента (хаки, если даты не заданы и нет связи, иначе null)
|
||||
NTASK_PROGRESS out number -- Прогресс элемента (проинициализирует null, если даты не заданы и нет связи)
|
||||
)
|
||||
is
|
||||
begin
|
||||
/* Проициниализируем цвет и прогресс */
|
||||
STASK_BG_COLOR := null;
|
||||
NTASK_PROGRESS := null;
|
||||
STASK_TEXT_COLOR := null;
|
||||
/* Если даты запуска и выпуска пусты */
|
||||
if ((DREP_DATE is null) and (DREP_DATE_TO is null)) then
|
||||
/* Указываем дату включения в план */
|
||||
DDATE_FROM := DINCL_DATE;
|
||||
DDATE_TO := DINCL_DATE;
|
||||
else
|
||||
/* Указываем даты исходя из дат запуска/выпуска */
|
||||
DDATE_FROM := COALESCE(DREP_DATE, DREP_DATE_TO);
|
||||
DDATE_TO := COALESCE(DREP_DATE_TO, DREP_DATE);
|
||||
end if;
|
||||
/* Если одна из дат не указана */
|
||||
if ((DREP_DATE is null) or (DREP_DATE_TO is null)) then
|
||||
/* Если спецификация также не имеет связей */
|
||||
if (NHAVE_LINK = 0) then
|
||||
/* Закрашиваем в черный */
|
||||
STASK_BG_COLOR := SBG_COLOR_BLACK;
|
||||
STASK_TEXT_COLOR := STEXT_COLOR_ORANGE;
|
||||
NTASK_PROGRESS := null;
|
||||
end if;
|
||||
end if;
|
||||
end FCPRODPLANSP_DATES_GET;
|
||||
|
||||
/* Получение списка спецификаций планов и отчетов производства изделий для диаграммы Ганта */
|
||||
procedure FCPRODPLANSP_GET
|
||||
(
|
||||
NFCPRODPLAN in number, -- Рег. номер родителя
|
||||
NLEVEL in number := null, -- Уровень отбора
|
||||
COUT out clob, -- Список проектов
|
||||
NMAX_LEVEL out number -- Максимальный уровень иерархии
|
||||
)
|
||||
is
|
||||
/* Переменные */
|
||||
RG PKG_P8PANELS_VISUAL.TGANTT; -- Описание диаграммы Ганта
|
||||
RGT PKG_P8PANELS_VISUAL.TGANTT_TASK; -- Описание задачи для диаграммы
|
||||
BREAD_ONLY_DATES boolean := false; -- Флаг доступности дат проекта только для чтения
|
||||
STASK_BG_COLOR PKG_STD.TSTRING; -- Цвет заливки задачи
|
||||
STASK_TEXT_COLOR PKG_STD.TSTRING; -- Цвет текста задачи
|
||||
STASK_BG_PROGRESS_COLOR PKG_STD.TSTRING; -- Цвет заливки прогресса задачи
|
||||
NTASK_PROGRESS PKG_STD.TNUMBER; -- Прогресс выполнения задачи
|
||||
DDATE_FROM PKG_STD.TLDATE; -- Дата запуска спецификации
|
||||
DDATE_TO PKG_STD.TLDATE; -- Дата выпуска спецификации
|
||||
begin
|
||||
/* Инициализируем диаграмму Ганта */
|
||||
RG := PKG_P8PANELS_VISUAL.TGANTT_MAKE(STITLE => TITLE_GET(NRN => NFCPRODPLAN),
|
||||
NZOOM => PKG_P8PANELS_VISUAL.NGANTT_ZOOM_DAY,
|
||||
BREAD_ONLY_DATES => BREAD_ONLY_DATES,
|
||||
BREAD_ONLY_PROGRESS => true);
|
||||
/* Добавим динамические атрибуты к спецификациям */
|
||||
PKG_P8PANELS_VISUAL.TGANTT_ADD_TASK_ATTR(RGANTT => RG,
|
||||
SNAME => STASK_ATTR_DEFRESLIZ,
|
||||
SCAPTION => 'Дефицит запуска');
|
||||
PKG_P8PANELS_VISUAL.TGANTT_ADD_TASK_ATTR(RGANTT => RG,
|
||||
SNAME => STASK_ATTR_REL_FACT,
|
||||
SCAPTION => 'Выпуск факт');
|
||||
PKG_P8PANELS_VISUAL.TGANTT_ADD_TASK_ATTR(RGANTT => RG,
|
||||
SNAME => STASK_ATTR_DEFSTART,
|
||||
SCAPTION => 'Дефицит выпуска');
|
||||
PKG_P8PANELS_VISUAL.TGANTT_ADD_TASK_ATTR(RGANTT => RG, SNAME => STASK_ATTR_LEVEL, SCAPTION => 'Уровень');
|
||||
/* Добавим описание цветов */
|
||||
PKG_P8PANELS_VISUAL.TGANTT_ADD_TASK_COLOR(RGANTT => RG,
|
||||
SBG_COLOR => SBG_COLOR_RED,
|
||||
SDESC => 'Для спецификаций планов и отчетов производства изделий с «Дефицит запуска» != 0.');
|
||||
PKG_P8PANELS_VISUAL.TGANTT_ADD_TASK_COLOR(RGANTT => RG,
|
||||
SBG_COLOR => SBG_COLOR_YELLOW,
|
||||
SDESC => 'Для спецификаций планов и отчетов производства изделий с «Дефицит запуска» = 0 и «Выпуск факт» = 0.');
|
||||
PKG_P8PANELS_VISUAL.TGANTT_ADD_TASK_COLOR(RGANTT => RG,
|
||||
SBG_COLOR => SBG_COLOR_GREEN,
|
||||
SDESC => 'Для спецификаций планов и отчетов производства изделий с «Дефицит выпуска» = 0.');
|
||||
PKG_P8PANELS_VISUAL.TGANTT_ADD_TASK_COLOR(RGANTT => RG,
|
||||
SBG_COLOR => SBG_COLOR_GREEN,
|
||||
SBG_PROGRESS_COLOR => SBG_COLOR_YELLOW,
|
||||
SDESC => 'Для спецификаций планов и отчетов производства изделий с «Дефицит запуска» = 0 и «Выпуск факт» != 0. ');
|
||||
PKG_P8PANELS_VISUAL.TGANTT_ADD_TASK_COLOR(RGANTT => RG,
|
||||
SBG_COLOR => SBG_COLOR_BLACK,
|
||||
STEXT_COLOR => STEXT_COLOR_ORANGE,
|
||||
SDESC => 'Для спецификаций планов и отчетов производства изделий с пустыми «Дата запуска» и «Дата выпуска» и не имеющих связей с разделами «Маршрутный лист» или «Приход из подразделения».');
|
||||
/* Определяем максимальный уровень иерархии */
|
||||
NMAX_LEVEL := PRODPLAN_MAX_LEVEL_GET(NPRODPLAN => NFCPRODPLAN);
|
||||
/* Цикл по спецификации плана с учетом иерархии */
|
||||
for REC in (select TMP.*,
|
||||
level
|
||||
from (select T.RN,
|
||||
T.REP_DATE,
|
||||
T.REP_DATE_TO,
|
||||
T.INCL_DATE,
|
||||
T.ROUTE,
|
||||
D.NOMEN_NAME,
|
||||
(T.QUANT_REST - T.START_FACT) DEFRESLIZ,
|
||||
T.REL_FACT,
|
||||
(T.MAIN_QUANT - T.REL_FACT) DEFSTART,
|
||||
(select 1
|
||||
from DUAL
|
||||
where exists
|
||||
(select null
|
||||
from DOCLINKS L
|
||||
where L.IN_DOCUMENT = T.RN
|
||||
and L.IN_UNITCODE = 'CostProductPlansSpecs'
|
||||
and (L.OUT_UNITCODE = 'CostRouteLists' or L.OUT_UNITCODE = 'IncomFromDeps')
|
||||
and ROWNUM = 1)) HAVE_LINK,
|
||||
T.UP_LEVEL
|
||||
from FCPRODPLANSP T,
|
||||
FCMATRESOURCE FM,
|
||||
DICNOMNS D
|
||||
where T.PRN = NFCPRODPLAN
|
||||
and ((T.REP_DATE is not null) or (T.REP_DATE_TO is not null) or (T.INCL_DATE is not null))
|
||||
and FM.RN = T.MATRES
|
||||
and D.RN = FM.NOMENCLATURE) TMP
|
||||
where ((NLEVEL is null) or ((NLEVEL is not null) and (level <= NLEVEL)))
|
||||
connect by prior TMP.RN = TMP.UP_LEVEL
|
||||
start with TMP.UP_LEVEL is null)
|
||||
loop
|
||||
/* Инициализируем даты и цвет (если необходимо) */
|
||||
FCPRODPLANSP_DATES_GET(DREP_DATE => REC.REP_DATE,
|
||||
DREP_DATE_TO => REC.REP_DATE_TO,
|
||||
DINCL_DATE => REC.INCL_DATE,
|
||||
NHAVE_LINK => COALESCE(REC.HAVE_LINK, 0),
|
||||
DDATE_FROM => DDATE_FROM,
|
||||
DDATE_TO => DDATE_TO,
|
||||
STASK_BG_COLOR => STASK_BG_COLOR,
|
||||
STASK_TEXT_COLOR => STASK_TEXT_COLOR,
|
||||
NTASK_PROGRESS => NTASK_PROGRESS);
|
||||
/* Если цвет изначально не указан и требуется анализирование */
|
||||
if (STASK_BG_COLOR is null) then
|
||||
/* Формирование характеристик элемента ганта */
|
||||
MAKE_GANT_ITEM(NDEFRESLIZ => REC.DEFRESLIZ,
|
||||
NREL_FACT => REC.REL_FACT,
|
||||
NDEFSTART => REC.DEFSTART,
|
||||
STASK_BG_COLOR => STASK_BG_COLOR,
|
||||
STASK_BG_PROGRESS_COLOR => STASK_BG_PROGRESS_COLOR,
|
||||
NTASK_PROGRESS => NTASK_PROGRESS);
|
||||
end if;
|
||||
/* Сформируем основную спецификацию */
|
||||
RGT := PKG_P8PANELS_VISUAL.TGANTT_TASK_MAKE(NRN => REC.RN,
|
||||
SNUMB => COALESCE(REC.ROUTE, 'Отсутствует'),
|
||||
SCAPTION => REC.NOMEN_NAME,
|
||||
SNAME => REC.NOMEN_NAME,
|
||||
DSTART => DDATE_FROM,
|
||||
DEND => DDATE_TO,
|
||||
NPROGRESS => NTASK_PROGRESS,
|
||||
SBG_COLOR => STASK_BG_COLOR,
|
||||
STEXT_COLOR => STASK_TEXT_COLOR,
|
||||
SBG_PROGRESS_COLOR => STASK_BG_PROGRESS_COLOR,
|
||||
BREAD_ONLY => true,
|
||||
BREAD_ONLY_DATES => true,
|
||||
BREAD_ONLY_PROGRESS => true);
|
||||
/* Добавим доп. атрибуты */
|
||||
PKG_P8PANELS_VISUAL.TGANTT_TASK_ADD_ATTR_VAL(RGANTT => RG,
|
||||
RTASK => RGT,
|
||||
SNAME => STASK_ATTR_DEFRESLIZ,
|
||||
SVALUE => TO_CHAR(REC.DEFRESLIZ),
|
||||
BCLEAR => true);
|
||||
PKG_P8PANELS_VISUAL.TGANTT_TASK_ADD_ATTR_VAL(RGANTT => RG,
|
||||
RTASK => RGT,
|
||||
SNAME => STASK_ATTR_REL_FACT,
|
||||
SVALUE => TO_CHAR(REC.REL_FACT));
|
||||
PKG_P8PANELS_VISUAL.TGANTT_TASK_ADD_ATTR_VAL(RGANTT => RG,
|
||||
RTASK => RGT,
|
||||
SNAME => STASK_ATTR_DEFSTART,
|
||||
SVALUE => TO_CHAR(REC.DEFSTART));
|
||||
PKG_P8PANELS_VISUAL.TGANTT_TASK_ADD_ATTR_VAL(RGANTT => RG,
|
||||
RTASK => RGT,
|
||||
SNAME => STASK_ATTR_LEVEL,
|
||||
SVALUE => REC.LEVEL);
|
||||
/* Собираем зависимости */
|
||||
for LINK in (select T.RN
|
||||
from FCPRODPLANSP T
|
||||
where T.PRN = NFCPRODPLAN
|
||||
and T.UP_LEVEL = REC.RN
|
||||
and ((NLEVEL is null) or ((NLEVEL is not null) and (NLEVEL >= REC.LEVEL + 1))))
|
||||
loop
|
||||
/* Добавляем зависимости */
|
||||
PKG_P8PANELS_VISUAL.TGANTT_TASK_ADD_DEPENDENCY(RTASK => RGT, NDEPENDENCY => LINK.RN);
|
||||
end loop;
|
||||
/* Добавляем основную спецификацию в диаграмму */
|
||||
PKG_P8PANELS_VISUAL.TGANTT_ADD_TASK(RGANTT => RG, RTASK => RGT);
|
||||
end loop;
|
||||
/* Формируем список */
|
||||
COUT := PKG_P8PANELS_VISUAL.TGANTT_TO_XML(RGANTT => RG);
|
||||
end FCPRODPLANSP_GET;
|
||||
|
||||
/* Инициализация планов и отчетов производства изделий */
|
||||
procedure PRODPLAN_INIT
|
||||
(
|
||||
COUT out clob -- Список планов и отчетов производства изделий
|
||||
)
|
||||
is
|
||||
begin
|
||||
/* Начинаем формирование XML */
|
||||
PKG_XFAST.PROLOGUE(ITYPE => PKG_XFAST.CONTENT_);
|
||||
/* Открываем корень */
|
||||
PKG_XFAST.DOWN_NODE(SNAME => 'XDATA');
|
||||
/* Цикл по планам и отчетам производства изделий */
|
||||
for REC in (select T.RN NRN,
|
||||
D.DOCCODE || ', ' || trim(T.PREFIX) || '/' || trim(T.NUMB) || ', ' ||
|
||||
TO_CHAR(T.DOCDATE, 'dd.mm.yyyy') SDOC_INFO
|
||||
from FCPRODPLAN T,
|
||||
DOCTYPES D,
|
||||
FINSTATE FS
|
||||
where T.CATEGORY = NFCPRODPLAN_CATEGORY
|
||||
and T.STATUS = NFCPRODPLAN_STATUS
|
||||
and D.RN = T.DOCTYPE
|
||||
and FS.RN = T.TYPE
|
||||
and FS.CODE = SFCPRODPLAN_TYPE
|
||||
and exists (select /*+ INDEX(UP I_USERPRIV_CATALOG_ROLEID) */
|
||||
null
|
||||
from USERPRIV UP
|
||||
where UP.CATALOG = T.CRN
|
||||
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_CATALOG_AUTHID) */
|
||||
null
|
||||
from USERPRIV UP
|
||||
where UP.CATALOG = T.CRN
|
||||
and UP.AUTHID = UTILIZER)
|
||||
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)
|
||||
order by T.DOCDATE desc)
|
||||
loop
|
||||
/* Открываем план */
|
||||
PKG_XFAST.DOWN_NODE(SNAME => 'XFCPRODPLANS');
|
||||
/* Описываем план */
|
||||
PKG_XFAST.ATTR(SNAME => 'NRN', NVALUE => REC.NRN);
|
||||
PKG_XFAST.ATTR(SNAME => 'SDOC_INFO', SVALUE => REC.SDOC_INFO);
|
||||
/* Закрываем план */
|
||||
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 PRODPLAN_INIT;
|
||||
|
||||
end PKG_P8PANELS_MECHREC;
|
||||
/
|
@ -2019,6 +2019,9 @@ text="Формат data_grid и gant как в chart"
|
||||
if (RGANTT.RTASK_COLORS(I).STEXT_COLOR is not null) then
|
||||
PKG_XFAST.ATTR(SNAME => SRESP_ATTR_TASK_TEXT_COLOR, SVALUE => RGANTT.RTASK_COLORS(I).STEXT_COLOR);
|
||||
end if;
|
||||
if (RGANTT.RTASK_COLORS(I).SBG_PROGRESS_COLOR is not null) then
|
||||
PKG_XFAST.ATTR(SNAME => SRESP_ATTR_TASK_BG_PRG_COLOR, SVALUE => RGANTT.RTASK_COLORS(I).SBG_PROGRESS_COLOR);
|
||||
end if;
|
||||
PKG_XFAST.ATTR(SNAME => SRESP_ATTR_DESC, SVALUE => RGANTT.RTASK_COLORS(I).SDESC);
|
||||
/* Закрываем описание цвета задачи */
|
||||
PKG_XFAST.UP();
|
||||
|
367
dist/p8-panels.js
vendored
367
dist/p8-panels.js
vendored
File diff suppressed because one or more lines are too long
@ -473,6 +473,9 @@ var Gantt = (function () {
|
||||
class: 'bar-progress',
|
||||
append_to: this.bar_group,
|
||||
});
|
||||
//ЦИТК
|
||||
if (this.task.bgProgressColor) this.$bar_progress.style.fill = this.task.bgProgressColor;
|
||||
//ЦИТК
|
||||
|
||||
animateSVG(this.$bar_progress, 'width', 0, this.progress_width);
|
||||
}
|
||||
|
@ -12,10 +12,16 @@
|
||||
</App>
|
||||
<App name="EquipSrv">
|
||||
<MenuItem parent="{BA073333-DFBC-4BA3-8EA7-172F3F6B4FEE}" separator="true"/>
|
||||
<MenuItem parent="{BA073333-DFBC-4BA3-8EA7-172F3F6B4FEE}" name="ShowEqsPanelsRoot" caption="Панели мониторинга" url="modules/p8-panels/"/>
|
||||
<MenuItem parent="{BA073333-DFBC-4BA3-8EA7-172F3F6B4FEE}" name="ShowEqsPanelsRoot" caption="Панели мониторинга" url="Modules/p8-panels/"/>
|
||||
<MenuItem parent="{BA073333-DFBC-4BA3-8EA7-172F3F6B4FEE}" separator="true"/>
|
||||
<MenuItem parent="{BA073333-DFBC-4BA3-8EA7-172F3F6B4FEE}" name="ShowEqsPrfrm" caption="Выполнение работ по ТОиР" panelName="EqsPrfrm"/>
|
||||
</App>
|
||||
<App name="MechanicalRecords">
|
||||
<MenuItem parent="{BA073333-DFBC-4BA3-8EA7-172F3F6B4FEE}" separator="true"/>
|
||||
<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}" name="ShowMechRecPanelCostProdPlans" caption="Производственная программа" panelName="MechRecCostProdPlans"/>
|
||||
</App>
|
||||
</MenuItems>
|
||||
<Panels urlBase="Modules/p8-panels/#/">
|
||||
<Panel
|
||||
@ -68,6 +74,16 @@
|
||||
icon="build"
|
||||
showInPanelsList="true"
|
||||
preview="./img/eqs_prfrm.jpg"/>
|
||||
<Panel
|
||||
name="MechRecCostProdPlans"
|
||||
group="Планирование и учёт в дискретном производстве"
|
||||
caption="Производственная программа"
|
||||
desc="Контроль исполнения производственной программы по срокам и количеству запуска и выпуска ДСЕ"
|
||||
url="mech_rec_cost_prod_plans"
|
||||
path="mech_rec_cost_prod_plans"
|
||||
icon="calendar_month"
|
||||
showInPanelsList="true"
|
||||
preview="./img/default_preview.png"/>
|
||||
<Panel
|
||||
name="Samples"
|
||||
group=""
|
||||
|
Loading…
x
Reference in New Issue
Block a user