/*
Парус 8 - Панели мониторинга
Компонент: Диаграмма Ганта
*/
//---------------------
//Подключение библиотек
//---------------------
import React, { useEffect, useState, useCallback } from "react"; //Классы React
import PropTypes from "prop-types"; //Контроль свойств компонента
import {
Box,
IconButton,
Icon,
Typography,
Dialog,
DialogActions,
DialogContent,
TextField,
Button,
List,
ListItem,
ListItemText,
Divider,
Slider,
Link
} from "@mui/material"; //Интерфейсные компоненты
import { P8PAppInlineError } from "./p8p_app_message"; //Встраиваемое сообщение об ошибке
//---------
//Константы
//---------
//Уровни масштаба
const P8P_GANTT_ZOOM = [0, 1, 2, 3, 4];
//Уровни масштаба (строковые наименования в терминах библиотеки)
const P8P_GANTT_ZOOM_VIEW_MODES = {
0: "Quarter Day",
1: "Half Day",
2: "Day",
3: "Week",
4: "Month"
};
//Структура задачи
const P8P_GANTT_TASK_SHAPE = PropTypes.shape({
id: PropTypes.string.isRequired,
rn: PropTypes.number.isRequired,
numb: PropTypes.string.isRequired,
name: PropTypes.string.isRequired,
fullName: PropTypes.string.isRequired,
start: PropTypes.string.isRequired,
end: PropTypes.string.isRequired,
progress: PropTypes.number,
dependencies: PropTypes.array,
readOnly: PropTypes.bool,
readOnlyDates: PropTypes.bool,
readOnlyProgress: PropTypes.bool,
bgColor: PropTypes.string,
textColor: PropTypes.string,
bgProgressColor: PropTypes.string
});
//Структура динамического атрибута задачи
const P8P_GANTT_TASK_ATTRIBUTE_SHAPE = PropTypes.shape({
name: PropTypes.string.isRequired,
caption: PropTypes.string.isRequired,
visible: PropTypes.bool.isRequired
});
//Структура описания цвета задачи
const P8P_GANTT_TASK_COLOR_SHAPE = PropTypes.shape({
bgColor: PropTypes.string,
textColor: PropTypes.string,
bgProgressColor: PropTypes.string,
desc: PropTypes.string.isRequired
});
//Высота заголовка
const TITLE_HEIGHT = "44px";
//Высота панели масштабирования
const ZOOM_HEIGHT = "56px";
//Стили
const STYLES = {
TASK_EDITOR_CONTENT: { minWidth: 400, overflowX: "auto" },
TASK_EDITOR_LIST: { width: "100%", minWidth: 300, maxWidth: 700, bgcolor: "background.paper" },
GANTT_TITLE: { height: TITLE_HEIGHT },
GANTT_ZOOM: { height: ZOOM_HEIGHT },
GANTT: (noData, title, zoomBar) => ({
height: `calc(100% - ${zoomBar ? ZOOM_HEIGHT : "0px"} - ${title ? TITLE_HEIGHT : "0px"})`,
display: noData ? "none" : ""
})
};
//--------------------------------
//Вспомогательные классы и функции
//--------------------------------
//Проверка существования значения
const hasValue = value => typeof value !== "undefined" && value !== null && value !== "";
//Формирование описания для легенды
const taskLegendDesc = ({ task, taskColors }) => {
if (Array.isArray(taskColors) && taskColors.length > 0) {
const colorDesc = taskColors.find(
color => task.bgColor === color.bgColor && task.textColor === color.textColor && task.bgProgressColor === color.bgProgressColor
);
if (colorDesc)
return {
text: colorDesc.desc,
style: {
...(colorDesc.bgProgressColor
? {
background: `linear-gradient(to right, ${colorDesc.bgProgressColor} ,${
colorDesc.bgColor ? colorDesc.bgColor : "transparent"
})`
}
: colorDesc.bgColor
? { backgroundColor: colorDesc.bgColor }
: {}),
...(colorDesc.textColor ? { color: colorDesc.textColor } : {})
}
};
else return null;
} else return null;
};
//Редактор задачи
const P8PGanttTaskEditor = ({
task,
taskAttributes,
taskColors,
onOk,
onCancel,
taskAttributeRenderer,
taskDialogRenderer,
numbCaption,
nameCaption,
startCaption,
endCaption,
progressCaption,
legendCaption,
okBtnCaption,
cancelBtnCaption
}) => {
//Собственное состояние
const [state, setState] = useState({
start: task.start,
end: task.end,
progress: task.progress
});
//Отображаемые атрибуты
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({ task, start: state.start, end: state.end, progress: state.progress }) : null);
//При отмене
const handleCancel = () => (onCancel ? onCancel() : null);
//При изменении сроков
const handlePeriodChanged = e => setState(prev => ({ ...prev, [e.target.name]: e.target.value }));
//При изменении прогресса
const handleProgressChanged = (e, newValue) => setState(prev => ({ ...prev, progress: newValue }));
//Описание легенды для задачи
const legendDesc = taskLegendDesc({ task, taskColors });
let legend = legendDesc ? (