From 69cb24ed6e9c61f074e08dac12b7d9bb85facf30 Mon Sep 17 00:00:00 2001 From: Mikhail Chechnev Date: Sun, 31 Mar 2024 23:04:33 +0300 Subject: [PATCH] =?UTF-8?q?WEB=20APP:=20P8PGantt=20-=20=D1=83=D0=BF=D1=80?= =?UTF-8?q?=D0=B0=D0=B2=D0=BB=D0=B5=D0=BD=D0=B8=D0=B5=20=D0=B2=D0=B8=D0=B4?= =?UTF-8?q?=D0=B8=D0=BC=D0=BE=D1=81=D1=82=D1=8C=D1=8E=20=D0=B0=D1=82=D1=80?= =?UTF-8?q?=D0=B8=D0=B1=D1=83=D1=82=D0=B0=20=D0=B7=D0=B0=D0=B4=D0=B0=D1=87?= =?UTF-8?q?=D0=B8,=20=D0=BF=D0=BE=D0=B4=D0=B4=D0=B5=D1=80=D0=B6=D0=BA?= =?UTF-8?q?=D0=B0=20=D0=BF=D0=BE=D0=BB=D1=8C=D0=B7=D0=BE=D0=B2=D0=B0=D1=82?= =?UTF-8?q?=D0=B5=D0=BB=D1=8C=D1=81=D0=BA=D0=B8=D1=85=20=D0=BA=D0=B0=D1=80?= =?UTF-8?q?=D1=82=D0=BE=D1=87=D0=B5=D0=BA=20=D0=B7=D0=B0=D0=B4=D0=B0=D1=87?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/components/p8p_gantt.js | 218 +++++++++++++++++++----------------- app/panels/samples/gantt.js | 50 ++++++++- 2 files changed, 163 insertions(+), 105 deletions(-) diff --git a/app/components/p8p_gantt.js b/app/components/p8p_gantt.js index 83ce867..55ff58d 100644 --- a/app/components/p8p_gantt.js +++ b/app/components/p8p_gantt.js @@ -79,6 +79,7 @@ const P8P_GANTT_TASK_COLOR_SHAPE = PropTypes.shape({ //Стили const STYLES = { + TASK_EDITOR_CONTENT: { minWidth: 400, overflowX: "auto" }, TASK_EDITOR_LIST: { width: "100%", minWidth: 300, maxWidth: 700, bgcolor: "background.paper" } }; @@ -97,6 +98,7 @@ const P8PGanttTaskEditor = ({ onOk, onCancel, taskAttributeRenderer, + taskDialogRenderer, numbCaption, nameCaption, startCaption, @@ -113,6 +115,10 @@ const P8PGanttTaskEditor = ({ 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); @@ -158,117 +164,121 @@ const P8PGanttTaskEditor = ({ //Генерация содержимого return ( - - - - - - - - - - - - - } - /> - - - - - } - /> - - - {hasValue(task.progress) ? ( - <> + {taskDialogRenderer ? ( + taskDialogRenderer({ task, taskAttributes, taskColors, close: handleCancel }) + ) : ( + <> + + + + + + + + + + } /> - - ) : null} - {legend ? ( - <> - {legend} - - - ) : null} - {Array.isArray(taskAttributes) && taskAttributes.length > 0 - ? taskAttributes - .filter(attr => hasValue(task[attr.name])) - .map((attr, i) => { - const defaultView = task[attr.name]; - const customView = taskAttributeRenderer ? taskAttributeRenderer({ task, attribute: attr }) : null; - return ( - - - - - {i < taskAttributes.length - 1 ? : null} - - ); - }) - : null} - - - - - - + + + } + /> + + {hasValue(task.progress) || legend || dispTaskAttributes.length > 0 ? : null} + {hasValue(task.progress) ? ( + <> + + + } + /> + + {legend || dispTaskAttributes.length > 0 ? : null} + + ) : null} + {legend ? ( + <> + {legend} + {dispTaskAttributes.length > 0 ? : null} + + ) : null} + {dispTaskAttributes.length > 0 + ? dispTaskAttributes.map((attr, i) => { + const defaultView = task[attr.name]; + const customView = taskAttributeRenderer ? taskAttributeRenderer({ task, attribute: attr }) : null; + return ( + + + + + {i < dispTaskAttributes.length - 1 ? : null} + + ); + }) + : null} + + + + + + + + )} ); }; @@ -281,6 +291,7 @@ P8PGanttTaskEditor.propTypes = { onOk: PropTypes.func, onCancel: PropTypes.func, taskAttributeRenderer: PropTypes.func, + taskDialogRenderer: PropTypes.func, numbCaption: PropTypes.string.isRequired, nameCaption: PropTypes.string.isRequired, startCaption: PropTypes.string.isRequired, @@ -312,6 +323,7 @@ const P8PGantt = ({ onTaskDatesChange, onTaskProgressChange, taskAttributeRenderer, + taskDialogRenderer, noDataFoundText, numbTaskEditorCaption, nameTaskEditorCaption, @@ -417,6 +429,7 @@ const P8PGantt = ({ onOk={handleTaskEditorSave} onCancel={handleTaskEditorCancel} taskAttributeRenderer={taskAttributeRenderer} + taskDialogRenderer={taskDialogRenderer} numbCaption={numbTaskEditorCaption} nameCaption={nameTaskEditorCaption} startCaption={startTaskEditorCaption} @@ -451,6 +464,7 @@ P8PGantt.propTypes = { onTaskDatesChange: PropTypes.func, onTaskProgressChange: PropTypes.func, taskAttributeRenderer: PropTypes.func, + taskDialogRenderer: PropTypes.func, noDataFoundText: PropTypes.string.isRequired, numbTaskEditorCaption: PropTypes.string.isRequired, nameTaskEditorCaption: PropTypes.string.isRequired, diff --git a/app/panels/samples/gantt.js b/app/panels/samples/gantt.js index 6ce43b9..adfaf02 100644 --- a/app/panels/samples/gantt.js +++ b/app/panels/samples/gantt.js @@ -9,8 +9,22 @@ import React, { useState, useContext, useCallback, useEffect } from "react"; //Классы React import PropTypes from "prop-types"; //Контроль свойств компонента -import { Typography, Grid, Stack, Icon, Box } from "@mui/material"; //Интерфейсные элементы -import { formatDateJSONDateOnly } from "../../core/utils"; //Вспомогательные функции +import { + Typography, + Grid, + Stack, + Icon, + Box, + FormControlLabel, + Checkbox, + Card, + CardHeader, + CardActions, + Avatar, + CardContent, + Button +} from "@mui/material"; //Интерфейсные элементы +import { formatDateJSONDateOnly, formatDateRF } from "../../core/utils"; //Вспомогательные функции import { P8PGantt } from "../../components/p8p_gantt"; //Диаграмма Ганта import { P8P_GANTT_CONFIG_PROPS } from "../../config_wrapper"; //Подключение компонентов к настройкам приложения import { BackEndСtx } from "../../context/backend"; //Контекст взаимодействия с сервером @@ -57,6 +71,30 @@ const taskAttributeRenderer = ({ task, attribute }) => { } }; +//Генерация кастомного диалога задачи +const taskDialogRenderer = ({ task, close }) => { + return ( + + {task.type == 0 ? "Эт" : "Ра"}} + title={task.name} + subheader={`с ${formatDateRF(task.start)} по ${formatDateRF(task.end)}`} + /> + + + Это пользовательский диалог с данными о задаче. Вы можете формировать такие указав свой функциональный компонент в качестве + свойства "taskDialogRenderer" компонента "P8PGantt". + + + + + + + ); +}; + //----------- //Тело модуля //----------- @@ -69,7 +107,8 @@ const Gantt = ({ title }) => { dataLoaded: false, ident: null, ganttDef: {}, - ganttTasks: [] + ganttTasks: [], + useCustomTaskDialog: false }); //Подключение к контексту взаимодействия с сервером @@ -132,6 +171,10 @@ const Gantt = ({ title }) => { {title} + setState(pv => ({ ...pv, useCustomTaskDialog: !pv.useCustomTaskDialog }))} />} + label="Отображать пользовательский диалог задачи" + /> {state.dataLoaded ? ( @@ -143,6 +186,7 @@ const Gantt = ({ title }) => { tasks={state.ganttTasks} onTaskDatesChange={handleTaskDatesChange} taskAttributeRenderer={taskAttributeRenderer} + taskDialogRenderer={state.useCustomTaskDialog ? taskDialogRenderer : null} /> ) : null}