forked from CITKParus/P8-Panels
Compare commits
50 Commits
814a15c80e
...
426864a4b7
Author | SHA1 | Date | |
---|---|---|---|
426864a4b7 | |||
|
bdc032fa67 | ||
|
6d10f6258b | ||
|
852abd5482 | ||
|
27bd43afb5 | ||
|
83b0c75a3b | ||
|
ba8b7a5ce0 | ||
|
cca42f0b38 | ||
|
9469b01295 | ||
|
40242dedd4 | ||
|
aca423f16e | ||
|
ccad22f6a7 | ||
|
252ef9e263 | ||
|
7683f1ad76 | ||
|
5261253d36 | ||
|
b2cc839cba | ||
|
b06ae0d242 | ||
|
dac9bc4ea2 | ||
|
efed4b8ea2 | ||
|
a8a76766f4 | ||
|
6fa9d97da4 | ||
014d3f2e9e | |||
|
b617a27c48 | ||
686d8ee5aa | |||
|
252dd4174c | ||
e5215d29b5 | |||
|
0d9505834c | ||
3fa1c4b048 | |||
3b763ec0c4 | |||
69c3b101a6 | |||
|
a45479bdca | ||
|
c84b96f21e | ||
af9f9815c5 | |||
|
4b52cea683 | ||
147114a4ae | |||
|
49309e5c0e | ||
2d1a07d071 | |||
68a3e8b2be | |||
078550ad06 | |||
1d6007c4b7 | |||
|
607e5d9ddc | ||
|
2bfce51fed | ||
db66f0c96b | |||
|
a8c9bf2fec | ||
|
47532b9c19 | ||
|
9f0c2aa946 | ||
|
cf76c80519 | ||
86b1dcd717 | |||
3a02384346 | |||
0c8222ea7e |
@ -53,6 +53,7 @@ export const CAPTIONS = {
|
||||
export const ERRORS = {
|
||||
UNDER_CONSTRUCTION: "Панель в разработке",
|
||||
P8O_API_UNAVAILABLE: '"ПАРУС 8 Онлайн" недоступен',
|
||||
P8O_API_UNSUPPORTED: 'Функция "ПАРУС 8 Онлайн" не поддерживается',
|
||||
DEFAULT: "Неожиданная ошибка"
|
||||
};
|
||||
|
||||
|
@ -23,7 +23,8 @@ import {
|
||||
ListItemIcon,
|
||||
ListItemText
|
||||
} from "@mui/material"; //Интерфейсные компоненты
|
||||
import { P8PPanelsMenuDrawer, P8P_PANELS_MENU_PANEL_SHAPE } from "./p8p_panels_menu";
|
||||
import { P8PPanelsMenuDrawer, P8P_PANELS_MENU_PANEL_SHAPE } from "./p8p_panels_menu"; //Меню
|
||||
import { APP_STYLES } from "../../app.styles"; //Типовые стили
|
||||
|
||||
//---------
|
||||
//Константы
|
||||
@ -34,6 +35,7 @@ const APP_BAR_HEIGHT = "64px";
|
||||
|
||||
//Стили
|
||||
const STYLES = {
|
||||
DRAWER: { [`& .MuiDrawer-paper`]: { ...APP_STYLES.SCROLL } },
|
||||
ROOT_BOX: { display: "flex" },
|
||||
APP_BAR: { position: "fixed" },
|
||||
APP_BAR_BUTTON: { mr: 2 },
|
||||
@ -88,7 +90,7 @@ const P8PAppWorkspace = ({ children, panels = [], selectedPanel, closeCaption, h
|
||||
</Typography>
|
||||
</Toolbar>
|
||||
</AppBar>
|
||||
<Drawer anchor="left" open={open} onClose={handleDrawerClose}>
|
||||
<Drawer anchor="left" open={open} onClose={handleDrawerClose} sx={STYLES.DRAWER}>
|
||||
<List>
|
||||
<ListItemButton onClick={handleDrawerClose}>
|
||||
<ListItemIcon>
|
||||
|
@ -7,7 +7,7 @@
|
||||
//Подключение библиотек
|
||||
//---------------------
|
||||
|
||||
import React, { useEffect, useRef } from "react"; //Классы React
|
||||
import React, { useCallback, useEffect, useRef } from "react"; //Классы React
|
||||
import PropTypes from "prop-types"; //Контроль свойств компонента
|
||||
import Chart from "chart.js/auto"; //Диаграммы и графики
|
||||
|
||||
@ -37,23 +37,26 @@ const P8P_CHART_DATASET_SHAPE = PropTypes.shape({
|
||||
//-----------
|
||||
|
||||
//График
|
||||
const P8PChart = ({ type, title, legendPosition, options, labels, datasets, onClick, style }) => {
|
||||
const P8PChart = ({ type, title, legendPosition, options = {}, labels = [], datasets = [], onClick, style }) => {
|
||||
//Ссылки на DOM
|
||||
const chartCanvasRef = useRef(null);
|
||||
const chartRef = useRef(null);
|
||||
|
||||
//Обработка нажатия на элемент графика
|
||||
const handleClick = e => {
|
||||
const bar = chartRef.current.getElementsAtEventForMode(e, "nearest", { intersect: true }, true)[0];
|
||||
if (onClick && bar)
|
||||
onClick({
|
||||
datasetIndex: bar.datasetIndex,
|
||||
itemIndex: bar.index,
|
||||
item: chartRef.current.data.datasets[bar.datasetIndex].items
|
||||
? chartRef.current.data.datasets[bar.datasetIndex].items[bar.index]
|
||||
: null
|
||||
});
|
||||
};
|
||||
const handleClick = useCallback(
|
||||
e => {
|
||||
const bar = chartRef.current.getElementsAtEventForMode(e, "nearest", { intersect: true }, true)[0];
|
||||
if (onClick && bar)
|
||||
onClick({
|
||||
datasetIndex: bar.datasetIndex,
|
||||
itemIndex: bar.index,
|
||||
item: chartRef.current.data.datasets[bar.datasetIndex].items
|
||||
? chartRef.current.data.datasets[bar.datasetIndex].items[bar.index]
|
||||
: null
|
||||
});
|
||||
},
|
||||
[onClick]
|
||||
);
|
||||
|
||||
//При подключении к старнице
|
||||
useEffect(() => {
|
||||
@ -89,9 +92,10 @@ const P8PChart = ({ type, title, legendPosition, options, labels, datasets, onCl
|
||||
if (chartRef.current) {
|
||||
chartRef.current.data.labels = [...labels];
|
||||
chartRef.current.data.datasets = [...datasets];
|
||||
chartRef.current.options.onClick = handleClick;
|
||||
chartRef.current.update();
|
||||
}
|
||||
}, [datasets, labels]);
|
||||
}, [datasets, labels, handleClick]);
|
||||
|
||||
//Генерация содержимого
|
||||
return (
|
||||
@ -107,7 +111,7 @@ P8PChart.propTypes = {
|
||||
title: PropTypes.string,
|
||||
legendPosition: PropTypes.string,
|
||||
options: PropTypes.object,
|
||||
labels: PropTypes.arrayOf(PropTypes.string).isRequired,
|
||||
labels: PropTypes.arrayOf(PropTypes.string),
|
||||
datasets: PropTypes.arrayOf(P8P_CHART_DATASET_SHAPE),
|
||||
onClick: PropTypes.func,
|
||||
style: PropTypes.object
|
||||
|
819
app/components/p8p_cyclogram.js
Normal file
819
app/components/p8p_cyclogram.js
Normal file
@ -0,0 +1,819 @@
|
||||
/*
|
||||
Парус 8 - Панели мониторинга
|
||||
Компонент: Циклограмма
|
||||
*/
|
||||
|
||||
//---------------------
|
||||
//Подключение библиотек
|
||||
//---------------------
|
||||
|
||||
import React, { useEffect, useState, useRef } from "react"; //Классы React
|
||||
import PropTypes from "prop-types"; //Контроль свойств компонента
|
||||
import {
|
||||
Box,
|
||||
Typography,
|
||||
Dialog,
|
||||
DialogActions,
|
||||
DialogContent,
|
||||
Button,
|
||||
List,
|
||||
ListItem,
|
||||
ListItemText,
|
||||
Link,
|
||||
Divider,
|
||||
IconButton,
|
||||
Icon
|
||||
} from "@mui/material"; //Интерфейсные компоненты
|
||||
import { P8PAppInlineError } from "./p8p_app_message"; //Встраиваемое сообщение об ошибке
|
||||
import { hasValue } from "../core/utils"; //Вспомогательный функции
|
||||
|
||||
//---------
|
||||
//Константы
|
||||
//---------
|
||||
|
||||
//Уровни масштаба
|
||||
const P8P_CYCLOGRAM_ZOOM = [0.2, 0.4, 0.7, 1, 1.5, 2, 2.5];
|
||||
|
||||
//Параметры элементов циклограммы
|
||||
const NDEFAULT_LINE_HEIGHT = 20;
|
||||
const NDEFAULT_HEADER_HEIGHT = 35;
|
||||
|
||||
//Высота заголовка
|
||||
const TITLE_HEIGHT = "44px";
|
||||
|
||||
//Высота панели масштабирования
|
||||
const ZOOM_HEIGHT = "56px";
|
||||
|
||||
//Стили
|
||||
const STYLES = {
|
||||
CYCLOGRAM_TITLE: { height: TITLE_HEIGHT },
|
||||
CYCLOGRAM_ZOOM: { height: ZOOM_HEIGHT },
|
||||
HEADER_COLUMN: {
|
||||
fontSize: "12px",
|
||||
textOverflow: "ellipsis",
|
||||
overflow: "hidden",
|
||||
whiteSpace: "pre",
|
||||
textAlign: "center",
|
||||
lineHeight: "3",
|
||||
padding: "0px 5px"
|
||||
},
|
||||
CYCLOGRAM_BOX: (noData, title, zoomBar) => ({
|
||||
position: "relative",
|
||||
overflow: "auto",
|
||||
padding: "0px 8px",
|
||||
height: `calc(100% - ${zoomBar ? ZOOM_HEIGHT : "0px"} - ${title ? TITLE_HEIGHT : "0px"})`,
|
||||
display: noData ? "none" : ""
|
||||
}),
|
||||
GRID_ROW: index => (index % 2 === 0 ? { backgroundColor: "#ffffff" } : { backgroundColor: "#f5f5f5" }),
|
||||
GROUP_HEADER_BOX: {
|
||||
border: "1px solid",
|
||||
backgroundColor: "#ebebeb",
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "center"
|
||||
},
|
||||
GROUP_HEADER: {
|
||||
fontSize: "14px",
|
||||
textAlign: "center",
|
||||
wordWrap: "break-word"
|
||||
},
|
||||
TASK_EDITOR_CONTENT: { minWidth: 400, overflowX: "auto" },
|
||||
TASK_EDITOR_LIST: { width: "100%", minWidth: 300, maxWidth: 700, bgcolor: "background.paper" },
|
||||
TASK_BOX: (lineHeight, bgColor, textColor, highlightColor) => ({
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
backgroundColor: bgColor ? bgColor : "#b4b9bf",
|
||||
...(textColor ? { color: textColor } : {}),
|
||||
height: lineHeight,
|
||||
"&:hover": {
|
||||
...(highlightColor
|
||||
? { backgroundColor: `${highlightColor} !important`, filter: "brightness(1) !important" }
|
||||
: { filter: "brightness(1.25) !important" }),
|
||||
cursor: "pointer !important"
|
||||
}
|
||||
}),
|
||||
TASK: lineHeight => {
|
||||
const availableLines = Math.floor(lineHeight / 18);
|
||||
return {
|
||||
width: "100%",
|
||||
fontSize: "12px",
|
||||
overflowWrap: "break-word",
|
||||
wordBreak: "break-all",
|
||||
overflow: "hidden",
|
||||
textOverflow: "ellipsis",
|
||||
display: "-webkit-box",
|
||||
lineHeight: "18px",
|
||||
maxHeight: lineHeight,
|
||||
WebkitLineClamp: availableLines < 1 ? 1 : availableLines,
|
||||
WebkitBoxOrient: "vertical"
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
//Структура колонки
|
||||
const P8P_CYCLOGRAM_COLUMN_SHAPE = PropTypes.shape({
|
||||
name: PropTypes.string.isRequired,
|
||||
start: PropTypes.number.isRequired,
|
||||
end: PropTypes.number.isRequired
|
||||
});
|
||||
|
||||
//Структура группы
|
||||
const P8P_CYCLOGRAM_GROUP_SHAPE = PropTypes.shape({
|
||||
name: PropTypes.string.isRequired,
|
||||
height: PropTypes.number.isRequired,
|
||||
width: PropTypes.number.isRequired,
|
||||
visible: PropTypes.bool.isRequired
|
||||
});
|
||||
|
||||
//Структура задачи
|
||||
const P8P_CYCLOGRAM_TASK_SHAPE = PropTypes.shape({
|
||||
id: PropTypes.string.isRequired,
|
||||
rn: PropTypes.number.isRequired,
|
||||
name: PropTypes.string.isRequired,
|
||||
fullName: PropTypes.string.isRequired,
|
||||
lineNumb: PropTypes.number.isRequired,
|
||||
start: PropTypes.number.isRequired,
|
||||
end: PropTypes.number.isRequired,
|
||||
group: PropTypes.string,
|
||||
bgColor: PropTypes.string,
|
||||
textColor: PropTypes.string,
|
||||
highlightColor: PropTypes.string
|
||||
});
|
||||
|
||||
//Структура динамического атрибута задачи
|
||||
const P8P_CYCLOGRAM_TASK_ATTRIBUTE_SHAPE = PropTypes.shape({
|
||||
name: PropTypes.string.isRequired,
|
||||
caption: PropTypes.string.isRequired,
|
||||
visible: PropTypes.bool.isRequired
|
||||
});
|
||||
|
||||
//--------------------------------
|
||||
//Вспомогательные классы и функции
|
||||
//--------------------------------
|
||||
|
||||
//Определение сдвига для максимальной ширины колонок
|
||||
const getShift = (columns, currentColumnsMaxWidth, maxCyclogramWidth) => {
|
||||
//Определяем доступное пространство для расширения
|
||||
let maxWidthDiff = maxCyclogramWidth - currentColumnsMaxWidth;
|
||||
//Инициализируем значение сдвига
|
||||
let shift = 1;
|
||||
//Если доступно больше ширины и есть пространство для расширения
|
||||
if (maxCyclogramWidth > currentColumnsMaxWidth && maxCyclogramWidth - maxWidthDiff > columns.length) {
|
||||
//Определяем доступный сдвиг колонок
|
||||
shift = maxCyclogramWidth / currentColumnsMaxWidth;
|
||||
}
|
||||
//Возвращаем сдвиг
|
||||
return shift;
|
||||
};
|
||||
|
||||
//Формирование стилей для группы
|
||||
const getGroupStyles = (indexGrp, highlightColor) => {
|
||||
return `.main .TaskGrp${indexGrp}:hover .TaskGrp${indexGrp} {
|
||||
${highlightColor ? `background: ${highlightColor};` : `filter: brightness(1.15);`}
|
||||
}
|
||||
.main:has(.TaskGrp${indexGrp}:hover) .TaskGrpHeader${indexGrp} {
|
||||
display: block;
|
||||
}
|
||||
`;
|
||||
//cursor: pointer;
|
||||
};
|
||||
|
||||
//Фон строк таблицы
|
||||
const P8PCyclogramRowsGrid = ({ rows, maxWidth, lineHeight }) => {
|
||||
return (
|
||||
<g>
|
||||
{rows.map((el, index) => (
|
||||
<foreignObject x="0" y={NDEFAULT_HEADER_HEIGHT + index * lineHeight} width={maxWidth} height={lineHeight} key={index}>
|
||||
<Box sx={STYLES.GRID_ROW(index)} height={lineHeight} />
|
||||
</foreignObject>
|
||||
))}
|
||||
</g>
|
||||
);
|
||||
};
|
||||
|
||||
//Контроль свойств - Фон строк таблицы
|
||||
P8PCyclogramRowsGrid.propTypes = {
|
||||
rows: PropTypes.array.isRequired,
|
||||
maxWidth: PropTypes.number.isRequired,
|
||||
lineHeight: PropTypes.number.isRequired
|
||||
};
|
||||
|
||||
//Линии строк таблицы
|
||||
const P8PCyclogramRowsLines = ({ rows, maxWidth, lineHeight }) => {
|
||||
return (
|
||||
<g>
|
||||
{rows.map((el, index) => (
|
||||
<line
|
||||
x1="0"
|
||||
y1={NDEFAULT_HEADER_HEIGHT + lineHeight + index * lineHeight}
|
||||
x2={maxWidth}
|
||||
y2={NDEFAULT_HEADER_HEIGHT + lineHeight + index * lineHeight}
|
||||
key={index}
|
||||
></line>
|
||||
))}
|
||||
</g>
|
||||
);
|
||||
};
|
||||
|
||||
//Контроль свойств - Линии строк таблицы
|
||||
P8PCyclogramRowsLines.propTypes = {
|
||||
rows: PropTypes.array.isRequired,
|
||||
maxWidth: PropTypes.number.isRequired,
|
||||
lineHeight: PropTypes.number.isRequired
|
||||
};
|
||||
|
||||
//Линии колонок таблицы
|
||||
const P8PCyclogramColumnsLines = ({ columns, shift, y1, y2 }) => {
|
||||
//Инициализируем старт текущей колонки
|
||||
let prevColumnEnd = 0;
|
||||
return (
|
||||
<g>
|
||||
{columns.map((column, index) => {
|
||||
//Аккумулируем окончание последней колонки с учетом сдвига
|
||||
prevColumnEnd = index !== 0 ? prevColumnEnd + (columns[index - 1].end - columns[index - 1].start) * shift : 0;
|
||||
return <line x1={prevColumnEnd} y1={y1} x2={prevColumnEnd} y2={y2} stroke="#e0e0e0" key={index} />;
|
||||
})}
|
||||
<line
|
||||
x1={prevColumnEnd + (columns[columns.length - 1].end - columns[columns.length - 1].start) * shift}
|
||||
y1={y1}
|
||||
x2={prevColumnEnd + (columns[columns.length - 1].end - columns[columns.length - 1].start) * shift}
|
||||
y2={y2}
|
||||
stroke="#e0e0e0"
|
||||
/>
|
||||
</g>
|
||||
);
|
||||
};
|
||||
|
||||
//Контроль свойств - Линии колонок таблицы
|
||||
P8PCyclogramColumnsLines.propTypes = {
|
||||
columns: PropTypes.array.isRequired,
|
||||
shift: PropTypes.number.isRequired,
|
||||
y1: PropTypes.number.isRequired,
|
||||
y2: PropTypes.number.isRequired
|
||||
};
|
||||
|
||||
//Фон таблицы циклограммы
|
||||
const P8PCyclogramGrid = ({ tasks, columns, shift, maxWidth, maxHeight, lineHeight }) => {
|
||||
//Формируем массив строк исходя из максимального значения строки задачи
|
||||
const rows = Array.from(Array(Math.max(...tasks.map(o => o.lineNumb)) + 1).keys());
|
||||
return (
|
||||
<g className="grid">
|
||||
<rect x="0" y="0" width={maxWidth} height={maxHeight}></rect>
|
||||
<P8PCyclogramRowsGrid rows={rows} maxWidth={maxWidth} lineHeight={lineHeight} />
|
||||
<P8PCyclogramRowsLines rows={rows} maxWidth={maxWidth} lineHeight={lineHeight} />
|
||||
<P8PCyclogramColumnsLines columns={columns} shift={shift} y1={NDEFAULT_HEADER_HEIGHT} y2={maxHeight} />
|
||||
</g>
|
||||
);
|
||||
};
|
||||
|
||||
//Контроль свойств - Фон таблицы циклограммы
|
||||
P8PCyclogramGrid.propTypes = {
|
||||
tasks: PropTypes.array.isRequired,
|
||||
columns: PropTypes.array.isRequired,
|
||||
shift: PropTypes.number.isRequired,
|
||||
maxWidth: PropTypes.number.isRequired,
|
||||
maxHeight: PropTypes.number.isRequired,
|
||||
lineHeight: PropTypes.number.isRequired
|
||||
};
|
||||
|
||||
//Колонка заголовка циклограммы
|
||||
const P8PCyclogramHeaderColumn = ({ column, start, shift, columnRenderer }) => {
|
||||
//Рассчитываем ширину колонки
|
||||
const columnWidth = column.end - column.start;
|
||||
//Формируем собственное отображение, если требуется
|
||||
const customView = columnRenderer ? columnRenderer({ column }) : null;
|
||||
return (
|
||||
<>
|
||||
<foreignObject x={start} y="0" width={columnWidth * shift} height={NDEFAULT_HEADER_HEIGHT}>
|
||||
{customView ? (
|
||||
customView
|
||||
) : (
|
||||
<Typography sx={{ ...STYLES.HEADER_COLUMN, height: NDEFAULT_HEADER_HEIGHT }} title={column.name}>
|
||||
{column.name}
|
||||
</Typography>
|
||||
)}
|
||||
</foreignObject>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
//Контроль свойств - Колонка заголовка циклограммы
|
||||
P8PCyclogramHeaderColumn.propTypes = {
|
||||
column: PropTypes.object.isRequired,
|
||||
start: PropTypes.number.isRequired,
|
||||
shift: PropTypes.number.isRequired,
|
||||
maxHeight: PropTypes.number.isRequired,
|
||||
lastElement: PropTypes.bool,
|
||||
columnRenderer: PropTypes.func
|
||||
};
|
||||
|
||||
//Заголовок циклограммы
|
||||
const P8PCyclogramHeader = ({ columns, shift, maxWidth, maxHeight, columnRenderer, headerBlock }) => {
|
||||
//Инициализируем старт текущей колонки
|
||||
let prevColumnEnd = 0;
|
||||
return (
|
||||
<g className="header" ref={headerBlock}>
|
||||
<rect x="0" y="0" width={maxWidth} height={NDEFAULT_HEADER_HEIGHT} fill="#ffffff" stroke="#e0e0e0" strokeWidth="1.4"></rect>
|
||||
{columns.map((column, index) => {
|
||||
//Аккумулируем окончание последней колонки с учетом сдвига
|
||||
prevColumnEnd = index !== 0 ? prevColumnEnd + (columns[index - 1].end - columns[index - 1].start) * shift : 0;
|
||||
return (
|
||||
<P8PCyclogramHeaderColumn
|
||||
column={column}
|
||||
shift={shift}
|
||||
start={prevColumnEnd}
|
||||
maxHeight={maxHeight}
|
||||
lastElement={columns.length - 1 === index}
|
||||
columnRenderer={columnRenderer}
|
||||
key={index}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
<g className="columnsDividers">
|
||||
<P8PCyclogramColumnsLines columns={columns} shift={shift} y1={0} y2={NDEFAULT_HEADER_HEIGHT} />
|
||||
</g>
|
||||
</g>
|
||||
);
|
||||
};
|
||||
|
||||
//Контроль свойств - Заголовок циклограммы
|
||||
P8PCyclogramHeader.propTypes = {
|
||||
columns: PropTypes.array.isRequired,
|
||||
shift: PropTypes.number.isRequired,
|
||||
maxWidth: PropTypes.number.isRequired,
|
||||
maxHeight: PropTypes.number.isRequired,
|
||||
columnRenderer: PropTypes.func,
|
||||
headerBlock: PropTypes.object
|
||||
};
|
||||
|
||||
//Задача циклограммы
|
||||
const P8PCyclogramTask = ({ task, indexGrp, shift, lineHeight, openTaskEditor, taskRenderer }) => {
|
||||
//Рассчитываем ширину задачи
|
||||
const width = task.end !== 0 ? (task.end - task.start) * shift : 0;
|
||||
//Формируем собственное отображение, если требуется
|
||||
const customView = taskRenderer ? taskRenderer({ task, taskHeight: lineHeight, taskWidth: width }) || {} : {};
|
||||
return (
|
||||
<foreignObject
|
||||
x={task.start !== 0 ? task.start * shift : 0}
|
||||
y={NDEFAULT_HEADER_HEIGHT + task.lineNumb * lineHeight}
|
||||
width={width}
|
||||
height={lineHeight}
|
||||
>
|
||||
<Box
|
||||
className={hasValue(indexGrp) ? `TaskGrp${indexGrp}` : null}
|
||||
sx={{ ...STYLES.TASK_BOX(lineHeight, task.bgColor, task.textColor, task.highlightColor), ...customView.taskStyle }}
|
||||
{...customView.taskProps}
|
||||
onClick={() => openTaskEditor(task)}
|
||||
>
|
||||
{customView.data ? (
|
||||
customView.data
|
||||
) : (
|
||||
<Typography sx={STYLES.TASK(lineHeight)} title={task.name}>
|
||||
{task.name}
|
||||
</Typography>
|
||||
)}
|
||||
</Box>
|
||||
</foreignObject>
|
||||
);
|
||||
};
|
||||
|
||||
//Контроль свойств - Группы циклограммы
|
||||
P8PCyclogramTask.propTypes = {
|
||||
task: PropTypes.object.isRequired,
|
||||
indexGrp: PropTypes.number,
|
||||
shift: PropTypes.number.isRequired,
|
||||
lineHeight: PropTypes.number.isRequired,
|
||||
openTaskEditor: PropTypes.func.isRequired,
|
||||
taskRenderer: PropTypes.func
|
||||
};
|
||||
|
||||
//Основная информация циклограммы
|
||||
const P8PCyclogramMain = ({
|
||||
columns,
|
||||
groups,
|
||||
tasks,
|
||||
shift,
|
||||
lineHeight,
|
||||
maxWidth,
|
||||
maxHeight,
|
||||
openTaskEditor,
|
||||
groupHeaderRenderer,
|
||||
taskRenderer,
|
||||
columnRenderer,
|
||||
headerBlock
|
||||
}) => {
|
||||
//Инициализируем коллекцию тасков с группами
|
||||
const tasksWithGroup = tasks.filter(task => hasValue(task.groupName));
|
||||
//Инициализируем коллекцию тасков без групп
|
||||
const tasksWithoutGroup = tasks.filter(task => !hasValue(task.groupName));
|
||||
//Инициализируем коллекцию отображаемых групп
|
||||
const visibleGroups = groups ? groups.filter(group => group.visible) : [];
|
||||
return (
|
||||
<g className="main">
|
||||
<g className="tasks">
|
||||
{visibleGroups.length !== 0
|
||||
? visibleGroups.map((grp, indexGrp) => {
|
||||
//Считываем задачи группы
|
||||
let groupTasks = tasksWithGroup.filter(task => task.groupName === grp.name);
|
||||
//Если по данной группе нет тасков - ничего не выводим
|
||||
if (groupTasks.length === 0) {
|
||||
return null;
|
||||
}
|
||||
return (
|
||||
<g className={`TaskGrp${indexGrp}`} key={indexGrp}>
|
||||
{groupTasks.map((task, index) => (
|
||||
<P8PCyclogramTask
|
||||
task={task}
|
||||
indexGrp={indexGrp}
|
||||
shift={shift}
|
||||
lineHeight={lineHeight}
|
||||
openTaskEditor={openTaskEditor}
|
||||
taskRenderer={taskRenderer}
|
||||
key={index}
|
||||
/>
|
||||
))}
|
||||
<style>{getGroupStyles(indexGrp, grp.highlightColor)}</style>
|
||||
</g>
|
||||
);
|
||||
})
|
||||
: null}
|
||||
<g className={`TasksWithoutGroups`}>
|
||||
{tasksWithoutGroup.map((task, index) => {
|
||||
return (
|
||||
<P8PCyclogramTask
|
||||
task={task}
|
||||
shift={shift}
|
||||
lineHeight={lineHeight}
|
||||
openTaskEditor={openTaskEditor}
|
||||
taskRenderer={taskRenderer}
|
||||
key={index}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</g>
|
||||
</g>
|
||||
<P8PCyclogramHeader
|
||||
columns={columns}
|
||||
shift={shift}
|
||||
maxWidth={maxWidth}
|
||||
maxHeight={maxHeight}
|
||||
columnRenderer={columnRenderer}
|
||||
headerBlock={headerBlock}
|
||||
/>
|
||||
{visibleGroups.length !== 0 ? (
|
||||
<g className="groups">
|
||||
{visibleGroups.map((grp, indexGrp) => {
|
||||
//Инициализируем параметры группы
|
||||
let defaultView = null;
|
||||
let customView = null;
|
||||
let groupHeaderX = 0;
|
||||
let groupHeaderY = 0;
|
||||
let groupTasks = tasksWithGroup.filter(task => task.groupName === grp.name);
|
||||
//Если по данной группе нет тасков - ничего не выводим
|
||||
if (groupTasks.length === 0) {
|
||||
return null;
|
||||
}
|
||||
//Если требуется отображать заголовок группы
|
||||
if (grp.visible) {
|
||||
//Формируем отображение по умолчанию
|
||||
defaultView = (
|
||||
<Box sx={{ ...STYLES.GROUP_HEADER_BOX, height: grp.height }}>
|
||||
<Typography sx={{ ...STYLES.GROUP_HEADER, maxWidth: grp.width, maxHeight: grp.height }}>{grp.name}</Typography>
|
||||
</Box>
|
||||
);
|
||||
//Формируем собственное отображение, если требуется
|
||||
customView = groupHeaderRenderer ? groupHeaderRenderer({ group: grp }) : null;
|
||||
//Рассчитываем координаты заголовка группы
|
||||
groupHeaderX = Math.min(...groupTasks.map(o => o.start)) * shift;
|
||||
groupHeaderY = NDEFAULT_HEADER_HEIGHT + Math.min(...groupTasks.map(o => o.lineNumb)) * lineHeight - grp.height - 5;
|
||||
}
|
||||
return (
|
||||
<foreignObject
|
||||
x={groupHeaderX}
|
||||
y={groupHeaderY}
|
||||
width={grp.width}
|
||||
height={grp.height}
|
||||
className={`TaskGrpHeader${indexGrp}`}
|
||||
display="none"
|
||||
key={indexGrp}
|
||||
>
|
||||
{customView ? customView : defaultView}
|
||||
</foreignObject>
|
||||
);
|
||||
})}
|
||||
</g>
|
||||
) : null}
|
||||
</g>
|
||||
);
|
||||
};
|
||||
|
||||
//Контроль свойств - Основная информация циклограммы
|
||||
P8PCyclogramMain.propTypes = {
|
||||
columns: PropTypes.array.isRequired,
|
||||
groups: PropTypes.array,
|
||||
tasks: PropTypes.array.isRequired,
|
||||
shift: PropTypes.number.isRequired,
|
||||
lineHeight: PropTypes.number.isRequired,
|
||||
maxWidth: PropTypes.number.isRequired,
|
||||
maxHeight: PropTypes.number.isRequired,
|
||||
openTaskEditor: PropTypes.func.isRequired,
|
||||
groupHeaderRenderer: PropTypes.func,
|
||||
taskRenderer: PropTypes.func,
|
||||
columnRenderer: PropTypes.func,
|
||||
headerBlock: PropTypes.object
|
||||
};
|
||||
|
||||
//Редактор задачи
|
||||
const P8PCyclogramTaskEditor = ({
|
||||
task,
|
||||
taskAttributes,
|
||||
onOk,
|
||||
onCancel,
|
||||
taskAttributeRenderer,
|
||||
taskDialogRenderer,
|
||||
nameCaption,
|
||||
okBtnCaption,
|
||||
cancelBtnCaption
|
||||
}) => {
|
||||
//Собственное состояние
|
||||
const [state] = useState({
|
||||
start: task.start,
|
||||
end: task.end
|
||||
});
|
||||
|
||||
//Отображаемые атрибуты
|
||||
const dispTaskAttributes =
|
||||
Array.isArray(taskAttributes) && taskAttributes.length > 0 ? taskAttributes.filter(attr => attr.visible && hasValue(task[attr.name])) : [];
|
||||
|
||||
//При сохранении
|
||||
const handleOk = () => (onOk && state.start && state.end ? onOk() : null);
|
||||
|
||||
//При отмене
|
||||
const handleCancel = () => (onCancel ? onCancel() : null);
|
||||
|
||||
//Генерация содержимого
|
||||
return (
|
||||
<Dialog open onClose={handleCancel}>
|
||||
{taskDialogRenderer ? (
|
||||
taskDialogRenderer({ task, taskAttributes, close: handleCancel })
|
||||
) : (
|
||||
<>
|
||||
<DialogContent sx={STYLES.TASK_EDITOR_CONTENT}>
|
||||
<List sx={STYLES.TASK_EDITOR_LIST}>
|
||||
<ListItem alignItems="flex-start">
|
||||
<ListItemText primary={nameCaption} secondary={task.fullName} />
|
||||
</ListItem>
|
||||
{dispTaskAttributes.length > 0 ? <Divider component="li" /> : null}
|
||||
{dispTaskAttributes.length > 0
|
||||
? dispTaskAttributes.map((attr, i) => {
|
||||
const defaultView = task[attr.name];
|
||||
const customView = taskAttributeRenderer ? taskAttributeRenderer({ task, attribute: attr }) : null;
|
||||
return (
|
||||
<React.Fragment key={i}>
|
||||
<ListItem alignItems="flex-start">
|
||||
<ListItemText
|
||||
primary={attr.caption}
|
||||
secondaryTypographyProps={{ component: "span" }}
|
||||
secondary={customView ? customView : defaultView}
|
||||
/>
|
||||
</ListItem>
|
||||
{i < dispTaskAttributes.length - 1 ? <Divider component="li" /> : null}
|
||||
</React.Fragment>
|
||||
);
|
||||
})
|
||||
: null}
|
||||
</List>
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
<Button onClick={handleOk}>{okBtnCaption}</Button>
|
||||
<Button onClick={handleCancel}>{cancelBtnCaption}</Button>
|
||||
</DialogActions>
|
||||
</>
|
||||
)}
|
||||
</Dialog>
|
||||
);
|
||||
};
|
||||
|
||||
//Контроль свойств - Редактор задачи
|
||||
P8PCyclogramTaskEditor.propTypes = {
|
||||
task: P8P_CYCLOGRAM_TASK_SHAPE,
|
||||
taskAttributes: PropTypes.arrayOf(P8P_CYCLOGRAM_TASK_ATTRIBUTE_SHAPE),
|
||||
onOk: PropTypes.func,
|
||||
onCancel: PropTypes.func,
|
||||
taskAttributeRenderer: PropTypes.func,
|
||||
taskDialogRenderer: PropTypes.func,
|
||||
nameCaption: PropTypes.string.isRequired,
|
||||
okBtnCaption: PropTypes.string.isRequired,
|
||||
cancelBtnCaption: PropTypes.string.isRequired
|
||||
};
|
||||
|
||||
//Циклограмма
|
||||
const P8PCyclogram = ({
|
||||
containerStyle,
|
||||
lineHeight,
|
||||
title,
|
||||
titleStyle,
|
||||
onTitleClick,
|
||||
zoomBar,
|
||||
zoom,
|
||||
columns,
|
||||
columnRenderer,
|
||||
groups,
|
||||
groupHeaderRenderer,
|
||||
tasks,
|
||||
taskRenderer,
|
||||
taskAttributes,
|
||||
taskAttributeRenderer,
|
||||
taskDialogRenderer,
|
||||
noDataFoundText,
|
||||
nameTaskEditorCaption,
|
||||
okTaskEditorBtnCaption,
|
||||
cancelTaskEditorBtnCaption
|
||||
}) => {
|
||||
//Хук основного блока (для последующего определения доступной ширины)
|
||||
const mainBlock = useRef(null);
|
||||
//Хук для заголовка таблицы
|
||||
const headerBlock = useRef(null);
|
||||
//Собственное состояние
|
||||
const [state, setState] = useState({
|
||||
noData: true,
|
||||
loaded: false,
|
||||
lineHeight: NDEFAULT_LINE_HEIGHT,
|
||||
maxWidth: 0,
|
||||
maxHeight: 0,
|
||||
shift: 0,
|
||||
zoom: P8P_CYCLOGRAM_ZOOM.includes(zoom) ? zoom : 1,
|
||||
tasks: [],
|
||||
editTask: null
|
||||
});
|
||||
|
||||
//Обновление масштаба циклограммы
|
||||
const handleZoomChange = direction => {
|
||||
//Считываем текущий индекс
|
||||
const currentIndex = P8P_CYCLOGRAM_ZOOM.indexOf(state.zoom);
|
||||
setState(pv => ({
|
||||
...pv,
|
||||
zoom:
|
||||
currentIndex + direction !== P8P_CYCLOGRAM_ZOOM.length && currentIndex + direction !== -1
|
||||
? P8P_CYCLOGRAM_ZOOM[currentIndex + direction]
|
||||
: pv.zoom
|
||||
}));
|
||||
};
|
||||
|
||||
//Открытие редактора задачи
|
||||
const openTaskEditor = task => setState(pv => ({ ...pv, editTask: { ...task } }));
|
||||
|
||||
//При сохранении задачи в редакторе
|
||||
const handleTaskEditorSave = () => {
|
||||
setState(pv => ({ ...pv, editTask: null }));
|
||||
};
|
||||
|
||||
//При закрытии редактора задачи без сохранения
|
||||
const handleTaskEditorCancel = () => setState(pv => ({ ...pv, editTask: null }));
|
||||
|
||||
//При скролле блока
|
||||
const handleScroll = e => {
|
||||
//Изменяем позицию заголовка таблицы относительно скролла
|
||||
headerBlock.current.setAttribute("transform", "translate(0," + e.currentTarget.scrollTop + ")");
|
||||
};
|
||||
|
||||
//При изменении данных
|
||||
useEffect(() => {
|
||||
//Если есть колонки и задачи
|
||||
if (Array.isArray(columns) && columns.length > 0 && Array.isArray(tasks) && tasks.length > 0) {
|
||||
//Определяем текущую максимальную ширину колонок
|
||||
let currentColumnsMaxWidth = Math.max(...columns.map(o => o.end));
|
||||
//Определяем доступный сдвиг для ширины колонок (16 - паддинг по бокам)
|
||||
let columnShift = getShift(columns, currentColumnsMaxWidth, mainBlock.current.offsetWidth - 16) * state.zoom;
|
||||
//Устанавливаем значения исходя из колонок/задач
|
||||
setState(pv => ({
|
||||
...pv,
|
||||
loaded: true,
|
||||
lineHeight: lineHeight ? lineHeight : NDEFAULT_LINE_HEIGHT,
|
||||
maxWidth: columnShift !== 0 ? currentColumnsMaxWidth * columnShift : currentColumnsMaxWidth,
|
||||
maxHeight: NDEFAULT_HEADER_HEIGHT + (Math.max(...tasks.map(o => o.lineNumb)) + 1) * (lineHeight ? lineHeight : NDEFAULT_LINE_HEIGHT),
|
||||
shift: columnShift,
|
||||
tasks: tasks,
|
||||
noData: false
|
||||
}));
|
||||
} else {
|
||||
//Устанавливаем значения исходя из колонок/задач
|
||||
setState(pv => ({
|
||||
...pv,
|
||||
noData: true
|
||||
}));
|
||||
}
|
||||
}, [columns, lineHeight, state.zoom, tasks]);
|
||||
|
||||
//Генерация содержимого
|
||||
return (
|
||||
<>
|
||||
<div ref={mainBlock} style={{ ...(containerStyle ? containerStyle : {}) }}>
|
||||
{state.noData ? <P8PAppInlineError text={noDataFoundText} /> : null}
|
||||
{state.loaded ? (
|
||||
<>
|
||||
{title ? (
|
||||
<Typography
|
||||
p={1}
|
||||
sx={{ ...STYLES.CYCLOGRAM_TITLE, ...(titleStyle ? titleStyle : {}) }}
|
||||
align="center"
|
||||
color="textSecondary"
|
||||
variant="subtitle1"
|
||||
>
|
||||
{onTitleClick ? (
|
||||
<Link component="button" variant="body2" underline="hover" onClick={() => onTitleClick()}>
|
||||
{title}
|
||||
</Link>
|
||||
) : (
|
||||
title
|
||||
)}
|
||||
</Typography>
|
||||
) : null}
|
||||
{zoomBar ? (
|
||||
<Box p={1} sx={STYLES.CYCLOGRAM_ZOOM}>
|
||||
<IconButton
|
||||
onClick={() => handleZoomChange(1)}
|
||||
disabled={state.zoom == P8P_CYCLOGRAM_ZOOM[P8P_CYCLOGRAM_ZOOM.length - 1]}
|
||||
>
|
||||
<Icon>zoom_in</Icon>
|
||||
</IconButton>
|
||||
<IconButton onClick={() => handleZoomChange(-1)} disabled={state.zoom == P8P_CYCLOGRAM_ZOOM[0]}>
|
||||
<Icon>zoom_out</Icon>
|
||||
</IconButton>
|
||||
</Box>
|
||||
) : null}
|
||||
<Box className="scroll" sx={STYLES.CYCLOGRAM_BOX(state.noData, title, zoomBar)} onScroll={handleScroll}>
|
||||
<svg id="cyclogram" width={state.maxWidth} height={state.maxHeight}>
|
||||
<P8PCyclogramGrid
|
||||
tasks={state.tasks}
|
||||
columns={columns}
|
||||
shift={state.shift}
|
||||
maxWidth={state.maxWidth}
|
||||
maxHeight={state.maxHeight}
|
||||
lineHeight={state.lineHeight}
|
||||
/>
|
||||
<P8PCyclogramMain
|
||||
columns={columns}
|
||||
groups={groups}
|
||||
tasks={state.tasks}
|
||||
shift={state.shift}
|
||||
lineHeight={state.lineHeight}
|
||||
maxWidth={state.maxWidth}
|
||||
maxHeight={state.maxHeight}
|
||||
groupHeaderRenderer={groupHeaderRenderer}
|
||||
openTaskEditor={openTaskEditor}
|
||||
taskRenderer={taskRenderer}
|
||||
columnRenderer={columnRenderer}
|
||||
headerBlock={headerBlock}
|
||||
/>
|
||||
</svg>
|
||||
</Box>
|
||||
</>
|
||||
) : null}
|
||||
{state.editTask ? (
|
||||
<P8PCyclogramTaskEditor
|
||||
task={state.editTask}
|
||||
taskAttributes={taskAttributes}
|
||||
onOk={handleTaskEditorSave}
|
||||
onCancel={handleTaskEditorCancel}
|
||||
taskAttributeRenderer={taskAttributeRenderer}
|
||||
taskDialogRenderer={taskDialogRenderer}
|
||||
nameCaption={nameTaskEditorCaption}
|
||||
okBtnCaption={okTaskEditorBtnCaption}
|
||||
cancelBtnCaption={cancelTaskEditorBtnCaption}
|
||||
/>
|
||||
) : null}
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
//Контроль свойств - Циклограмма
|
||||
P8PCyclogram.propTypes = {
|
||||
containerStyle: PropTypes.object,
|
||||
lineHeight: PropTypes.number,
|
||||
title: PropTypes.string,
|
||||
titleStyle: PropTypes.object,
|
||||
onTitleClick: PropTypes.func,
|
||||
zoomBar: PropTypes.bool,
|
||||
zoom: PropTypes.number,
|
||||
columns: PropTypes.arrayOf(P8P_CYCLOGRAM_COLUMN_SHAPE).isRequired,
|
||||
columnRenderer: PropTypes.func,
|
||||
groups: PropTypes.arrayOf(P8P_CYCLOGRAM_GROUP_SHAPE),
|
||||
groupHeaderRenderer: PropTypes.func,
|
||||
tasks: PropTypes.arrayOf(P8P_CYCLOGRAM_TASK_SHAPE).isRequired,
|
||||
taskRenderer: PropTypes.func,
|
||||
taskAttributes: PropTypes.arrayOf(P8P_CYCLOGRAM_TASK_ATTRIBUTE_SHAPE),
|
||||
taskAttributeRenderer: PropTypes.func,
|
||||
taskDialogRenderer: PropTypes.func,
|
||||
noDataFoundText: PropTypes.string.isRequired,
|
||||
nameTaskEditorCaption: PropTypes.string.isRequired,
|
||||
okTaskEditorBtnCaption: PropTypes.string.isRequired,
|
||||
cancelTaskEditorBtnCaption: PropTypes.string.isRequired
|
||||
};
|
||||
|
||||
//----------------
|
||||
//Интерфейс модуля
|
||||
//----------------
|
||||
|
||||
export { P8PCyclogram };
|
@ -36,15 +36,15 @@ const P8P_DATA_GRID_FILTERS_HEIGHT = P8P_TABLE_FILTERS_HEIGHT;
|
||||
|
||||
//Таблица данных
|
||||
const P8PDataGrid = ({
|
||||
columnsDef,
|
||||
columnsDef = [],
|
||||
filtersInitial,
|
||||
groups,
|
||||
rows,
|
||||
groups = [],
|
||||
rows = [],
|
||||
size,
|
||||
fixedHeader = false,
|
||||
fixedColumns = 0,
|
||||
morePages = false,
|
||||
reloading,
|
||||
reloading = false,
|
||||
expandable,
|
||||
orderAscMenuItemCaption,
|
||||
orderDescMenuItemCaption,
|
||||
@ -154,15 +154,15 @@ const P8PDataGrid = ({
|
||||
|
||||
//Контроль свойств - Таблица данных
|
||||
P8PDataGrid.propTypes = {
|
||||
columnsDef: PropTypes.array.isRequired,
|
||||
columnsDef: PropTypes.array,
|
||||
filtersInitial: PropTypes.arrayOf(P8P_DATA_GRID_FILTER_SHAPE),
|
||||
groups: PropTypes.array,
|
||||
rows: PropTypes.array.isRequired,
|
||||
rows: PropTypes.array,
|
||||
size: PropTypes.string,
|
||||
fixedHeader: PropTypes.bool,
|
||||
fixedColumns: PropTypes.number,
|
||||
morePages: PropTypes.bool,
|
||||
reloading: PropTypes.bool.isRequired,
|
||||
reloading: PropTypes.bool,
|
||||
expandable: PropTypes.bool,
|
||||
orderAscMenuItemCaption: PropTypes.string.isRequired,
|
||||
orderDescMenuItemCaption: PropTypes.string.isRequired,
|
||||
|
@ -27,7 +27,7 @@ const STYLES = {
|
||||
//-----------
|
||||
|
||||
//Полноэкранный диалог
|
||||
const P8PFullScreenDialog = ({ title, onClose, children }) => {
|
||||
const P8PFullScreenDialog = ({ title, onClose, contentProps, children }) => {
|
||||
const handleClose = () => {
|
||||
onClose ? onClose() : null;
|
||||
};
|
||||
@ -46,7 +46,7 @@ const P8PFullScreenDialog = ({ title, onClose, children }) => {
|
||||
</Toolbar>
|
||||
</AppBar>
|
||||
</DialogTitle>
|
||||
<DialogContent>{children}</DialogContent>
|
||||
<DialogContent {...(contentProps ? contentProps : {})}>{children}</DialogContent>
|
||||
</Dialog>
|
||||
);
|
||||
};
|
||||
@ -55,7 +55,8 @@ const P8PFullScreenDialog = ({ title, onClose, children }) => {
|
||||
P8PFullScreenDialog.propTypes = {
|
||||
title: PropTypes.string.isRequired,
|
||||
onClose: PropTypes.func,
|
||||
children: PropTypes.element
|
||||
children: PropTypes.element,
|
||||
contentProps: PropTypes.object
|
||||
};
|
||||
|
||||
//----------------
|
||||
|
@ -33,7 +33,7 @@ import { P8PAppInlineError } from "./p8p_app_message"; //Встраиваемо
|
||||
//---------
|
||||
|
||||
//Уровни масштаба
|
||||
const P8P_GANTT_ZOOM = [0, 1, 2, 3, 4];
|
||||
const P8P_GANTT_ZOOM = [0, 1, 2, 3, 4, 5];
|
||||
|
||||
//Уровни масштаба (строковые наименования в терминах библиотеки)
|
||||
const P8P_GANTT_ZOOM_VIEW_MODES = {
|
||||
@ -41,7 +41,8 @@ const P8P_GANTT_ZOOM_VIEW_MODES = {
|
||||
1: "Half Day",
|
||||
2: "Day",
|
||||
3: "Week",
|
||||
4: "Month"
|
||||
4: "Month",
|
||||
5: "Year"
|
||||
};
|
||||
|
||||
//Структура задачи
|
||||
|
@ -62,8 +62,15 @@ const STYLES = {
|
||||
GRID_PANEL_CARD_CONTENT_TITLE_ICON: { paddingTop: "4px" },
|
||||
GRID_PANEL_CARD_ACTIONS: { marginTop: "auto", display: "flex", justifyContent: "flex-end", alignItems: "flex-start" },
|
||||
DESKTOP_GROUP_HEADER: { fontWeight: "bold", fontFamily: "tahoma, arial, verdana, sans-serif!important", fontSize: "13px!important" },
|
||||
DESKTOP_ITEM_BUTTON: { fontSize: "12px", textTransform: "none", "&:hover": { backgroundColor: "#c3e1ff" }, maxWidth: "150px" },
|
||||
DESKTOP_ITEM_STACK: { justifyContent: "center", alignItems: "center", fontSize: "12px" },
|
||||
DESKTOP_ITEM_BUTTON: {
|
||||
fontSize: "12px",
|
||||
textTransform: "none",
|
||||
"&:hover": { backgroundColor: "#c3e1ff" },
|
||||
width: "150px",
|
||||
height: "90px",
|
||||
flexDirection: "column",
|
||||
justifyContent: "flex-start"
|
||||
},
|
||||
DESKTOP_ITEM_ICON: { width: "48px", height: "48px", fontSize: "48px" },
|
||||
DESKTOP_ITEM_CATION: {
|
||||
display: "-webkit-box",
|
||||
@ -128,7 +135,14 @@ const getPanelsLinks = ({ variant, panels, selectedPanel, group, defaultGroupTyt
|
||||
<Card sx={STYLES.GRID_PANEL_CARD}>
|
||||
{panel.preview ? (
|
||||
<CardMedia component="img" alt={panel.name} image={panel.preview} sx={STYLES.GRID_PANEL_CARD_MEDIA} />
|
||||
) : null}
|
||||
) : (
|
||||
<CardMedia
|
||||
component="img"
|
||||
alt={panel.name}
|
||||
image={"./img/default_preview.png"}
|
||||
sx={STYLES.GRID_PANEL_CARD_MEDIA}
|
||||
/>
|
||||
)}
|
||||
<CardContent>
|
||||
<Stack gap={1} direction="row" sx={STYLES.GRID_PANEL_CARD_CONTENT_TITLE}>
|
||||
{panel.icon ? <Icon sx={STYLES.GRID_PANEL_CARD_CONTENT_TITLE_ICON}>{panel.icon}</Icon> : null}
|
||||
@ -165,12 +179,10 @@ const getPanelsLinks = ({ variant, panels, selectedPanel, group, defaultGroupTyt
|
||||
sx={STYLES.DESKTOP_ITEM_BUTTON}
|
||||
title={panel.caption}
|
||||
>
|
||||
<Stack sx={STYLES.DESKTOP_ITEM_STACK}>
|
||||
<Icon sx={STYLES.DESKTOP_ITEM_ICON}>{panel.icon}</Icon>
|
||||
<Typography sx={STYLES.DESKTOP_ITEM_CATION} variant="body1">
|
||||
{panel.caption}
|
||||
</Typography>
|
||||
</Stack>
|
||||
<Icon sx={STYLES.DESKTOP_ITEM_ICON}>{panel.icon}</Icon>
|
||||
<Typography sx={STYLES.DESKTOP_ITEM_CATION} variant="body1">
|
||||
{panel.caption}
|
||||
</Typography>
|
||||
</Button>
|
||||
)
|
||||
);
|
||||
@ -230,7 +242,12 @@ const P8PPanelsMenuDesktop = ({ group, onItemNavigate, panels = [], defaultGroup
|
||||
const panelsLinks = getPanelsLinks({ variant: P8P_PANELS_MENU_VARIANT.DESKTOP, panels, group, defaultGroupTytle, onItemNavigate });
|
||||
|
||||
//Генерация содержимого
|
||||
return <Box p={2}>{panelsLinks}</Box>;
|
||||
return (
|
||||
<Box p={2}>
|
||||
{panelsLinks[0]}
|
||||
<Stack direction="row">{panelsLinks.map((l, i) => (i > 0 ? l : null))}</Stack>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
//Контроль свойств - Меню панелей - рабочий стол
|
||||
|
@ -118,7 +118,9 @@ const STYLES = {
|
||||
},
|
||||
TABLE_CELL_EXPAND_CONTAINER: {
|
||||
paddingBottom: 0,
|
||||
paddingTop: 0
|
||||
paddingTop: 0,
|
||||
paddingLeft: 0,
|
||||
paddingRight: 0
|
||||
},
|
||||
TABLE_CELL_GROUP_HEADER: {
|
||||
backgroundColor: "lightgray"
|
||||
@ -486,16 +488,16 @@ P8PTableFiltersChips.propTypes = {
|
||||
|
||||
//Таблица
|
||||
const P8PTable = ({
|
||||
columnsDef,
|
||||
groups,
|
||||
rows,
|
||||
columnsDef = [],
|
||||
groups = [],
|
||||
rows = [],
|
||||
orders,
|
||||
filters,
|
||||
size,
|
||||
fixedHeader = false,
|
||||
fixedColumns = 0,
|
||||
morePages = false,
|
||||
reloading,
|
||||
reloading = false,
|
||||
expandable,
|
||||
orderAscMenuItemCaption,
|
||||
orderDescMenuItemCaption,
|
||||
@ -531,7 +533,9 @@ const P8PTable = ({
|
||||
const [expanded, setExpanded] = useState({});
|
||||
|
||||
//Собственное состояния - развёрнутые группы
|
||||
const [expandedGroups, setExpandedGroups] = useState({});
|
||||
const [expandedGroups, setExpandedGroups] = useState(
|
||||
Array.isArray(groups) && groups.length > 0 ? Object.assign({}, ...groups.map(g => ({ [g.name]: g.expanded }))) : {}
|
||||
);
|
||||
|
||||
//Собственное состояние - колонка с отображаемой подсказкой
|
||||
const [displayHintColumn, setDisplayHintColumn] = useState(null);
|
||||
@ -931,7 +935,7 @@ P8PTable.propTypes = {
|
||||
fixedHeader: PropTypes.bool,
|
||||
fixedColumns: PropTypes.number,
|
||||
morePages: PropTypes.bool,
|
||||
reloading: PropTypes.bool.isRequired,
|
||||
reloading: PropTypes.bool,
|
||||
expandable: PropTypes.bool,
|
||||
orderAscMenuItemCaption: PropTypes.string.isRequired,
|
||||
orderDescMenuItemCaption: PropTypes.string.isRequired,
|
||||
|
@ -15,6 +15,7 @@ import { P8PAppWorkspace } from "./components/p8p_app_workspace"; //Рабоче
|
||||
import { P8PTable, P8P_TABLE_DATA_TYPE, P8P_TABLE_SIZE, P8P_TABLE_FILTER_SHAPE } from "./components/p8p_table"; //Таблица данных
|
||||
import { P8PDataGrid, P8P_DATA_GRID_DATA_TYPE, P8P_DATA_GRID_SIZE, P8P_DATA_GRID_FILTER_SHAPE } from "./components/p8p_data_grid"; //Таблица данных
|
||||
import { P8PGantt, P8P_GANTT_TASK_SHAPE, P8P_GANTT_TASK_ATTRIBUTE_SHAPE, P8P_GANTT_TASK_COLOR_SHAPE } from "./components/p8p_gantt"; //Диаграмма Ганта
|
||||
import { P8PCyclogram } from "./components/p8p_cyclogram"; //Циклограмма
|
||||
|
||||
//---------
|
||||
//Константы
|
||||
@ -76,6 +77,14 @@ const P8P_GANTT_CONFIG_PROPS = {
|
||||
cancelTaskEditorBtnCaption: BUTTONS.CANCEL
|
||||
};
|
||||
|
||||
//Конфигурируемые свойства "Циклограммы" (P8PCyclogram)
|
||||
const P8P_CYCLOGRAM_CONFIG_PROPS = {
|
||||
noDataFoundText: TEXTS.NO_DATA_FOUND,
|
||||
nameTaskEditorCaption: CAPTIONS.NAME,
|
||||
okTaskEditorBtnCaption: BUTTONS.OK,
|
||||
cancelTaskEditorBtnCaption: BUTTONS.CANCEL
|
||||
};
|
||||
|
||||
//-----------------------
|
||||
//Вспомогательные функции
|
||||
//-----------------------
|
||||
@ -90,6 +99,7 @@ const addConfigChildProps = children =>
|
||||
if (child.type.name === "P8PTable") configProps = P8P_TABLE_CONFIG_PROPS;
|
||||
if (child.type.name === "P8PDataGrid") configProps = P8P_DATA_GRID_CONFIG_PROPS;
|
||||
if (child.type.name === "P8PGantt") configProps = P8P_GANTT_CONFIG_PROPS;
|
||||
if (child.type.name === "P8PCyclogram") configProps = P8P_CYCLOGRAM_CONFIG_PROPS;
|
||||
return React.createElement(child.type, { ...configProps, ...restProps }, addConfigChildProps(children));
|
||||
});
|
||||
|
||||
@ -112,6 +122,9 @@ const P8PDataGridConfigWrapped = (props = {}) => <P8PDataGrid {...P8P_DATA_GRID_
|
||||
//Обёртка для компонента "Диаграмма Ганта" (P8PGantt)
|
||||
const P8PGanttConfigWrapped = (props = {}) => <P8PGantt {...P8P_GANTT_CONFIG_PROPS} {...props} />;
|
||||
|
||||
//Обёртка для компонента "Циклограмма" (P8PCyclogram)
|
||||
const P8PCyclogramConfigWrapped = (props = {}) => <P8PCyclogram {...P8P_GANTT_CONFIG_PROPS} {...props} />;
|
||||
|
||||
//Универсальный элемент-обёртка в параметры конфигурации
|
||||
const ConfigWrapper = ({ children }) => addConfigChildProps(children);
|
||||
|
||||
@ -132,6 +145,7 @@ export {
|
||||
P8P_DATA_GRID_SIZE,
|
||||
P8P_DATA_GRID_FILTER_SHAPE,
|
||||
P8P_GANTT_CONFIG_PROPS,
|
||||
P8P_CYCLOGRAM_CONFIG_PROPS,
|
||||
P8P_GANTT_TASK_SHAPE,
|
||||
P8P_GANTT_TASK_ATTRIBUTE_SHAPE,
|
||||
P8P_GANTT_TASK_COLOR_SHAPE,
|
||||
@ -140,5 +154,6 @@ export {
|
||||
P8PTableConfigWrapped,
|
||||
P8PDataGridConfigWrapped,
|
||||
P8PGanttConfigWrapped,
|
||||
P8PCyclogramConfigWrapped,
|
||||
ConfigWrapper
|
||||
};
|
||||
|
@ -22,7 +22,8 @@ const P8O_API = window.top?.parus?.clientApi;
|
||||
|
||||
//Структура объекта с описанием ошибок
|
||||
const APPLICATION_CONTEXT_ERRORS_SHAPE = PropTypes.shape({
|
||||
P8O_API_UNAVAILABLE: PropTypes.string.isRequired
|
||||
P8O_API_UNAVAILABLE: PropTypes.string.isRequired,
|
||||
P8O_API_UNSUPPORTED: PropTypes.string.isRequired
|
||||
});
|
||||
|
||||
//----------------
|
||||
@ -72,21 +73,38 @@ export const ApplicationContext = ({ errors, displaySizeGetter, guidGenerator, c
|
||||
|
||||
//Отображение раздела "ПАРУС 8 Онлайн"
|
||||
const pOnlineShowUnit = useCallback(
|
||||
({ unitCode, showMethod = "main", inputParameters }) => {
|
||||
if (P8O_API) P8O_API.fn.openDocumentModal({ unitcode: unitCode, method: showMethod, inputParameters });
|
||||
({ unitCode, showMethod = "main", inputParameters, modal = true }) => {
|
||||
if (P8O_API)
|
||||
modal
|
||||
? P8O_API.fn.openDocumentModal({ unitcode: unitCode, method: showMethod, inputParameters })
|
||||
: P8O_API.fn.openDocument
|
||||
? P8O_API.fn.openDocument({ unitcode: unitCode, method: showMethod, inputParameters })
|
||||
: showMsgErr(errors.P8O_API_UNSUPPORTED);
|
||||
else showMsgErr(errors.P8O_API_UNAVAILABLE);
|
||||
},
|
||||
[showMsgErr, errors.P8O_API_UNAVAILABLE]
|
||||
[showMsgErr, errors.P8O_API_UNAVAILABLE, errors.P8O_API_UNSUPPORTED]
|
||||
);
|
||||
|
||||
//Отображение документа "ПАРУС 8 Онлайн"
|
||||
const pOnlineShowDocument = useCallback(
|
||||
({ unitCode, document, showMethod = "main", inRnParameter = "in_RN" }) => {
|
||||
({ unitCode, document, showMethod = "main", inRnParameter = "in_RN", modal = true }) => {
|
||||
if (P8O_API)
|
||||
P8O_API.fn.openDocumentModal({ unitcode: unitCode, method: showMethod, inputParameters: [{ name: inRnParameter, value: document }] });
|
||||
modal
|
||||
? P8O_API.fn.openDocumentModal({
|
||||
unitcode: unitCode,
|
||||
method: showMethod,
|
||||
inputParameters: [{ name: inRnParameter, value: document }]
|
||||
})
|
||||
: P8O_API.fn.openDocument
|
||||
? P8O_API.fn.openDocument({
|
||||
unitcode: unitCode,
|
||||
method: showMethod,
|
||||
inputParameters: [{ name: inRnParameter, value: document }]
|
||||
})
|
||||
: showMsgErr(errors.P8O_API_UNSUPPORTED);
|
||||
else showMsgErr(errors.P8O_API_UNAVAILABLE);
|
||||
},
|
||||
[showMsgErr, errors.P8O_API_UNAVAILABLE]
|
||||
[showMsgErr, errors.P8O_API_UNAVAILABLE, errors.P8O_API_UNSUPPORTED]
|
||||
);
|
||||
|
||||
//Отображение словаря "ПАРУС 8 Онлайн"
|
||||
|
@ -33,34 +33,42 @@ const DISPLAY_SIZE = {
|
||||
//Типовые пути конвертации в массив (при переводе XML -> JSON)
|
||||
const XML_ALWAYS_ARRAY_PATHS = [
|
||||
"XRESPOND.XPAYLOAD.XOUT_ARGUMENTS",
|
||||
"XRESPOND.XPAYLOAD.XROWS",
|
||||
"XRESPOND.XPAYLOAD.XCOLUMNS_DEF",
|
||||
"XRESPOND.XPAYLOAD.XCOLUMNS_DEF.values",
|
||||
"XRESPOND.XPAYLOAD.XGROUPS",
|
||||
"XRESPOND.XPAYLOAD.XGANTT_DEF.taskAttributes",
|
||||
"XRESPOND.XPAYLOAD.XGANTT_DEF.taskColors",
|
||||
"XRESPOND.XPAYLOAD.XGANTT_TASKS",
|
||||
"XRESPOND.XPAYLOAD.XGANTT_TASKS.dependencies",
|
||||
"XRESPOND.XPAYLOAD.XDATA_GRID.rows",
|
||||
"XRESPOND.XPAYLOAD.XDATA_GRID.columnsDef",
|
||||
"XRESPOND.XPAYLOAD.XDATA_GRID.columnsDef.values",
|
||||
"XRESPOND.XPAYLOAD.XDATA_GRID.groups",
|
||||
"XRESPOND.XPAYLOAD.XGANTT.taskAttributes",
|
||||
"XRESPOND.XPAYLOAD.XGANTT.taskColors",
|
||||
"XRESPOND.XPAYLOAD.XGANTT.tasks",
|
||||
"XRESPOND.XPAYLOAD.XGANTT.tasks.dependencies",
|
||||
"XRESPOND.XPAYLOAD.XCHART.labels",
|
||||
"XRESPOND.XPAYLOAD.XCHART.datasets",
|
||||
"XRESPOND.XPAYLOAD.XCHART.datasets.data",
|
||||
"XRESPOND.XPAYLOAD.XCHART.datasets.items"
|
||||
"XRESPOND.XPAYLOAD.XCHART.datasets.items",
|
||||
"XRESPOND.XPAYLOAD.XCYCLOGRAM.taskAttributes",
|
||||
"XRESPOND.XPAYLOAD.XCYCLOGRAM.columns",
|
||||
"XRESPOND.XPAYLOAD.XCYCLOGRAM.groups",
|
||||
"XRESPOND.XPAYLOAD.XCYCLOGRAM.tasks"
|
||||
];
|
||||
|
||||
//Типовые шаблоны конвертации в массив (при переводе XML -> JSON)
|
||||
const XML_ALWAYS_ARRAY_PATH_PATTERNS = [
|
||||
/(.*)XROWS$/,
|
||||
/(.*)XCOLUMNS_DEF$/,
|
||||
/(.*)XCOLUMNS_DEF.values$/,
|
||||
/(.*)XGROUPS$/,
|
||||
/(.*)XGANTT_DEF.taskAttributes$/,
|
||||
/(.*)XGANTT_DEF.taskColors$/,
|
||||
/(.*)XGANTT_TASKS$/,
|
||||
/(.*)XGANTT_TASKS.dependencies$/,
|
||||
/(.*)XDATA_GRID.rows$/,
|
||||
/(.*)XDATA_GRID.columnsDef$/,
|
||||
/(.*)XDATA_GRID.columnsDef.values$/,
|
||||
/(.*)XDATA_GRID.groups$/,
|
||||
/(.*)XGANTT.taskAttributes$/,
|
||||
/(.*)XGANTT.taskColors$/,
|
||||
/(.*)XGANTT.tasks$/,
|
||||
/(.*)XGANTT.tasks.dependencies$/,
|
||||
/(.*)XCHART.labels$/,
|
||||
/(.*)XCHART.datasets$/,
|
||||
/(.*)XCHART.datasets.data$/,
|
||||
/(.*)XCHART.datasets.items$/
|
||||
/(.*)XCHART.datasets.items$/,
|
||||
/(.*)XCYCLOGRAM.taskAttributes$/,
|
||||
/(.*)XCYCLOGRAM.columns$/,
|
||||
/(.*)XCYCLOGRAM.groups$/,
|
||||
/(.*)XCYCLOGRAM.tasks$/
|
||||
];
|
||||
|
||||
//Типовой постфикс тега для массива (при переводе XML -> JSON)
|
||||
@ -68,11 +76,13 @@ const XML_ALWAYS_ARRAY_POSTFIX = "__SYSTEM__ARRAY__";
|
||||
|
||||
//Типовые шаблоны конвертации значения атрибута в строку (при переводе XML -> JSON)
|
||||
const XML_ATTR_ALWAYS_STR_PATH_PATTERNS = [
|
||||
/(.*)XCOLUMNS_DEF.name$/,
|
||||
/(.*)XCOLUMNS_DEF.caption$/,
|
||||
/(.*)XCOLUMNS_DEF.parent$/,
|
||||
/(.*)XGROUPS.name$/,
|
||||
/(.*)XGROUPS.caption$/
|
||||
/(.*)XDATA_GRID.columnsDef.name$/,
|
||||
/(.*)XDATA_GRID.columnsDef.caption$/,
|
||||
/(.*)XDATA_GRID.columnsDef.parent$/,
|
||||
/(.*)XDATA_GRID.groups.name$/,
|
||||
/(.*)XDATA_GRID.groups.caption$/,
|
||||
/(.*)XCYCLOGRAM.columns.name$/,
|
||||
/(.*)XCYCLOGRAM.groups.name$/
|
||||
];
|
||||
|
||||
//-----------
|
||||
@ -97,7 +107,6 @@ const deepCopyObject = obj => JSON.parse(JSON.stringify(obj));
|
||||
//Конвертация объекта в Base64 XML
|
||||
const object2Base64XML = (obj, builderOptions) => {
|
||||
const builder = new XMLBuilder(builderOptions);
|
||||
//onOrderChanged({ orders: btoa(ordersBuilder.build(newOrders)) });
|
||||
return btoa(unescape(encodeURIComponent(builder.build(obj))));
|
||||
};
|
||||
|
||||
@ -140,6 +149,9 @@ const xml2JSON = ({ xmlDoc, isArray, transformTagName, tagValueProcessor, attrib
|
||||
//Форматирование даты в формат РФ
|
||||
const formatDateRF = value => (value ? dayjs(value).format("DD.MM.YYYY") : null);
|
||||
|
||||
//Форматирование даты и времени в формат РФ
|
||||
const formatDateTimeRF = value => (value ? dayjs(value).format("DD.MM.YYYY HH:mm:ss") : null);
|
||||
|
||||
//Форматирование даты в формат JSON (только дата, без времени)
|
||||
const formatDateJSONDateOnly = value => (value ? dayjs(value).format("YYYY-MM-DD") : null);
|
||||
|
||||
@ -163,6 +175,7 @@ export {
|
||||
object2Base64XML,
|
||||
xml2JSON,
|
||||
formatDateRF,
|
||||
formatDateTimeRF,
|
||||
formatDateJSONDateOnly,
|
||||
formatNumberRFCurrency,
|
||||
genGUID
|
||||
|
@ -119,8 +119,8 @@ const EqsPrfrm = () => {
|
||||
let cF = 0;
|
||||
let sF = 0;
|
||||
let properties = [];
|
||||
if (data.XROWS != null) {
|
||||
data.XROWS.map(row => {
|
||||
if (data.XDATA_GRID.rows != null) {
|
||||
data.XDATA_GRID.rows.map(row => {
|
||||
properties = [];
|
||||
Object.entries(row).forEach(([key, value]) => properties.push({ name: key, data: value }));
|
||||
let info2 = properties.find(element => {
|
||||
@ -156,11 +156,10 @@ const EqsPrfrm = () => {
|
||||
}
|
||||
setDataGrid(pv => ({
|
||||
...pv,
|
||||
columnsDef: data.XCOLUMNS_DEF ? [...data.XCOLUMNS_DEF] : pv.columnsDef,
|
||||
rows: [...(data.XROWS || [])],
|
||||
fixedHeader: data.XDATA_GRID.fixedHeader,
|
||||
fixedColumns: data.XDATA_GRID.fixedColumns,
|
||||
groups: [...(data.XGROUPS || [])],
|
||||
...data.XDATA_GRID,
|
||||
columnsDef: data.XDATA_GRID.columnsDef ? [...data.XDATA_GRID.columnsDef] : pv.columnsDef,
|
||||
rows: [...(data.XDATA_GRID.rows || [])],
|
||||
groups: [...(data.XDATA_GRID.groups || [])],
|
||||
dataLoaded: true,
|
||||
reload: false
|
||||
}));
|
||||
@ -214,7 +213,7 @@ const EqsPrfrm = () => {
|
||||
}
|
||||
});
|
||||
if (data.NIDENT) {
|
||||
if (type == 0) pOnlineShowUnit({ unitCode: "EquipTechServices", inputParameters: [{ name: "in_SelectList_Ident", value: data.NIDENT }] });
|
||||
if (type == 0) pOnlineShowUnit({ unitCode: "EquipTechServices", inputParameters: [{ name: "in_Ident", value: data.NIDENT }] });
|
||||
else pOnlineShowUnit({ unitCode: "EquipRepairSheets", inputParameters: [{ name: "in_Ident", value: data.NIDENT }] });
|
||||
} else showMsgErr(TEXTS.NO_DATA_FOUND);
|
||||
};
|
||||
|
@ -15,6 +15,7 @@ import { P8PSVG } from "../../../components/p8p_svg"; //Интерактивны
|
||||
import { P8P_DATA_GRID_CONFIG_PROPS } from "../../../config_wrapper"; //Подключение компонентов к настройкам приложения
|
||||
import { useCostProductComposition, useProductDetailsTable } from "../hooks"; //Вспомогательные хуки
|
||||
import { ProgressBox } from "./progress_box"; //Информация по прогрессу объекта
|
||||
import { APP_STYLES } from "../../../../app.styles"; //Типовые стили
|
||||
|
||||
//---------
|
||||
//Константы
|
||||
@ -26,6 +27,7 @@ const STYLES = {
|
||||
border: "1px solid",
|
||||
borderRadius: "25px",
|
||||
height: "35vh",
|
||||
minHeight: "250px",
|
||||
backgroundColor: "background.detail_table"
|
||||
},
|
||||
BOX_INFO_SUB: isMessage => ({
|
||||
@ -47,6 +49,7 @@ const STYLES = {
|
||||
border: "1px solid",
|
||||
borderRadius: "25px",
|
||||
height: "17vh",
|
||||
minHeight: "120px",
|
||||
backgroundColor: "background.detail_info"
|
||||
},
|
||||
PRODUCT_SELECTOR_CONTAINER: {
|
||||
@ -57,6 +60,7 @@ const STYLES = {
|
||||
border: "1px solid",
|
||||
borderRadius: "25px",
|
||||
height: "53vh",
|
||||
minHeight: "379px",
|
||||
marginTop: "16px",
|
||||
backgroundColor: "background.product_selector"
|
||||
},
|
||||
@ -72,7 +76,12 @@ const STYLES = {
|
||||
width: "280px",
|
||||
borderBottom: "1px solid"
|
||||
},
|
||||
TABLE_DETAILS: { backgroundColor: "background.detail_table", height: "240px" },
|
||||
TABLE_DETAILS: {
|
||||
backgroundColor: "background.detail_table",
|
||||
height: "28vh",
|
||||
minHeight: "187px",
|
||||
...APP_STYLES.SCROLL
|
||||
},
|
||||
TABLE_DETAILS_HEADER_CELL: maxWidth => ({
|
||||
backgroundColor: "background.detail_table",
|
||||
color: "text.detail_table.fontColor",
|
||||
@ -107,7 +116,7 @@ const PlanSpecInfo = ({ planSpec }) => {
|
||||
<Box sx={STYLES.PLAN_INFO_MAIN}>
|
||||
<Box sx={STYLES.PLAN_INFO_SUB}>
|
||||
<Typography variant="PlanSpecInfo" mt={1}>
|
||||
Номер борта:
|
||||
Номер заказа:
|
||||
</Typography>
|
||||
<Typography variant="subtitle2">{planSpec.SNUMB}</Typography>
|
||||
</Box>
|
||||
|
@ -70,11 +70,11 @@ const PlanSpecsListItem = ({ card, cardIndex, onClick }) => {
|
||||
return (
|
||||
<Box sx={STYLES.CONTAINER} onClick={() => (onClick ? onClick(card, cardIndex) : null)}>
|
||||
<PlanSpecsListItemImage card={card} />
|
||||
<Box textAlign="center">
|
||||
<Box textAlign="center" height="70px">
|
||||
<Typography variant="PlanSpecInfo" sx={STYLES.TEXT_INFO_FIELD}>
|
||||
Номер борта
|
||||
Номер заказа
|
||||
</Typography>
|
||||
<Typography variant="h2">{card.SNUMB}</Typography>
|
||||
<Typography variant="h2">{card.SNUMB || "-"}</Typography>
|
||||
</Box>
|
||||
<ProgressBox
|
||||
progress={card.NPROGRESS}
|
||||
@ -84,12 +84,12 @@ const PlanSpecsListItem = ({ card, cardIndex, onClick }) => {
|
||||
progressVariant={"h3"}
|
||||
detailVariant={"PlanSpecProgressDetail"}
|
||||
/>
|
||||
<Box>
|
||||
<Box height="70px">
|
||||
<Typography variant="PlanSpecInfo" sx={STYLES.TEXT_INFO_FIELD}>
|
||||
Год выпуска:
|
||||
</Typography>
|
||||
<Typography variant="subtitle1" mt={-1}>
|
||||
{card.NYEAR}
|
||||
{card.NYEAR || "-"}
|
||||
</Typography>
|
||||
</Box>
|
||||
</Box>
|
||||
|
@ -195,9 +195,10 @@ const useProductDetailsTable = (planSpec, product, orders, pageNumber, stored) =
|
||||
});
|
||||
setData(pv => ({
|
||||
...pv,
|
||||
columnsDef: data.XCOLUMNS_DEF ? [...data.XCOLUMNS_DEF] : pv.columnsDef,
|
||||
rows: pageNumber == 1 ? [...(data.XROWS || [])] : [...pv.rows, ...(data.XROWS || [])],
|
||||
morePages: DATA_GRID_PAGE_SIZE == 0 ? false : (data.XROWS || []).length >= DATA_GRID_PAGE_SIZE,
|
||||
...data.XDATA_GRID,
|
||||
columnsDef: data.XDATA_GRID.columnsDef ? [...data.XDATA_GRID.columnsDef] : pv.columnsDef,
|
||||
rows: pageNumber == 1 ? [...(data.XDATA_GRID.rows || [])] : [...pv.rows, ...(data.XDATA_GRID.rows || [])],
|
||||
morePages: DATA_GRID_PAGE_SIZE == 0 ? false : (data.XDATA_GRID.rows || []).length >= DATA_GRID_PAGE_SIZE,
|
||||
init: true
|
||||
}));
|
||||
} finally {
|
||||
|
@ -27,6 +27,7 @@ import {
|
||||
Icon
|
||||
} from "@mui/material"; //Интерфейсные элементы
|
||||
import { ThemeProvider } from "@mui/material/styles"; //Подключение темы
|
||||
import { APP_STYLES } from "../../../app.styles"; //Типовые стили
|
||||
import { PlanSpecsList } from "./components/plans_list"; //Список планов
|
||||
import { PlanSpecDetail } from "./components/plan_detail"; //Детали плана
|
||||
import { lightTheme, darkTheme } from "./styles/themes"; //Стиль темы
|
||||
@ -63,7 +64,8 @@ const STYLES = {
|
||||
display: "inline-block",
|
||||
boxSizing: "border-box",
|
||||
backgroundColor: "background.plans_drawer_paper",
|
||||
color: "text.plans_finder.fontColor"
|
||||
color: "text.plans_finder.fontColor",
|
||||
...APP_STYLES.SCROLL
|
||||
}
|
||||
},
|
||||
PLANS_LIST_BOX: { paddingTop: "20px" },
|
||||
@ -240,26 +242,32 @@ const MechRecAssemblyMon = () => {
|
||||
</Stack>
|
||||
{state.init == true ? (
|
||||
state.selectedPlanCtlg.NRN ? (
|
||||
<>
|
||||
<Typography variant="h3" sx={STYLES.MAIN_TITLE} pb={2}>
|
||||
{title}
|
||||
state.planSpecs.length !== 0 ? (
|
||||
<>
|
||||
<Typography variant="h3" sx={STYLES.MAIN_TITLE} pb={2}>
|
||||
{title}
|
||||
</Typography>
|
||||
{state.planSpecsLoaded == true ? (
|
||||
state.selectedPlanSpec.NRN ? (
|
||||
<PlanSpecDetail
|
||||
planSpec={state.selectedPlanSpec}
|
||||
disableNavigatePrev={planDetailNavigation.disableNavigatePrev}
|
||||
disableNavigateNext={planDetailNavigation.disableNavigateNext}
|
||||
onNavigate={handlePlanDetailNavigateClick}
|
||||
onBack={handlePlanDetailBackClick}
|
||||
/>
|
||||
) : (
|
||||
<Box sx={STYLES.PLANS_LIST_BOX}>
|
||||
<PlanSpecsList planSpecs={state.planSpecs} onItemClick={handlePlanClick} />
|
||||
</Box>
|
||||
)
|
||||
) : null}
|
||||
</>
|
||||
) : (
|
||||
<Typography variant="h4" sx={STYLES.MAIN_TITLE}>
|
||||
В каталоге планов отсутствуют записи подходящих первичных документов
|
||||
</Typography>
|
||||
{state.planSpecsLoaded == true ? (
|
||||
state.selectedPlanSpec.NRN ? (
|
||||
<PlanSpecDetail
|
||||
planSpec={state.selectedPlanSpec}
|
||||
disableNavigatePrev={planDetailNavigation.disableNavigatePrev}
|
||||
disableNavigateNext={planDetailNavigation.disableNavigateNext}
|
||||
onNavigate={handlePlanDetailNavigateClick}
|
||||
onBack={handlePlanDetailBackClick}
|
||||
/>
|
||||
) : (
|
||||
<Box sx={STYLES.PLANS_LIST_BOX}>
|
||||
<PlanSpecsList planSpecs={state.planSpecs} onItemClick={handlePlanClick} />
|
||||
</Box>
|
||||
)
|
||||
) : null}
|
||||
</>
|
||||
)
|
||||
) : (
|
||||
<Typography variant="h4" sx={STYLES.MAIN_TITLE}>
|
||||
Укажите каталог планов для отображения спецификаций
|
||||
|
@ -150,12 +150,13 @@ const useCostJobsSpecs = task => {
|
||||
});
|
||||
setCostJobsSpecs(pv => ({
|
||||
...pv,
|
||||
...data.XDATA_GRID,
|
||||
task: task,
|
||||
columnsDef: data.XCOLUMNS_DEF ? [...data.XCOLUMNS_DEF] : pv.columnsDef,
|
||||
rows: pv.pageNumber == 1 ? [...(data.XROWS || [])] : [...pv.rows, ...(data.XROWS || [])],
|
||||
columnsDef: data.XDATA_GRID.columnsDef ? [...data.XDATA_GRID.columnsDef] : pv.columnsDef,
|
||||
rows: pv.pageNumber == 1 ? [...(data.XDATA_GRID.rows || [])] : [...pv.rows, ...(data.XDATA_GRID.rows || [])],
|
||||
dataLoaded: true,
|
||||
reload: false,
|
||||
morePages: (data.XROWS || []).length >= DATA_GRID_PAGE_SIZE
|
||||
morePages: (data.XDATA_GRID.rows || []).length >= DATA_GRID_PAGE_SIZE
|
||||
}));
|
||||
};
|
||||
loadData();
|
||||
@ -256,12 +257,13 @@ const useEquipConfiguration = (task, fromAction) => {
|
||||
});
|
||||
setEquipConfiguration(pv => ({
|
||||
...pv,
|
||||
...data.XDATA_GRID,
|
||||
task: task,
|
||||
columnsDef: data.XCOLUMNS_DEF ? [...data.XCOLUMNS_DEF] : pv.columnsDef,
|
||||
rows: pv.pageNumber == 1 ? [...(data.XROWS || [])] : [...pv.rows, ...(data.XROWS || [])],
|
||||
columnsDef: data.XDATA_GRID.columnsDef ? [...data.XDATA_GRID.columnsDef] : pv.columnsDef,
|
||||
rows: pv.pageNumber == 1 ? [...(data.XDATA_GRID.rows || [])] : [...pv.rows, ...(data.XDATA_GRID.rows || [])],
|
||||
dataLoaded: true,
|
||||
reload: false,
|
||||
morePages: (data.XROWS || []).length >= DATA_GRID_PAGE_SIZE
|
||||
morePages: (data.XDATA_GRID.rows || []).length >= DATA_GRID_PAGE_SIZE
|
||||
}));
|
||||
};
|
||||
loadData();
|
||||
|
@ -10,6 +10,7 @@
|
||||
import React, { useContext, useState } from "react"; //Классы React
|
||||
import PropTypes from "prop-types"; //Контроль свойств компонента
|
||||
import { Drawer, Fab, Box, List, ListItemButton, ListItemText, Typography, TextField } from "@mui/material"; //Интерфейсные элементы
|
||||
import { APP_STYLES } from "../../../app.styles"; //Типовые стили
|
||||
import { MessagingСtx } from "../../context/messaging"; //Контекст сообщений
|
||||
import { CostJobsSpecsDataGrid } from "./fcjobssp"; //Собственные хуки таблиц
|
||||
import { useCostJobs, useFilteredFcjobs } from "./hooks"; //Вспомогательные хуки
|
||||
@ -35,7 +36,7 @@ const STYLES = {
|
||||
width: "350px",
|
||||
display: "inline-block",
|
||||
flexShrink: 0,
|
||||
[`& .MuiDrawer-paper`]: { width: "350px", display: "inline-block", boxSizing: "border-box" }
|
||||
[`& .MuiDrawer-paper`]: { width: "350px", display: "inline-block", boxSizing: "border-box", ...APP_STYLES.SCROLL }
|
||||
},
|
||||
CONTAINER: { textAlign: "center" }
|
||||
};
|
||||
|
@ -53,14 +53,15 @@ const useCostRouteLists = (task, taskType) => {
|
||||
});
|
||||
setCostRouteLists(pv => ({
|
||||
...pv,
|
||||
columnsDef: data.XCOLUMNS_DEF ? [...data.XCOLUMNS_DEF] : pv.columnsDef,
|
||||
rows: pv.pageNumber == 1 ? [...(data.XROWS || [])] : [...pv.rows, ...(data.XROWS || [])],
|
||||
...data.XDATA_GRID,
|
||||
columnsDef: data.XDATA_GRID.columnsDef ? [...data.XDATA_GRID.columnsDef] : pv.columnsDef,
|
||||
rows: pv.pageNumber == 1 ? [...(data.XDATA_GRID.rows || [])] : [...pv.rows, ...(data.XDATA_GRID.rows || [])],
|
||||
dataLoaded: true,
|
||||
reload: false,
|
||||
morePages: (data.XROWS || []).length >= DATA_GRID_PAGE_SIZE,
|
||||
quantPlanSum: data.XROWS ? data.XROWS.reduce((a, b) => a + b["NQUANT_PLAN"], 0) : 0,
|
||||
uniqueNomns: data.XROWS
|
||||
? data.XROWS.reduce((accumulator, current) => {
|
||||
morePages: (data.XDATA_GRID.rows || []).length >= DATA_GRID_PAGE_SIZE,
|
||||
quantPlanSum: data.XDATA_GRID.rows ? data.XDATA_GRID.rows.reduce((a, b) => a + b["NQUANT_PLAN"], 0) : 0,
|
||||
uniqueNomns: data.XDATA_GRID.rows
|
||||
? data.XDATA_GRID.rows.reduce((accumulator, current) => {
|
||||
if (!accumulator.find(item => item.SMATRES_PLAN_NOMEN === current.SMATRES_PLAN_NOMEN)) {
|
||||
accumulator.push(current);
|
||||
}
|
||||
@ -122,11 +123,12 @@ const useIncomFromDeps = (task, taskType) => {
|
||||
});
|
||||
setIncomFromDeps(pv => ({
|
||||
...pv,
|
||||
columnsDef: data.XCOLUMNS_DEF ? [...data.XCOLUMNS_DEF] : pv.columnsDef,
|
||||
rows: pv.pageNumber == 1 ? [...(data.XROWS || [])] : [...pv.rows, ...(data.XROWS || [])],
|
||||
...data.XDATA_GRID,
|
||||
columnsDef: data.XDATA_GRID.columnsDef ? [...data.XDATA_GRID.columnsDef] : pv.columnsDef,
|
||||
rows: pv.pageNumber == 1 ? [...(data.XDATA_GRID.rows || [])] : [...pv.rows, ...(data.XDATA_GRID.rows || [])],
|
||||
dataLoaded: true,
|
||||
reload: false,
|
||||
morePages: (data.XROWS || []).length >= DATA_GRID_PAGE_SIZE
|
||||
morePages: (data.XDATA_GRID.rows || []).length >= DATA_GRID_PAGE_SIZE
|
||||
}));
|
||||
}
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
@ -172,11 +174,12 @@ const useGoodsParties = mainRowRN => {
|
||||
});
|
||||
setGoodsParties(pv => ({
|
||||
...pv,
|
||||
columnsDef: data.XCOLUMNS_DEF ? [...data.XCOLUMNS_DEF] : pv.columnsDef,
|
||||
rows: pv.pageNumber == 1 ? [...(data.XROWS || [])] : [...pv.rows, ...(data.XROWS || [])],
|
||||
...data.XDATA_GRID,
|
||||
columnsDef: data.XDATA_GRID.columnsDef ? [...data.XDATA_GRID.columnsDef] : pv.columnsDef,
|
||||
rows: pv.pageNumber == 1 ? [...(data.XDATA_GRID.rows || [])] : [...pv.rows, ...(data.XDATA_GRID.rows || [])],
|
||||
dataLoaded: true,
|
||||
reload: false,
|
||||
morePages: (data.XROWS || []).length >= DATA_GRID_PAGE_SIZE
|
||||
morePages: (data.XDATA_GRID.rows || []).length >= DATA_GRID_PAGE_SIZE
|
||||
}));
|
||||
}
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
@ -223,11 +226,12 @@ const useCostDeliveryLists = mainRowRN => {
|
||||
});
|
||||
setCostDeliveryLists(pv => ({
|
||||
...pv,
|
||||
columnsDef: data.XCOLUMNS_DEF ? [...data.XCOLUMNS_DEF] : pv.columnsDef,
|
||||
rows: pv.pageNumber == 1 ? [...(data.XROWS || [])] : [...pv.rows, ...(data.XROWS || [])],
|
||||
...data.XDATA_GRID,
|
||||
columnsDef: data.XDATA_GRID.columnsDef ? [...data.XDATA_GRID.columnsDef] : pv.columnsDef,
|
||||
rows: pv.pageNumber == 1 ? [...(data.XDATA_GRID.rows || [])] : [...pv.rows, ...(data.XDATA_GRID.rows || [])],
|
||||
dataLoaded: true,
|
||||
reload: false,
|
||||
morePages: (data.XROWS || []).length >= DATA_GRID_PAGE_SIZE
|
||||
morePages: (data.XDATA_GRID.rows || []).length >= DATA_GRID_PAGE_SIZE
|
||||
}));
|
||||
}
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
|
@ -43,11 +43,12 @@ 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 { APP_STYLES } from "../../../app.styles"; //Типовые стили
|
||||
import { P8PGantt, taskLegendDesc } from "../../components/p8p_gantt"; //Диаграмма Ганта
|
||||
import { xml2JSON, formatDateJSONDateOnly, formatDateRF, hasValue } from "../../core/utils"; //Вспомогательные функции
|
||||
import { useFilteredPlanCtlgs } from "./hooks"; //Вспомогательные хуки
|
||||
import { CostRouteListsDataGrid } from "./datagrids/fcroutlst";
|
||||
import { IncomFromDepsDataGrid } from "./datagrids/incomefromdeps";
|
||||
import { CostRouteListsDataGrid } from "./datagrids/fcroutlst"; //Таблица "Маршрутные листы"
|
||||
import { IncomFromDepsDataGrid } from "./datagrids/incomefromdeps"; //Таблица "Приходы из подразделений"
|
||||
|
||||
//---------
|
||||
//Константы
|
||||
@ -72,7 +73,7 @@ const STYLES = {
|
||||
width: "350px",
|
||||
display: "inline-block",
|
||||
flexShrink: 0,
|
||||
[`& .MuiDrawer-paper`]: { width: "350px", display: "inline-block", boxSizing: "border-box" }
|
||||
[`& .MuiDrawer-paper`]: { width: "350px", display: "inline-block", boxSizing: "border-box", ...APP_STYLES.SCROLL }
|
||||
},
|
||||
GANTT_CONTAINER: { height: `calc(100vh - ${APP_BAR_HEIGHT})`, width: "100vw", paddingTop: "24px" },
|
||||
GANTT_TITLE: { paddingLeft: "250px", paddingRight: "250px" },
|
||||
@ -97,7 +98,7 @@ const parseProdPlanSpXML = async xmlDoc => {
|
||||
attributeValueProcessor: (name, val) =>
|
||||
["numb", "title"].includes(name) ? undefined : ["start", "end"].includes(name) ? formatDateJSONDateOnly(val) : val
|
||||
});
|
||||
return data.XDATA;
|
||||
return data.XDATA.XGANTT;
|
||||
};
|
||||
|
||||
//Форматирование для отображения количества документов
|
||||
@ -237,8 +238,7 @@ const MechRecCostProdPlans = () => {
|
||||
selectedPlanCtlgLevel: null,
|
||||
selectedPlanCtlgSort: null,
|
||||
selectedPlanCtlgMenuItems: null,
|
||||
selectedPlanCtlgGanttDef: {},
|
||||
selectedPlanCtlgSpecs: [],
|
||||
gantt: {},
|
||||
selectedTaskDetail: null,
|
||||
selectedTaskDetailType: null,
|
||||
planSpec: null
|
||||
@ -282,8 +282,7 @@ const MechRecCostProdPlans = () => {
|
||||
selectedPlanCtlgLevel: null,
|
||||
selectedPlanCtlgSort: null,
|
||||
selectedPlanCtlgMenuItems: null,
|
||||
selectedPlanCtlgSpecs: [],
|
||||
selectedPlanCtlgGanttDef: {},
|
||||
gantt: {},
|
||||
showPlanList: false,
|
||||
selectedTaskDetail: null,
|
||||
selectedTaskDetailType: null
|
||||
@ -300,8 +299,7 @@ const MechRecCostProdPlans = () => {
|
||||
selectedPlanCtlgLevel: null,
|
||||
selectedPlanCtlgSort: null,
|
||||
selectedPlanCtlgMenuItems: null,
|
||||
selectedPlanCtlgSpecs: [],
|
||||
selectedPlanCtlgGanttDef: {},
|
||||
gantt: {},
|
||||
showPlanList: false,
|
||||
selectedTaskDetail: null,
|
||||
selectedTaskDetailType: null
|
||||
@ -324,8 +322,7 @@ const MechRecCostProdPlans = () => {
|
||||
? state.selectedPlanCtlgMenuItems
|
||||
: [...Array(data.NMAX_LEVEL).keys()].map(el => el + 1),
|
||||
selectedPlanCtlgSpecsLoaded: true,
|
||||
selectedPlanCtlgGanttDef: doc.XGANTT_DEF ? { ...doc.XGANTT_DEF } : {},
|
||||
selectedPlanCtlgSpecs: [...(doc?.XGANTT_TASKS || [])]
|
||||
gantt: { ...doc, tasks: [...(doc?.tasks || [])] }
|
||||
}));
|
||||
},
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
@ -401,7 +398,7 @@ const MechRecCostProdPlans = () => {
|
||||
<Grid container>
|
||||
<Grid item xs={12}>
|
||||
{state.selectedPlanCtlgSpecsLoaded ? (
|
||||
state.selectedPlanCtlgSpecs.length === 0 ? (
|
||||
state.gantt.tasks.length === 0 ? (
|
||||
<Box pt={3}>
|
||||
<InlineMsgInfo
|
||||
okBtn={false}
|
||||
@ -459,10 +456,9 @@ const MechRecCostProdPlans = () => {
|
||||
) : null}
|
||||
<P8PGantt
|
||||
{...P8P_GANTT_CONFIG_PROPS}
|
||||
{...state.selectedPlanCtlgGanttDef}
|
||||
{...state.gantt}
|
||||
containerStyle={STYLES.GANTT_CONTAINER}
|
||||
titleStyle={STYLES.GANTT_TITLE}
|
||||
tasks={state.selectedPlanCtlgSpecs}
|
||||
taskDialogRenderer={prms => taskDialogRenderer({ ...prms, handleTaskDetailOpen })}
|
||||
/>
|
||||
</Box>
|
||||
|
@ -62,13 +62,12 @@ const useMechRecDeptCostJobs = (subdiv, fullDate, workHours) => {
|
||||
});
|
||||
setCostJobs(pv => ({
|
||||
...pv,
|
||||
fixedHeader: data.XDATA_GRID.fixedHeader,
|
||||
fixedColumns: data.XDATA_GRID.fixedColumns,
|
||||
columnsDef: data.XCOLUMNS_DEF ? [...data.XCOLUMNS_DEF] : pv.columnsDef,
|
||||
rows: pv.pageNumber == 1 ? [...(data.XROWS || [])] : [...pv.rows, ...(data.XROWS || [])],
|
||||
...data.XDATA_GRID,
|
||||
columnsDef: data.XDATA_GRID.columnsDef ? [...data.XDATA_GRID.columnsDef] : pv.columnsDef,
|
||||
rows: pv.pageNumber == 1 ? [...(data.XDATA_GRID.rows || [])] : [...pv.rows, ...(data.XDATA_GRID.rows || [])],
|
||||
dataLoaded: true,
|
||||
reload: false,
|
||||
morePages: (data.XROWS || []).length >= DATA_GRID_PAGE_SIZE_LARGE,
|
||||
morePages: (data.XDATA_GRID.rows || []).length >= DATA_GRID_PAGE_SIZE_LARGE,
|
||||
date: fullDate
|
||||
}));
|
||||
};
|
||||
@ -109,11 +108,12 @@ const useInsDepartment = fullDate => {
|
||||
});
|
||||
setInsDepartments(pv => ({
|
||||
...pv,
|
||||
columnsDef: data.XCOLUMNS_DEF ? [...data.XCOLUMNS_DEF] : pv.columnsDef,
|
||||
rows: pv.pageNumber == 1 ? [...(data.XROWS || [])] : [...pv.rows, ...(data.XROWS || [])],
|
||||
...data.XDATA_GRID,
|
||||
columnsDef: data.XDATA_GRID.columnsDef ? [...data.XDATA_GRID.columnsDef] : pv.columnsDef,
|
||||
rows: pv.pageNumber == 1 ? [...(data.XDATA_GRID.rows || [])] : [...pv.rows, ...(data.XDATA_GRID.rows || [])],
|
||||
dataLoaded: true,
|
||||
reload: false,
|
||||
morePages: (data.XROWS || []).length >= DATA_GRID_PAGE_SIZE_SMALL
|
||||
morePages: (data.XDATA_GRID.rows || []).length >= DATA_GRID_PAGE_SIZE_SMALL
|
||||
}));
|
||||
};
|
||||
if (insDepartments.reload) {
|
||||
|
@ -75,13 +75,12 @@ const useDeptCostProdPlans = () => {
|
||||
});
|
||||
setState(pv => ({
|
||||
...pv,
|
||||
fixedHeader: data.XDATA_GRID.fixedHeader,
|
||||
fixedColumns: data.XDATA_GRID.fixedColumns,
|
||||
columnsDef: data.XCOLUMNS_DEF ? [...data.XCOLUMNS_DEF] : pv.columnsDef,
|
||||
rows: pv.pageNumber == 1 ? [...(data.XROWS || [])] : [...pv.rows, ...(data.XROWS || [])],
|
||||
...data.XDATA_GRID,
|
||||
columnsDef: data.XDATA_GRID.columnsDef ? [...data.XDATA_GRID.columnsDef] : pv.columnsDef,
|
||||
rows: pv.pageNumber == 1 ? [...(data.XDATA_GRID.rows || [])] : [...pv.rows, ...(data.XDATA_GRID.rows || [])],
|
||||
dataLoaded: true,
|
||||
reload: false,
|
||||
morePages: (data.XROWS || []).length >= DATA_GRID_PAGE_SIZE_LARGE
|
||||
morePages: (data.XDATA_GRID.rows || []).length >= DATA_GRID_PAGE_SIZE_LARGE
|
||||
}));
|
||||
};
|
||||
if (state.reload) {
|
||||
@ -144,11 +143,12 @@ const useCostRouteLists = task => {
|
||||
});
|
||||
setCostRouteLists(pv => ({
|
||||
...pv,
|
||||
columnsDef: data.XCOLUMNS_DEF ? [...data.XCOLUMNS_DEF] : pv.columnsDef,
|
||||
rows: pv.pageNumber == 1 ? [...(data.XROWS || [])] : [...pv.rows, ...(data.XROWS || [])],
|
||||
...data.XDATA_GRID,
|
||||
columnsDef: data.XDATA_GRID.columnsDef ? [...data.XDATA_GRID.columnsDef] : pv.columnsDef,
|
||||
rows: pv.pageNumber == 1 ? [...(data.XDATA_GRID.rows || [])] : [...pv.rows, ...(data.XDATA_GRID.rows || [])],
|
||||
dataLoaded: true,
|
||||
reload: false,
|
||||
morePages: (data.XROWS || []).length >= DATA_GRID_PAGE_SIZE_SMALL
|
||||
morePages: (data.XDATA_GRID.rows || []).length >= DATA_GRID_PAGE_SIZE_SMALL
|
||||
}));
|
||||
};
|
||||
if (costRouteLists.reload && task) {
|
||||
@ -202,11 +202,12 @@ const useCostRouteListsSpecs = mainRowRN => {
|
||||
});
|
||||
setCostRouteListsSpecs(pv => ({
|
||||
...pv,
|
||||
columnsDef: data.XCOLUMNS_DEF ? [...data.XCOLUMNS_DEF] : pv.columnsDef,
|
||||
rows: pv.pageNumber == 1 ? [...(data.XROWS || [])] : [...pv.rows, ...(data.XROWS || [])],
|
||||
...data.XDATA_GRID,
|
||||
columnsDef: data.XDATA_GRID.columnsDef ? [...data.XDATA_GRID.columnsDef] : pv.columnsDef,
|
||||
rows: pv.pageNumber == 1 ? [...(data.XDATA_GRID.rows || [])] : [...pv.rows, ...(data.XDATA_GRID.rows || [])],
|
||||
dataLoaded: true,
|
||||
reload: false,
|
||||
morePages: (data.XROWS || []).length >= DATA_GRID_PAGE_SIZE_LARGE
|
||||
morePages: (data.XDATA_GRID.rows || []).length >= DATA_GRID_PAGE_SIZE_LARGE
|
||||
}));
|
||||
};
|
||||
if (costRouteListsSpecs.reload) {
|
||||
@ -258,11 +259,12 @@ const useIncomFromDeps = task => {
|
||||
});
|
||||
setIncomFromDeps(pv => ({
|
||||
...pv,
|
||||
columnsDef: data.XCOLUMNS_DEF ? [...data.XCOLUMNS_DEF] : pv.columnsDef,
|
||||
rows: pv.pageNumber == 1 ? [...(data.XROWS || [])] : [...pv.rows, ...(data.XROWS || [])],
|
||||
...data.XDATA_GRID,
|
||||
columnsDef: data.XDATA_GRID.columnsDef ? [...data.XDATA_GRID.columnsDef] : pv.columnsDef,
|
||||
rows: pv.pageNumber == 1 ? [...(data.XDATA_GRID.rows || [])] : [...pv.rows, ...(data.XDATA_GRID.rows || [])],
|
||||
dataLoaded: true,
|
||||
reload: false,
|
||||
morePages: (data.XROWS || []).length >= DATA_GRID_PAGE_SIZE_LARGE
|
||||
morePages: (data.XDATA_GRID.rows || []).length >= DATA_GRID_PAGE_SIZE_LARGE
|
||||
}));
|
||||
};
|
||||
if (incomFromDeps.reload) {
|
||||
|
@ -41,7 +41,7 @@ const STYLES = {
|
||||
width: "350px",
|
||||
display: "inline-block",
|
||||
flexShrink: 0,
|
||||
[`& .MuiDrawer-paper`]: { width: "350px", display: "inline-block", boxSizing: "border-box" }
|
||||
[`& .MuiDrawer-paper`]: { width: "350px", display: "inline-block", boxSizing: "border-box", ...APP_STYLES.SCROLL }
|
||||
},
|
||||
CONTAINER: { textAlign: "center" },
|
||||
TITLE: { height: TITLE_HEIGHT, overflow: "hidden", paddingTop: TITLE_PADDING_TOP, paddingBottom: TITLE_PADDING_BOTTOM, display: "inline-table" },
|
||||
|
@ -23,6 +23,13 @@ export const PANEL_UNITS = {
|
||||
PROJECT_STAGE_ARTS: "PROJECT_STAGE_ARTS"
|
||||
};
|
||||
|
||||
//Общие стили
|
||||
export const COMMON_PROJECTS_STYLES = {
|
||||
FULL_SCREEN_DIALOG_CONTENT: {
|
||||
padding: 0
|
||||
}
|
||||
};
|
||||
|
||||
//-----------
|
||||
//Тело модуля
|
||||
//-----------
|
||||
@ -250,6 +257,7 @@ export const rowExpandRender = ({
|
||||
columnsDef,
|
||||
row,
|
||||
pOnlineShowDocument,
|
||||
pOnlineShowUnit,
|
||||
showStages,
|
||||
showPayNotes,
|
||||
showCostNotes,
|
||||
@ -275,42 +283,55 @@ export const rowExpandRender = ({
|
||||
const linkButtons = () =>
|
||||
panelUnit === PANEL_UNITS.PROJECTS ? (
|
||||
<>
|
||||
<Button fullWidth variant="contained" onClick={() => showStages({ sender: row })}>
|
||||
<Button variant="outlined" onClick={() => showStages({ sender: row })}>
|
||||
Этапы
|
||||
</Button>
|
||||
<Button fullWidth variant="contained" onClick={() => pOnlineShowDocument({ unitCode: "Projects", document: row.NRN })}>
|
||||
В раздел
|
||||
<Button variant="outlined" onClick={() => pOnlineShowDocument({ unitCode: "Projects", document: row.NRN, modal: false })}>
|
||||
К проекту
|
||||
</Button>
|
||||
</>
|
||||
) : panelUnit === PANEL_UNITS.PROJECT_STAGES ? (
|
||||
<>
|
||||
<Button fullWidth variant="contained" onClick={() => showStageArts({ sender: row })}>
|
||||
<Button variant="outlined" onClick={() => showStageArts({ sender: row })}>
|
||||
Статьи
|
||||
</Button>
|
||||
<Button fullWidth variant="contained" onClick={() => showContracts({ sender: row })}>
|
||||
<Button variant="outlined" onClick={() => showContracts({ sender: row })}>
|
||||
Сисполнители
|
||||
</Button>
|
||||
<Button fullWidth variant="contained" onClick={() => pOnlineShowDocument({ unitCode: "ProjectsStages", document: row.NRN })}>
|
||||
В раздел
|
||||
<Button
|
||||
variant="outlined"
|
||||
onClick={() =>
|
||||
pOnlineShowUnit({
|
||||
unitCode: "Projects",
|
||||
inputParameters: [
|
||||
{ name: "in_RN", value: row.NPROJECT },
|
||||
{ name: "in_STAGE_RN", value: row.NRN }
|
||||
],
|
||||
modal: false
|
||||
})
|
||||
}
|
||||
>
|
||||
К этапу
|
||||
</Button>
|
||||
</>
|
||||
) : panelUnit === PANEL_UNITS.PROJECT_STAGE_CONTRACTS ? (
|
||||
<Button
|
||||
fullWidth
|
||||
variant="contained"
|
||||
onClick={() => pOnlineShowDocument({ unitCode: row.SLNK_UNIT_SDOC_PREF, document: row.NLNK_DOCUMENT_SDOC_PREF })}
|
||||
variant="outlined"
|
||||
onClick={() => pOnlineShowDocument({ unitCode: row.SLNK_UNIT_SDOC_PREF, document: row.NLNK_DOCUMENT_SDOC_PREF, modal: false })}
|
||||
>
|
||||
В раздел
|
||||
К договору
|
||||
</Button>
|
||||
) : null;
|
||||
//Сборка содержимого
|
||||
return (
|
||||
<Box p={2}>
|
||||
<Grid container spacing={2}>
|
||||
<Grid item xs={12} md={1}>
|
||||
<Stack spacing={2}>{linkButtons()}</Stack>
|
||||
<Grid item xs={12} md={12}>
|
||||
<Stack spacing={2} direction="row">
|
||||
{linkButtons()}
|
||||
</Stack>
|
||||
</Grid>
|
||||
<Grid item xs={12} md={11}>
|
||||
<Grid item xs={12} md={12}>
|
||||
<Paper elevation={5}>
|
||||
<Table sx={{ width: "100%" }} size="small">
|
||||
<TableBody>
|
||||
|
@ -11,23 +11,34 @@ import React, { useState, useCallback, useEffect, useContext } from "react"; //
|
||||
import { Box, Grid, Paper, Fab, Icon } from "@mui/material"; //Интерфейсные компоненты
|
||||
import { object2Base64XML } from "../../core/utils"; //Вспомогательные процедуры и функции
|
||||
import { TEXTS } from "../../../app.text"; //Тектовые ресурсы и константы
|
||||
import { P8PDataGrid, P8P_DATA_GRID_SIZE } from "../../components/p8p_data_grid"; //Таблица данных
|
||||
import { APP_STYLES } from "../../../app.styles"; //Типовые стили
|
||||
import { APP_BAR_HEIGHT } from "../../components/p8p_app_workspace"; //Заголовок страницы
|
||||
import { P8PDataGrid, P8P_DATA_GRID_SIZE, P8P_DATA_GRID_MORE_HEIGHT, P8P_DATA_GRID_FILTERS_HEIGHT } from "../../components/p8p_data_grid"; //Таблица данных
|
||||
import { P8PFullScreenDialog } from "../../components/p8p_fullscreen_dialog"; //Полноэкранный диалог
|
||||
import { P8PChart } from "../../components/p8p_chart"; //График
|
||||
import { BackEndСtx } from "../../context/backend"; //Контекст взаимодействия с сервером
|
||||
import { ApplicationСtx } from "../../context/application"; //Контекст приложения
|
||||
import { MessagingСtx } from "../../context/messaging"; //Контекст сообщений
|
||||
import { P8P_DATA_GRID_CONFIG_PROPS } from "../../config_wrapper"; //Подключение компонентов к настройкам приложения
|
||||
import { PANEL_UNITS, headCellRender, dataCellRender, valueFormatter, rowExpandRender } from "./layouts"; //Дополнительная разметка и вёрстка клиентских элементов
|
||||
import { COMMON_PROJECTS_STYLES, PANEL_UNITS, headCellRender, dataCellRender, valueFormatter, rowExpandRender } from "./layouts"; //Дополнительная разметка и вёрстка клиентских элементов
|
||||
import { Stages } from "./stages"; //Список этапов проекта
|
||||
|
||||
//---------
|
||||
//Константы
|
||||
//---------
|
||||
|
||||
//Высота графиков
|
||||
const CHART_HEIGHT = "300px";
|
||||
|
||||
//Стили
|
||||
const STYLES = {
|
||||
CHART: { maxHeight: "300px", display: "flex", justifyContent: "center" },
|
||||
TABLE_PROJECTS: (showCharts, morePages, filters) => ({
|
||||
height: `calc(100vh - ${APP_BAR_HEIGHT} - ${showCharts ? CHART_HEIGHT : "0px"} - ${morePages ? P8P_DATA_GRID_MORE_HEIGHT : "0px"} - ${
|
||||
filters ? P8P_DATA_GRID_FILTERS_HEIGHT : "0px"
|
||||
} - 25px)`,
|
||||
...APP_STYLES.SCROLL
|
||||
}),
|
||||
CHART: { maxHeight: CHART_HEIGHT, display: "flex", justifyContent: "center" },
|
||||
CHART_PAPER: { height: "100%" },
|
||||
CHART_FAB: { position: "absolute", top: 80, left: 16 }
|
||||
};
|
||||
@ -84,11 +95,12 @@ const Projects = () => {
|
||||
});
|
||||
setProjectsDataGrid(pv => ({
|
||||
...pv,
|
||||
columnsDef: data.XCOLUMNS_DEF ? [...data.XCOLUMNS_DEF] : pv.columnsDef,
|
||||
rows: pv.pageNumber == 1 ? [...(data.XROWS || [])] : [...pv.rows, ...(data.XROWS || [])],
|
||||
...data.XDATA_GRID,
|
||||
columnsDef: data.XDATA_GRID.columnsDef ? [...data.XDATA_GRID.columnsDef] : pv.columnsDef,
|
||||
rows: pv.pageNumber == 1 ? [...(data.XDATA_GRID.rows || [])] : [...pv.rows, ...(data.XDATA_GRID.rows || [])],
|
||||
dataLoaded: true,
|
||||
reload: false,
|
||||
morePages: (data.XROWS || []).length >= configSystemPageSize
|
||||
morePages: (data.XDATA_GRID.rows || []).length >= configSystemPageSize
|
||||
}));
|
||||
}
|
||||
}, [
|
||||
@ -219,12 +231,16 @@ const Projects = () => {
|
||||
{projectsDataGrid.dataLoaded ? (
|
||||
<P8PDataGrid
|
||||
{...P8P_DATA_GRID_CONFIG_PROPS}
|
||||
containerComponentProps={{
|
||||
sx: STYLES.TABLE_PROJECTS(showCharts, projectsDataGrid.morePages, (projectsDataGrid.filters || []).length > 0)
|
||||
}}
|
||||
columnsDef={projectsDataGrid.columnsDef}
|
||||
rows={projectsDataGrid.rows}
|
||||
size={P8P_DATA_GRID_SIZE.SMALL}
|
||||
filtersInitial={projectsDataGrid.filters}
|
||||
morePages={projectsDataGrid.morePages}
|
||||
reloading={projectsDataGrid.reload}
|
||||
fixedHeader={true}
|
||||
expandable={true}
|
||||
headCellRender={headCellRender}
|
||||
dataCellRender={prms => dataCellRender({ ...prms, panelUnit: PANEL_UNITS.PROJECTS, showStages })}
|
||||
@ -244,7 +260,11 @@ const Projects = () => {
|
||||
/>
|
||||
) : null}
|
||||
{projectsDataGrid.selectedProject ? (
|
||||
<P8PFullScreenDialog title={`Этапы проекта "${projectsDataGrid.selectedProject.SNAME_USL}"`} onClose={handleStagesClose}>
|
||||
<P8PFullScreenDialog
|
||||
title={`Этапы проекта "${projectsDataGrid.selectedProject.SNAME_USL}"`}
|
||||
onClose={handleStagesClose}
|
||||
contentProps={{ sx: COMMON_PROJECTS_STYLES.FULL_SCREEN_DIALOG_CONTENT }}
|
||||
>
|
||||
<Stages
|
||||
project={projectsDataGrid.selectedProject.NRN}
|
||||
projectName={projectsDataGrid.selectedProject.SNAME_USL}
|
||||
|
@ -12,13 +12,27 @@ import PropTypes from "prop-types"; //Контроль свойств компо
|
||||
import { Box } from "@mui/material"; //Интерфейсные компоненты
|
||||
import { object2Base64XML } from "../../core/utils"; //Вспомогательные процедуры и функции
|
||||
import { TEXTS } from "../../../app.text"; //Тектовые ресурсы и константы
|
||||
import { P8PDataGrid, P8P_DATA_GRID_SIZE, P8P_DATA_GRID_FILTER_SHAPE } from "../../components/p8p_data_grid"; //Таблица данных
|
||||
import { APP_STYLES } from "../../../app.styles"; //Типовые стили
|
||||
import { APP_BAR_HEIGHT } from "../../components/p8p_app_workspace"; //Заголовок страницы
|
||||
import { P8PDataGrid, P8P_DATA_GRID_SIZE, P8P_DATA_GRID_FILTER_SHAPE, P8P_DATA_GRID_FILTERS_HEIGHT } from "../../components/p8p_data_grid"; //Таблица данных
|
||||
import { BackEndСtx } from "../../context/backend"; //Контекст взаимодействия с сервером
|
||||
import { ApplicationСtx } from "../../context/application"; //Контекст приложения
|
||||
import { MessagingСtx } from "../../context/messaging"; //Контекст сообщений
|
||||
import { P8P_DATA_GRID_CONFIG_PROPS } from "../../config_wrapper"; //Подключение компонентов к настройкам приложения
|
||||
import { PANEL_UNITS, dataCellRender, valueFormatter } from "./layouts"; //Дополнительная разметка и вёрстка клиентских элементов
|
||||
|
||||
//---------
|
||||
//Константы
|
||||
//---------
|
||||
|
||||
//Стили
|
||||
const STYLES = {
|
||||
TABLE_ARTS: filters => ({
|
||||
height: `calc(100vh - ${APP_BAR_HEIGHT} - ${filters ? P8P_DATA_GRID_FILTERS_HEIGHT : "0px"} - 16px)`,
|
||||
...APP_STYLES.SCROLL
|
||||
})
|
||||
};
|
||||
|
||||
//-----------
|
||||
//Тело модуля
|
||||
//-----------
|
||||
@ -57,8 +71,9 @@ const StageArts = ({ stage, filters }) => {
|
||||
});
|
||||
setStageArtsDataGrid(pv => ({
|
||||
...pv,
|
||||
columnsDef: data.XCOLUMNS_DEF ? [...data.XCOLUMNS_DEF] : pv.columnsDef,
|
||||
rows: [...(data.XROWS || [])],
|
||||
...data.XDATA_GRID,
|
||||
columnsDef: data.XDATA_GRID.columnsDef ? [...data.XDATA_GRID.columnsDef] : pv.columnsDef,
|
||||
rows: [...(data.XDATA_GRID.rows || [])],
|
||||
dataLoaded: true,
|
||||
reload: false
|
||||
}));
|
||||
@ -99,10 +114,12 @@ const StageArts = ({ stage, filters }) => {
|
||||
{stageArtsDataGrid.dataLoaded ? (
|
||||
<P8PDataGrid
|
||||
{...P8P_DATA_GRID_CONFIG_PROPS}
|
||||
containerComponentProps={{ sx: STYLES.TABLE_ARTS((stageArtsDataGrid.filters || []).length > 0), elevation: 0 }}
|
||||
columnsDef={stageArtsDataGrid.columnsDef}
|
||||
filtersInitial={filters}
|
||||
rows={stageArtsDataGrid.rows}
|
||||
size={P8P_DATA_GRID_SIZE.SMALL}
|
||||
fixedHeader={true}
|
||||
morePages={false}
|
||||
reloading={stageArtsDataGrid.reload}
|
||||
dataCellRender={prms => dataCellRender({ ...prms, panelUnit: PANEL_UNITS.PROJECT_STAGE_ARTS, showCostNotes, showContracts })}
|
||||
|
@ -12,13 +12,35 @@ import PropTypes from "prop-types"; //Контроль свойств компо
|
||||
import { Box } from "@mui/material"; //Интерфейсные компоненты
|
||||
import { object2Base64XML } from "../../core/utils"; //Вспомогательные процедуры и функции
|
||||
import { TEXTS } from "../../../app.text"; //Тектовые ресурсы и константы
|
||||
import { P8PDataGrid, P8P_DATA_GRID_SIZE, P8P_DATA_GRID_FILTER_SHAPE } from "../../components/p8p_data_grid"; //Таблица данных
|
||||
import { APP_STYLES } from "../../../app.styles"; //Типовые стили
|
||||
import { APP_BAR_HEIGHT } from "../../components/p8p_app_workspace"; //Заголовок страницы
|
||||
import {
|
||||
P8PDataGrid,
|
||||
P8P_DATA_GRID_SIZE,
|
||||
P8P_DATA_GRID_FILTER_SHAPE,
|
||||
P8P_DATA_GRID_MORE_HEIGHT,
|
||||
P8P_DATA_GRID_FILTERS_HEIGHT
|
||||
} from "../../components/p8p_data_grid"; //Таблица данных
|
||||
import { BackEndСtx } from "../../context/backend"; //Контекст взаимодействия с сервером
|
||||
import { ApplicationСtx } from "../../context/application"; //Контекст приложения
|
||||
import { MessagingСtx } from "../../context/messaging"; //Контекст сообщений
|
||||
import { P8P_DATA_GRID_CONFIG_PROPS } from "../../config_wrapper"; //Подключение компонентов к настройкам приложения
|
||||
import { PANEL_UNITS, dataCellRender, valueFormatter, rowExpandRender } from "./layouts"; //Дополнительная разметка и вёрстка клиентских элементов
|
||||
|
||||
//---------
|
||||
//Константы
|
||||
//---------
|
||||
|
||||
//Стили
|
||||
const STYLES = {
|
||||
TABLE_CONTRACTS: (morePages, filters) => ({
|
||||
height: `calc(100vh - ${APP_BAR_HEIGHT} - ${morePages ? P8P_DATA_GRID_MORE_HEIGHT : "0px"} - ${
|
||||
filters ? P8P_DATA_GRID_FILTERS_HEIGHT : "0px"
|
||||
} - 16px)`,
|
||||
...APP_STYLES.SCROLL
|
||||
})
|
||||
};
|
||||
|
||||
//-----------
|
||||
//Тело модуля
|
||||
//-----------
|
||||
@ -67,11 +89,12 @@ const StageContracts = ({ stage, filters }) => {
|
||||
});
|
||||
setStageContractsDataGrid(pv => ({
|
||||
...pv,
|
||||
columnsDef: data.XCOLUMNS_DEF ? [...data.XCOLUMNS_DEF] : pv.columnsDef,
|
||||
rows: pv.pageNumber == 1 ? [...(data.XROWS || [])] : [...pv.rows, ...(data.XROWS || [])],
|
||||
...data.XDATA_GRID,
|
||||
columnsDef: data.XDATA_GRID.columnsDef ? [...data.XDATA_GRID.columnsDef] : pv.columnsDef,
|
||||
rows: pv.pageNumber == 1 ? [...(data.XDATA_GRID.rows || [])] : [...pv.rows, ...(data.XDATA_GRID.rows || [])],
|
||||
dataLoaded: true,
|
||||
reload: false,
|
||||
morePages: (data.XROWS || []).length >= configSystemPageSize
|
||||
morePages: (data.XDATA_GRID.rows || []).length >= configSystemPageSize
|
||||
}));
|
||||
}
|
||||
}, [
|
||||
@ -136,12 +159,17 @@ const StageContracts = ({ stage, filters }) => {
|
||||
{stageContractsDataGrid.dataLoaded ? (
|
||||
<P8PDataGrid
|
||||
{...P8P_DATA_GRID_CONFIG_PROPS}
|
||||
containerComponentProps={{
|
||||
sx: STYLES.TABLE_CONTRACTS(stageContractsDataGrid.morePages, (stageContractsDataGrid.filters || []).length > 0),
|
||||
elevation: 0
|
||||
}}
|
||||
columnsDef={stageContractsDataGrid.columnsDef}
|
||||
filtersInitial={filters}
|
||||
rows={stageContractsDataGrid.rows}
|
||||
size={P8P_DATA_GRID_SIZE.SMALL}
|
||||
morePages={stageContractsDataGrid.morePages}
|
||||
reloading={stageContractsDataGrid.reload}
|
||||
fixedHeader={true}
|
||||
expandable={true}
|
||||
dataCellRender={prms => dataCellRender({ ...prms, panelUnit: PANEL_UNITS.PROJECT_STAGE_CONTRACTS, pOnlineShowDocument })}
|
||||
rowExpandRender={prms =>
|
||||
|
@ -12,7 +12,15 @@ import PropTypes from "prop-types"; //Контроль свойств компо
|
||||
import { Box } from "@mui/material"; //Интерфейсные компоненты
|
||||
import { object2Base64XML } from "../../core/utils"; //Вспомогательные процедуры и функции
|
||||
import { TEXTS } from "../../../app.text"; //Тектовые ресурсы и константы
|
||||
import { P8PDataGrid, P8P_DATA_GRID_SIZE, P8P_DATA_GRID_FILTER_SHAPE } from "../../components/p8p_data_grid"; //Таблица данных
|
||||
import { APP_STYLES } from "../../../app.styles"; //Типовые стили
|
||||
import { APP_BAR_HEIGHT } from "../../components/p8p_app_workspace"; //Заголовок страницы
|
||||
import {
|
||||
P8PDataGrid,
|
||||
P8P_DATA_GRID_SIZE,
|
||||
P8P_DATA_GRID_FILTER_SHAPE,
|
||||
P8P_DATA_GRID_MORE_HEIGHT,
|
||||
P8P_DATA_GRID_FILTERS_HEIGHT
|
||||
} from "../../components/p8p_data_grid"; //Таблица данных
|
||||
import { P8PFullScreenDialog } from "../../components/p8p_fullscreen_dialog"; //Полноэкранный диалог
|
||||
import { StageArts } from "./stage_arts"; //Калькуляция этапа проекта
|
||||
import { StageContracts } from "./stage_contracts"; //Договоры с соисполнителями этапа проекта
|
||||
@ -20,7 +28,21 @@ import { BackEndСtx } from "../../context/backend"; //Контекст взаи
|
||||
import { ApplicationСtx } from "../../context/application"; //Контекст приложения
|
||||
import { MessagingСtx } from "../../context/messaging"; //Контекст сообщений
|
||||
import { P8P_DATA_GRID_CONFIG_PROPS } from "../../config_wrapper"; //Подключение компонентов к настройкам приложения
|
||||
import { PANEL_UNITS, headCellRender, dataCellRender, valueFormatter, rowExpandRender } from "./layouts"; //Дополнительная разметка и вёрстка клиентских элементов
|
||||
import { COMMON_PROJECTS_STYLES, PANEL_UNITS, headCellRender, dataCellRender, valueFormatter, rowExpandRender } from "./layouts"; //Дополнительная разметка и вёрстка клиентских элементов
|
||||
|
||||
//---------
|
||||
//Константы
|
||||
//---------
|
||||
|
||||
//Стили
|
||||
const STYLES = {
|
||||
TABLE_STAGES: (morePages, filters) => ({
|
||||
height: `calc(100vh - ${APP_BAR_HEIGHT} - ${morePages ? P8P_DATA_GRID_MORE_HEIGHT : "0px"} - ${
|
||||
filters ? P8P_DATA_GRID_FILTERS_HEIGHT : "0px"
|
||||
} - 16px)`,
|
||||
...APP_STYLES.SCROLL
|
||||
})
|
||||
};
|
||||
|
||||
//-----------
|
||||
//Тело модуля
|
||||
@ -71,11 +93,12 @@ const Stages = ({ project, projectName, filters }) => {
|
||||
});
|
||||
setStagesDataGrid(pv => ({
|
||||
...pv,
|
||||
columnsDef: data.XCOLUMNS_DEF ? [...data.XCOLUMNS_DEF] : pv.columnsDef,
|
||||
rows: pv.pageNumber == 1 ? [...(data.XROWS || [])] : [...pv.rows, ...(data.XROWS || [])],
|
||||
...data.XDATA_GRID,
|
||||
columnsDef: data.XDATA_GRID.columnsDef ? [...data.XDATA_GRID.columnsDef] : pv.columnsDef,
|
||||
rows: pv.pageNumber == 1 ? [...(data.XDATA_GRID.rows || [])] : [...pv.rows, ...(data.XDATA_GRID.rows || [])],
|
||||
dataLoaded: true,
|
||||
reload: false,
|
||||
morePages: (data.XROWS || []).length >= configSystemPageSize
|
||||
morePages: (data.XDATA_GRID.rows || []).length >= configSystemPageSize
|
||||
}));
|
||||
}
|
||||
}, [
|
||||
@ -154,12 +177,17 @@ const Stages = ({ project, projectName, filters }) => {
|
||||
{stagesDataGrid.dataLoaded ? (
|
||||
<P8PDataGrid
|
||||
{...P8P_DATA_GRID_CONFIG_PROPS}
|
||||
containerComponentProps={{
|
||||
sx: STYLES.TABLE_STAGES(stagesDataGrid.morePages, (stagesDataGrid.filters || []).length > 0),
|
||||
elevation: 0
|
||||
}}
|
||||
columnsDef={stagesDataGrid.columnsDef}
|
||||
filtersInitial={filters}
|
||||
rows={stagesDataGrid.rows}
|
||||
size={P8P_DATA_GRID_SIZE.SMALL}
|
||||
morePages={stagesDataGrid.morePages}
|
||||
reloading={stagesDataGrid.reload}
|
||||
fixedHeader={true}
|
||||
expandable={true}
|
||||
headCellRender={headCellRender}
|
||||
dataCellRender={prms => dataCellRender({ ...prms, panelUnit: PANEL_UNITS.PROJECT_STAGES, showStageArts, showContracts })}
|
||||
@ -168,6 +196,7 @@ const Stages = ({ project, projectName, filters }) => {
|
||||
...prms,
|
||||
panelUnit: PANEL_UNITS.PROJECT_STAGES,
|
||||
pOnlineShowDocument,
|
||||
pOnlineShowUnit,
|
||||
showStageArts,
|
||||
showContracts,
|
||||
showPayNotes,
|
||||
@ -185,6 +214,7 @@ const Stages = ({ project, projectName, filters }) => {
|
||||
<P8PFullScreenDialog
|
||||
title={`Договоры этапа "${stagesDataGrid.selectedStageNumb}" проекта "${projectName}"`}
|
||||
onClose={handleStageContractsClose}
|
||||
contentProps={{ sx: COMMON_PROJECTS_STYLES.FULL_SCREEN_DIALOG_CONTENT }}
|
||||
>
|
||||
<StageContracts stage={stagesDataGrid.showStageContracts} filters={stagesDataGrid.stageContractsFilters} />
|
||||
</P8PFullScreenDialog>
|
||||
@ -193,6 +223,7 @@ const Stages = ({ project, projectName, filters }) => {
|
||||
<P8PFullScreenDialog
|
||||
title={`Калькуляция этапа "${stagesDataGrid.selectedStageNumb}" проекта "${projectName}"`}
|
||||
onClose={handleStageArtsClose}
|
||||
contentProps={{ sx: COMMON_PROJECTS_STYLES.FULL_SCREEN_DIALOG_CONTENT }}
|
||||
>
|
||||
<StageArts stage={stagesDataGrid.showStageArts} filters={stagesDataGrid.stageArtsFilters} />
|
||||
</P8PFullScreenDialog>
|
||||
|
@ -55,11 +55,10 @@ const PrjGraph = () => {
|
||||
const data = await executeStored({ stored: "PKG_P8PANELS_PROJECTS.GRAPH", args: {}, respArg: "COUT" });
|
||||
setdataGrid(pv => ({
|
||||
...pv,
|
||||
fixedHeader: data.XDATA_GRID.fixedHeader,
|
||||
fixedColumns: data.XDATA_GRID.fixedColumns,
|
||||
columnsDef: data.XCOLUMNS_DEF ? [...data.XCOLUMNS_DEF] : pv.columnsDef,
|
||||
rows: [...(data.XROWS || [])],
|
||||
groups: [...(data.XGROUPS || [])],
|
||||
...data.XDATA_GRID,
|
||||
columnsDef: data.XDATA_GRID.columnsDef ? [...data.XDATA_GRID.columnsDef] : pv.columnsDef,
|
||||
rows: [...(data.XDATA_GRID.rows || [])],
|
||||
groups: [...(data.XDATA_GRID.groups || [])],
|
||||
dataLoaded: true,
|
||||
reload: false
|
||||
}));
|
||||
|
@ -57,11 +57,12 @@ const LabFactRptDtl = ({ periodId, title, onHide }) => {
|
||||
});
|
||||
setFactRptDtl(pv => ({
|
||||
...pv,
|
||||
columnsDef: data.XCOLUMNS_DEF ? [...data.XCOLUMNS_DEF] : pv.columnsDef,
|
||||
rows: pv.pageNumber == 1 ? [...(data.XROWS || [])] : [...pv.rows, ...(data.XROWS || [])],
|
||||
...data.XDATA_GRID,
|
||||
columnsDef: data.XDATA_GRID.columnsDef ? [...data.XDATA_GRID.columnsDef] : pv.columnsDef,
|
||||
rows: pv.pageNumber == 1 ? [...(data.XDATA_GRID.rows || [])] : [...pv.rows, ...(data.XDATA_GRID.rows || [])],
|
||||
dataLoaded: true,
|
||||
reload: false,
|
||||
morePages: (data.XROWS || []).length >= configSystemPageSize
|
||||
morePages: (data.XDATA_GRID.rows || []).length >= configSystemPageSize
|
||||
}));
|
||||
}
|
||||
}, [
|
||||
|
@ -56,11 +56,12 @@ const LabPlanFOTDtl = ({ periodId, title, onHide }) => {
|
||||
});
|
||||
setPlanFOTDtl(pv => ({
|
||||
...pv,
|
||||
columnsDef: data.XCOLUMNS_DEF ? [...data.XCOLUMNS_DEF] : pv.columnsDef,
|
||||
rows: pv.pageNumber == 1 ? [...(data.XROWS || [])] : [...pv.rows, ...(data.XROWS || [])],
|
||||
...data.XDATA_GRID,
|
||||
columnsDef: data.XDATA_GRID.columnsDef ? [...data.XDATA_GRID.columnsDef] : pv.columnsDef,
|
||||
rows: pv.pageNumber == 1 ? [...(data.XDATA_GRID.rows || [])] : [...pv.rows, ...(data.XDATA_GRID.rows || [])],
|
||||
dataLoaded: true,
|
||||
reload: false,
|
||||
morePages: (data.XROWS || []).length >= configSystemPageSize
|
||||
morePages: (data.XDATA_GRID.rows || []).length >= configSystemPageSize
|
||||
}));
|
||||
}
|
||||
}, [
|
||||
|
@ -61,11 +61,12 @@ const LabPlanJobsDtl = ({ periodId, title, onHide, onProjectClick }) => {
|
||||
});
|
||||
setPlanJobsDtl(pv => ({
|
||||
...pv,
|
||||
columnsDef: data.XCOLUMNS_DEF ? [...data.XCOLUMNS_DEF] : pv.columnsDef,
|
||||
rows: pv.pageNumber == 1 ? [...(data.XROWS || [])] : [...pv.rows, ...(data.XROWS || [])],
|
||||
...data.XDATA_GRID,
|
||||
columnsDef: data.XDATA_GRID.columnsDef ? [...data.XDATA_GRID.columnsDef] : pv.columnsDef,
|
||||
rows: pv.pageNumber == 1 ? [...(data.XDATA_GRID.rows || [])] : [...pv.rows, ...(data.XDATA_GRID.rows || [])],
|
||||
dataLoaded: true,
|
||||
reload: false,
|
||||
morePages: (data.XROWS || []).length >= configSystemPageSize
|
||||
morePages: (data.XDATA_GRID.rows || []).length >= configSystemPageSize
|
||||
}));
|
||||
}
|
||||
}, [
|
||||
|
@ -265,8 +265,7 @@ const PrjJobs = () => {
|
||||
selectedProjectJobsLoaded: false,
|
||||
selectedProject: null,
|
||||
selectedProjectDocRn: null,
|
||||
selectedProjectGanttDef: {},
|
||||
selectedProjectTasks: [],
|
||||
gantt: {},
|
||||
showInitDialog: false
|
||||
});
|
||||
|
||||
@ -308,8 +307,9 @@ const PrjJobs = () => {
|
||||
setState(pv => ({
|
||||
...pv,
|
||||
selectedProjectJobsLoaded: true,
|
||||
selectedProjectGanttDef: tasksOnly === true ? { ...pv.selectedProjectGanttDef } : data.XGANTT_DEF ? { ...data.XGANTT_DEF } : {},
|
||||
selectedProjectTasks: [...data.XGANTT_TASKS]
|
||||
gantt: {
|
||||
...(tasksOnly === true ? { ...pv.gantt, tasks: [...data.XGANTT.tasks] } : data.XGANTT ? { ...data.XGANTT } : {})
|
||||
}
|
||||
}));
|
||||
},
|
||||
[executeStored, state.ident, state.selectedProject]
|
||||
@ -394,8 +394,7 @@ const PrjJobs = () => {
|
||||
selectedProject: project,
|
||||
selectedProjectDocRn: projectDocRn,
|
||||
selectedProjectJobsLoaded: false,
|
||||
selectedProjectTasks: [],
|
||||
selectedProjectGanttDef: {},
|
||||
gantt: {},
|
||||
showProjectsList: false
|
||||
}));
|
||||
};
|
||||
@ -407,8 +406,7 @@ const PrjJobs = () => {
|
||||
selectedProjectJobsLoaded: false,
|
||||
selectedProject: null,
|
||||
selectedProjectDocRn: null,
|
||||
selectedProjectTasks: [],
|
||||
selectedProjectGanttDef: {},
|
||||
gantt: {},
|
||||
showProjectsList: false
|
||||
}));
|
||||
|
||||
@ -515,11 +513,10 @@ const PrjJobs = () => {
|
||||
{state.selectedProjectJobsLoaded ? (
|
||||
<P8PGantt
|
||||
{...P8P_GANTT_CONFIG_PROPS}
|
||||
{...state.selectedProjectGanttDef}
|
||||
{...state.gantt}
|
||||
containerStyle={STYLES.GANTT_CONTAINER}
|
||||
titleStyle={STYLES.GANTT_TITLE}
|
||||
onTitleClick={handleTitleClick}
|
||||
tasks={state.selectedProjectTasks}
|
||||
onTaskDatesChange={handleTaskDatesChange}
|
||||
taskAttributeRenderer={taskAttributeRenderer}
|
||||
/>
|
||||
|
@ -79,11 +79,12 @@ const ResMon = ({ ident, onPlanJobsDtlProjectClick }) => {
|
||||
});
|
||||
setPeriods(pv => ({
|
||||
...pv,
|
||||
columnsDef: data.XCOLUMNS_DEF ? [...data.XCOLUMNS_DEF] : pv.columnsDef,
|
||||
rows: pv.pageNumber == 1 ? [...(data.XROWS || [])] : [...pv.rows, ...(data.XROWS || [])],
|
||||
...data.XDATA_GRID,
|
||||
columnsDef: data.XDATA_GRID.columnsDef ? [...data.XDATA_GRID.columnsDef] : pv.columnsDef,
|
||||
rows: pv.pageNumber == 1 ? [...(data.XDATA_GRID.rows || [])] : [...pv.rows, ...(data.XDATA_GRID.rows || [])],
|
||||
dataLoaded: true,
|
||||
reload: false,
|
||||
morePages: (data.XROWS || []).length >= configSystemPageSize
|
||||
morePages: (data.XDATA_GRID.rows || []).length >= configSystemPageSize
|
||||
}));
|
||||
}
|
||||
}, [ident, peridos.reload, peridos.orders, peridos.dataLoaded, peridos.pageNumber, executeStored, configSystemPageSize, SERV_DATA_TYPE_CLOB]);
|
||||
|
@ -97,16 +97,15 @@ const useConf = (currentTab, handleSectionChange) => {
|
||||
sections.map(s => {
|
||||
let dg = {};
|
||||
Object.assign(dg, dataGrid, {
|
||||
...s.XDATA.XDATA_GRID,
|
||||
rn: s.NRN,
|
||||
code: s.SCODE,
|
||||
name: s.SNAME,
|
||||
delete_allow: s.NDELETE_ALLOW,
|
||||
dataLoaded: true,
|
||||
columnsDef: [...(s.XDATA.XCOLUMNS_DEF || [])],
|
||||
groups: [...(s.XDATA.XGROUPS || [])],
|
||||
rows: [...(s.XDATA.XROWS || [])],
|
||||
fixedHeader: s.XDATA.XDATA_GRID.fixedHeader,
|
||||
fixedColumns: s.XDATA.XDATA_GRID.fixedColumns,
|
||||
columnsDef: [...(s.XDATA.XDATA_GRID.columnsDef || [])],
|
||||
groups: [...(s.XDATA.XDATA_GRID.groups || [])],
|
||||
rows: [...(s.XDATA.XDATA_GRID.rows || [])],
|
||||
reload: false
|
||||
});
|
||||
//Если раздел имеет составы показателей
|
||||
|
@ -33,7 +33,7 @@ const STYLES = {
|
||||
//Пример: Графики "P8PChart"
|
||||
const Chart = ({ title }) => {
|
||||
//Собственное состояние - график
|
||||
const [chart, setChart] = useState({ loaded: false, labels: [], datasets: [] });
|
||||
const [chart, setChart] = useState({ loaded: false });
|
||||
|
||||
//Подключение к контексту взаимодействия с сервером
|
||||
const { executeStored } = useContext(BackEndСtx);
|
||||
|
301
app/panels/samples/cyclogram.js
Normal file
301
app/panels/samples/cyclogram.js
Normal file
@ -0,0 +1,301 @@
|
||||
/*
|
||||
Парус 8 - Панели мониторинга - Примеры для разработчиков
|
||||
Пример: Циклограмма "P8PCyclogram"
|
||||
*/
|
||||
|
||||
//---------------------
|
||||
//Подключение библиотек
|
||||
//---------------------
|
||||
|
||||
import React, { useState, useContext, useCallback, useEffect } from "react"; //Классы React
|
||||
import PropTypes from "prop-types"; //Контроль свойств компонента
|
||||
import {
|
||||
Typography,
|
||||
Grid,
|
||||
Button,
|
||||
Box,
|
||||
DialogContent,
|
||||
List,
|
||||
ListItem,
|
||||
ListItemText,
|
||||
Divider,
|
||||
TextField,
|
||||
DialogActions,
|
||||
Stack,
|
||||
Icon
|
||||
} from "@mui/material"; //Интерфейсные элементы
|
||||
import { formatDateJSONDateOnly, formatDateRF } from "../../core/utils"; //Вспомогательные функции
|
||||
import { APP_BAR_HEIGHT } from "../../components/p8p_app_workspace"; //Заголовок страницы
|
||||
import { P8PCyclogram } from "../../components/p8p_cyclogram"; //Циклограмма
|
||||
import { P8P_CYCLOGRAM_CONFIG_PROPS } from "../../config_wrapper"; //Подключение компонентов к настройкам приложения
|
||||
import { BackEndСtx } from "../../context/backend"; //Контекст взаимодействия с сервером
|
||||
|
||||
//---------
|
||||
//Константы
|
||||
//---------
|
||||
|
||||
//Отступ контейнера страницы от заголовка
|
||||
const CONTAINER_PADDING_TOP = "20px";
|
||||
|
||||
//Высота заголовка страницы
|
||||
const TITLE_HEIGHT = "47px";
|
||||
|
||||
//Высота строк
|
||||
const LINE_HEIGHT = 30;
|
||||
|
||||
//Стили
|
||||
const STYLES = {
|
||||
CONTAINER: { textAlign: "center", paddingTop: CONTAINER_PADDING_TOP },
|
||||
TITLE: { paddingBottom: "15px", height: TITLE_HEIGHT },
|
||||
CYCLOGRAM_CONTAINER: {
|
||||
height: `calc(100vh - ${APP_BAR_HEIGHT} - ${TITLE_HEIGHT} - ${CONTAINER_PADDING_TOP})`,
|
||||
width: "100vw",
|
||||
paddingTop: "5px"
|
||||
},
|
||||
TASK_EDITOR_CONTENT: { minWidth: 400, overflowX: "auto" },
|
||||
TASK_EDITOR_LIST: { width: "100%", minWidth: 300, maxWidth: 700, bgcolor: "background.paper" },
|
||||
GROUP_HEADER: height => ({
|
||||
border: "1px solid",
|
||||
backgroundColor: "#ecf8fb",
|
||||
height: height,
|
||||
borderRadius: "10px",
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "space-around"
|
||||
})
|
||||
};
|
||||
|
||||
//---------------------------------------------
|
||||
//Вспомогательные функции форматирования данных
|
||||
//---------------------------------------------
|
||||
|
||||
//Диалог открытия задачи
|
||||
const CustomTaskDialog = ({ task, ident, handleReload, close }) => {
|
||||
//Собственное состояние
|
||||
const [taskDates, setTaskDates] = useState({ start: task.ddate_start, end: task.ddate_end });
|
||||
|
||||
//Тип проекта
|
||||
const textType = task.type === 0 ? "Задачи проекта" : task.type === 1 ? "Этап проекта" : "Работа проекта";
|
||||
|
||||
//Подключение к контексту взаимодействия с сервером
|
||||
const { executeStored } = useContext(BackEndСtx);
|
||||
|
||||
//Изменение дат задачи
|
||||
const changeDates = useCallback(async () => {
|
||||
//Изменяем даты задачи
|
||||
await executeStored({
|
||||
stored: "PKG_P8PANELS_SAMPLES.CYCLOGRAM_TASK_MODIFY",
|
||||
args: {
|
||||
NIDENT: ident,
|
||||
NRN: task.rn,
|
||||
SDATE_FROM: formatDateRF(taskDates.start),
|
||||
SDATE_TO: formatDateRF(taskDates.end)
|
||||
}
|
||||
});
|
||||
handleReload();
|
||||
close();
|
||||
}, [close, executeStored, handleReload, ident, task.rn, taskDates.end, taskDates.start]);
|
||||
|
||||
//При нажатии OK
|
||||
const handleOk = () => {
|
||||
//Изменяем даты задачи
|
||||
changeDates();
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<DialogContent sx={STYLES.TASK_EDITOR_CONTENT}>
|
||||
<List sx={STYLES.TASK_EDITOR_LIST}>
|
||||
<ListItem alignItems="flex-start">
|
||||
<ListItemText primary={"Наименование"} secondary={task.fullName} />
|
||||
</ListItem>
|
||||
<Divider component="li" />
|
||||
<ListItem alignItems="flex-start">
|
||||
<ListItemText
|
||||
secondaryTypographyProps={{ component: "span" }}
|
||||
primary={"Начало"}
|
||||
secondary={
|
||||
<TextField
|
||||
error={!taskDates.start}
|
||||
disabled={task.type !== 2}
|
||||
name="start"
|
||||
fullWidth
|
||||
required
|
||||
InputLabelProps={{ shrink: true }}
|
||||
type={"date"}
|
||||
value={taskDates.start}
|
||||
onChange={e => setTaskDates(pv => ({ ...pv, start: e.target.value }))}
|
||||
variant="standard"
|
||||
size="small"
|
||||
margin="normal"
|
||||
></TextField>
|
||||
}
|
||||
/>
|
||||
</ListItem>
|
||||
<Divider component="li" />
|
||||
<ListItem alignItems="flex-start">
|
||||
<ListItemText
|
||||
secondaryTypographyProps={{ component: "span" }}
|
||||
primary={"Окончание"}
|
||||
secondary={
|
||||
<TextField
|
||||
error={!taskDates.end}
|
||||
disabled={task.type !== 2}
|
||||
name="end"
|
||||
fullWidth
|
||||
required
|
||||
InputLabelProps={{ shrink: true }}
|
||||
type={"date"}
|
||||
value={taskDates.end}
|
||||
onChange={e => setTaskDates(pv => ({ ...pv, end: e.target.value }))}
|
||||
variant="standard"
|
||||
size="small"
|
||||
margin="normal"
|
||||
></TextField>
|
||||
}
|
||||
/>
|
||||
</ListItem>
|
||||
<Divider component="li" />
|
||||
<ListItem alignItems="flex-start">
|
||||
<ListItemText
|
||||
primary={"Тип"}
|
||||
secondaryTypographyProps={{ component: "span" }}
|
||||
secondary={
|
||||
<Stack direction="row" gap={0.5}>
|
||||
<Icon title={textType}>{task.type === 0 ? "description" : task.type === 1 ? "check" : "work_outline"}</Icon>
|
||||
{textType}
|
||||
</Stack>
|
||||
}
|
||||
/>
|
||||
</ListItem>
|
||||
</List>
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
<Button onClick={handleOk}>ОК</Button>
|
||||
<Button onClick={close}>Отмена</Button>
|
||||
</DialogActions>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
//Контроль свойств - Диалог открытия задачи
|
||||
CustomTaskDialog.propTypes = {
|
||||
task: PropTypes.object.isRequired,
|
||||
ident: PropTypes.number.isRequired,
|
||||
handleReload: PropTypes.func.isRequired,
|
||||
close: PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
//Заголовок группы
|
||||
const CustomGroupHeader = ({ group }) => {
|
||||
return (
|
||||
<Box sx={STYLES.GROUP_HEADER(group.height)}>
|
||||
<Typography variant="body2">{group.name}</Typography>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
//Контроль свойств - Заголовок группы
|
||||
CustomGroupHeader.propTypes = {
|
||||
group: PropTypes.object.isRequired
|
||||
};
|
||||
|
||||
//Отображение задачи
|
||||
const taskRenderer = ({ task }) => {
|
||||
//Если это задачи проекта
|
||||
if (task.type === 0) {
|
||||
return {
|
||||
taskStyle: { border: "3px solid #ebe058" }
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
//-----------
|
||||
//Тело модуля
|
||||
//-----------
|
||||
|
||||
//Пример: Циклограмма "P8PCyclogram"
|
||||
const Cyclogram = ({ title }) => {
|
||||
//Собственное состояние
|
||||
const [state, setState] = useState({
|
||||
init: false,
|
||||
dataLoaded: false,
|
||||
reload: true,
|
||||
ident: null
|
||||
});
|
||||
|
||||
//Подключение к контексту взаимодействия с сервером
|
||||
const { executeStored } = useContext(BackEndСtx);
|
||||
|
||||
//При необходимости перезагрузки
|
||||
const handleReload = () => {
|
||||
setState(pv => ({ ...pv, reload: true }));
|
||||
};
|
||||
|
||||
//При необходимости обновить данные таблицы
|
||||
useEffect(() => {
|
||||
//Загрузка данных циклограммы с сервера
|
||||
const loadData = async () => {
|
||||
const data = await executeStored({
|
||||
stored: "PKG_P8PANELS_SAMPLES.CYCLOGRAM",
|
||||
args: { NIDENT: state.ident },
|
||||
attributeValueProcessor: (name, val) => (["ddate_start", "ddate_end"].includes(name) ? formatDateJSONDateOnly(val) : val),
|
||||
respArg: "COUT"
|
||||
});
|
||||
setState(pv => ({ ...pv, dataLoaded: true, ...data.XCYCLOGRAM, reload: false }));
|
||||
};
|
||||
//Если указан идентификатор и требуется перезагрузить
|
||||
if (state.ident && state.reload) loadData();
|
||||
}, [state.ident, state.reload, executeStored]);
|
||||
|
||||
//При подключении компонента к странице
|
||||
useEffect(() => {
|
||||
//Инициализация данных циклограммы
|
||||
const initData = async () => {
|
||||
const data = await executeStored({ stored: "PKG_P8PANELS_SAMPLES.CYCLOGRAM_INIT", args: { NIDENT: state.ident } });
|
||||
setState(pv => ({ ...pv, init: true, ident: data.NIDENT, reload: true }));
|
||||
};
|
||||
//Если требуется проинициализировать
|
||||
if (!state.init) {
|
||||
initData();
|
||||
}
|
||||
}, [executeStored, state.ident, state.init]);
|
||||
|
||||
return (
|
||||
<Box>
|
||||
<div style={STYLES.CONTAINER}>
|
||||
<Typography sx={STYLES.TITLE} variant={"h6"}>
|
||||
{title}
|
||||
</Typography>
|
||||
<Grid container direction="column" alignItems="center">
|
||||
<Grid item xs={12}>
|
||||
{state.dataLoaded ? (
|
||||
<P8PCyclogram
|
||||
{...P8P_CYCLOGRAM_CONFIG_PROPS}
|
||||
{...state}
|
||||
containerStyle={STYLES.CYCLOGRAM_CONTAINER}
|
||||
lineHeight={LINE_HEIGHT}
|
||||
taskDialogRenderer={prms => (
|
||||
<CustomTaskDialog task={prms.task} ident={state.ident} handleReload={handleReload} close={prms.close} />
|
||||
)}
|
||||
taskRenderer={prms => taskRenderer(prms)}
|
||||
groupHeaderRenderer={prms => <CustomGroupHeader group={prms.group} />}
|
||||
/>
|
||||
) : null}
|
||||
</Grid>
|
||||
</Grid>
|
||||
</div>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
//Контроль свойств - Пример: Циклограмма "P8PCyclogram"
|
||||
Cyclogram.propTypes = {
|
||||
title: PropTypes.string.isRequired
|
||||
};
|
||||
|
||||
//----------------
|
||||
//Интерфейс модуля
|
||||
//----------------
|
||||
|
||||
export { Cyclogram };
|
@ -15,6 +15,7 @@ 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 { ApplicationСtx } from "../../context/application"; //Контекст приложения
|
||||
import { APP_STYLES } from "../../../app.styles"; //Типовые стили
|
||||
|
||||
//---------
|
||||
//Константы
|
||||
@ -27,7 +28,7 @@ const DATA_GRID_PAGE_SIZE = 5;
|
||||
const STYLES = {
|
||||
CONTAINER: { textAlign: "center", paddingTop: "20px" },
|
||||
TITLE: { paddingBottom: "15px" },
|
||||
DATA_GRID_CONTAINER: { maxWidth: 700, maxHeight: 500, minHeight: 500 }
|
||||
DATA_GRID_CONTAINER: { maxWidth: 700, maxHeight: 500, minHeight: 500, ...APP_STYLES.SCROLL }
|
||||
};
|
||||
|
||||
//---------------------------------------------
|
||||
@ -86,18 +87,14 @@ export const groupCellRender = () => ({ cellStyle: { padding: "2px" } });
|
||||
//Пример: Таблица данных "P8PDataGrid"
|
||||
const DataGrid = ({ title }) => {
|
||||
//Собственное состояние - таблица данных
|
||||
const [dataGrid, setdataGrid] = useState({
|
||||
const [dataGrid, setDataGrid] = useState({
|
||||
dataLoaded: false,
|
||||
columnsDef: [],
|
||||
filters: null,
|
||||
orders: null,
|
||||
groups: [],
|
||||
rows: [],
|
||||
reload: true,
|
||||
pageNumber: 1,
|
||||
morePages: true,
|
||||
fixedHeader: false,
|
||||
fixedColumns: 0
|
||||
expandable: true,
|
||||
reloading: true
|
||||
});
|
||||
|
||||
//Подключение к контексту взаимодействия с сервером
|
||||
@ -108,7 +105,7 @@ const DataGrid = ({ title }) => {
|
||||
|
||||
//Загрузка данных таблицы с сервера
|
||||
const loadData = useCallback(async () => {
|
||||
if (dataGrid.reload) {
|
||||
if (dataGrid.reloading) {
|
||||
const data = await executeStored({
|
||||
stored: "PKG_P8PANELS_SAMPLES.DATA_GRID",
|
||||
args: {
|
||||
@ -120,32 +117,31 @@ const DataGrid = ({ title }) => {
|
||||
},
|
||||
respArg: "COUT"
|
||||
});
|
||||
setdataGrid(pv => ({
|
||||
setDataGrid(pv => ({
|
||||
...pv,
|
||||
fixedHeader: data.XDATA_GRID.fixedHeader,
|
||||
fixedColumns: data.XDATA_GRID.fixedColumns,
|
||||
columnsDef: data.XCOLUMNS_DEF ? [...data.XCOLUMNS_DEF] : pv.columnsDef,
|
||||
rows: pv.pageNumber == 1 ? [...(data.XROWS || [])] : [...pv.rows, ...(data.XROWS || [])],
|
||||
groups: data.XGROUPS
|
||||
...data.XDATA_GRID,
|
||||
columnsDef: data.XDATA_GRID.columnsDef ? [...data.XDATA_GRID.columnsDef] : pv.columnsDef || [],
|
||||
rows: pv.pageNumber == 1 ? [...(data.XDATA_GRID.rows || [])] : [...(pv.rows || []), ...(data.XDATA_GRID.rows || [])],
|
||||
groups: data.XDATA_GRID.groups
|
||||
? pv.pageNumber == 1
|
||||
? [...data.XGROUPS]
|
||||
: [...pv.groups, ...data.XGROUPS.filter(g => !pv.groups.find(pg => pg.name == g.name))]
|
||||
: [...pv.groups],
|
||||
? [...data.XDATA_GRID.groups]
|
||||
: [...(pv.groups || []), ...data.XDATA_GRID.groups.filter(g => !pv.groups.find(pg => pg.name == g.name))]
|
||||
: [...(pv.groups || [])],
|
||||
dataLoaded: true,
|
||||
reload: false,
|
||||
morePages: (data.XROWS || []).length >= DATA_GRID_PAGE_SIZE
|
||||
reloading: false,
|
||||
morePages: (data.XDATA_GRID.rows || []).length >= DATA_GRID_PAGE_SIZE
|
||||
}));
|
||||
}
|
||||
}, [dataGrid.reload, dataGrid.filters, dataGrid.orders, dataGrid.dataLoaded, dataGrid.pageNumber, executeStored, SERV_DATA_TYPE_CLOB]);
|
||||
}, [dataGrid.reloading, dataGrid.filters, dataGrid.orders, dataGrid.dataLoaded, dataGrid.pageNumber, executeStored, SERV_DATA_TYPE_CLOB]);
|
||||
|
||||
//При изменении состояния фильтра
|
||||
const handleFilterChanged = ({ filters }) => setdataGrid(pv => ({ ...pv, filters: [...filters], pageNumber: 1, reload: true }));
|
||||
const handleFilterChanged = ({ filters }) => setDataGrid(pv => ({ ...pv, filters: [...filters], pageNumber: 1, reloading: true }));
|
||||
|
||||
//При изменении состояния сортировки
|
||||
const handleOrderChanged = ({ orders }) => setdataGrid(pv => ({ ...pv, orders: [...orders], pageNumber: 1, reload: true }));
|
||||
const handleOrderChanged = ({ orders }) => setDataGrid(pv => ({ ...pv, orders: [...orders], pageNumber: 1, reloading: true }));
|
||||
|
||||
//При изменении количества отображаемых страниц
|
||||
const handlePagesCountChanged = () => setdataGrid(pv => ({ ...pv, pageNumber: pv.pageNumber + 1, reload: true }));
|
||||
const handlePagesCountChanged = () => setDataGrid(pv => ({ ...pv, pageNumber: pv.pageNumber + 1, reloading: true }));
|
||||
|
||||
//При нажатии на копку контрагента
|
||||
const handleAgnButtonClicked = agnCode => pOnlineShowDocument({ unitCode: "AGNLIST", document: agnCode, inRnParameter: "in_AGNABBR" });
|
||||
@ -153,7 +149,7 @@ const DataGrid = ({ title }) => {
|
||||
//При необходимости обновить данные таблицы
|
||||
useEffect(() => {
|
||||
loadData();
|
||||
}, [dataGrid.reload, loadData]);
|
||||
}, [dataGrid.reloading, loadData]);
|
||||
|
||||
//Генерация содержимого
|
||||
return (
|
||||
@ -167,16 +163,9 @@ const DataGrid = ({ title }) => {
|
||||
{dataGrid.dataLoaded ? (
|
||||
<P8PDataGrid
|
||||
{...P8P_DATA_GRID_CONFIG_PROPS}
|
||||
containerComponentProps={{ elevation: 6, style: STYLES.DATA_GRID_CONTAINER }}
|
||||
columnsDef={dataGrid.columnsDef}
|
||||
groups={dataGrid.groups}
|
||||
rows={dataGrid.rows}
|
||||
{...dataGrid}
|
||||
size={P8P_DATA_GRID_SIZE.LARGE}
|
||||
fixedHeader={dataGrid.fixedHeader}
|
||||
fixedColumns={dataGrid.fixedColumns}
|
||||
filtersInitial={dataGrid.filters}
|
||||
morePages={dataGrid.morePages}
|
||||
reloading={dataGrid.reload}
|
||||
containerComponentProps={{ elevation: 6, sx: STYLES.DATA_GRID_CONTAINER }}
|
||||
valueFormatter={valueFormatter}
|
||||
headCellRender={headCellRender}
|
||||
dataCellRender={dataCellRender}
|
||||
@ -184,7 +173,6 @@ const DataGrid = ({ title }) => {
|
||||
onOrderChanged={handleOrderChanged}
|
||||
onFilterChanged={handleFilterChanged}
|
||||
onPagesCountChanged={handlePagesCountChanged}
|
||||
expandable={true}
|
||||
rowExpandRender={({ row }) => (
|
||||
<Button onClick={() => handleAgnButtonClicked(row.SAGNABBR)}>Показать в разделе</Button>
|
||||
)}
|
||||
|
@ -97,12 +97,10 @@ const taskDialogRenderer = ({ task, close }) => {
|
||||
//Пример: Диаграмма Ганта "P8Gantt"
|
||||
const Gantt = ({ title }) => {
|
||||
//Собственное состояние
|
||||
const [state, setState] = useState({
|
||||
const [gantt, setGantt] = useState({
|
||||
init: false,
|
||||
dataLoaded: false,
|
||||
ident: null,
|
||||
ganttDef: {},
|
||||
ganttTasks: [],
|
||||
useCustomTaskDialog: false
|
||||
});
|
||||
|
||||
@ -113,21 +111,21 @@ const Gantt = ({ title }) => {
|
||||
const loadData = useCallback(async () => {
|
||||
const data = await executeStored({
|
||||
stored: "PKG_P8PANELS_SAMPLES.GANTT",
|
||||
args: { NIDENT: state.ident },
|
||||
args: { NIDENT: gantt.ident },
|
||||
attributeValueProcessor: (name, val) =>
|
||||
name == "numb" ? undefined : ["start", "end"].includes(name) ? formatDateJSONDateOnly(val) : val,
|
||||
respArg: "COUT"
|
||||
});
|
||||
setState(pv => ({ ...pv, dataLoaded: true, ganttDef: { ...data.XGANTT_DEF }, ganttTasks: [...data.XGANTT_TASKS] }));
|
||||
}, [state.ident, executeStored]);
|
||||
setGantt(pv => ({ ...pv, dataLoaded: true, ...data.XGANTT }));
|
||||
}, [gantt.ident, executeStored]);
|
||||
|
||||
//Инициализация данных диаграммы
|
||||
const initData = useCallback(async () => {
|
||||
if (!state.init) {
|
||||
const data = await executeStored({ stored: "PKG_P8PANELS_SAMPLES.GANTT_INIT", args: { NIDENT: state.ident } });
|
||||
setState(pv => ({ ...pv, init: true, ident: data.NIDENT }));
|
||||
if (!gantt.init) {
|
||||
const data = await executeStored({ stored: "PKG_P8PANELS_SAMPLES.GANTT_INIT", args: { NIDENT: gantt.ident } });
|
||||
setGantt(pv => ({ ...pv, init: true, ident: data.NIDENT }));
|
||||
}
|
||||
}, [state.init, state.ident, executeStored]);
|
||||
}, [gantt.init, gantt.ident, executeStored]);
|
||||
|
||||
//Изменение данных диаграммы
|
||||
const modifyData = useCallback(
|
||||
@ -135,13 +133,13 @@ const Gantt = ({ title }) => {
|
||||
try {
|
||||
await executeStored({
|
||||
stored: "PKG_P8PANELS_SAMPLES.GANTT_MODIFY",
|
||||
args: { NIDENT: state.ident, NRN: rn, DDATE_FROM: new Date(start), DDATE_TO: new Date(end) }
|
||||
args: { NIDENT: gantt.ident, NRN: rn, DDATE_FROM: new Date(start), DDATE_TO: new Date(end) }
|
||||
});
|
||||
} finally {
|
||||
loadData();
|
||||
}
|
||||
},
|
||||
[state.ident, executeStored, loadData]
|
||||
[gantt.ident, executeStored, loadData]
|
||||
);
|
||||
|
||||
//Обработка измненения сроков задачи в диаграмме Гантта
|
||||
@ -151,8 +149,8 @@ const Gantt = ({ title }) => {
|
||||
|
||||
//При необходимости обновить данные таблицы
|
||||
useEffect(() => {
|
||||
if (state.ident) loadData();
|
||||
}, [state.ident, loadData]);
|
||||
if (gantt.ident) loadData();
|
||||
}, [gantt.ident, loadData]);
|
||||
|
||||
//При подключении компонента к странице
|
||||
useEffect(() => {
|
||||
@ -168,20 +166,19 @@ const Gantt = ({ title }) => {
|
||||
</Typography>
|
||||
<FormControlLabel
|
||||
sx={STYLES.CONTROL}
|
||||
control={<Checkbox onChange={() => setState(pv => ({ ...pv, useCustomTaskDialog: !pv.useCustomTaskDialog }))} />}
|
||||
control={<Checkbox onChange={() => setGantt(pv => ({ ...pv, useCustomTaskDialog: !pv.useCustomTaskDialog }))} />}
|
||||
label="Отображать пользовательский диалог задачи"
|
||||
/>
|
||||
<Grid container direction="column" alignItems="center">
|
||||
<Grid item xs={12}>
|
||||
{state.dataLoaded ? (
|
||||
{gantt.dataLoaded ? (
|
||||
<P8PGantt
|
||||
{...P8P_GANTT_CONFIG_PROPS}
|
||||
{...state.ganttDef}
|
||||
{...gantt}
|
||||
containerStyle={STYLES.GANTT_CONTAINER}
|
||||
tasks={state.ganttTasks}
|
||||
onTaskDatesChange={handleTaskDatesChange}
|
||||
taskAttributeRenderer={taskAttributeRenderer}
|
||||
taskDialogRenderer={state.useCustomTaskDialog ? taskDialogRenderer : null}
|
||||
taskDialogRenderer={gantt.useCustomTaskDialog ? taskDialogRenderer : null}
|
||||
/>
|
||||
) : null}
|
||||
</Grid>
|
||||
|
@ -18,6 +18,7 @@ import { DataGrid } from "./data_grid"; //Пример: Таблица данн
|
||||
import { Chart } from "./chart"; //Пример: Графики "P8PChart"
|
||||
import { Gantt } from "./gantt"; //Пример: Диаграмма Ганта "P8PGantt"
|
||||
import { Svg } from "./svg"; //Пример: Интерактивные изображения "P8PSVG"
|
||||
import { Cyclogram } from "./cyclogram"; //Пример: Циклограмма "P8PCyclogram"
|
||||
|
||||
//---------
|
||||
//Константы
|
||||
@ -32,7 +33,8 @@ const MODES = {
|
||||
DATAGRID: { name: "DATAGRID", caption: 'Таблица данных "P8PDataGrid"', component: DataGrid },
|
||||
CHART: { name: "CHART", caption: 'Графики "P8PChart"', component: Chart },
|
||||
GANTT: { name: "GANTT", caption: 'Диаграмма Ганта "P8PGantt"', component: Gantt },
|
||||
SVG: { name: "SVG", caption: 'Интерактивные изображения "P8PSVG"', component: Svg }
|
||||
SVG: { name: "SVG", caption: 'Интерактивные изображения "P8PSVG"', component: Svg },
|
||||
CYCLOGRAM: { name: "CYCLOGRAM", caption: 'Циклограмма "P8PCyclogram"', component: Cyclogram }
|
||||
};
|
||||
|
||||
//Стили
|
||||
|
@ -19,8 +19,8 @@ create table P8PNL_JB_JOBS
|
||||
EDITABLE number(1) default 0 not null, -- Признак возможности редактирования (0 - нет, 1 - да)
|
||||
CHANGED number(1) default 0 not null, -- Признак наличия изменений, требующих сохранения (0 - нет, 1 - да)
|
||||
constraint C_P8PNL_JB_JOBS_RN_PK primary key (RN),
|
||||
constraint C_P8PNL_JB_JOBS_PRN_FK foreign key (PRN) references P8PNL_JB_PRJCTS (RN),
|
||||
constraint C_P8PNL_JB_JOBS_HRN_FK foreign key (HRN) references P8PNL_JB_JOBS (RN),
|
||||
constraint C_P8PNL_JB_JOBS_PRN_FK foreign key (PRN) references P8PNL_JB_PRJCTS (RN) on delete cascade,
|
||||
constraint C_P8PNL_JB_JOBS_HRN_FK foreign key (HRN) references P8PNL_JB_JOBS (RN) on delete cascade,
|
||||
constraint C_P8PNL_JB_JOBS_STAGE_VAL check (STAGE in (0, 1)),
|
||||
constraint C_P8PNL_JB_JOBS_EDTBL_VAL check (EDITABLE in (0, 1)),
|
||||
constraint C_P8PNL_JB_JOBS_CHNGD_VAL check (CHANGED in (0, 1)),
|
||||
|
@ -9,7 +9,7 @@ create table P8PNL_JB_JOBSPREV
|
||||
PRN number(17) not null, -- Рег. номер родителя
|
||||
JB_JOBS number(17) not null, -- Рег. номер предшествующей работы/этапа
|
||||
constraint C_P8PNL_JB_JOBSPREV_RN_PK primary key (RN),
|
||||
constraint C_P8PNL_JB_JOBSPREV_PRN_FK foreign key (PRN) references P8PNL_JB_JOBS (RN),
|
||||
constraint C_P8PNL_JB_JOBSPREV_JB_JOBS_FK foreign key (JB_JOBS) references P8PNL_JB_JOBS (RN),
|
||||
constraint C_P8PNL_JB_JOBSPREV_PRN_FK foreign key (PRN) references P8PNL_JB_JOBS (RN) on delete cascade,
|
||||
constraint C_P8PNL_JB_JOBSPREV_JB_JOBS_FK foreign key (JB_JOBS) references P8PNL_JB_JOBS (RN) on delete cascade,
|
||||
constraint C_P8PNL_JB_JOBSPREV_UN unique (IDENT, PRN, JB_JOBS)
|
||||
);
|
||||
|
@ -15,7 +15,7 @@ create table P8PNL_JB_PERIODS
|
||||
LAB_PLAN_JOBS number(17,3) default 0 not null, -- Трудоёмкость (план, по графику)
|
||||
constraint C_P8PNL_JB_PERIODS_RN_PK primary key (RN),
|
||||
constraint C_P8PNL_JB_PERIODS_DATE_VAL check (DATE_FROM <= DATE_TO),
|
||||
constraint C_P8PNL_JB_PERIODS_INS_DEP_FK foreign key (INS_DEPARTMENT) references INS_DEPARTMENT (RN),
|
||||
constraint C_P8PNL_JB_PERIODS_FCMNPWR_FK foreign key (FCMANPOWER) references FCMANPOWER (RN),
|
||||
constraint C_P8PNL_JB_PERIODS_INS_DEP_FK foreign key (INS_DEPARTMENT) references INS_DEPARTMENT (RN) on delete cascade,
|
||||
constraint C_P8PNL_JB_PERIODS_FCMNPWR_FK foreign key (FCMANPOWER) references FCMANPOWER (RN) on delete cascade,
|
||||
constraint C_P8PNL_JB_PERIODS_UN unique (IDENT, DATE_FROM, INS_DEPARTMENT, FCMANPOWER)
|
||||
);
|
||||
|
@ -11,7 +11,7 @@ create table P8PNL_JB_PRJCTS
|
||||
EDITABLE number(1) default 0 not null, -- Признак возможности редактирования (0 - нет, 1 - да)
|
||||
CHANGED number(1) default 0 not null, -- Признак наличия изменений, требующих сохранения (0 - нет, 1 - да)
|
||||
constraint C_P8PNL_JB_PRJCTS_RN_PK primary key (RN),
|
||||
constraint C_P8PNL_JB_PRJCTS_PROJECT_FK foreign key (PROJECT) references PROJECT (RN),
|
||||
constraint C_P8PNL_JB_PRJCTS_PROJECT_FK foreign key (PROJECT) references PROJECT (RN) on delete cascade,
|
||||
constraint C_P8PNL_JB_PRJCTS_JOBS_VAL check (JOBS in (0, 1)),
|
||||
constraint C_P8PNL_JB_PRJCTS_EDTBL_VAL check (EDITABLE in (0, 1)),
|
||||
constraint C_P8PNL_JB_PRJCTS_CHNGD_VAL check (CHANGED in (0, 1)),
|
||||
|
18
db/P8PNL_SMPL_CYCLOGRAM.sql
Normal file
18
db/P8PNL_SMPL_CYCLOGRAM.sql
Normal file
@ -0,0 +1,18 @@
|
||||
/*
|
||||
Парус 8 - Панели мониторинга - Примеры
|
||||
Буфер для циклограммы
|
||||
*/
|
||||
create table P8PNL_SMPL_CYCLOGRAM
|
||||
(
|
||||
RN number(17) not null, -- Рег. номер записи
|
||||
IDENT number(17) not null, -- Идентификатор процесса
|
||||
TYPE number(1) not null, -- Тип (0 - колонка, 1 - группа, 2 - задача)
|
||||
NAME varchar2(200) not null, -- Наименование
|
||||
POS_START number(17) default null, -- Начальная позиция на циклограмме
|
||||
POS_END number(17) default null, -- Конечная позиция на циклограмме
|
||||
DATE_FROM date default null, -- Дата начала
|
||||
DATE_TO date default null, -- Дата окончания
|
||||
TASK_GROUP number(17) default null, -- Группа задач
|
||||
constraint C_P8PNL_SMPL_CYCLOGRAM_RN_PK primary key (RN),
|
||||
constraint C_P8PNL_SMPL_CYCLOGRAM_TP_VAL check (TYPE in (0, 1, 2))
|
||||
);
|
@ -27,6 +27,13 @@ create or replace package PKG_P8PANELS_BASE as
|
||||
NDOCUMENT in number -- Рег. номер документа
|
||||
) return number; -- Флаг доступности (см. константы NACCESS_*)
|
||||
|
||||
/* Подготовка пользовательской строки поиска для вставки в запрос */
|
||||
procedure UTL_SEARCH_PREPARE
|
||||
(
|
||||
SSEARCH in varchar2, -- Пользовательская строка поиска
|
||||
SSEARCH_PREPARED out varchar2 -- Подготовленная строка поиска
|
||||
);
|
||||
|
||||
/* Базовое исполнение действий */
|
||||
procedure PROCESS
|
||||
(
|
||||
@ -191,6 +198,36 @@ create or replace package body PKG_P8PANELS_BASE as
|
||||
return NACCESS_NO;
|
||||
end UTL_DOC_ACCESS_CHECK;
|
||||
|
||||
/* Подготовка пользовательской строки поиска для вставки в запрос */
|
||||
procedure UTL_SEARCH_PREPARE
|
||||
(
|
||||
SSEARCH in varchar2, -- Пользовательская строка поиска
|
||||
SSEARCH_PREPARED out varchar2 -- Подготовленная строка поиска
|
||||
)
|
||||
is
|
||||
/* Локальные константы */
|
||||
SANY_SYS constant char(1) := '%'; -- Маска "любое количество любых символов" Oracle
|
||||
SONE_SYS constant char(1) := '_'; -- Маска "любой один символ" Oracle
|
||||
SENT_WRD_DELIM constant varchar2(1) := ' '; -- Разделитель слов в предложении
|
||||
SANY_PRS constant varchar2(240) := PKG_OPTIONS.STARSYMB; -- Маска "любое количество любых символов" Парус
|
||||
SONE_PRS constant varchar2(240) := PKG_OPTIONS.QUESTSYMB; -- Маска "любой один символ" Парус
|
||||
begin
|
||||
/* Если пользовательская строка пустая - то это всё что угодно */
|
||||
if (SSEARCH is null)
|
||||
then
|
||||
SSEARCH_PREPARED := SANY_SYS;
|
||||
else
|
||||
/* Подменим пользовательские маски на системные и соберем подготовленную строку поиска */
|
||||
SSEARCH_PREPARED := '%' || replace(replace(replace(SSEARCH
|
||||
,SANY_PRS
|
||||
,SANY_SYS)
|
||||
,SONE_PRS
|
||||
,SONE_SYS)
|
||||
,SENT_WRD_DELIM
|
||||
,SANY_SYS) || '%';
|
||||
end if;
|
||||
end UTL_SEARCH_PREPARE;
|
||||
|
||||
/* Формирование сообщения об отсутствии значения */
|
||||
function MSG_NO_DATA_MAKE
|
||||
(
|
||||
|
@ -227,10 +227,10 @@ create or replace package body PKG_P8PANELS_EQUIPSRV as
|
||||
NCOMPANY PKG_STD.TREF := GET_SESSION_COMPANY(); -- Рег. номер организации
|
||||
SPRJ_GROUP_NAME PKG_STD.TSTRING; -- Наименование группы для проекта
|
||||
BEXPANDED boolean; -- Флаг раскрытости уровня
|
||||
RDG PKG_P8PANELS_VISUAL.TDATA_GRID; -- Описание таблицы
|
||||
RDG_ROW_INFO PKG_P8PANELS_VISUAL.TROW; -- Строка таблицы с информацией по объекту ремонта
|
||||
RDG_ROW_PLAN PKG_P8PANELS_VISUAL.TROW; -- Строка таблицы с планом по объекту ремонта
|
||||
RDG_ROW_FACT PKG_P8PANELS_VISUAL.TROW; -- Строка таблицы с фактом по объекту ремонта
|
||||
RDG PKG_P8PANELS_VISUAL.TDG; -- Описание таблицы
|
||||
RDG_ROW_INFO PKG_P8PANELS_VISUAL.TDG_ROW; -- Строка таблицы с информацией по объекту ремонта
|
||||
RDG_ROW_PLAN PKG_P8PANELS_VISUAL.TDG_ROW; -- Строка таблицы с планом по объекту ремонта
|
||||
RDG_ROW_FACT PKG_P8PANELS_VISUAL.TDG_ROW; -- Строка таблицы с фактом по объекту ремонта
|
||||
NCURYEAR PKG_STD.TNUMBER; -- Текущий год
|
||||
NCURMONTH PKG_STD.TNUMBER; -- Текущий месяц
|
||||
NTOTALDAYS PKG_STD.TNUMBER; -- Дней в текущем месяце
|
||||
@ -399,99 +399,99 @@ create or replace package body PKG_P8PANELS_EQUIPSRV as
|
||||
/* Определим дату конца периода */
|
||||
NTODATE := LAST_DAY(TO_DATE('01.' || LPAD(TO_CHAR(NTOMONTH), 2, '0') || '.' || TO_CHAR(NTOYEAR), 'dd.mm.yyyy'));
|
||||
/* Инициализируем таблицу данных */
|
||||
RDG := PKG_P8PANELS_VISUAL.TDATA_GRID_MAKE(BFIXED_HEADER => true, NFIXED_COLUMNS => 2);
|
||||
RDG := PKG_P8PANELS_VISUAL.TDG_MAKE(BFIXED_HEADER => true, NFIXED_COLUMNS => 2);
|
||||
/* Формируем структуру заголовка */
|
||||
PKG_P8PANELS_VISUAL.TDATA_GRID_ADD_COL_DEF(RDATA_GRID => RDG,
|
||||
SNAME => 'SOBJINFO',
|
||||
SCAPTION => 'Информация по объекту ремонта',
|
||||
SDATA_TYPE => PKG_P8PANELS_VISUAL.SDATA_TYPE_STR,
|
||||
NWIDTH => 80);
|
||||
PKG_P8PANELS_VISUAL.TDATA_GRID_ADD_COL_DEF(RDATA_GRID => RDG,
|
||||
SNAME => 'SINFO',
|
||||
SCAPTION => 'Объект ремонта',
|
||||
SDATA_TYPE => PKG_P8PANELS_VISUAL.SDATA_TYPE_STR,
|
||||
NWIDTH => 80);
|
||||
PKG_P8PANELS_VISUAL.TDATA_GRID_ADD_COL_DEF(RDATA_GRID => RDG,
|
||||
SNAME => 'SWRKTYPE',
|
||||
SCAPTION => 'Тип работ',
|
||||
SDATA_TYPE => PKG_P8PANELS_VISUAL.SDATA_TYPE_STR,
|
||||
SPARENT => 'SINFO',
|
||||
NWIDTH => 80);
|
||||
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 => 'SWORKNAME',
|
||||
SCAPTION => 'Наименование работы',
|
||||
SDATA_TYPE => PKG_P8PANELS_VISUAL.SDATA_TYPE_STR,
|
||||
BVISIBLE => false);
|
||||
PKG_P8PANELS_VISUAL.TDATA_GRID_ADD_COL_DEF(RDATA_GRID => RDG,
|
||||
SNAME => 'STECHOBJCODE',
|
||||
SCAPTION => 'Код тех. объекта',
|
||||
SDATA_TYPE => PKG_P8PANELS_VISUAL.SDATA_TYPE_STR,
|
||||
BVISIBLE => false);
|
||||
PKG_P8PANELS_VISUAL.TDATA_GRID_ADD_COL_DEF(RDATA_GRID => RDG,
|
||||
SNAME => 'STECHOBJNAME',
|
||||
SCAPTION => 'Наименование тех. объекта',
|
||||
SDATA_TYPE => PKG_P8PANELS_VISUAL.SDATA_TYPE_STR,
|
||||
BVISIBLE => false);
|
||||
PKG_P8PANELS_VISUAL.TDATA_GRID_ADD_COL_DEF(RDATA_GRID => RDG,
|
||||
SNAME => 'SBELONG',
|
||||
SCAPTION => 'Принадлежность',
|
||||
SDATA_TYPE => PKG_P8PANELS_VISUAL.SDATA_TYPE_STR,
|
||||
BVISIBLE => false);
|
||||
PKG_P8PANELS_VISUAL.TDATA_GRID_ADD_COL_DEF(RDATA_GRID => RDG,
|
||||
SNAME => 'SPRODOBJ',
|
||||
SCAPTION => 'Производственный объект',
|
||||
SDATA_TYPE => PKG_P8PANELS_VISUAL.SDATA_TYPE_STR,
|
||||
BVISIBLE => false);
|
||||
PKG_P8PANELS_VISUAL.TDATA_GRID_ADD_COL_DEF(RDATA_GRID => RDG,
|
||||
SNAME => 'STECHSERV',
|
||||
SCAPTION => 'Тех. служба',
|
||||
SDATA_TYPE => PKG_P8PANELS_VISUAL.SDATA_TYPE_STR,
|
||||
BVISIBLE => false);
|
||||
PKG_P8PANELS_VISUAL.TDATA_GRID_ADD_COL_DEF(RDATA_GRID => RDG,
|
||||
SNAME => 'SRESPDEP',
|
||||
SCAPTION => 'Отвественное подразделение',
|
||||
SDATA_TYPE => PKG_P8PANELS_VISUAL.SDATA_TYPE_STR,
|
||||
BVISIBLE => false);
|
||||
PKG_P8PANELS_VISUAL.TDATA_GRID_ADD_COL_DEF(RDATA_GRID => RDG,
|
||||
SNAME => 'STECSERVCODE',
|
||||
SCAPTION => 'Вид ремонта',
|
||||
SDATA_TYPE => PKG_P8PANELS_VISUAL.SDATA_TYPE_STR,
|
||||
BVISIBLE => false);
|
||||
PKG_P8PANELS_VISUAL.TDATA_GRID_ADD_COL_DEF(RDATA_GRID => RDG,
|
||||
SNAME => 'DDATEPLANBEG',
|
||||
SCAPTION => 'Начало работы (план)',
|
||||
SDATA_TYPE => PKG_P8PANELS_VISUAL.SDATA_TYPE_DATE,
|
||||
BVISIBLE => false);
|
||||
PKG_P8PANELS_VISUAL.TDATA_GRID_ADD_COL_DEF(RDATA_GRID => RDG,
|
||||
SNAME => 'DDATEPLANEND',
|
||||
SCAPTION => 'Окончание работы (план)',
|
||||
SDATA_TYPE => PKG_P8PANELS_VISUAL.SDATA_TYPE_DATE,
|
||||
BVISIBLE => false);
|
||||
PKG_P8PANELS_VISUAL.TDATA_GRID_ADD_COL_DEF(RDATA_GRID => RDG,
|
||||
SNAME => 'DDATEFACTBEG',
|
||||
SCAPTION => 'Начало работы (факт)',
|
||||
SDATA_TYPE => PKG_P8PANELS_VISUAL.SDATA_TYPE_DATE,
|
||||
BVISIBLE => false);
|
||||
PKG_P8PANELS_VISUAL.TDATA_GRID_ADD_COL_DEF(RDATA_GRID => RDG,
|
||||
SNAME => 'DDATEFACTEND',
|
||||
SCAPTION => 'Окончание работы (факт)',
|
||||
SDATA_TYPE => PKG_P8PANELS_VISUAL.SDATA_TYPE_DATE,
|
||||
BVISIBLE => false);
|
||||
PKG_P8PANELS_VISUAL.TDATA_GRID_ADD_COL_DEF(RDATA_GRID => RDG,
|
||||
SNAME => 'STECSRVKINDCODE',
|
||||
SCAPTION => 'Код типа работы',
|
||||
SDATA_TYPE => PKG_P8PANELS_VISUAL.SDATA_TYPE_STR,
|
||||
BVISIBLE => false);
|
||||
PKG_P8PANELS_VISUAL.TDATA_GRID_ADD_COL_DEF(RDATA_GRID => RDG,
|
||||
SNAME => 'STECSRVKINDNAME',
|
||||
SCAPTION => 'Наименование типа работы',
|
||||
SDATA_TYPE => PKG_P8PANELS_VISUAL.SDATA_TYPE_STR,
|
||||
BVISIBLE => false);
|
||||
PKG_P8PANELS_VISUAL.TDG_ADD_COL_DEF(RDATA_GRID => RDG,
|
||||
SNAME => 'SOBJINFO',
|
||||
SCAPTION => 'Информация по объекту ремонта',
|
||||
SDATA_TYPE => PKG_P8PANELS_VISUAL.SDATA_TYPE_STR,
|
||||
NWIDTH => 80);
|
||||
PKG_P8PANELS_VISUAL.TDG_ADD_COL_DEF(RDATA_GRID => RDG,
|
||||
SNAME => 'SINFO',
|
||||
SCAPTION => 'Объект ремонта',
|
||||
SDATA_TYPE => PKG_P8PANELS_VISUAL.SDATA_TYPE_STR,
|
||||
NWIDTH => 80);
|
||||
PKG_P8PANELS_VISUAL.TDG_ADD_COL_DEF(RDATA_GRID => RDG,
|
||||
SNAME => 'SWRKTYPE',
|
||||
SCAPTION => 'Тип работ',
|
||||
SDATA_TYPE => PKG_P8PANELS_VISUAL.SDATA_TYPE_STR,
|
||||
SPARENT => 'SINFO',
|
||||
NWIDTH => 80);
|
||||
PKG_P8PANELS_VISUAL.TDG_ADD_COL_DEF(RDATA_GRID => RDG,
|
||||
SNAME => 'NRN',
|
||||
SCAPTION => 'Рег. номер',
|
||||
SDATA_TYPE => PKG_P8PANELS_VISUAL.SDATA_TYPE_NUMB,
|
||||
BVISIBLE => false);
|
||||
PKG_P8PANELS_VISUAL.TDG_ADD_COL_DEF(RDATA_GRID => RDG,
|
||||
SNAME => 'SWORKNAME',
|
||||
SCAPTION => 'Наименование работы',
|
||||
SDATA_TYPE => PKG_P8PANELS_VISUAL.SDATA_TYPE_STR,
|
||||
BVISIBLE => false);
|
||||
PKG_P8PANELS_VISUAL.TDG_ADD_COL_DEF(RDATA_GRID => RDG,
|
||||
SNAME => 'STECHOBJCODE',
|
||||
SCAPTION => 'Код тех. объекта',
|
||||
SDATA_TYPE => PKG_P8PANELS_VISUAL.SDATA_TYPE_STR,
|
||||
BVISIBLE => false);
|
||||
PKG_P8PANELS_VISUAL.TDG_ADD_COL_DEF(RDATA_GRID => RDG,
|
||||
SNAME => 'STECHOBJNAME',
|
||||
SCAPTION => 'Наименование тех. объекта',
|
||||
SDATA_TYPE => PKG_P8PANELS_VISUAL.SDATA_TYPE_STR,
|
||||
BVISIBLE => false);
|
||||
PKG_P8PANELS_VISUAL.TDG_ADD_COL_DEF(RDATA_GRID => RDG,
|
||||
SNAME => 'SBELONG',
|
||||
SCAPTION => 'Принадлежность',
|
||||
SDATA_TYPE => PKG_P8PANELS_VISUAL.SDATA_TYPE_STR,
|
||||
BVISIBLE => false);
|
||||
PKG_P8PANELS_VISUAL.TDG_ADD_COL_DEF(RDATA_GRID => RDG,
|
||||
SNAME => 'SPRODOBJ',
|
||||
SCAPTION => 'Производственный объект',
|
||||
SDATA_TYPE => PKG_P8PANELS_VISUAL.SDATA_TYPE_STR,
|
||||
BVISIBLE => false);
|
||||
PKG_P8PANELS_VISUAL.TDG_ADD_COL_DEF(RDATA_GRID => RDG,
|
||||
SNAME => 'STECHSERV',
|
||||
SCAPTION => 'Тех. служба',
|
||||
SDATA_TYPE => PKG_P8PANELS_VISUAL.SDATA_TYPE_STR,
|
||||
BVISIBLE => false);
|
||||
PKG_P8PANELS_VISUAL.TDG_ADD_COL_DEF(RDATA_GRID => RDG,
|
||||
SNAME => 'SRESPDEP',
|
||||
SCAPTION => 'Отвественное подразделение',
|
||||
SDATA_TYPE => PKG_P8PANELS_VISUAL.SDATA_TYPE_STR,
|
||||
BVISIBLE => false);
|
||||
PKG_P8PANELS_VISUAL.TDG_ADD_COL_DEF(RDATA_GRID => RDG,
|
||||
SNAME => 'STECSERVCODE',
|
||||
SCAPTION => 'Вид ремонта',
|
||||
SDATA_TYPE => PKG_P8PANELS_VISUAL.SDATA_TYPE_STR,
|
||||
BVISIBLE => false);
|
||||
PKG_P8PANELS_VISUAL.TDG_ADD_COL_DEF(RDATA_GRID => RDG,
|
||||
SNAME => 'DDATEPLANBEG',
|
||||
SCAPTION => 'Начало работы (план)',
|
||||
SDATA_TYPE => PKG_P8PANELS_VISUAL.SDATA_TYPE_DATE,
|
||||
BVISIBLE => false);
|
||||
PKG_P8PANELS_VISUAL.TDG_ADD_COL_DEF(RDATA_GRID => RDG,
|
||||
SNAME => 'DDATEPLANEND',
|
||||
SCAPTION => 'Окончание работы (план)',
|
||||
SDATA_TYPE => PKG_P8PANELS_VISUAL.SDATA_TYPE_DATE,
|
||||
BVISIBLE => false);
|
||||
PKG_P8PANELS_VISUAL.TDG_ADD_COL_DEF(RDATA_GRID => RDG,
|
||||
SNAME => 'DDATEFACTBEG',
|
||||
SCAPTION => 'Начало работы (факт)',
|
||||
SDATA_TYPE => PKG_P8PANELS_VISUAL.SDATA_TYPE_DATE,
|
||||
BVISIBLE => false);
|
||||
PKG_P8PANELS_VISUAL.TDG_ADD_COL_DEF(RDATA_GRID => RDG,
|
||||
SNAME => 'DDATEFACTEND',
|
||||
SCAPTION => 'Окончание работы (факт)',
|
||||
SDATA_TYPE => PKG_P8PANELS_VISUAL.SDATA_TYPE_DATE,
|
||||
BVISIBLE => false);
|
||||
PKG_P8PANELS_VISUAL.TDG_ADD_COL_DEF(RDATA_GRID => RDG,
|
||||
SNAME => 'STECSRVKINDCODE',
|
||||
SCAPTION => 'Код типа работы',
|
||||
SDATA_TYPE => PKG_P8PANELS_VISUAL.SDATA_TYPE_STR,
|
||||
BVISIBLE => false);
|
||||
PKG_P8PANELS_VISUAL.TDG_ADD_COL_DEF(RDATA_GRID => RDG,
|
||||
SNAME => 'STECSRVKINDNAME',
|
||||
SCAPTION => 'Наименование типа работы',
|
||||
SDATA_TYPE => PKG_P8PANELS_VISUAL.SDATA_TYPE_STR,
|
||||
BVISIBLE => false);
|
||||
/* Очистка коллекций */
|
||||
PKG_CONTVALLOC1S.PURGE(RCONTAINER => YM);
|
||||
PKG_CONTVALLOC1S.PURGE(RCONTAINER => MCLR);
|
||||
@ -530,12 +530,12 @@ create or replace package body PKG_P8PANELS_EQUIPSRV as
|
||||
else
|
||||
BEXPANDED := false;
|
||||
end if;
|
||||
PKG_P8PANELS_VISUAL.TDATA_GRID_ADD_COL_DEF(RDATA_GRID => RDG,
|
||||
SNAME => '_' || TO_CHAR(Y) || '_' || TO_CHAR(M),
|
||||
SCAPTION => LPAD(TO_CHAR(M), 2, '0') || ' ' || TO_CHAR(Y),
|
||||
SDATA_TYPE => PKG_P8PANELS_VISUAL.SDATA_TYPE_STR,
|
||||
BEXPANDABLE => true,
|
||||
BEXPANDED => BEXPANDED);
|
||||
PKG_P8PANELS_VISUAL.TDG_ADD_COL_DEF(RDATA_GRID => RDG,
|
||||
SNAME => '_' || TO_CHAR(Y) || '_' || TO_CHAR(M),
|
||||
SCAPTION => LPAD(TO_CHAR(M), 2, '0') || ' ' || TO_CHAR(Y),
|
||||
SDATA_TYPE => PKG_P8PANELS_VISUAL.SDATA_TYPE_STR,
|
||||
BEXPANDABLE => true,
|
||||
BEXPANDED => BEXPANDED);
|
||||
/* Подсчёт кол-ва дней в месяце */
|
||||
NTOTALDAYS := TO_NUMBER(TO_CHAR(LAST_DAY(TO_DATE('01.' || LPAD(TO_CHAR(M), 2, '0') || '.' || TO_CHAR(Y),
|
||||
'dd.mm.yyyy')),
|
||||
@ -544,12 +544,11 @@ create or replace package body PKG_P8PANELS_EQUIPSRV as
|
||||
/* Цикл по дням месяца */
|
||||
for D in 1 .. NTOTALDAYS
|
||||
loop
|
||||
PKG_P8PANELS_VISUAL.TDATA_GRID_ADD_COL_DEF(RDATA_GRID => RDG,
|
||||
SNAME => '_' || TO_CHAR(Y) || '_' || TO_CHAR(M) || '_' ||
|
||||
TO_CHAR(D),
|
||||
SCAPTION => TO_CHAR(D, '99'),
|
||||
SDATA_TYPE => PKG_P8PANELS_VISUAL.SDATA_TYPE_STR,
|
||||
SPARENT => '_' || TO_CHAR(Y) || '_' || TO_CHAR(M));
|
||||
PKG_P8PANELS_VISUAL.TDG_ADD_COL_DEF(RDATA_GRID => RDG,
|
||||
SNAME => '_' || TO_CHAR(Y) || '_' || TO_CHAR(M) || '_' || TO_CHAR(D),
|
||||
SCAPTION => TO_CHAR(D, '99'),
|
||||
SDATA_TYPE => PKG_P8PANELS_VISUAL.SDATA_TYPE_STR,
|
||||
SPARENT => '_' || TO_CHAR(Y) || '_' || TO_CHAR(M));
|
||||
end loop;
|
||||
end loop;
|
||||
end loop;
|
||||
@ -573,7 +572,7 @@ create or replace package body PKG_P8PANELS_EQUIPSRV as
|
||||
if (NFROMYEAR = NTOYEAR) then
|
||||
NMS := NFROMMONTH;
|
||||
NME := NTOMONTH;
|
||||
/* Иначе вычисляем кол-во месяцев в каждом году периода отчёта */
|
||||
/* Иначе вычисляем кол-во месяцев в каждом году периода отчёта */
|
||||
else
|
||||
if (Y = NFROMYEAR) then
|
||||
NMS := NFROMMONTH;
|
||||
@ -590,14 +589,14 @@ create or replace package body PKG_P8PANELS_EQUIPSRV as
|
||||
for M in NMS .. NME
|
||||
loop
|
||||
SPERIODNAME := '_' || TO_CHAR(Y) || '_' || TO_CHAR(M);
|
||||
PKG_P8PANELS_VISUAL.TROW_ADD_COL(RROW => RDG_ROW_INFO,
|
||||
SNAME => SPERIODNAME,
|
||||
SVALUE => 'план: ' || HOURS_STR(NHOURS => TRUNC(PKG_CONTVALLOC1S.GETN(RCONTAINER => YM,
|
||||
SROWID => SPERIODNAME || '_P'),
|
||||
1)) || ' факт: ' ||
|
||||
HOURS_STR(NHOURS => TRUNC(PKG_CONTVALLOC1S.GETN(RCONTAINER => YM,
|
||||
SROWID => SPERIODNAME || '_F'),
|
||||
1)));
|
||||
PKG_P8PANELS_VISUAL.TDG_ROW_ADD_COL(RROW => RDG_ROW_INFO,
|
||||
SNAME => SPERIODNAME,
|
||||
SVALUE => 'план: ' || HOURS_STR(NHOURS => TRUNC(PKG_CONTVALLOC1S.GETN(RCONTAINER => YM,
|
||||
SROWID => SPERIODNAME || '_P'),
|
||||
1)) || ' факт: ' ||
|
||||
HOURS_STR(NHOURS => TRUNC(PKG_CONTVALLOC1S.GETN(RCONTAINER => YM,
|
||||
SROWID => SPERIODNAME || '_F'),
|
||||
1)));
|
||||
/* Добавление в коллекцию трудоёмкость план */
|
||||
PKG_CONTVALLOC1S.PUTN(RCONTAINER => YM, SROWID => SPERIODNAME || '_P', NVALUE => 0);
|
||||
/* Добавление в коллекцию трудоёмкость факт */
|
||||
@ -605,17 +604,17 @@ create or replace package body PKG_P8PANELS_EQUIPSRV as
|
||||
end loop;
|
||||
end loop;
|
||||
/* Добавление строки с трудоёмкостью */
|
||||
PKG_P8PANELS_VISUAL.TDATA_GRID_ADD_ROW(RDATA_GRID => RDG, RROW => RDG_ROW_INFO);
|
||||
PKG_P8PANELS_VISUAL.TDG_ADD_ROW(RDATA_GRID => RDG, RROW => RDG_ROW_INFO);
|
||||
end if;
|
||||
/* Добавление группы с объектом ремонта */
|
||||
SCURTECHOBJ := QQ.STECHOBJNAME;
|
||||
SPRJ_GROUP_NAME := SCURTECHOBJ;
|
||||
PKG_P8PANELS_VISUAL.TDATA_GRID_ADD_GROUP(RDATA_GRID => RDG,
|
||||
SNAME => SPRJ_GROUP_NAME,
|
||||
SCAPTION => QQ.STECHOBJNAME,
|
||||
BEXPANDABLE => false);
|
||||
RDG_ROW_INFO := PKG_P8PANELS_VISUAL.TROW_MAKE(SGROUP => SPRJ_GROUP_NAME);
|
||||
PKG_P8PANELS_VISUAL.TROW_ADD_COL(RROW => RDG_ROW_INFO, SNAME => 'SOBJINFO', SVALUE => SCURTECHOBJ);
|
||||
PKG_P8PANELS_VISUAL.TDG_ADD_GROUP(RDATA_GRID => RDG,
|
||||
SNAME => SPRJ_GROUP_NAME,
|
||||
SCAPTION => QQ.STECHOBJNAME,
|
||||
BEXPANDABLE => false);
|
||||
RDG_ROW_INFO := PKG_P8PANELS_VISUAL.TDG_ROW_MAKE(SGROUP => SPRJ_GROUP_NAME);
|
||||
PKG_P8PANELS_VISUAL.TDG_ROW_ADD_COL(RROW => RDG_ROW_INFO, SNAME => 'SOBJINFO', SVALUE => SCURTECHOBJ);
|
||||
end if;
|
||||
/* Формируем имя группы для вида ремонта */
|
||||
SCURTSKCODE := SCURTECHOBJ || '_' || QQ.STECSRVKINDCODE;
|
||||
@ -623,7 +622,7 @@ create or replace package body PKG_P8PANELS_EQUIPSRV as
|
||||
if (PKG_CONTVALLOC1S.EXISTS_(RCONTAINER => GF, SROWID => SCURTSKCODE) = false) then
|
||||
/* Добавляем строку плана */
|
||||
if (RDG_ROW_PLAN.RCOLS is not null) then
|
||||
PKG_P8PANELS_VISUAL.TDATA_GRID_ADD_ROW(RDATA_GRID => RDG, RROW => RDG_ROW_PLAN);
|
||||
PKG_P8PANELS_VISUAL.TDG_ADD_ROW(RDATA_GRID => RDG, RROW => RDG_ROW_PLAN);
|
||||
end if;
|
||||
/* Добавляем строку факта */
|
||||
if (RDG_ROW_FACT.RCOLS is not null) then
|
||||
@ -631,27 +630,27 @@ create or replace package body PKG_P8PANELS_EQUIPSRV as
|
||||
/* Цикл по коллекции для закрашивания месяцев */
|
||||
for Z in 1 .. PKG_CONTVALLOC1S.COUNT_(RCONTAINER => MCLR)
|
||||
loop
|
||||
PKG_P8PANELS_VISUAL.TROW_ADD_COL(RROW => RDG_ROW_FACT,
|
||||
SNAME => CR,
|
||||
SVALUE => PKG_CONTVALLOC1S.GETS(RCONTAINER => MCLR, SROWID => CR));
|
||||
PKG_P8PANELS_VISUAL.TDG_ROW_ADD_COL(RROW => RDG_ROW_FACT,
|
||||
SNAME => CR,
|
||||
SVALUE => PKG_CONTVALLOC1S.GETS(RCONTAINER => MCLR, SROWID => CR));
|
||||
CR := PKG_CONTVALLOC1S.NEXT_(RCONTAINER => MCLR, SROWID => CR);
|
||||
end loop;
|
||||
PKG_P8PANELS_VISUAL.TDATA_GRID_ADD_ROW(RDATA_GRID => RDG, RROW => RDG_ROW_FACT);
|
||||
PKG_P8PANELS_VISUAL.TDG_ADD_ROW(RDATA_GRID => RDG, RROW => RDG_ROW_FACT);
|
||||
end if;
|
||||
PKG_CONTVALLOC1S.PURGE(RCONTAINER => MCLR);
|
||||
/* Добвим группу для вида ремонта */
|
||||
SPRJ_GROUP_NAME := SCURTSKCODE;
|
||||
PKG_P8PANELS_VISUAL.TDATA_GRID_ADD_GROUP(RDATA_GRID => RDG,
|
||||
SNAME => SPRJ_GROUP_NAME,
|
||||
SCAPTION => QQ.STECSRVKINDCODE,
|
||||
BEXPANDABLE => false);
|
||||
PKG_P8PANELS_VISUAL.TDG_ADD_GROUP(RDATA_GRID => RDG,
|
||||
SNAME => SPRJ_GROUP_NAME,
|
||||
SCAPTION => QQ.STECSRVKINDCODE,
|
||||
BEXPANDABLE => false);
|
||||
/* Строка плана */
|
||||
RDG_ROW_PLAN := PKG_P8PANELS_VISUAL.TROW_MAKE(SGROUP => SPRJ_GROUP_NAME);
|
||||
PKG_P8PANELS_VISUAL.TROW_ADD_COL(RROW => RDG_ROW_PLAN, SNAME => 'SOBJINFO', SVALUE => QQ.STECSRVKINDCODE);
|
||||
PKG_P8PANELS_VISUAL.TROW_ADD_COL(RROW => RDG_ROW_PLAN, SNAME => 'SWRKTYPE', SVALUE => 'План');
|
||||
RDG_ROW_PLAN := PKG_P8PANELS_VISUAL.TDG_ROW_MAKE(SGROUP => SPRJ_GROUP_NAME);
|
||||
PKG_P8PANELS_VISUAL.TDG_ROW_ADD_COL(RROW => RDG_ROW_PLAN, SNAME => 'SOBJINFO', SVALUE => QQ.STECSRVKINDCODE);
|
||||
PKG_P8PANELS_VISUAL.TDG_ROW_ADD_COL(RROW => RDG_ROW_PLAN, SNAME => 'SWRKTYPE', SVALUE => 'План');
|
||||
/* Строка факта */
|
||||
RDG_ROW_FACT := PKG_P8PANELS_VISUAL.TROW_MAKE(SGROUP => SPRJ_GROUP_NAME);
|
||||
PKG_P8PANELS_VISUAL.TROW_ADD_COL(RROW => RDG_ROW_FACT, SNAME => 'SWRKTYPE', SVALUE => 'Факт');
|
||||
RDG_ROW_FACT := PKG_P8PANELS_VISUAL.TDG_ROW_MAKE(SGROUP => SPRJ_GROUP_NAME);
|
||||
PKG_P8PANELS_VISUAL.TDG_ROW_ADD_COL(RROW => RDG_ROW_FACT, SNAME => 'SWRKTYPE', SVALUE => 'Факт');
|
||||
/* Добавляем в заполненные группы */
|
||||
PKG_CONTVALLOC1S.PUTS(RCONTAINER => GF, SROWID => SPRJ_GROUP_NAME, SVALUE => '');
|
||||
end if;
|
||||
@ -676,7 +675,7 @@ create or replace package body PKG_P8PANELS_EQUIPSRV as
|
||||
/* Закрашивание месяца плана синим */
|
||||
if (PKG_CONTVALLOC1S.EXISTS_(RCONTAINER => COLS, SROWID => SPRJ_GROUP_NAME || ' ' || SPERIODNAME || ' PLAN') =
|
||||
false) then
|
||||
PKG_P8PANELS_VISUAL.TROW_ADD_COL(RROW => RDG_ROW_PLAN, SNAME => SPERIODNAME, SVALUE => 'blue');
|
||||
PKG_P8PANELS_VISUAL.TDG_ROW_ADD_COL(RROW => RDG_ROW_PLAN, SNAME => SPERIODNAME, SVALUE => 'blue');
|
||||
PKG_CONTVALLOC1S.PUTS(RCONTAINER => COLS,
|
||||
SROWID => SPRJ_GROUP_NAME || ' ' || SPERIODNAME || ' PLAN',
|
||||
SVALUE => '');
|
||||
@ -686,7 +685,7 @@ create or replace package body PKG_P8PANELS_EQUIPSRV as
|
||||
/* Закрашивание дня плана синим */
|
||||
if (PKG_CONTVALLOC1S.EXISTS_(RCONTAINER => COLS, SROWID => SPRJ_GROUP_NAME || ' ' || SPERIODNAME || ' PLAN') =
|
||||
false) then
|
||||
PKG_P8PANELS_VISUAL.TROW_ADD_COL(RROW => RDG_ROW_PLAN, SNAME => SPERIODNAME, SVALUE => 'blue');
|
||||
PKG_P8PANELS_VISUAL.TDG_ROW_ADD_COL(RROW => RDG_ROW_PLAN, SNAME => SPERIODNAME, SVALUE => 'blue');
|
||||
PKG_CONTVALLOC1S.PUTS(RCONTAINER => COLS,
|
||||
SROWID => SPRJ_GROUP_NAME || ' ' || SPERIODNAME || ' PLAN',
|
||||
SVALUE => '');
|
||||
@ -783,37 +782,37 @@ create or replace package body PKG_P8PANELS_EQUIPSRV as
|
||||
for M in NMS .. NME
|
||||
loop
|
||||
SPERIODNAME := '_' || TO_CHAR(Y) || '_' || TO_CHAR(M);
|
||||
PKG_P8PANELS_VISUAL.TROW_ADD_COL(RROW => RDG_ROW_INFO,
|
||||
SNAME => SPERIODNAME,
|
||||
SVALUE => 'план: ' || HOURS_STR(NHOURS => TRUNC(PKG_CONTVALLOC1S.GETN(RCONTAINER => YM,
|
||||
SROWID => SPERIODNAME || '_P'),
|
||||
1)) || ' факт: ' ||
|
||||
HOURS_STR(NHOURS => TRUNC(PKG_CONTVALLOC1S.GETN(RCONTAINER => YM,
|
||||
SROWID => SPERIODNAME || '_F'),
|
||||
1)));
|
||||
PKG_P8PANELS_VISUAL.TDG_ROW_ADD_COL(RROW => RDG_ROW_INFO,
|
||||
SNAME => SPERIODNAME,
|
||||
SVALUE => 'план: ' || HOURS_STR(NHOURS => TRUNC(PKG_CONTVALLOC1S.GETN(RCONTAINER => YM,
|
||||
SROWID => SPERIODNAME || '_P'),
|
||||
1)) || ' факт: ' ||
|
||||
HOURS_STR(NHOURS => TRUNC(PKG_CONTVALLOC1S.GETN(RCONTAINER => YM,
|
||||
SROWID => SPERIODNAME || '_F'),
|
||||
1)));
|
||||
end loop;
|
||||
end loop;
|
||||
PKG_P8PANELS_VISUAL.TDATA_GRID_ADD_ROW(RDATA_GRID => RDG, RROW => RDG_ROW_INFO);
|
||||
PKG_P8PANELS_VISUAL.TDG_ADD_ROW(RDATA_GRID => RDG, RROW => RDG_ROW_INFO);
|
||||
end if;
|
||||
/* План для последней записи */
|
||||
if ((RDG_ROW_PLAN.RCOLS is not null) and (NROWS = 0)) then
|
||||
PKG_P8PANELS_VISUAL.TDATA_GRID_ADD_ROW(RDATA_GRID => RDG, RROW => RDG_ROW_PLAN);
|
||||
PKG_P8PANELS_VISUAL.TDG_ADD_ROW(RDATA_GRID => RDG, RROW => RDG_ROW_PLAN);
|
||||
end if;
|
||||
/* Факт для последней записи */
|
||||
if ((RDG_ROW_FACT.RCOLS is not null) and (NROWS = 0)) then
|
||||
CR := PKG_CONTVALLOC1S.FIRST_(RCONTAINER => MCLR);
|
||||
for Z in 1 .. PKG_CONTVALLOC1S.COUNT_(RCONTAINER => MCLR)
|
||||
loop
|
||||
PKG_P8PANELS_VISUAL.TROW_ADD_COL(RROW => RDG_ROW_FACT,
|
||||
SNAME => CR,
|
||||
SVALUE => PKG_CONTVALLOC1S.GETS(RCONTAINER => MCLR, SROWID => CR));
|
||||
PKG_P8PANELS_VISUAL.TDG_ROW_ADD_COL(RROW => RDG_ROW_FACT,
|
||||
SNAME => CR,
|
||||
SVALUE => PKG_CONTVALLOC1S.GETS(RCONTAINER => MCLR, SROWID => CR));
|
||||
CR := PKG_CONTVALLOC1S.NEXT_(RCONTAINER => MCLR, SROWID => CR);
|
||||
end loop;
|
||||
PKG_P8PANELS_VISUAL.TDATA_GRID_ADD_ROW(RDATA_GRID => RDG, RROW => RDG_ROW_FACT);
|
||||
PKG_P8PANELS_VISUAL.TDG_ADD_ROW(RDATA_GRID => RDG, RROW => RDG_ROW_FACT);
|
||||
end if;
|
||||
end loop;
|
||||
/* Сериализуем описание */
|
||||
COUT := PKG_P8PANELS_VISUAL.TDATA_GRID_TO_XML(RDATA_GRID => RDG, NINCLUDE_DEF => 1);
|
||||
COUT := PKG_P8PANELS_VISUAL.TDG_TO_XML(RDATA_GRID => RDG, NINCLUDE_DEF => 1);
|
||||
/* Очищаем контейнеры */
|
||||
PKG_CONTVALLOC1S.PURGE(RCONTAINER => YM);
|
||||
PKG_CONTVALLOC1S.PURGE(RCONTAINER => MCLR);
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -784,8 +784,8 @@ create or replace package body PKG_P8PANELS_RRPCONFED as
|
||||
is
|
||||
NVERSION PKG_STD.TREF; -- Рег. номер версии словаря контрагентов
|
||||
NCOMPANY PKG_STD.TREF := GET_SESSION_COMPANY(); -- Организация сеанса
|
||||
RDG PKG_P8PANELS_VISUAL.TDATA_GRID; -- Описание таблицы
|
||||
RDG_ROW PKG_P8PANELS_VISUAL.TROW; -- Строка таблицы
|
||||
RDG PKG_P8PANELS_VISUAL.TDG; -- Описание таблицы
|
||||
RDG_ROW PKG_P8PANELS_VISUAL.TDG_ROW; -- Строка таблицы
|
||||
CDG clob; -- XML данных раздела
|
||||
CXML PKG_CONTVALLOC2NS.TCONTAINER; -- Контейнер для данных XML
|
||||
RRRPCONFSCTNMRK RRPCONFSCTNMRK%rowtype; -- Рег. номер показателя
|
||||
@ -798,8 +798,8 @@ create or replace package body PKG_P8PANELS_RRPCONFED as
|
||||
/* Инициализация колонок граф показателей */
|
||||
procedure MARKS_COLUMNS_INIT
|
||||
(
|
||||
RDG in out nocopy PKG_P8PANELS_VISUAL.TDATA_GRID, -- Описание таблицы
|
||||
NRRPCONFSCTN in number -- Рег. номер раздела
|
||||
RDG in out nocopy PKG_P8PANELS_VISUAL.TDG, -- Описание таблицы
|
||||
NRRPCONFSCTN in number -- Рег. номер раздела
|
||||
)
|
||||
is
|
||||
begin
|
||||
@ -816,35 +816,35 @@ create or replace package body PKG_P8PANELS_RRPCONFED as
|
||||
order by C.CODE)
|
||||
loop
|
||||
/* Наименование графы */
|
||||
PKG_P8PANELS_VISUAL.TDATA_GRID_ADD_COL_DEF(RDATA_GRID => RDG,
|
||||
SNAME => 'SCOL_' || REC.CODE,
|
||||
SCAPTION => REC.NAME,
|
||||
SDATA_TYPE => PKG_P8PANELS_VISUAL.SDATA_TYPE_STR,
|
||||
NWIDTH => 200);
|
||||
PKG_P8PANELS_VISUAL.TDG_ADD_COL_DEF(RDATA_GRID => RDG,
|
||||
SNAME => 'SCOL_' || REC.CODE,
|
||||
SCAPTION => REC.NAME,
|
||||
SDATA_TYPE => PKG_P8PANELS_VISUAL.SDATA_TYPE_STR,
|
||||
NWIDTH => 200);
|
||||
/* Рег. номер графы */
|
||||
PKG_P8PANELS_VISUAL.TDATA_GRID_ADD_COL_DEF(RDATA_GRID => RDG,
|
||||
SNAME => 'NCOL_RN_' || REC.CODE,
|
||||
SCAPTION => REC.NAME || ' рег. номер',
|
||||
SDATA_TYPE => PKG_P8PANELS_VISUAL.SDATA_TYPE_NUMB,
|
||||
BVISIBLE => false);
|
||||
PKG_P8PANELS_VISUAL.TDG_ADD_COL_DEF(RDATA_GRID => RDG,
|
||||
SNAME => 'NCOL_RN_' || REC.CODE,
|
||||
SCAPTION => REC.NAME || ' рег. номер',
|
||||
SDATA_TYPE => PKG_P8PANELS_VISUAL.SDATA_TYPE_NUMB,
|
||||
BVISIBLE => false);
|
||||
/* Рег. номер показателя */
|
||||
PKG_P8PANELS_VISUAL.TDATA_GRID_ADD_COL_DEF(RDATA_GRID => RDG,
|
||||
SNAME => 'NMARK_RN_' || REC.CODE,
|
||||
SCAPTION => REC.NAME || ' рег. номер показателя',
|
||||
SDATA_TYPE => PKG_P8PANELS_VISUAL.SDATA_TYPE_NUMB,
|
||||
BVISIBLE => false);
|
||||
PKG_P8PANELS_VISUAL.TDG_ADD_COL_DEF(RDATA_GRID => RDG,
|
||||
SNAME => 'NMARK_RN_' || REC.CODE,
|
||||
SCAPTION => REC.NAME || ' рег. номер показателя',
|
||||
SDATA_TYPE => PKG_P8PANELS_VISUAL.SDATA_TYPE_NUMB,
|
||||
BVISIBLE => false);
|
||||
/* Мнемокод показателя */
|
||||
PKG_P8PANELS_VISUAL.TDATA_GRID_ADD_COL_DEF(RDATA_GRID => RDG,
|
||||
SNAME => 'SMARK_CODE_' || REC.CODE,
|
||||
SCAPTION => REC.NAME || ' мнемокод показателя',
|
||||
SDATA_TYPE => PKG_P8PANELS_VISUAL.SDATA_TYPE_STR,
|
||||
BVISIBLE => false);
|
||||
PKG_P8PANELS_VISUAL.TDG_ADD_COL_DEF(RDATA_GRID => RDG,
|
||||
SNAME => 'SMARK_CODE_' || REC.CODE,
|
||||
SCAPTION => REC.NAME || ' мнемокод показателя',
|
||||
SDATA_TYPE => PKG_P8PANELS_VISUAL.SDATA_TYPE_STR,
|
||||
BVISIBLE => false);
|
||||
/* Для составов показтелей */
|
||||
PKG_P8PANELS_VISUAL.TDATA_GRID_ADD_COL_DEF(RDATA_GRID => RDG,
|
||||
SNAME => 'MARK_CNS_' || REC.CODE,
|
||||
SCAPTION => REC.NAME || ' состав показателя',
|
||||
SDATA_TYPE => PKG_P8PANELS_VISUAL.SDATA_TYPE_STR,
|
||||
BVISIBLE => false);
|
||||
PKG_P8PANELS_VISUAL.TDG_ADD_COL_DEF(RDATA_GRID => RDG,
|
||||
SNAME => 'MARK_CNS_' || REC.CODE,
|
||||
SCAPTION => REC.NAME || ' состав показателя',
|
||||
SDATA_TYPE => PKG_P8PANELS_VISUAL.SDATA_TYPE_STR,
|
||||
BVISIBLE => false);
|
||||
end loop;
|
||||
end MARKS_COLUMNS_INIT;
|
||||
|
||||
@ -897,25 +897,25 @@ create or replace package body PKG_P8PANELS_RRPCONFED as
|
||||
order by T.CODE)
|
||||
loop
|
||||
/* Инициализируем таблицу данных */
|
||||
RDG := PKG_P8PANELS_VISUAL.TDATA_GRID_MAKE(BFIXED_HEADER => true, NFIXED_COLUMNS => 1);
|
||||
RDG := PKG_P8PANELS_VISUAL.TDG_MAKE(BFIXED_HEADER => true, NFIXED_COLUMNS => 1);
|
||||
/* Формируем структуру заголовка */
|
||||
PKG_P8PANELS_VISUAL.TDATA_GRID_ADD_COL_DEF(RDATA_GRID => RDG,
|
||||
SNAME => 'SROW_NAME',
|
||||
SCAPTION => '',
|
||||
SDATA_TYPE => PKG_P8PANELS_VISUAL.SDATA_TYPE_STR,
|
||||
NWIDTH => 150);
|
||||
PKG_P8PANELS_VISUAL.TDG_ADD_COL_DEF(RDATA_GRID => RDG,
|
||||
SNAME => 'SROW_NAME',
|
||||
SCAPTION => '',
|
||||
SDATA_TYPE => PKG_P8PANELS_VISUAL.SDATA_TYPE_STR,
|
||||
NWIDTH => 150);
|
||||
/* Формируем структуру заголовка */
|
||||
PKG_P8PANELS_VISUAL.TDATA_GRID_ADD_COL_DEF(RDATA_GRID => RDG,
|
||||
SNAME => 'SROW_CODE',
|
||||
SCAPTION => 'Мнемокод строки',
|
||||
SDATA_TYPE => PKG_P8PANELS_VISUAL.SDATA_TYPE_STR,
|
||||
BVISIBLE => false);
|
||||
PKG_P8PANELS_VISUAL.TDG_ADD_COL_DEF(RDATA_GRID => RDG,
|
||||
SNAME => 'SROW_CODE',
|
||||
SCAPTION => 'Мнемокод строки',
|
||||
SDATA_TYPE => PKG_P8PANELS_VISUAL.SDATA_TYPE_STR,
|
||||
BVISIBLE => false);
|
||||
/* Формируем структуру заголовка */
|
||||
PKG_P8PANELS_VISUAL.TDATA_GRID_ADD_COL_DEF(RDATA_GRID => RDG,
|
||||
SNAME => 'NROW_RN',
|
||||
SCAPTION => 'Рег. номер строки',
|
||||
SDATA_TYPE => PKG_P8PANELS_VISUAL.SDATA_TYPE_NUMB,
|
||||
BVISIBLE => false);
|
||||
PKG_P8PANELS_VISUAL.TDG_ADD_COL_DEF(RDATA_GRID => RDG,
|
||||
SNAME => 'NROW_RN',
|
||||
SCAPTION => 'Рег. номер строки',
|
||||
SDATA_TYPE => PKG_P8PANELS_VISUAL.SDATA_TYPE_NUMB,
|
||||
BVISIBLE => false);
|
||||
/* Если раздел содержит показатели */
|
||||
if (S.NMARKS_EXISTS = 1) then
|
||||
/* Инициализируем колонки граф */
|
||||
@ -938,11 +938,11 @@ create or replace package body PKG_P8PANELS_RRPCONFED as
|
||||
LPAD(R.CODE, 20, '0'))
|
||||
loop
|
||||
/* Заполняем наименование строки */
|
||||
PKG_P8PANELS_VISUAL.TROW_ADD_COL(RROW => RDG_ROW, SNAME => 'SROW_NAME', SVALUE => R.NAME, BCLEAR => true);
|
||||
PKG_P8PANELS_VISUAL.TDG_ROW_ADD_COL(RROW => RDG_ROW, SNAME => 'SROW_NAME', SVALUE => R.NAME, BCLEAR => true);
|
||||
/* Заполняем мнемокод строки */
|
||||
PKG_P8PANELS_VISUAL.TROW_ADD_COL(RROW => RDG_ROW, SNAME => 'SROW_CODE', SVALUE => R.CODE);
|
||||
PKG_P8PANELS_VISUAL.TDG_ROW_ADD_COL(RROW => RDG_ROW, SNAME => 'SROW_CODE', SVALUE => R.CODE);
|
||||
/* Заполняем рег. номер строки */
|
||||
PKG_P8PANELS_VISUAL.TROW_ADD_COL(RROW => RDG_ROW, SNAME => 'NROW_RN', NVALUE => R.RN);
|
||||
PKG_P8PANELS_VISUAL.TDG_ROW_ADD_COL(RROW => RDG_ROW, SNAME => 'NROW_RN', NVALUE => R.RN);
|
||||
/* Обходим графы раздела */
|
||||
for C in (select C.RN,
|
||||
C.CODE,
|
||||
@ -963,29 +963,29 @@ create or replace package body PKG_P8PANELS_RRPCONFED as
|
||||
/* Считываем показатель по строке/графе */
|
||||
RRRPCONFSCTNMRK := RRPCONFSCTNMRK_GET_ROWCOL(NRRPCONFSCTN => S.NRN, NRRPROW => R.RN, NRRPCOLUMN => C.RN);
|
||||
/* Заполняем рег. номер графы */
|
||||
PKG_P8PANELS_VISUAL.TROW_ADD_COL(RROW => RDG_ROW, SNAME => 'SCOL_' || C.CODE, SVALUE => C.NAME);
|
||||
PKG_P8PANELS_VISUAL.TDG_ROW_ADD_COL(RROW => RDG_ROW, SNAME => 'SCOL_' || C.CODE, SVALUE => C.NAME);
|
||||
/* Заполняем рег. номер графы */
|
||||
PKG_P8PANELS_VISUAL.TROW_ADD_COL(RROW => RDG_ROW, SNAME => 'NCOL_RN_' || C.CODE, NVALUE => C.RN);
|
||||
PKG_P8PANELS_VISUAL.TDG_ROW_ADD_COL(RROW => RDG_ROW, SNAME => 'NCOL_RN_' || C.CODE, NVALUE => C.RN);
|
||||
/* Заполняем рег. номер показателя */
|
||||
PKG_P8PANELS_VISUAL.TROW_ADD_COL(RROW => RDG_ROW,
|
||||
SNAME => 'NMARK_RN_' || C.CODE,
|
||||
NVALUE => RRRPCONFSCTNMRK.RN);
|
||||
PKG_P8PANELS_VISUAL.TDG_ROW_ADD_COL(RROW => RDG_ROW,
|
||||
SNAME => 'NMARK_RN_' || C.CODE,
|
||||
NVALUE => RRRPCONFSCTNMRK.RN);
|
||||
/* Если ошибка считывания показателя */
|
||||
if (RRRPCONFSCTNMRK.RN is not null) then
|
||||
/* Заполняем мнемокод показателя */
|
||||
PKG_P8PANELS_VISUAL.TROW_ADD_COL(RROW => RDG_ROW,
|
||||
SNAME => 'SMARK_CODE_' || C.CODE,
|
||||
SVALUE => RRRPCONFSCTNMRK.CODE);
|
||||
PKG_P8PANELS_VISUAL.TDG_ROW_ADD_COL(RROW => RDG_ROW,
|
||||
SNAME => 'SMARK_CODE_' || C.CODE,
|
||||
SVALUE => RRRPCONFSCTNMRK.CODE);
|
||||
/* Добавляем атрибут состава показателей */
|
||||
PKG_P8PANELS_VISUAL.TROW_ADD_COL(RROW => RDG_ROW, SNAME => 'MARK_CNS_' || C.CODE, SVALUE => null);
|
||||
PKG_P8PANELS_VISUAL.TDG_ROW_ADD_COL(RROW => RDG_ROW, SNAME => 'MARK_CNS_' || C.CODE, SVALUE => null);
|
||||
end if;
|
||||
end loop;
|
||||
/* Добавим строку для раздела */
|
||||
PKG_P8PANELS_VISUAL.TDATA_GRID_ADD_ROW(RDATA_GRID => RDG, RROW => RDG_ROW);
|
||||
PKG_P8PANELS_VISUAL.TDG_ADD_ROW(RDATA_GRID => RDG, RROW => RDG_ROW);
|
||||
end loop;
|
||||
end if;
|
||||
/* Сериализуем описание */
|
||||
CDG := PKG_P8PANELS_VISUAL.TDATA_GRID_TO_XML(RDATA_GRID => RDG, NINCLUDE_DEF => 1);
|
||||
CDG := PKG_P8PANELS_VISUAL.TDG_TO_XML(RDATA_GRID => RDG, NINCLUDE_DEF => 1);
|
||||
/* Заполняем контейнер данными о разделе */
|
||||
PKG_CONTVALLOC2NS.PUTN(RCONTAINER => CXML, NTABID => S.RNUM, SROWID => 'RN', NVALUE => S.NRN);
|
||||
PKG_CONTVALLOC2NS.PUTS(RCONTAINER => CXML, NTABID => S.RNUM, SROWID => 'CODE', SVALUE => S.SCODE);
|
||||
|
@ -59,10 +59,35 @@ create or replace package PKG_P8PANELS_SAMPLES as
|
||||
DDATE_TO in date -- Дата окончания задачи
|
||||
);
|
||||
|
||||
/* Инициализация буфера данных для диаграммы Ганта */
|
||||
procedure CYCLOGRAM_INIT
|
||||
(
|
||||
NIDENT in out number -- Идентификатор буфера сформированных данных (null - сгенерировать новый, !null - удалить старые данные и пересоздать с указанным идентификатором)
|
||||
);
|
||||
|
||||
/* Сбор данных для отображения циклограммы */
|
||||
procedure CYCLOGRAM
|
||||
(
|
||||
NIDENT in number, -- Идентификатор процесса
|
||||
COUT out clob -- Сериализованные данные для циклограммы
|
||||
);
|
||||
|
||||
/* Изменение задачи циклограммы */
|
||||
procedure CYCLOGRAM_TASK_MODIFY
|
||||
(
|
||||
NIDENT in number, -- Идентификатор буфера
|
||||
NRN in number, -- Рег. номер записи
|
||||
SDATE_FROM in varchar2, -- Дата начала (в строковом представлении)
|
||||
SDATE_TO in varchar2 -- Дата окончания (в строковом представлении)
|
||||
);
|
||||
|
||||
end PKG_P8PANELS_SAMPLES;
|
||||
/
|
||||
create or replace package body PKG_P8PANELS_SAMPLES as
|
||||
|
||||
/* Константы - циклограмма */
|
||||
NCG_MULTIPLIER constant PKG_STD.TNUMBER := 5; -- Множитель для ширины отображения
|
||||
|
||||
/* Получение списка контрагентов */
|
||||
procedure AGNLIST_GET
|
||||
(
|
||||
@ -205,6 +230,7 @@ create or replace package body PKG_P8PANELS_SAMPLES as
|
||||
NCONTACT_METHOD => null,
|
||||
SMF_ID => null,
|
||||
SOKOGU => null,
|
||||
NJURPERS_SUBDIV => null,
|
||||
NRN => NRN);
|
||||
end AGNLIST_INSERT;
|
||||
|
||||
@ -231,11 +257,11 @@ create or replace package body PKG_P8PANELS_SAMPLES as
|
||||
is
|
||||
NCOMPANY PKG_STD.TREF := GET_SESSION_COMPANY(); -- Организация сеанса
|
||||
NIDENT PKG_STD.TREF := GEN_IDENT(); -- Идентификатор отбора
|
||||
RF PKG_P8PANELS_VISUAL.TFILTERS; -- Фильтры
|
||||
RO PKG_P8PANELS_VISUAL.TORDERS; -- Сортировки
|
||||
RDG PKG_P8PANELS_VISUAL.TDATA_GRID; -- Описание таблицы
|
||||
RAGN_TYPES PKG_P8PANELS_VISUAL.TCOL_VALS; -- Предопределенные значения "Типа контрагентов"
|
||||
RDG_ROW PKG_P8PANELS_VISUAL.TROW; -- Строка таблицы
|
||||
RF PKG_P8PANELS_VISUAL.TDG_FILTERS; -- Фильтры
|
||||
RO PKG_P8PANELS_VISUAL.TDG_ORDERS; -- Сортировки
|
||||
RDG PKG_P8PANELS_VISUAL.TDG; -- Описание таблицы
|
||||
RAGN_TYPES PKG_P8PANELS_VISUAL.TDG_COL_VALS; -- Предопределенные значения "Типа контрагентов"
|
||||
RDG_ROW PKG_P8PANELS_VISUAL.TDG_ROW; -- Строка таблицы
|
||||
NROW_FROM PKG_STD.TREF; -- Номер строки с
|
||||
NROW_TO PKG_STD.TREF; -- Номер строки по
|
||||
CSQL clob; -- Буфер для запроса
|
||||
@ -246,71 +272,71 @@ create or replace package body PKG_P8PANELS_SAMPLES as
|
||||
NAGNTYPE PKG_STD.TREF; -- Буфер для "Типа"
|
||||
begin
|
||||
/* Читаем фильтры */
|
||||
RF := PKG_P8PANELS_VISUAL.TFILTERS_FROM_XML(CFILTERS => CFILTERS);
|
||||
RF := PKG_P8PANELS_VISUAL.TDG_FILTERS_FROM_XML(CFILTERS => CFILTERS);
|
||||
/* Читем сортировки */
|
||||
RO := PKG_P8PANELS_VISUAL.TORDERS_FROM_XML(CORDERS => CORDERS);
|
||||
RO := PKG_P8PANELS_VISUAL.TDG_ORDERS_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(BFIXED_HEADER => true, NFIXED_COLUMNS => 2);
|
||||
RDG := PKG_P8PANELS_VISUAL.TDG_MAKE(BFIXED_HEADER => true, NFIXED_COLUMNS => 2);
|
||||
/* Описываем колонки таблицы данных */
|
||||
PKG_P8PANELS_VISUAL.TDATA_GRID_ADD_COL_DEF(RDATA_GRID => RDG,
|
||||
SNAME => 'SAGNABBR',
|
||||
SCAPTION => 'Мнемокод',
|
||||
SDATA_TYPE => PKG_P8PANELS_VISUAL.SDATA_TYPE_STR,
|
||||
SCOND_FROM => 'AgentAbbr',
|
||||
BVISIBLE => true,
|
||||
BORDER => true,
|
||||
BFILTER => true,
|
||||
NWIDTH => 150);
|
||||
PKG_P8PANELS_VISUAL.TDATA_GRID_ADD_COL_DEF(RDATA_GRID => RDG,
|
||||
SNAME => 'SAGNINFO',
|
||||
SCAPTION => 'Сведения',
|
||||
SDATA_TYPE => PKG_P8PANELS_VISUAL.SDATA_TYPE_STR,
|
||||
BVISIBLE => true,
|
||||
BORDER => false,
|
||||
BFILTER => false,
|
||||
BEXPANDABLE => true,
|
||||
NWIDTH => 300);
|
||||
PKG_P8PANELS_VISUAL.TDATA_GRID_ADD_COL_DEF(RDATA_GRID => RDG,
|
||||
SNAME => 'SAGNNAME',
|
||||
SCAPTION => 'Наименование',
|
||||
SDATA_TYPE => PKG_P8PANELS_VISUAL.SDATA_TYPE_STR,
|
||||
SCOND_FROM => 'AgentName',
|
||||
BVISIBLE => true,
|
||||
BORDER => true,
|
||||
BFILTER => true,
|
||||
SPARENT => 'SAGNINFO',
|
||||
NWIDTH => 200);
|
||||
PKG_P8PANELS_VISUAL.TCOL_VALS_ADD(RCOL_VALS => RAGN_TYPES, NVALUE => 0);
|
||||
PKG_P8PANELS_VISUAL.TCOL_VALS_ADD(RCOL_VALS => RAGN_TYPES, NVALUE => 1);
|
||||
PKG_P8PANELS_VISUAL.TDATA_GRID_ADD_COL_DEF(RDATA_GRID => RDG,
|
||||
SNAME => 'NAGNTYPE',
|
||||
SCAPTION => 'Тип',
|
||||
SDATA_TYPE => PKG_P8PANELS_VISUAL.SDATA_TYPE_NUMB,
|
||||
SCOND_FROM => 'AgentType',
|
||||
BVISIBLE => true,
|
||||
BORDER => true,
|
||||
BFILTER => true,
|
||||
SPARENT => 'SAGNINFO',
|
||||
NWIDTH => 100,
|
||||
RCOL_VALS => RAGN_TYPES,
|
||||
SHINT => 'В Системе бывают контрагенты двух типов:<br>' ||
|
||||
'<b style="color:blue">Юридическое лицо</b> - организация, которая имеет в собственности, хозяйственном ведении ' ||
|
||||
'или оперативном управлении обособленное имущество, отвечает по своим обязательствам этим имуществом, может от своего ' ||
|
||||
'имени приобретать и осуществлять имущественные и личные неимущественные права, отвечать по своим обязанностям.<br>' ||
|
||||
'<b style="color:green">Физическое лицо</b> - субъект правовых отношений, представляющий собой одного человека.');
|
||||
PKG_P8PANELS_VISUAL.TDATA_GRID_ADD_COL_DEF(RDATA_GRID => RDG,
|
||||
SNAME => 'SFULLNAME',
|
||||
SCAPTION => 'Полное наименование',
|
||||
SDATA_TYPE => PKG_P8PANELS_VISUAL.SDATA_TYPE_STR);
|
||||
PKG_P8PANELS_VISUAL.TDATA_GRID_ADD_COL_DEF(RDATA_GRID => RDG,
|
||||
SNAME => 'SAGNIDNUMB',
|
||||
SCAPTION => 'ИНН',
|
||||
SDATA_TYPE => PKG_P8PANELS_VISUAL.SDATA_TYPE_STR);
|
||||
PKG_P8PANELS_VISUAL.TDG_ADD_COL_DEF(RDATA_GRID => RDG,
|
||||
SNAME => 'SAGNABBR',
|
||||
SCAPTION => 'Мнемокод',
|
||||
SDATA_TYPE => PKG_P8PANELS_VISUAL.SDATA_TYPE_STR,
|
||||
SCOND_FROM => 'AgentAbbr',
|
||||
BVISIBLE => true,
|
||||
BORDER => true,
|
||||
BFILTER => true,
|
||||
NWIDTH => 150);
|
||||
PKG_P8PANELS_VISUAL.TDG_ADD_COL_DEF(RDATA_GRID => RDG,
|
||||
SNAME => 'SAGNINFO',
|
||||
SCAPTION => 'Сведения',
|
||||
SDATA_TYPE => PKG_P8PANELS_VISUAL.SDATA_TYPE_STR,
|
||||
BVISIBLE => true,
|
||||
BORDER => false,
|
||||
BFILTER => false,
|
||||
BEXPANDABLE => true,
|
||||
NWIDTH => 300);
|
||||
PKG_P8PANELS_VISUAL.TDG_ADD_COL_DEF(RDATA_GRID => RDG,
|
||||
SNAME => 'SAGNNAME',
|
||||
SCAPTION => 'Наименование',
|
||||
SDATA_TYPE => PKG_P8PANELS_VISUAL.SDATA_TYPE_STR,
|
||||
SCOND_FROM => 'AgentName',
|
||||
BVISIBLE => true,
|
||||
BORDER => true,
|
||||
BFILTER => true,
|
||||
SPARENT => 'SAGNINFO',
|
||||
NWIDTH => 200);
|
||||
PKG_P8PANELS_VISUAL.TDG_COL_VALS_ADD(RCOL_VALS => RAGN_TYPES, NVALUE => 0);
|
||||
PKG_P8PANELS_VISUAL.TDG_COL_VALS_ADD(RCOL_VALS => RAGN_TYPES, NVALUE => 1);
|
||||
PKG_P8PANELS_VISUAL.TDG_ADD_COL_DEF(RDATA_GRID => RDG,
|
||||
SNAME => 'NAGNTYPE',
|
||||
SCAPTION => 'Тип',
|
||||
SDATA_TYPE => PKG_P8PANELS_VISUAL.SDATA_TYPE_NUMB,
|
||||
SCOND_FROM => 'AgentType',
|
||||
BVISIBLE => true,
|
||||
BORDER => true,
|
||||
BFILTER => true,
|
||||
SPARENT => 'SAGNINFO',
|
||||
NWIDTH => 100,
|
||||
RCOL_VALS => RAGN_TYPES,
|
||||
SHINT => 'В Системе бывают контрагенты двух типов:<br>' ||
|
||||
'<b style="color:blue">Юридическое лицо</b> - организация, которая имеет в собственности, хозяйственном ведении ' ||
|
||||
'или оперативном управлении обособленное имущество, отвечает по своим обязательствам этим имуществом, может от своего ' ||
|
||||
'имени приобретать и осуществлять имущественные и личные неимущественные права, отвечать по своим обязанностям.<br>' ||
|
||||
'<b style="color:green">Физическое лицо</b> - субъект правовых отношений, представляющий собой одного человека.');
|
||||
PKG_P8PANELS_VISUAL.TDG_ADD_COL_DEF(RDATA_GRID => RDG,
|
||||
SNAME => 'SFULLNAME',
|
||||
SCAPTION => 'Полное наименование',
|
||||
SDATA_TYPE => PKG_P8PANELS_VISUAL.SDATA_TYPE_STR);
|
||||
PKG_P8PANELS_VISUAL.TDG_ADD_COL_DEF(RDATA_GRID => RDG,
|
||||
SNAME => 'SAGNIDNUMB',
|
||||
SCAPTION => 'ИНН',
|
||||
SDATA_TYPE => PKG_P8PANELS_VISUAL.SDATA_TYPE_STR);
|
||||
/* Обходим данные */
|
||||
begin
|
||||
/* Добавляем подсказку совместимости */
|
||||
@ -336,14 +362,17 @@ create or replace package body PKG_P8PANELS_SAMPLES as
|
||||
PKG_SQL_BUILD.APPEND(SSQL => CSQL, SELEMENT1 => ' and AG.RN in (select ID from COND_BROKER_IDSMART where IDENT = :NIDENT) %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);
|
||||
PKG_P8PANELS_VISUAL.TDG_ORDERS_SET_QUERY(RDATA_GRID => RDG,
|
||||
RORDERS => RO,
|
||||
SPATTERN => '%ORDER_BY%',
|
||||
CSQL => CSQL);
|
||||
/* Учтём фильтры */
|
||||
PKG_P8PANELS_VISUAL.TFILTERS_SET_QUERY(NIDENT => NIDENT,
|
||||
NCOMPANY => NCOMPANY,
|
||||
SUNIT => 'AGNLIST',
|
||||
SPROCEDURE => 'P_AGNLIST_BASE_COND',
|
||||
RDATA_GRID => RDG,
|
||||
RFILTERS => RF);
|
||||
PKG_P8PANELS_VISUAL.TDG_FILTERS_SET_QUERY(NIDENT => NIDENT,
|
||||
NCOMPANY => NCOMPANY,
|
||||
SUNIT => 'AGNLIST',
|
||||
SPROCEDURE => 'P_AGNLIST_BASE_COND',
|
||||
RDATA_GRID => RDG,
|
||||
RFILTERS => RF);
|
||||
/* Разбираем его */
|
||||
ICURSOR := PKG_SQL_DML.OPEN_CURSOR(SWHAT => 'SELECT');
|
||||
PKG_SQL_DML.PARSE(ICURSOR => ICURSOR, SQUERY => CSQL);
|
||||
@ -356,7 +385,7 @@ create or replace package body PKG_P8PANELS_SAMPLES as
|
||||
PKG_SQL_DML.DEFINE_COLUMN_STR(ICURSOR => ICURSOR, IPOSITION => 2);
|
||||
PKG_SQL_DML.DEFINE_COLUMN_NUM(ICURSOR => ICURSOR, IPOSITION => 3);
|
||||
PKG_SQL_DML.DEFINE_COLUMN_STR(ICURSOR => ICURSOR, IPOSITION => 4);
|
||||
PKG_SQL_DML.DEFINE_COLUMN_STR(ICURSOR => ICURSOR, IPOSITION => 5);
|
||||
PKG_SQL_DML.DEFINE_COLUMN_STR(ICURSOR => ICURSOR, IPOSITION => 5);
|
||||
PKG_SQL_DML.DEFINE_COLUMN_NUM(ICURSOR => ICURSOR, IPOSITION => 6);
|
||||
/* Делаем выборку */
|
||||
if (PKG_SQL_DML.EXECUTE(ICURSOR => ICURSOR) = 0) then
|
||||
@ -371,29 +400,38 @@ create or replace package body PKG_P8PANELS_SAMPLES as
|
||||
if (NAGNTYPE = 0) then
|
||||
SGROUP := 'JUR';
|
||||
SAGNINFO := SAGNNAME || ', ЮЛ';
|
||||
PKG_P8PANELS_VISUAL.TDATA_GRID_ADD_GROUP(RDATA_GRID => RDG,
|
||||
SNAME => SGROUP,
|
||||
SCAPTION => 'Юридические лица',
|
||||
BEXPANDABLE => true,
|
||||
BEXPANDED => false);
|
||||
PKG_P8PANELS_VISUAL.TDG_ADD_GROUP(RDATA_GRID => RDG,
|
||||
SNAME => SGROUP,
|
||||
SCAPTION => 'Юридические лица',
|
||||
BEXPANDABLE => true,
|
||||
BEXPANDED => false);
|
||||
else
|
||||
SGROUP := 'PERS';
|
||||
SAGNINFO := SAGNNAME || ', ФЛ';
|
||||
PKG_P8PANELS_VISUAL.TDATA_GRID_ADD_GROUP(RDATA_GRID => RDG,
|
||||
SNAME => SGROUP,
|
||||
SCAPTION => 'Физические лица',
|
||||
BEXPANDABLE => true,
|
||||
BEXPANDED => false);
|
||||
PKG_P8PANELS_VISUAL.TDG_ADD_GROUP(RDATA_GRID => RDG,
|
||||
SNAME => SGROUP,
|
||||
SCAPTION => 'Физические лица',
|
||||
BEXPANDABLE => true,
|
||||
BEXPANDED => false);
|
||||
end if;
|
||||
RDG_ROW := PKG_P8PANELS_VISUAL.TROW_MAKE(SGROUP => SGROUP);
|
||||
PKG_P8PANELS_VISUAL.TROW_ADD_CUR_COLS(RROW => RDG_ROW, SNAME => 'SAGNABBR', ICURSOR => ICURSOR, NPOSITION => 1);
|
||||
PKG_P8PANELS_VISUAL.TROW_ADD_COL(RROW => RDG_ROW, SNAME => 'SAGNINFO', SVALUE => SAGNINFO);
|
||||
PKG_P8PANELS_VISUAL.TROW_ADD_COL(RROW => RDG_ROW, SNAME => 'SAGNNAME', SVALUE => SAGNNAME);
|
||||
PKG_P8PANELS_VISUAL.TROW_ADD_COL(RROW => RDG_ROW, SNAME => 'NAGNTYPE', NVALUE => NAGNTYPE);
|
||||
PKG_P8PANELS_VISUAL.TROW_ADD_CUR_COLS(RROW => RDG_ROW, SNAME => 'SFULLNAME', ICURSOR => ICURSOR, NPOSITION => 4);
|
||||
PKG_P8PANELS_VISUAL.TROW_ADD_CUR_COLS(RROW => RDG_ROW, SNAME => 'SAGNIDNUMB', ICURSOR => ICURSOR, NPOSITION => 5);
|
||||
RDG_ROW := PKG_P8PANELS_VISUAL.TDG_ROW_MAKE(SGROUP => SGROUP);
|
||||
PKG_P8PANELS_VISUAL.TDG_ROW_ADD_CUR_COLS(RROW => RDG_ROW,
|
||||
SNAME => 'SAGNABBR',
|
||||
ICURSOR => ICURSOR,
|
||||
NPOSITION => 1);
|
||||
PKG_P8PANELS_VISUAL.TDG_ROW_ADD_COL(RROW => RDG_ROW, SNAME => 'SAGNINFO', SVALUE => SAGNINFO);
|
||||
PKG_P8PANELS_VISUAL.TDG_ROW_ADD_COL(RROW => RDG_ROW, SNAME => 'SAGNNAME', SVALUE => SAGNNAME);
|
||||
PKG_P8PANELS_VISUAL.TDG_ROW_ADD_COL(RROW => RDG_ROW, SNAME => 'NAGNTYPE', NVALUE => NAGNTYPE);
|
||||
PKG_P8PANELS_VISUAL.TDG_ROW_ADD_CUR_COLS(RROW => RDG_ROW,
|
||||
SNAME => 'SFULLNAME',
|
||||
ICURSOR => ICURSOR,
|
||||
NPOSITION => 4);
|
||||
PKG_P8PANELS_VISUAL.TDG_ROW_ADD_CUR_COLS(RROW => RDG_ROW,
|
||||
SNAME => 'SAGNIDNUMB',
|
||||
ICURSOR => ICURSOR,
|
||||
NPOSITION => 5);
|
||||
/* Добавляем строку в таблицу */
|
||||
PKG_P8PANELS_VISUAL.TDATA_GRID_ADD_ROW(RDATA_GRID => RDG, RROW => RDG_ROW);
|
||||
PKG_P8PANELS_VISUAL.TDG_ADD_ROW(RDATA_GRID => RDG, RROW => RDG_ROW);
|
||||
end loop;
|
||||
/* Освобождаем курсор */
|
||||
PKG_SQL_DML.CLOSE_CURSOR(ICURSOR => ICURSOR);
|
||||
@ -403,7 +441,7 @@ create or replace package body PKG_P8PANELS_SAMPLES as
|
||||
raise;
|
||||
end;
|
||||
/* Сериализуем описание */
|
||||
COUT := PKG_P8PANELS_VISUAL.TDATA_GRID_TO_XML(RDATA_GRID => RDG, NINCLUDE_DEF => NINCLUDE_DEF);
|
||||
COUT := PKG_P8PANELS_VISUAL.TDG_TO_XML(RDATA_GRID => RDG, NINCLUDE_DEF => NINCLUDE_DEF);
|
||||
end DATA_GRID;
|
||||
|
||||
/* График */
|
||||
@ -666,6 +704,533 @@ create or replace package body PKG_P8PANELS_SAMPLES as
|
||||
DDATE_TO => TRUNC(DDATE_TO));
|
||||
end loop;
|
||||
end GANTT_MODIFY;
|
||||
|
||||
/* Очистка буфера данных для циклограммы */
|
||||
procedure CYCLOGRAM_BASE_CLEAN
|
||||
(
|
||||
NIDENT in number -- Идентификатор буфера
|
||||
)
|
||||
is
|
||||
begin
|
||||
/* Удалим из буфера всё с указанным идентификатором */
|
||||
delete from P8PNL_SMPL_CYCLOGRAM T where T.IDENT = NIDENT;
|
||||
end CYCLOGRAM_BASE_CLEAN;
|
||||
|
||||
/* Добавление данных в буфер циклограммы */
|
||||
procedure CYCLOGRAM_BASE_INSERT
|
||||
(
|
||||
NIDENT in number, -- Идентификатор буфера
|
||||
NTYPE in number, -- Тип (0 - колонка, 1 - группа, 2 - задача)
|
||||
SNAME in varchar2, -- Наименование
|
||||
NPOS_START in number := null, -- Позиция начала элемента
|
||||
NPOS_END in number := null, -- Позиция окончания элемента
|
||||
DDATE_FROM in date := null, -- Дата начала
|
||||
DDATE_TO in date := null, -- Дата окончания
|
||||
NTASK_GROUP in number := null, -- Рег. номер группы
|
||||
NRN out number -- Рег. номер записи
|
||||
)
|
||||
is
|
||||
begin
|
||||
/* Генерируем рег. номер записи */
|
||||
NRN := GEN_ID();
|
||||
/* Добавим запись */
|
||||
insert into P8PNL_SMPL_CYCLOGRAM
|
||||
(RN, IDENT, type, name, POS_START, POS_END, DATE_FROM, DATE_TO, TASK_GROUP)
|
||||
values
|
||||
(NRN, NIDENT, NTYPE, SNAME, NPOS_START, NPOS_END, DDATE_FROM, DDATE_TO, NTASK_GROUP);
|
||||
end CYCLOGRAM_BASE_INSERT;
|
||||
|
||||
/* Исправление данных в буфере циклограммы */
|
||||
procedure CYCLOGRAM_BASE_UPDATE
|
||||
(
|
||||
NIDENT in number, -- Идентификатор буфера
|
||||
NRN in number, -- Рег. номер записи
|
||||
NTYPE in number, -- Тип задачи (0 - этап/веха, 1 - работа)
|
||||
SNAME in varchar2, -- Наименование
|
||||
NPOS_START in number, -- Позиция начала
|
||||
NPOS_END in number, -- Позиция окончания
|
||||
DDATE_FROM in date, -- Дата начала
|
||||
DDATE_TO in date, -- Дата окончания
|
||||
NTASK_GROUP in number -- Рег. номер группы
|
||||
)
|
||||
is
|
||||
begin
|
||||
/* Изменим запись */
|
||||
update P8PNL_SMPL_CYCLOGRAM T
|
||||
set T.TYPE = NTYPE,
|
||||
T.NAME = SNAME,
|
||||
T.POS_START = NPOS_START,
|
||||
T.POS_END = NPOS_END,
|
||||
T.DATE_FROM = DDATE_FROM,
|
||||
T.DATE_TO = DDATE_TO,
|
||||
T.TASK_GROUP = NTASK_GROUP
|
||||
where T.RN = NRN
|
||||
and T.IDENT = NIDENT;
|
||||
end CYCLOGRAM_BASE_UPDATE;
|
||||
|
||||
/* Инициализация буфера данных для циклограммы */
|
||||
procedure CYCLOGRAM_INIT
|
||||
(
|
||||
NIDENT in out number -- Идентификатор буфера сформированных данных (null - сгенерировать новый, !null - удалить старые данные и пересоздать с указанным идентификатором)
|
||||
)
|
||||
is
|
||||
NYEAR PKG_STD.TNUMBER; -- Текущий год
|
||||
DCYCLOGRAM_START PKG_STD.TLDATE; -- Дата начала циклограммы
|
||||
DMONTH_CUR PKG_STD.TLDATE; -- Текущий месяц (для расчетов)
|
||||
DMONTH_START PKG_STD.TLDATE; -- Начало месяца (для расчетов)
|
||||
DMONTH_END PKG_STD.TLDATE; -- Окончание месяца (для расчетов)
|
||||
NMONTH_DAYS PKG_STD.TNUMBER; -- Количество дней месяца
|
||||
NSTART PKG_STD.TNUMBER := 0; -- Позиция начала элемента
|
||||
NEND PKG_STD.TNUMBER := 0; -- Позиция окончания элемента
|
||||
NGROUP PKG_STD.TNUMBER; -- Рег. номер группы
|
||||
NDUMMY PKG_STD.TNUMBER; -- Буфер для рег. номера
|
||||
NMONTH PKG_STD.TNUMBER; -- Месяц даты
|
||||
|
||||
/* Инициализация группы */
|
||||
procedure INIT_GROUP
|
||||
(
|
||||
NIDENT in number, -- Идентификатор буфера
|
||||
DDATE in date, -- Текущая обрабатываемая дата
|
||||
NRN in out number -- Рег. номер группы
|
||||
)
|
||||
is
|
||||
NMONTH PKG_STD.TNUMBER; -- Месяц даты
|
||||
begin
|
||||
/* Считываем текущий месяц */
|
||||
NMONTH := D_MONTH(DDATE => DDATE);
|
||||
/* Исходим от даты (формируем группу на начало каждого квартала) */
|
||||
case NMONTH
|
||||
/* Первый квартал */
|
||||
when 1 then
|
||||
/* Добавляем группу */
|
||||
CYCLOGRAM_BASE_INSERT(NIDENT => NIDENT, NTYPE => 1, SNAME => 'I группа', NRN => NRN);
|
||||
/* Второй квартал */
|
||||
when 4 then
|
||||
/* Добавляем группу */
|
||||
CYCLOGRAM_BASE_INSERT(NIDENT => NIDENT, NTYPE => 1, SNAME => 'II группа', NRN => NRN);
|
||||
/* Третий квартал */
|
||||
when 7 then
|
||||
/* Добавляем группу */
|
||||
CYCLOGRAM_BASE_INSERT(NIDENT => NIDENT, NTYPE => 1, SNAME => 'III группа', NRN => NRN);
|
||||
/* Четвертый квартал */
|
||||
when 10 then
|
||||
/* ДОбавляем группу */
|
||||
CYCLOGRAM_BASE_INSERT(NIDENT => NIDENT, NTYPE => 1, SNAME => 'IV группа', NRN => NRN);
|
||||
else
|
||||
null;
|
||||
end case;
|
||||
end INIT_GROUP;
|
||||
begin
|
||||
/* Удаляем старые данные из буфера */
|
||||
if (NIDENT is not null) then
|
||||
CYCLOGRAM_BASE_CLEAN(NIDENT => NIDENT);
|
||||
else
|
||||
/* Илиформируем новый идентификатор, если не задан */
|
||||
NIDENT := GEN_IDENT();
|
||||
end if;
|
||||
/* Фиксируем текущий год */
|
||||
NYEAR := EXTRACT(year from sysdate);
|
||||
/* Фиксируем дату начала циклограммы */
|
||||
DCYCLOGRAM_START := TO_DATE('01.01.' || NYEAR, 'dd.mm.yyyy');
|
||||
/* Добавляем колонки и групповые задачи (месяцы года) */
|
||||
for I in 0 .. 11
|
||||
loop
|
||||
/* Рассчитываем текущий месяц */
|
||||
DMONTH_CUR := ADD_MONTHS(DCYCLOGRAM_START, I);
|
||||
/* Считываем первый и последний день месяца */
|
||||
P_FIRST_LAST_DAY(DCALCDATE => DMONTH_CUR, DBGNDATE => DMONTH_START, DENDDATE => DMONTH_END);
|
||||
/* Рассчитываем количество дней месяца */
|
||||
NMONTH_DAYS := DMONTH_END - DMONTH_START + 1;
|
||||
/* Рассчитываем позицию окончания элемента */
|
||||
NEND := NSTART + (NMONTH_DAYS * NCG_MULTIPLIER);
|
||||
/* Определяем номер месяца */
|
||||
NMONTH := D_MONTH(DDATE => DMONTH_CUR);
|
||||
/* Добавляем колонку в таблицу */
|
||||
CYCLOGRAM_BASE_INSERT(NIDENT => NIDENT,
|
||||
NTYPE => 0,
|
||||
SNAME => TO_CHAR(NMONTH),
|
||||
NPOS_START => NSTART,
|
||||
NPOS_END => NEND,
|
||||
NRN => NDUMMY);
|
||||
/* Инициализируем группу */
|
||||
INIT_GROUP(NIDENT => NIDENT, DDATE => DMONTH_CUR, NRN => NGROUP);
|
||||
/* Добавляем задачу */
|
||||
CYCLOGRAM_BASE_INSERT(NIDENT => NIDENT,
|
||||
NTYPE => 2,
|
||||
SNAME => 'Работа ' || TO_CHAR(I + 1),
|
||||
NPOS_START => NSTART,
|
||||
NPOS_END => NEND,
|
||||
DDATE_FROM => DMONTH_START,
|
||||
DDATE_TO => DMONTH_END,
|
||||
NTASK_GROUP => NGROUP,
|
||||
NRN => NDUMMY);
|
||||
/* Если это февраль, май, август или ноябрь - добавляем особосбленную задачу */
|
||||
if (NMONTH in (2, 5, 8, 11)) then
|
||||
/* Добавляем обособленную задачу */
|
||||
CYCLOGRAM_BASE_INSERT(NIDENT => NIDENT,
|
||||
NTYPE => 2,
|
||||
SNAME => 'Обособленная работа ' || NMONTH,
|
||||
NPOS_START => NSTART,
|
||||
NPOS_END => NEND,
|
||||
DDATE_FROM => DMONTH_START,
|
||||
DDATE_TO => DMONTH_END,
|
||||
NRN => NDUMMY);
|
||||
end if;
|
||||
/* Рассчитываем начало следующего месяца */
|
||||
NSTART := NEND;
|
||||
end loop;
|
||||
end CYCLOGRAM_INIT;
|
||||
|
||||
/* Сбор данных для отображения циклограммы */
|
||||
procedure CYCLOGRAM
|
||||
(
|
||||
NIDENT in number, -- Идентификатор процесса
|
||||
COUT out clob -- Сериализованные данные для циклограммы
|
||||
)
|
||||
is
|
||||
CG PKG_P8PANELS_VISUAL.TCYCLOGRAM; -- Описание циклограммы
|
||||
RTASK PKG_P8PANELS_VISUAL.TCYCLOGRAM_TASK; -- Описание задачи циклограммы
|
||||
NLINE_NUMB PKG_STD.TNUMBER := 0; -- Номер строки
|
||||
NLINE_NUMB_TMP PKG_STD.TNUMBER := 0; -- Номер строки (буфер)
|
||||
DTASK_DATE_START PKG_STD.TLDATE; -- Дата начала этапа
|
||||
DTASK_DATE_END PKG_STD.TLDATE; -- Дата окончания этапа
|
||||
NTASK_START PKG_STD.TNUMBER := 0; -- Позиция начала этапа
|
||||
NTASK_END PKG_STD.TNUMBER := 0; -- Позиция окончания этапа
|
||||
STASK_NAME PKG_STD.TSTRING; -- Наименование задачи
|
||||
SCOLOR_WHITE PKG_STD.TSTRING := 'white'; -- Цвет - белый
|
||||
SBG_TASK_COLOR_W_GRP PKG_STD.TSTRING := '#6bc982'; -- Цвет задачи с группой
|
||||
SHL_TASK_COLOR_W_GRP PKG_STD.TSTRING := '#7dd592'; -- Цвет наведения задачи с группой
|
||||
SBG_TASK_COLOR_WO_GRP PKG_STD.TSTRING := '#e36d6d'; -- Цвет задачи без группы
|
||||
STEXT_COLOR_TASK_WO_GRP PKG_STD.TSTRING := '#e5e5e5'; -- Цвет текста задачи без группы
|
||||
SBG_TASK_COLOR_GRP PKG_STD.TSTRING := 'cadetblue'; -- Цвет групповой задачи
|
||||
SHL_TASK_COLOR_GRP PKG_STD.TSTRING := '#6fadaf'; -- Цвет наведения групповой задачи
|
||||
|
||||
/* Считывание значений группирующей задачи */
|
||||
procedure GROUP_TASK_GET
|
||||
(
|
||||
NIDENT in number, -- Идентификатор процесса
|
||||
NGROUP in number := null, -- Рег. номер группы
|
||||
NFLAG_WO_GROUP in number := 0, -- Признак отбора задач без групп (0 - нет, 1 - да)
|
||||
DTASK_DATE_START out date, -- Дата начала этапа
|
||||
DTASK_DATE_END out date, -- Дата окончания этапа
|
||||
NTASK_START out number, -- Позиция начала этапа
|
||||
NTASK_END out number -- Позиция окончания этапа
|
||||
)
|
||||
is
|
||||
begin
|
||||
/* Считываем начало и окончание этапа */
|
||||
begin
|
||||
select min(T.DATE_FROM),
|
||||
max(T.DATE_TO),
|
||||
min(T.POS_START),
|
||||
max(T.POS_END)
|
||||
into DTASK_DATE_START,
|
||||
DTASK_DATE_END,
|
||||
NTASK_START,
|
||||
NTASK_END
|
||||
from P8PNL_SMPL_CYCLOGRAM T
|
||||
where T.IDENT = NIDENT
|
||||
and (((NFLAG_WO_GROUP = 1) and (T.TASK_GROUP is null)) or ((NFLAG_WO_GROUP = 0) and (T.TASK_GROUP is not null)))
|
||||
and ((NGROUP is null) or ((NGROUP is not null) and (T.TASK_GROUP = NGROUP)))
|
||||
and T.TYPE = 2;
|
||||
end;
|
||||
end GROUP_TASK_GET;
|
||||
begin
|
||||
/* Инициализируем циклограмму */
|
||||
CG := PKG_P8PANELS_VISUAL.TCYCLOGRAM_MAKE(STITLE => 'Задачи на ' || TO_CHAR(EXTRACT(year from sysdate)) || ' год');
|
||||
/* Добавляем атрибуты */
|
||||
PKG_P8PANELS_VISUAL.TCYCLOGRAM_ADD_TASK_ATTR(RCYCLOGRAM => CG,
|
||||
SNAME => 'ddate_start',
|
||||
SCAPTION => 'Дата начала',
|
||||
BVISIBLE => true,
|
||||
BCLEAR => true);
|
||||
PKG_P8PANELS_VISUAL.TCYCLOGRAM_ADD_TASK_ATTR(RCYCLOGRAM => CG,
|
||||
SNAME => 'ddate_end',
|
||||
SCAPTION => 'Дата окончания',
|
||||
BVISIBLE => true);
|
||||
PKG_P8PANELS_VISUAL.TCYCLOGRAM_ADD_TASK_ATTR(RCYCLOGRAM => CG,
|
||||
SNAME => 'type',
|
||||
SCAPTION => 'Тип',
|
||||
BVISIBLE => false);
|
||||
/* Обходим колонки */
|
||||
for CLMN in (select T.NAME,
|
||||
T.POS_START,
|
||||
T.POS_END
|
||||
from P8PNL_SMPL_CYCLOGRAM T
|
||||
where T.IDENT = NIDENT
|
||||
and T.TYPE = 0)
|
||||
loop
|
||||
/* Добавляем колонку */
|
||||
PKG_P8PANELS_VISUAL.TCYCLOGRAM_ADD_COLUMN(RCYCLOGRAM => CG,
|
||||
SNAME => CLMN.NAME,
|
||||
NSTART => CLMN.POS_START,
|
||||
NEND => CLMN.POS_END);
|
||||
end loop;
|
||||
/* Считываем значения для задач проекта */
|
||||
GROUP_TASK_GET(NIDENT => NIDENT,
|
||||
NFLAG_WO_GROUP => 0,
|
||||
DTASK_DATE_START => DTASK_DATE_START,
|
||||
DTASK_DATE_END => DTASK_DATE_END,
|
||||
NTASK_START => NTASK_START,
|
||||
NTASK_END => NTASK_END);
|
||||
/* Формируем задачу (этап) */
|
||||
RTASK := PKG_P8PANELS_VISUAL.TCYCLOGRAM_TASK_MAKE(NRN => 1,
|
||||
SCAPTION => 'Задачи проекта',
|
||||
SNAME => 'Задачи проекта',
|
||||
NLINE_NUMB => NLINE_NUMB,
|
||||
NSTART => NTASK_START,
|
||||
NEND => NTASK_END,
|
||||
SBG_COLOR => SCOLOR_WHITE);
|
||||
/* Добавляем атрибуты */
|
||||
PKG_P8PANELS_VISUAL.TCYCLOGRAM_TASK_ADD_ATTR_VAL(RCYCLOGRAM => CG,
|
||||
RTASK => RTASK,
|
||||
SNAME => 'ddate_start',
|
||||
SVALUE => PKG_XCONVERT.DATE_TO_XML(DVALUE => DTASK_DATE_START),
|
||||
BCLEAR => true);
|
||||
PKG_P8PANELS_VISUAL.TCYCLOGRAM_TASK_ADD_ATTR_VAL(RCYCLOGRAM => CG,
|
||||
RTASK => RTASK,
|
||||
SNAME => 'ddate_end',
|
||||
SVALUE => PKG_XCONVERT.DATE_TO_XML(DVALUE => DTASK_DATE_END));
|
||||
PKG_P8PANELS_VISUAL.TCYCLOGRAM_TASK_ADD_ATTR_VAL(RCYCLOGRAM => CG, RTASK => RTASK, SNAME => 'type', SVALUE => 0);
|
||||
/* Добавляем задачу в циклограмму */
|
||||
PKG_P8PANELS_VISUAL.TCYCLOGRAM_ADD_TASK(RCYCLOGRAM => CG, RTASK => RTASK);
|
||||
/* Указываем следующую строку */
|
||||
NLINE_NUMB := NLINE_NUMB + 1;
|
||||
/* Обходим группы */
|
||||
for GRP in (select T.RN,
|
||||
T.NAME,
|
||||
ROWNUM RNUM
|
||||
from P8PNL_SMPL_CYCLOGRAM T
|
||||
where T.IDENT = NIDENT
|
||||
and T.TYPE = 1
|
||||
order by T.RN asc)
|
||||
loop
|
||||
/* Если это вторая группа - сохраним номер строки */
|
||||
if (GRP.RNUM = 2) then
|
||||
NLINE_NUMB_TMP := NLINE_NUMB;
|
||||
end if;
|
||||
/* Если это третья группа - вернемся на уровень второй группы */
|
||||
if (GRP.RNUM = 3) then
|
||||
NLINE_NUMB := NLINE_NUMB_TMP;
|
||||
end if;
|
||||
/* Добавляем группу */
|
||||
PKG_P8PANELS_VISUAL.TCYCLOGRAM_ADD_GROUP(RCYCLOGRAM => CG,
|
||||
SNAME => GRP.NAME,
|
||||
NHEADER_HEIGHT => 30,
|
||||
NHEADER_WIDTH => 200);
|
||||
/* Считываем значения этапа группы */
|
||||
GROUP_TASK_GET(NIDENT => NIDENT,
|
||||
NGROUP => GRP.RN,
|
||||
DTASK_DATE_START => DTASK_DATE_START,
|
||||
DTASK_DATE_END => DTASK_DATE_END,
|
||||
NTASK_START => NTASK_START,
|
||||
NTASK_END => NTASK_END);
|
||||
/* Формируем задачу (этап) */
|
||||
RTASK := PKG_P8PANELS_VISUAL.TCYCLOGRAM_TASK_MAKE(NRN => GRP.RN,
|
||||
SCAPTION => 'Этап ' || TO_CHAR(GRP.RNUM),
|
||||
SNAME => 'Этап ' || TO_CHAR(GRP.RNUM),
|
||||
NLINE_NUMB => NLINE_NUMB,
|
||||
NSTART => NTASK_START,
|
||||
NEND => NTASK_END,
|
||||
SBG_COLOR => SBG_TASK_COLOR_GRP,
|
||||
STEXT_COLOR => SCOLOR_WHITE,
|
||||
SHIGHLIGHT_COLOR => SHL_TASK_COLOR_GRP);
|
||||
/* Добавляем атрибуты */
|
||||
PKG_P8PANELS_VISUAL.TCYCLOGRAM_TASK_ADD_ATTR_VAL(RCYCLOGRAM => CG,
|
||||
RTASK => RTASK,
|
||||
SNAME => 'ddate_start',
|
||||
SVALUE => PKG_XCONVERT.DATE_TO_XML(DVALUE => DTASK_DATE_START),
|
||||
BCLEAR => true);
|
||||
PKG_P8PANELS_VISUAL.TCYCLOGRAM_TASK_ADD_ATTR_VAL(RCYCLOGRAM => CG,
|
||||
RTASK => RTASK,
|
||||
SNAME => 'ddate_end',
|
||||
SVALUE => PKG_XCONVERT.DATE_TO_XML(DVALUE => DTASK_DATE_END));
|
||||
PKG_P8PANELS_VISUAL.TCYCLOGRAM_TASK_ADD_ATTR_VAL(RCYCLOGRAM => CG, RTASK => RTASK, SNAME => 'type', SVALUE => 1);
|
||||
/* Добавляем задачу в циклограмму */
|
||||
PKG_P8PANELS_VISUAL.TCYCLOGRAM_ADD_TASK(RCYCLOGRAM => CG, RTASK => RTASK);
|
||||
/* Обходим задачи группы */
|
||||
for TASK in (select T.RN,
|
||||
T.NAME,
|
||||
T.POS_START,
|
||||
T.POS_END,
|
||||
T.DATE_FROM,
|
||||
T.DATE_TO,
|
||||
ROWNUM RNUM
|
||||
from P8PNL_SMPL_CYCLOGRAM T
|
||||
where T.IDENT = NIDENT
|
||||
and T.TYPE = 2
|
||||
and T.TASK_GROUP = GRP.RN)
|
||||
loop
|
||||
/* Указываем следующую строку */
|
||||
NLINE_NUMB := NLINE_NUMB + 1;
|
||||
/* Формируем наименование задачи */
|
||||
STASK_NAME := 'Работа ' || TO_CHAR(TASK.RNUM) || ' этапа ' || TO_CHAR(GRP.RNUM);
|
||||
/* Формируем задачу */
|
||||
RTASK := PKG_P8PANELS_VISUAL.TCYCLOGRAM_TASK_MAKE(NRN => TASK.RN,
|
||||
SCAPTION => STASK_NAME,
|
||||
SNAME => STASK_NAME,
|
||||
NLINE_NUMB => NLINE_NUMB,
|
||||
NSTART => TASK.POS_START,
|
||||
NEND => TASK.POS_END,
|
||||
SGROUP => GRP.NAME,
|
||||
SBG_COLOR => SBG_TASK_COLOR_W_GRP,
|
||||
STEXT_COLOR => SCOLOR_WHITE,
|
||||
SHIGHLIGHT_COLOR => SHL_TASK_COLOR_W_GRP);
|
||||
/* Добавляем атрибуты */
|
||||
PKG_P8PANELS_VISUAL.TCYCLOGRAM_TASK_ADD_ATTR_VAL(RCYCLOGRAM => CG,
|
||||
RTASK => RTASK,
|
||||
SNAME => 'ddate_start',
|
||||
SVALUE => PKG_XCONVERT.DATE_TO_XML(DVALUE => TASK.DATE_FROM),
|
||||
BCLEAR => true);
|
||||
PKG_P8PANELS_VISUAL.TCYCLOGRAM_TASK_ADD_ATTR_VAL(RCYCLOGRAM => CG,
|
||||
RTASK => RTASK,
|
||||
SNAME => 'ddate_end',
|
||||
SVALUE => PKG_XCONVERT.DATE_TO_XML(DVALUE => TASK.DATE_TO));
|
||||
PKG_P8PANELS_VISUAL.TCYCLOGRAM_TASK_ADD_ATTR_VAL(RCYCLOGRAM => CG,
|
||||
RTASK => RTASK,
|
||||
SNAME => 'type',
|
||||
SVALUE => 2);
|
||||
/* Добавляем задачу в циклограмму */
|
||||
PKG_P8PANELS_VISUAL.TCYCLOGRAM_ADD_TASK(RCYCLOGRAM => CG, RTASK => RTASK);
|
||||
end loop;
|
||||
/* Указываем следующую строку */
|
||||
NLINE_NUMB := NLINE_NUMB + 1;
|
||||
end loop;
|
||||
/* Указываем следующую строку */
|
||||
NLINE_NUMB := NLINE_NUMB + 1;
|
||||
/* Считываем значения для обособленных задач */
|
||||
GROUP_TASK_GET(NIDENT => NIDENT,
|
||||
NFLAG_WO_GROUP => 1,
|
||||
DTASK_DATE_START => DTASK_DATE_START,
|
||||
DTASK_DATE_END => DTASK_DATE_END,
|
||||
NTASK_START => NTASK_START,
|
||||
NTASK_END => NTASK_END);
|
||||
/* Формируем задачу (этап) */
|
||||
RTASK := PKG_P8PANELS_VISUAL.TCYCLOGRAM_TASK_MAKE(NRN => 1,
|
||||
SCAPTION => 'Обособленные задачи',
|
||||
SNAME => 'Обособленные задачи',
|
||||
NLINE_NUMB => NLINE_NUMB,
|
||||
NSTART => NTASK_START,
|
||||
NEND => NTASK_END,
|
||||
SBG_COLOR => SCOLOR_WHITE);
|
||||
/* Добавляем атрибуты */
|
||||
PKG_P8PANELS_VISUAL.TCYCLOGRAM_TASK_ADD_ATTR_VAL(RCYCLOGRAM => CG,
|
||||
RTASK => RTASK,
|
||||
SNAME => 'ddate_start',
|
||||
SVALUE => PKG_XCONVERT.DATE_TO_XML(DVALUE => DTASK_DATE_START),
|
||||
BCLEAR => true);
|
||||
PKG_P8PANELS_VISUAL.TCYCLOGRAM_TASK_ADD_ATTR_VAL(RCYCLOGRAM => CG,
|
||||
RTASK => RTASK,
|
||||
SNAME => 'ddate_end',
|
||||
SVALUE => PKG_XCONVERT.DATE_TO_XML(DVALUE => DTASK_DATE_END));
|
||||
PKG_P8PANELS_VISUAL.TCYCLOGRAM_TASK_ADD_ATTR_VAL(RCYCLOGRAM => CG, RTASK => RTASK, SNAME => 'type', SVALUE => 0);
|
||||
/* Добавляем задачу в циклограмму */
|
||||
PKG_P8PANELS_VISUAL.TCYCLOGRAM_ADD_TASK(RCYCLOGRAM => CG, RTASK => RTASK);
|
||||
/* Указываем следующую строку */
|
||||
NLINE_NUMB := NLINE_NUMB + 1;
|
||||
/* Цикл по обособленным задачам */
|
||||
for REC in (select T.RN,
|
||||
T.NAME,
|
||||
T.POS_START,
|
||||
T.POS_END,
|
||||
T.DATE_FROM,
|
||||
T.DATE_TO,
|
||||
ROWNUM RNUM
|
||||
from P8PNL_SMPL_CYCLOGRAM T
|
||||
where T.IDENT = NIDENT
|
||||
and T.TYPE = 2
|
||||
and T.TASK_GROUP is null)
|
||||
loop
|
||||
/* Формируем наименование задачи */
|
||||
STASK_NAME := 'Работа ' || TO_CHAR(REC.RNUM) || ' без этапа ';
|
||||
/* Формируем задачу */
|
||||
RTASK := PKG_P8PANELS_VISUAL.TCYCLOGRAM_TASK_MAKE(NRN => REC.RN,
|
||||
SCAPTION => STASK_NAME,
|
||||
SNAME => STASK_NAME,
|
||||
NLINE_NUMB => NLINE_NUMB,
|
||||
NSTART => REC.POS_START,
|
||||
NEND => REC.POS_END,
|
||||
SBG_COLOR => SBG_TASK_COLOR_WO_GRP,
|
||||
STEXT_COLOR => STEXT_COLOR_TASK_WO_GRP);
|
||||
/* Добавляем атрибуты */
|
||||
PKG_P8PANELS_VISUAL.TCYCLOGRAM_TASK_ADD_ATTR_VAL(RCYCLOGRAM => CG,
|
||||
RTASK => RTASK,
|
||||
SNAME => 'ddate_start',
|
||||
SVALUE => PKG_XCONVERT.DATE_TO_XML(DVALUE => REC.DATE_FROM),
|
||||
BCLEAR => true);
|
||||
PKG_P8PANELS_VISUAL.TCYCLOGRAM_TASK_ADD_ATTR_VAL(RCYCLOGRAM => CG,
|
||||
RTASK => RTASK,
|
||||
SNAME => 'ddate_end',
|
||||
SVALUE => PKG_XCONVERT.DATE_TO_XML(DVALUE => REC.DATE_TO));
|
||||
PKG_P8PANELS_VISUAL.TCYCLOGRAM_TASK_ADD_ATTR_VAL(RCYCLOGRAM => CG, RTASK => RTASK, SNAME => 'type', SVALUE => 2);
|
||||
/* Добавляем задачу в циклограмму */
|
||||
PKG_P8PANELS_VISUAL.TCYCLOGRAM_ADD_TASK(RCYCLOGRAM => CG, RTASK => RTASK);
|
||||
end loop;
|
||||
/* Формируем список */
|
||||
COUT := PKG_P8PANELS_VISUAL.TCYCLOGRAM_TO_XML(RCYCLOGRAM => CG);
|
||||
end CYCLOGRAM;
|
||||
|
||||
/* Изменение задачи циклограммы */
|
||||
procedure CYCLOGRAM_TASK_MODIFY
|
||||
(
|
||||
NIDENT in number, -- Идентификатор буфера
|
||||
NRN in number, -- Рег. номер записи
|
||||
SDATE_FROM in varchar2, -- Дата начала (в строковом представлении)
|
||||
SDATE_TO in varchar2 -- Дата окончания (в строковом представлении)
|
||||
)
|
||||
is
|
||||
DDATE_FROM PKG_STD.TLDATE; -- Дата начала
|
||||
DDATE_TO PKG_STD.TLDATE; -- Дата окончания
|
||||
NYEAR PKG_STD.TNUMBER; -- Текущий год
|
||||
DCYCLOGRAM_START PKG_STD.TLDATE; -- Дата начала циклограммы
|
||||
NSTART PKG_STD.TNUMBER; -- Позиция начала элемента
|
||||
NEND PKG_STD.TNUMBER; -- Позиция окончания элемента
|
||||
begin
|
||||
/* Фиксируем текущий год */
|
||||
NYEAR := EXTRACT(year from sysdate);
|
||||
/* Переводим даты */
|
||||
DDATE_FROM := TO_DATE(SDATE_FROM, 'dd.mm.yyyy');
|
||||
DDATE_TO := TO_DATE(SDATE_TO, 'dd.mm.yyyy');
|
||||
/* Если дата начала выходит за границы года */
|
||||
if (D_YEAR(DDATE => DDATE_FROM) <> NYEAR) then
|
||||
P_EXCEPTION(0,
|
||||
'Дата начала задачи выходит за границы текущего года (%s).',
|
||||
NYEAR);
|
||||
end if;
|
||||
/* Если дата окончания выходит за границы года */
|
||||
if (D_YEAR(DDATE => DDATE_TO) <> NYEAR) then
|
||||
P_EXCEPTION(0,
|
||||
'Дата окончания задачи выходит за границы текущего года (%s).',
|
||||
NYEAR);
|
||||
end if;
|
||||
/* Дата окончания не может быть меньше даты начала */
|
||||
if (DDATE_TO < DDATE_FROM) then
|
||||
P_EXCEPTION(0, 'Дата окончания не может быть меньше даты начала.');
|
||||
end if;
|
||||
/* Фиксируем дату начала циклограммы */
|
||||
DCYCLOGRAM_START := TO_DATE('01.01.' || NYEAR, 'dd.mm.yyyy');
|
||||
/* Рассчитываем новую позицию начала */
|
||||
NSTART := (DDATE_FROM - DCYCLOGRAM_START) * NCG_MULTIPLIER;
|
||||
/* Рассчитываем новую позицию окончания */
|
||||
NEND := NSTART + ((DDATE_TO - DDATE_FROM + 1) * NCG_MULTIPLIER);
|
||||
/* Считываем запись */
|
||||
for REC in (select T.*
|
||||
from P8PNL_SMPL_CYCLOGRAM T
|
||||
where T.RN = NRN
|
||||
and T.IDENT = NIDENT)
|
||||
loop
|
||||
/* Обновляем запись циклограммы */
|
||||
CYCLOGRAM_BASE_UPDATE(NIDENT => REC.IDENT,
|
||||
NRN => REC.RN,
|
||||
NTYPE => REC.TYPE,
|
||||
SNAME => REC.NAME,
|
||||
NPOS_START => NSTART,
|
||||
NPOS_END => NEND,
|
||||
DDATE_FROM => DDATE_FROM,
|
||||
DDATE_TO => DDATE_TO,
|
||||
NTASK_GROUP => REC.TASK_GROUP);
|
||||
end loop;
|
||||
end CYCLOGRAM_TASK_MODIFY;
|
||||
|
||||
end PKG_P8PANELS_SAMPLES;
|
||||
/
|
||||
|
File diff suppressed because it is too large
Load Diff
102
dist/p8-panels.js
vendored
102
dist/p8-panels.js
vendored
File diff suppressed because one or more lines are too long
BIN
docs/img/72.png
Normal file
BIN
docs/img/72.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 44 KiB |
BIN
docs/img/73.png
Normal file
BIN
docs/img/73.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 58 KiB |
@ -16,7 +16,7 @@
|
||||
<script src="./libs/frappe-gantt/frappe-gantt.js"></script>
|
||||
<link rel="stylesheet" href="./libs/frappe-gantt/frappe-gantt.css" />
|
||||
</head>
|
||||
<body style="display: block; margin: 0px">
|
||||
<body style="display: block; margin: 0px" class="scroll">
|
||||
<div id="app-content"></div>
|
||||
<script src="dist/p8-panels.js"></script>
|
||||
</body>
|
||||
|
Loading…
x
Reference in New Issue
Block a user