diff --git a/README.md b/README.md index d76dab1..095024e 100644 --- a/README.md +++ b/README.md @@ -1135,6 +1135,7 @@ const MyPanel = () => { `clearFilterBtnCaption` - обязательный, строка, текст кнопки очистки введённого значения фильтра\ `cancelFilterBtnCaption` - обязательный, строка, текст кнопки отмены ввода значения фильтра\ `morePagesBtnCaption` - обязательный, строка, текст кнопки догрузки данных\ +`morePagesBtnProps` - необязательный, объект, содержит свойства, которые будут переданы компоненту `Button` - кнопке догрузки данных таблицы\ `noDataFoundText` - необязательный, строка, текст ошибки об отсутствии данных в таблице (если не указн - ошибка не отображается)\ `headCellRender` - необязательный, функция формирования представления заголовка колонки (если не указана - отображение по умолчанию, согласно `columnsDef`). Сигнатура функции: `f({columnDef})`. Будет вызвана для каждой колонки таблицы, в функцию будет передан объект, поле `columnDef` которого будет содержать описание текущей генерируемой колонки. Должна возвращать объект вида `{cellStyle: <СТИЛИ_ДЛЯ_TableCell>, cellProps: <СВОЙСТВА_ДЛЯ_TableCell>, stackStyle: <СТИЛИ_ДЛЯ_КОНТЕЙНЕРА_Stack>, stackProps: <СВОЙСТВА_ДЛЯ_КОНТЕЙНЕРА_Stack>, data: <ЗНАЧЕНИЕ_ИЛИ_КОМПОНЕТ_Ract_ДЛЯ_СОДЕРЖИМОГО_ЗАГОЛОВКА_КОЛОНКИ>}` или `undefined`, если для заголовка колонки не предполагается специального представления.\ `dataCellRender` - необязательный, функция формирования представления ячейки (если не указана - отображение по умолчанию, согласно `columnsDef` и текущему элементу `rows`). Сигнатура функции `f({row, columnDef})`. Будет вызвана для каждой ячейки таблицы, в функцию будет передан объект, поле `row` которого будет содержать данные текущей генерируемой строки таблицы, а поле `columnDef` - текущей генерируемой колонки. Должна возвращать объект вида `{cellStyle: <СТИЛИ_ДЛЯ_TableCell>, cellProps: <СВОЙСТВА_ДЛЯ_TableCell>, data: <ЗНАЧЕНИЕ_ИЛИ_КОМПОНЕТ_Ract_ДЛЯ_СОДЕРЖИМОГО_ЯЧЕЙКИ>}` или `undefined`, если для ячейки не предполагается специального представления.\ @@ -1737,9 +1738,11 @@ const Chart = ({ title }) => { - Дополнение задачи произвольными учётными атрибутами - Диалоговый редактор задачи, отображающий её дополнительные атрибуты с возможностью настройки их форматирования - Отображение связей между задачами +- Отображение произвольного пользовательского диалога в качестве карточки задачи/редактора задачи -![Пример P8PGantt](docs/img/68.png) -![Пример P8PGantt (редактор)](docs/img/69.png) +![Пример P8PGantt](docs/img/68.png)\ +![Пример P8PGantt (редактор)](docs/img/69.png)\ +![Пример P8PGantt (пользовательский диалог задачи)](docs/img/70.png)\ **Подключение** @@ -1768,12 +1771,13 @@ const MyPanel = () => { `readOnlyDates` - необязательный, логический, признак возможности редактирования дат элементов диаграммы (по умолчанию - редактирование возможно)\ `readOnlyProgress` - необязательный, логический, признак возможности редактирования прогресса исполнения элементов диаграммы (по умолчанию - редактирование возможно)\ `zoom` - необязательный, число, масштаб диаграммы\ -`tasks` - обязательный, массив, задачи, отображаемые на диаграмме, должен состоять из объектов вида `{id: <УНИКАЛЬНЫЙ_ИДЕНТИФИКАТОР>, rn: <ССЫЛКА_НА_ЗАПИСЬ_В_СИСТЕМЕ>, numb: <НОМЕР>, name: <НАИМЕНОВАНИЕ>, fullName: <ПОЛНОЕ_НАИМЕНОВАНИЕ>, start: <ДАТА_НАЧАЛА_В_JSON_ФОРМАТЕ_ДАТЫ>, end: <ДАТА_ОКОНЧАНИЯ_В_JSON_ФОРМАТЕ_ДАТЫ>, progress: <ПРОГРЕСС_ИСПОЛНЕНИЯ>, dependencies: <МАССИВ_ИДЕНТИФИКАТОРОВ_ЗАВИСИМЫХ_ЗАДАЧ>, readOnly: <ДОСТУПНОСТЬ_РЕДАКТИРОВАНИЯ>, readOnlyDates: <ДОСТУПНОСТЬ_РЕДАКТИРОВАНИЯ_СРОКОВ>, readOnlyProgress: <ДОСТУПНОСТЬ_РЕДАКТИРОВАНИЯ_ПРОГРЕССА_ИСПОЛНЕНИЯ>, bgColor: <ЦВЕТ_ЗАЛИВКИ>, textColor: <ЦВЕТ_ТЕКСТА>[, <ИМЯ_ДОПОЛНИТЕЛЬНОГО_АТРИБУТА1>:<ЗНАЧЕНИЕ1>, <ИМЯ_ДОПОЛНИТЕЛЬНОГО_АТРИБУТА2>:<ЗНАЧЕНИЕ2>,...]}` (см. константу `P8P_GANTT_TASK_SHAPE` в коде компонента)\ -`taskAttributes` - необязательный, массив, состав (не значения) дополнительных атрибутутов задач, должен состоять из объектов вида `{name: <ИМЯ_ДОПОЛНИТЕЛЬНОГО_АТРИБУТА>, caption: <ЗАГОЛОВОК_ДОПОЛНИТЕЛЬНОГО_АТРИБУТА>}` (см. константу `P8P_GANTT_TASK_ATTRIBUTE_SHAPE` в коде компонента)\ -`taskColors` - необязательный, массив, описания цветов заливки и текста элементов диаграммы, для построения легенды, должен состоять из объектов вида `{bgColor: <ЦВЕТ_ЗАЛИВКИ_В_ФОРМАТЕ_CSS>, textColor: <ЦВЕТ_ТЕКСТА_В_ФОРМАТЕ_CSS>, desc: <ОПИСАНИЕ>}` (см. константу `P8P_GANTT_TASK_COLOR_SHAPE` в коде компонента)\ +`tasks` - обязательный, массив, задачи, отображаемые на диаграмме, должен состоять из объектов вида `{id: <УНИКАЛЬНЫЙ_ИДЕНТИФИКАТОР>, rn: <ССЫЛКА_НА_ЗАПИСЬ_В_СИСТЕМЕ>, numb: <НОМЕР>, name: <НАИМЕНОВАНИЕ>, fullName: <ПОЛНОЕ_НАИМЕНОВАНИЕ>, start: <ДАТА_НАЧАЛА_В_JSON_ФОРМАТЕ_ДАТЫ>, end: <ДАТА_ОКОНЧАНИЯ_В_JSON_ФОРМАТЕ_ДАТЫ>, progress: <ПРОГРЕСС_ИСПОЛНЕНИЯ>, dependencies: <МАССИВ_ИДЕНТИФИКАТОРОВ_ЗАВИСИМЫХ_ЗАДАЧ>, readOnly: <ДОСТУПНОСТЬ_РЕДАКТИРОВАНИЯ>, readOnlyDates: <ДОСТУПНОСТЬ_РЕДАКТИРОВАНИЯ_СРОКОВ>, readOnlyProgress: <ДОСТУПНОСТЬ_РЕДАКТИРОВАНИЯ_ПРОГРЕССА_ИСПОЛНЕНИЯ>, bgColor: <ЦВЕТ_ЗАЛИВКИ>, textColor: <ЦВЕТ_ТЕКСТА>, bgProgressColor: <ЦВЕТ_ЗАЛИВКИ_ПРОГРЕССА_ИСПОЛНЕНИЯ_ЗАДАЧИ>[, <ИМЯ_ДОПОЛНИТЕЛЬНОГО_АТРИБУТА1>:<ЗНАЧЕНИЕ1>, <ИМЯ_ДОПОЛНИТЕЛЬНОГО_АТРИБУТА2>:<ЗНАЧЕНИЕ2>,...]}` (см. константу `P8P_GANTT_TASK_SHAPE` в коде компонента)\ +`taskAttributes` - необязательный, массив, состав (не значения) дополнительных атрибутутов задач, должен состоять из объектов вида `{name: <ИМЯ_ДОПОЛНИТЕЛЬНОГО_АТРИБУТА>, caption: <ЗАГОЛОВОК_ДОПОЛНИТЕЛЬНОГО_АТРИБУТА>, visible: <ПРИЗНАК_ОТОБРАЖЕНИЯ_ДОПОЛНИТЕЛЬНОГО_АТРИБУТА - true|false>}` (см. константу `P8P_GANTT_TASK_ATTRIBUTE_SHAPE` в коде компонента)\ +`taskColors` - необязательный, массив, описания цветов заливки и текста элементов диаграммы, для построения легенды, должен состоять из объектов вида `{bgColor: <ЦВЕТ_ЗАЛИВКИ_В_ФОРМАТЕ_CSS>, textColor: <ЦВЕТ_ТЕКСТА_В_ФОРМАТЕ_CSS>, bgProgressColor: <ЦВЕТ_ЗАЛИВКИ_ПРОГРЕССА_ИСПОЛНЕНИЯ_ЗАДАЧИ>, desc: <ОПИСАНИЕ>}` (см. константу `P8P_GANTT_TASK_COLOR_SHAPE` в коде компонента)\ `onTaskDatesChange` - необязательный, функция, если указана - будет вызвана при изменении (перетаскиванием или через редактор) дат элемента диаграммы, сигнатура функции `f({task, start, end, isMain})`, результат функции не интерпретируется. В функцию будет передан объект в поле `task`, которого, будет содержаться описание изменённой задачи (элемент массива `tasks`, см. выше описание полей), в поле `start` - новая дата начала задачи, в поле `end` - новая дата окончания задачи, в поле `isMain` - флаг изменения родительской задачи (`true` - `onTaskDatesChange` вызана для обработки изменения основной задачи, `false` - `onTaskDatesChange` вызвана для обработки изменения одной из зависимых задач).\ `onTaskProgressChange` - необязательный, функция, если указана - будет вызвана при изменении прогресса исполнения элемента диаграммы, сигнатура функции `f({task, progress})`, результат функции не интерпретируется. В функцию будет передан объект в поле `task`, которого, будет содержаться описание изменённой задачи (элемент массива `tasks`, см. выше описание полей), в поле `progress` - новое значение прогресса исполнения задачи.\ `taskAttributeRenderer` - необязательный, функция, если указана - будет вызвана при отображении диалога редактора здачи, результат функции будет применён для отображения области дополнительных атрибутов задачи в диалоге редактора, если не указана - дополнительные атрибуты будут отображены с форматированием по умолчанию. Сигнатура функции - `f({task, attribute})`, в функцию будет передан объект в поле `task`, которого, будет содержаться описание задачи для которой отображается редактор (элемент массива `tasks`, см. выше описание полей), в поле `attribute` - описание дополнительного атрибута формируемого в диалоге редактора (элемент массива `taskAttributes`, см. выше описание полей). Должна возвращать значение или React-компонент.\ +`taskDialogRenderer` - необязательный, функция, если указана - будет вызвана до отображения диалога редактора задачи. Результат функции будет показан в качестве содержимого диалога редактора, вместо типовой формы. Сигнатура функции - `f({task, taskAttributes, taskColors, close})`, в функцию будет передан объект в поле `task`, которого, будет содержаться описание задачи для которой отображается редактор (элемент массива `tasks`, см. выше описание полей), в поле `taskAttributes` - массив `taskAttributes` (см. выше описание полей), описывающий состав полей задачи, в поле `taskColors` - массив `taskColors` (см. выше описание полей), описывающий цвета заливки, определённые для задачи, в поле `close` - функция закрытия диалога задачи, может быть вызвана возвращаемым Reac-компонентом для сокрытия диалога. Должна возвращать значение или React-компонент.\ `noDataFoundText` - обязательный, строка, текст для отображения ошибки об отсутствии данных\ `numbTaskEditorCaption` - обязательный, строка, подпись стандартного атрибута `numb` в диалоге редактора задачи\ `nameTaskEditorCaption` - обязательный, строка, подпись стандартного атрибута `name` в диалоге редактора задачи\ @@ -1836,7 +1840,11 @@ const MyPanel = () => { RG := PKG_P8PANELS_VISUAL.TGANTT_MAKE(STITLE => 'Задачи на ' || TO_CHAR(EXTRACT(year from sysdate)) || ' год', NZOOM => PKG_P8PANELS_VISUAL.NGANTT_ZOOM_MONTH); /* Добавим динамические атрибуты к задачам */ - PKG_P8PANELS_VISUAL.TGANTT_ADD_TASK_ATTR(RGANTT => RG, SNAME => 'type', SCAPTION => 'Тип'); + PKG_P8PANELS_VISUAL.TGANTT_ADD_TASK_ATTR(RGANTT => RG, SNAME => 'type', SCAPTION => 'Тип', BVISIBLE => true); + PKG_P8PANELS_VISUAL.TGANTT_ADD_TASK_ATTR(RGANTT => RG, + SNAME => 'state', + SCAPTION => 'Состояние', + BVISIBLE => false); /* Добавим описание цветов задач */ PKG_P8PANELS_VISUAL.TGANTT_ADD_TASK_COLOR(RGANTT => RG, SBG_COLOR => SBG_COLOR_JOB, @@ -1866,6 +1874,7 @@ const MyPanel = () => { SNAME => 'type', SVALUE => C.TYPE, BCLEAR => true); + PKG_P8PANELS_VISUAL.TGANTT_TASK_ADD_ATTR_VAL(RGANTT => RG, RTASK => RGT, SNAME => 'state', SVALUE => C.STATE); /* Добавляем задачу в диаграмму */ PKG_P8PANELS_VISUAL.TGANTT_ADD_TASK(RGANTT => RG, RTASK => RGT); end loop; @@ -1878,14 +1887,14 @@ const MyPanel = () => { ``` import React, { useState, useContext, useCallback, useEffect } from "react"; //Классы React -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"; //Контекст взаимодействия с сервером //Высота диаграммы Ганта -const GANTT_HEIGHT = "600px"; +const GANTT_HEIGHT = "70vh"; //Ширина диаграммы Ганта const GANTT_WIDTH = "98vw"; @@ -1918,6 +1927,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". + + + + + + + ); +}; + //Пример: Диаграмма Ганта "P8Gantt" const Gantt = ({ title }) => { //Собственное состояние @@ -1926,7 +1959,8 @@ const Gantt = ({ title }) => { dataLoaded: false, ident: null, ganttDef: {}, - ganttTasks: [] + ganttTasks: [], + useCustomTaskDialog: false }); //Подключение к контексту взаимодействия с сервером @@ -1989,6 +2023,10 @@ const Gantt = ({ title }) => { {title} + setState(pv => ({ ...pv, useCustomTaskDialog: !pv.useCustomTaskDialog }))} />} + label="Отображать пользовательский диалог задачи" + /> {state.dataLoaded ? ( @@ -2000,6 +2038,7 @@ const Gantt = ({ title }) => { tasks={state.ganttTasks} onTaskDatesChange={handleTaskDatesChange} taskAttributeRenderer={taskAttributeRenderer} + taskDialogRenderer={state.useCustomTaskDialog ? taskDialogRenderer : null} /> ) : null} diff --git a/docs/Image Sources.pptx b/docs/Image Sources.pptx index 1ceec39..f3536ff 100644 Binary files a/docs/Image Sources.pptx and b/docs/Image Sources.pptx differ diff --git a/docs/img/68.png b/docs/img/68.png index 21c3ed2..60dbbfd 100644 Binary files a/docs/img/68.png and b/docs/img/68.png differ diff --git a/docs/img/69.png b/docs/img/69.png index 312e603..3e07d6f 100644 Binary files a/docs/img/69.png and b/docs/img/69.png differ diff --git a/docs/img/70.png b/docs/img/70.png new file mode 100644 index 0000000..63cc020 Binary files /dev/null and b/docs/img/70.png differ