forked from CITKParus/P8-Panels
WEB APP: P8PGantt - управление видимостью атрибута задачи, поддержка пользовательских карточек задач
This commit is contained in:
parent
30c75fb079
commit
69cb24ed6e
@ -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,7 +164,11 @@ const P8PGanttTaskEditor = ({
|
||||
//Генерация содержимого
|
||||
return (
|
||||
<Dialog open onClose={handleCancel}>
|
||||
<DialogContent>
|
||||
{taskDialogRenderer ? (
|
||||
taskDialogRenderer({ task, taskAttributes, taskColors, close: handleCancel })
|
||||
) : (
|
||||
<>
|
||||
<DialogContent sx={STYLES.TASK_EDITOR_CONTENT}>
|
||||
<List sx={STYLES.TASK_EDITOR_LIST}>
|
||||
<ListItem alignItems="flex-start">
|
||||
<ListItemText primary={numbCaption} secondary={task.numb} />
|
||||
@ -213,7 +223,7 @@ const P8PGanttTaskEditor = ({
|
||||
}
|
||||
/>
|
||||
</ListItem>
|
||||
<Divider component="li" />
|
||||
{hasValue(task.progress) || legend || dispTaskAttributes.length > 0 ? <Divider component="li" /> : null}
|
||||
{hasValue(task.progress) ? (
|
||||
<>
|
||||
<ListItem alignItems="flex-start">
|
||||
@ -232,19 +242,17 @@ const P8PGanttTaskEditor = ({
|
||||
}
|
||||
/>
|
||||
</ListItem>
|
||||
<Divider component="li" />
|
||||
{legend || dispTaskAttributes.length > 0 ? <Divider component="li" /> : null}
|
||||
</>
|
||||
) : null}
|
||||
{legend ? (
|
||||
<>
|
||||
<ListItem alignItems="flex-start">{legend}</ListItem>
|
||||
<Divider component="li" />
|
||||
{dispTaskAttributes.length > 0 ? <Divider component="li" /> : null}
|
||||
</>
|
||||
) : null}
|
||||
{Array.isArray(taskAttributes) && taskAttributes.length > 0
|
||||
? taskAttributes
|
||||
.filter(attr => hasValue(task[attr.name]))
|
||||
.map((attr, i) => {
|
||||
{dispTaskAttributes.length > 0
|
||||
? dispTaskAttributes.map((attr, i) => {
|
||||
const defaultView = task[attr.name];
|
||||
const customView = taskAttributeRenderer ? taskAttributeRenderer({ task, attribute: attr }) : null;
|
||||
return (
|
||||
@ -256,7 +264,7 @@ const P8PGanttTaskEditor = ({
|
||||
secondary={customView ? customView : defaultView}
|
||||
/>
|
||||
</ListItem>
|
||||
{i < taskAttributes.length - 1 ? <Divider component="li" /> : null}
|
||||
{i < dispTaskAttributes.length - 1 ? <Divider component="li" /> : null}
|
||||
</React.Fragment>
|
||||
);
|
||||
})
|
||||
@ -269,6 +277,8 @@ const P8PGanttTaskEditor = ({
|
||||
</Button>
|
||||
<Button onClick={handleCancel}>{cancelBtnCaption}</Button>
|
||||
</DialogActions>
|
||||
</>
|
||||
)}
|
||||
</Dialog>
|
||||
);
|
||||
};
|
||||
@ -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,
|
||||
|
@ -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 (
|
||||
<Card>
|
||||
<CardHeader
|
||||
avatar={<Avatar sx={{ bgcolor: task.bgColor }}>{task.type == 0 ? "Эт" : "Ра"}</Avatar>}
|
||||
title={task.name}
|
||||
subheader={`с ${formatDateRF(task.start)} по ${formatDateRF(task.end)}`}
|
||||
/>
|
||||
<CardContent>
|
||||
<Typography variant="body2" color="text.secondary">
|
||||
Это пользовательский диалог с данными о задаче. Вы можете формировать такие указав свой функциональный компонент в качестве
|
||||
свойства "taskDialogRenderer" компонента "P8PGantt".
|
||||
</Typography>
|
||||
</CardContent>
|
||||
<CardActions disableSpacing>
|
||||
<Button size="small" onClick={close}>
|
||||
Закрыть
|
||||
</Button>
|
||||
</CardActions>
|
||||
</Card>
|
||||
);
|
||||
};
|
||||
|
||||
//-----------
|
||||
//Тело модуля
|
||||
//-----------
|
||||
@ -69,7 +107,8 @@ const Gantt = ({ title }) => {
|
||||
dataLoaded: false,
|
||||
ident: null,
|
||||
ganttDef: {},
|
||||
ganttTasks: []
|
||||
ganttTasks: [],
|
||||
useCustomTaskDialog: false
|
||||
});
|
||||
|
||||
//Подключение к контексту взаимодействия с сервером
|
||||
@ -132,6 +171,10 @@ const Gantt = ({ title }) => {
|
||||
<Typography sx={STYLES.TITLE} variant={"h6"}>
|
||||
{title}
|
||||
</Typography>
|
||||
<FormControlLabel
|
||||
control={<Checkbox onChange={() => setState(pv => ({ ...pv, useCustomTaskDialog: !pv.useCustomTaskDialog }))} />}
|
||||
label="Отображать пользовательский диалог задачи"
|
||||
/>
|
||||
<Grid container spacing={0} direction="column" alignItems="center">
|
||||
<Grid item xs={12}>
|
||||
{state.dataLoaded ? (
|
||||
@ -143,6 +186,7 @@ const Gantt = ({ title }) => {
|
||||
tasks={state.ganttTasks}
|
||||
onTaskDatesChange={handleTaskDatesChange}
|
||||
taskAttributeRenderer={taskAttributeRenderer}
|
||||
taskDialogRenderer={state.useCustomTaskDialog ? taskDialogRenderer : null}
|
||||
/>
|
||||
</Box>
|
||||
) : null}
|
||||
|
Loading…
x
Reference in New Issue
Block a user