/* Парус 8 - Панели мониторинга Компонент: Циклограмма */ //--------------------- //Подключение библиотек //--------------------- import React, { useEffect, useState, useRef } from "react"; //Классы React import PropTypes from "prop-types"; //Контроль свойств компонента import { Box, Typography, Link, IconButton, Icon } from "@mui/material"; //Интерфейсные компоненты import { P8PAppInlineError } from "./p8p_app_message"; //Встраиваемое сообщение об ошибке import { useP8PCyclogram } from "./p8p_cyclogram_hooks"; //Хук для циклограммы import { P8PCyclogramTaskEditor } from "./p8p_cyclogram/p8p_cyclogram_task_editor"; //Редактор задачи import { P8P_TYPOGRAPHY_VARIANT } from "../theme/p8p_typography"; //Варианты шрифтов import { P8P_COMPONENT_HEIGHT } from "../theme/styles/common"; //Стили - общие import { P8P_BOX_CYCLOGRAM } from "../theme/styles/box"; //Стили контейнеров import { getShift } from "./p8p_cyclogram/p8p_cyclogram_utils"; //Вспомогательные функции циклограммы import { P8P_CYCLOGRAM_ZOOM, NDEFAULT_LINE_HEIGHT, NDEFAULT_HEADER_HEIGHT, TITLE_HEIGHT, ZOOM_HEIGHT, P8P_CYCLOGRAM_COLUMN_SHAPE, P8P_CYCLOGRAM_GROUP_SHAPE, P8P_CYCLOGRAM_TASK_SHAPE, P8P_CYCLOGRAM_TASK_ATTRIBUTE_SHAPE } from "./p8p_cyclogram/p8p_cyclogram_constants"; //Константы циклограммы import { P8PCyclogramGrid } from "./p8p_cyclogram/p8p_cyclogram_grid"; //Фон таблицы циклограммы import { P8PCyclogramView } from "./p8p_cyclogram/p8p_cyclogram_view"; //Представление циклограммы import { P8P_TYPOGRAPHY_TITLE } from "../theme/styles/typography"; //Стили текста //----------- //Тело модуля //----------- //Циклограмма 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 ( <>
{state.noData ? : null} {state.loaded ? ( <> {title ? ( {onTitleClick ? ( onTitleClick()}> {title} ) : ( title )} ) : null} {zoomBar ? ( handleZoomChange(1)} disabled={state.zoom == P8P_CYCLOGRAM_ZOOM[P8P_CYCLOGRAM_ZOOM.length - 1]} > zoom_in handleZoomChange(-1)} disabled={state.zoom == P8P_CYCLOGRAM_ZOOM[0]}> zoom_out ) : null} ) : null} {state.editTask ? ( ) : null}
); }; //Контроль свойств - Циклограмма 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, useP8PCyclogram };