268 lines
13 KiB
JavaScript
268 lines
13 KiB
JavaScript
/*
|
|
Парус 8 - Панели мониторинга - Диаграмма Ганта
|
|
Компонент: Редактор задачи
|
|
*/
|
|
|
|
//---------------------
|
|
//Подключение библиотек
|
|
//---------------------
|
|
|
|
import React, { useState } from "react"; //Классы React
|
|
import PropTypes from "prop-types"; //Контроль свойств компонента
|
|
import { Dialog, DialogActions, DialogContent, TextField, Button, List, ListItem, ListItemText, Divider, Slider } from "@mui/material"; //Интерфейсные компоненты
|
|
import { P8P_GANTT_TASK_SHAPE, P8P_GANTT_TASK_ATTRIBUTE_SHAPE, P8P_GANTT_TASK_COLOR_SHAPE } from "./p8p_gantt_constants"; //Константы диаграммы Ганта
|
|
import { P8P_DIALOG_CONTENT_VARIANT } from "../../theme/variants/p8p_dialog_content_variants"; //Варианты диалогов (содержимое)
|
|
import { P8P_LIST_VARIANT } from "../../theme/variants/p8p_list_variants"; //Варианты списков
|
|
import { P8P_LIST_ITEM_TEXT_VARIANT } from "../../theme/variants/p8p_list_item_text_variants"; //Варианты значений списков
|
|
import { P8P_TEXT_FIELD_VARIANT } from "../../theme/variants/p8p_text_field_variants"; //Варианты полей ввода
|
|
import { P8P_BUTTON_VARIANT } from "../../theme/variants/p8p_button_variants"; //Варианты кнопок
|
|
|
|
//--------------------------------
|
|
//Вспомогательные классы и функции
|
|
//--------------------------------
|
|
|
|
//Проверка существования значения
|
|
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,
|
|
taskDialogProps,
|
|
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 ? (
|
|
<ListItemText
|
|
variant={P8P_LIST_ITEM_TEXT_VARIANT.PRIMARY}
|
|
secondaryTypographyProps={{
|
|
p: 1,
|
|
sx: legendDesc.style
|
|
}}
|
|
primary={legendCaption}
|
|
secondary={legendDesc.text}
|
|
/>
|
|
) : null;
|
|
|
|
//Генерация содержимого
|
|
return (
|
|
<Dialog open onClose={handleCancel} {...(taskDialogProps ? taskDialogProps : {})}>
|
|
{taskDialogRenderer ? (
|
|
taskDialogRenderer({ task, taskAttributes, taskColors, close: handleCancel })
|
|
) : (
|
|
<>
|
|
<DialogContent variant={P8P_DIALOG_CONTENT_VARIANT.TASK}>
|
|
<List variant={P8P_LIST_VARIANT.GANTT_TASK}>
|
|
<ListItem alignItems="flex-start">
|
|
<ListItemText variant={P8P_LIST_ITEM_TEXT_VARIANT.PRIMARY} primary={numbCaption} secondary={task.numb} />
|
|
</ListItem>
|
|
<Divider component="li" />
|
|
<ListItem alignItems="flex-start">
|
|
<ListItemText variant={P8P_LIST_ITEM_TEXT_VARIANT.PRIMARY} primary={nameCaption} secondary={task.fullName} />
|
|
</ListItem>
|
|
<Divider component="li" />
|
|
<ListItem alignItems="flex-start">
|
|
<ListItemText
|
|
variant={P8P_LIST_ITEM_TEXT_VARIANT.PRIMARY}
|
|
secondaryTypographyProps={{ component: "span" }}
|
|
primary={startCaption}
|
|
secondary={
|
|
<TextField
|
|
error={!state.start}
|
|
disabled={task.readOnly === true || task.readOnlyDates === true}
|
|
name="start"
|
|
fullWidth
|
|
required
|
|
InputLabelProps={{ shrink: true }}
|
|
type={"date"}
|
|
value={state.start}
|
|
onChange={handlePeriodChanged}
|
|
variant="standard"
|
|
data-variant={P8P_TEXT_FIELD_VARIANT.PRIMARY}
|
|
size="small"
|
|
margin="normal"
|
|
/>
|
|
}
|
|
/>
|
|
</ListItem>
|
|
<Divider component="li" />
|
|
<ListItem alignItems="flex-start">
|
|
<ListItemText
|
|
variant={P8P_LIST_ITEM_TEXT_VARIANT.PRIMARY}
|
|
secondaryTypographyProps={{ component: "span" }}
|
|
primary={endCaption}
|
|
secondary={
|
|
<TextField
|
|
error={!state.end}
|
|
disabled={task.readOnly === true || task.readOnlyDates === true}
|
|
name="end"
|
|
fullWidth
|
|
required
|
|
InputLabelProps={{ shrink: true }}
|
|
type={"date"}
|
|
value={state.end}
|
|
onChange={handlePeriodChanged}
|
|
variant="standard"
|
|
data-variant={P8P_TEXT_FIELD_VARIANT.PRIMARY}
|
|
size="small"
|
|
margin="normal"
|
|
/>
|
|
}
|
|
/>
|
|
</ListItem>
|
|
{hasValue(task.progress) || legend || dispTaskAttributes.length > 0 ? <Divider component="li" /> : null}
|
|
{hasValue(task.progress) ? (
|
|
<>
|
|
<ListItem alignItems="flex-start">
|
|
<ListItemText
|
|
variant={P8P_LIST_ITEM_TEXT_VARIANT.PRIMARY}
|
|
secondaryTypographyProps={{ component: "span" }}
|
|
primary={`${progressCaption}${
|
|
task.readOnly === true || task.readOnlyProgress === true ? ` (${task.progress}%)` : ""
|
|
}`}
|
|
secondary={
|
|
<Slider
|
|
disabled={task.readOnly === true || task.readOnlyProgress === true}
|
|
defaultValue={task.progress}
|
|
valueLabelDisplay="auto"
|
|
onChange={handleProgressChanged}
|
|
/>
|
|
}
|
|
/>
|
|
</ListItem>
|
|
{legend || dispTaskAttributes.length > 0 ? <Divider component="li" /> : null}
|
|
</>
|
|
) : null}
|
|
{legend ? (
|
|
<>
|
|
<ListItem alignItems="flex-start">{legend}</ListItem>
|
|
{dispTaskAttributes.length > 0 ? <Divider component="li" /> : null}
|
|
</>
|
|
) : null}
|
|
{dispTaskAttributes.length > 0
|
|
? dispTaskAttributes.map((attr, i) => {
|
|
const defaultView = task[attr.name];
|
|
const customView = taskAttributeRenderer ? taskAttributeRenderer({ task, attribute: attr }) : null;
|
|
return (
|
|
<React.Fragment key={i}>
|
|
<ListItem alignItems="flex-start">
|
|
<ListItemText
|
|
variant={P8P_LIST_ITEM_TEXT_VARIANT.PRIMARY}
|
|
primary={attr.caption}
|
|
secondaryTypographyProps={{ component: "span" }}
|
|
secondary={customView ? customView : defaultView}
|
|
/>
|
|
</ListItem>
|
|
{i < dispTaskAttributes.length - 1 ? <Divider component="li" /> : null}
|
|
</React.Fragment>
|
|
);
|
|
})
|
|
: null}
|
|
</List>
|
|
</DialogContent>
|
|
<DialogActions>
|
|
<Button variant={P8P_BUTTON_VARIANT.SECONDARY} onClick={handleCancel}>
|
|
{cancelBtnCaption}
|
|
</Button>
|
|
<Button variant={P8P_BUTTON_VARIANT.PRIMARY} disabled={!state.start || !state.end || task.readOnly} onClick={handleOk}>
|
|
{okBtnCaption}
|
|
</Button>
|
|
</DialogActions>
|
|
</>
|
|
)}
|
|
</Dialog>
|
|
);
|
|
};
|
|
|
|
//Контроль свойств - Редактор задачи
|
|
P8PGanttTaskEditor.propTypes = {
|
|
task: P8P_GANTT_TASK_SHAPE,
|
|
taskAttributes: PropTypes.arrayOf(P8P_GANTT_TASK_ATTRIBUTE_SHAPE),
|
|
taskColors: PropTypes.arrayOf(P8P_GANTT_TASK_COLOR_SHAPE),
|
|
onOk: PropTypes.func,
|
|
onCancel: PropTypes.func,
|
|
taskAttributeRenderer: PropTypes.func,
|
|
taskDialogRenderer: PropTypes.func,
|
|
taskDialogProps: PropTypes.object,
|
|
numbCaption: PropTypes.string.isRequired,
|
|
nameCaption: PropTypes.string.isRequired,
|
|
startCaption: PropTypes.string.isRequired,
|
|
endCaption: PropTypes.string.isRequired,
|
|
progressCaption: PropTypes.string.isRequired,
|
|
legendCaption: PropTypes.string.isRequired,
|
|
okBtnCaption: PropTypes.string.isRequired,
|
|
cancelBtnCaption: PropTypes.string.isRequired
|
|
};
|
|
|
|
//----------------
|
|
//Интерфейс модуля
|
|
//----------------
|
|
|
|
export { P8PGanttTaskEditor, taskLegendDesc };
|