/*
Парус 8 - Панели мониторинга - ПУП - Работы проектов
Панель мониторинга: Корневая панель работ проектов
*/
//---------------------
//Подключение библиотек
//---------------------
import React, { useContext, useState, useCallback, useEffect } from "react"; //Классы React
import PropTypes from "prop-types"; //Контроль свойств компонента
import { Drawer, Fab, Box, Grid, List, ListItemButton, ListItemText, ListItemIcon, Icon, Typography, Stack } from "@mui/material"; //Интерфейсные элементы
import { BackEndСtx } from "../../context/backend"; //Контекст взаимодействия с сервером
import { MessagingСtx } from "../../context/messaging"; //Контекст сообщений
import { ApplicationСtx } from "../../context/application"; //Контекст приложения
import { P8P_GANTT_CONFIG_PROPS } from "../../config_wrapper"; //Подключение компонентов к настройкам приложения
import { P8PGantt } from "../../components/p8p_gantt"; //Диаграмма Ганта
import { formatDateJSONDateOnly } from "../../core/utils"; //Вспомогательные функции
//---------
//Константы
//---------
//Высота диаграммы Ганта
const GANTT_HEIGHT = "650px";
//Ширина диаграммы Ганта
const GANTT_WIDTH = "98vw";
//Стили
const STYLES = {
PROJECTS_LIST_ITEM_NOJOBS: { backgroundColor: "#ff000045" },
PROJECTS_LIST_ITEM_PRIMARY: { wordWrap: "break-word" },
PROJECTS_LIST_ITEM_SECONDARY: { wordWrap: "break-word", fontSize: "0.5rem", textTransform: "uppercase" },
PROJECTS_LIST_ITEM_SECONDARY_NOJOBS: { color: "red" },
PROJECTS_LIST_ITEM_SECONDARY_NOEDIT: { color: "gray" },
PROJECTS_LIST_ITEM_SECONDARY_CHANGED: { color: "green" },
PROJECTS_BUTTON: { position: "absolute" },
PROJECTS_DRAWER: { width: "250px", flexShrink: 0, [`& .MuiDrawer-paper`]: { width: "250px", boxSizing: "border-box" } },
GANTT_CONTAINER: { height: GANTT_HEIGHT, width: GANTT_WIDTH },
GANTT_TITLE: { paddingLeft: "100px", paddingRight: "100px" }
};
//------------------------------------
//Вспомогательные функции и компоненты
//------------------------------------
//Формирование значения для колонки "Состояние" этапа
const formatStageStatusValue = value => {
const [text, icon] =
value == 0
? ["Зарегистрирован", "app_registration"]
: value == 1
? ["Открыт", "lock_open"]
: value == 2
? ["Закрыт", "lock_outline"]
: value == 3
? ["Согласован", "thumb_up_alt"]
: value == 4
? ["Исполнение прекращено", "block"]
: ["Остановлен", "do_not_disturb_on"];
return (
{icon}
{text}
);
};
//Формирование значения для колонки "Состояние" работы
const formatJobStatusValue = value => {
const [text, icon] =
value == 0
? ["Не начата", "not_started"]
: value == 1
? ["Выполняется", "loop"]
: value == 2
? ["Выполнена", "task_alt"]
: value == 3
? ["Остановлена", "do_not_disturb_on"]
: ["Отменена", "cancel"];
return (
{icon}
{text}
);
};
//Список проектов
const ProjectsList = ({ projects = [], selectedProject, onClick } = {}) => {
//Подключение к контексту сообщений
const { InlineMsgErr } = useContext(MessagingСtx);
//Генерация содержимого
return projects.length > 0 ? (
{projects.map(p => (
(onClick ? onClick(p) : null)}
>
{p.NEDITABLE == 1 ? "edit" : "edit_off"}
{p.SNAME}}
secondary={
{p.NJOBS == 1
? p.NEDITABLE == 1
? p.NCHANGED == 1
? "Изменён"
: "Не изменён"
: "Редактирование недоступно"
: "Работы не определены"}
}
/>
))}
) : (
);
};
//Контроль свойств - Список проектов
ProjectsList.propTypes = {
projects: PropTypes.array,
selectedProject: PropTypes.number,
onClick: PropTypes.func
};
//-----------
//Тело модуля
//-----------
//Корневая панель работ проектов
const PrjJobs = () => {
//Собственное состояние
let [state, setState] = useState({
showProjectsList: false,
init: false,
ident: null,
projects: [],
projectsLoaded: false,
selectedProjectJobsLoaded: false,
selectedProject: null,
selectedProjectDocRn: null,
selectedProjectGanttDef: {},
selectedProjectTasks: []
});
//Подключение к контексту приложения
const { pOnlineShowDocument } = useContext(ApplicationСtx);
//Подключение к контексту сообщений
const { InlineMsgInfo } = useContext(MessagingСtx);
//Подключение к контексту взаимодействия с сервером
const { executeStored } = useContext(BackEndСtx);
//Загрузка списка проектов
const loadProjects = useCallback(async () => {
if (!state.projectsLoaded) {
const data = await executeStored({
stored: "PKG_P8PANELS_PROJECTS.JB_PRJCTS_LIST",
args: {
NIDENT: state.ident
},
respArg: "COUT"
});
setState(pv => ({ ...pv, projectsLoaded: true, projects: [...(data?.XPROJECTS || [])] }));
}
}, [executeStored, state.ident, state.projectsLoaded]);
//Загрузка списка работ проекта
const loadProjectJobs = useCallback(
async (tasksOnly = false) => {
const data = await executeStored({
stored: "PKG_P8PANELS_PROJECTS.JB_JOBS_LIST",
args: {
NIDENT: state.ident,
NPRN: state.selectedProject,
NINCLUDE_DEF: tasksOnly === false ? 1 : 0
},
attributeValueProcessor: (name, val) =>
name == "numb" ? undefined : ["start", "end"].includes(name) ? formatDateJSONDateOnly(val) : val,
respArg: "COUT"
});
setState(pv => ({
...pv,
selectedProjectJobsLoaded: true,
selectedProjectGanttDef: tasksOnly === true ? { ...pv.selectedProjectGanttDef } : data.XGANTT_DEF ? { ...data.XGANTT_DEF } : {},
selectedProjectTasks: [...data.XGANTT_TASKS]
}));
},
[executeStored, state.ident, state.selectedProject]
);
//Инициализация данных балансировки
const initJobs = useCallback(async () => {
if (!state.init) {
const data = await executeStored({
stored: "PKG_P8PANELS_PROJECTS.JB_INIT",
args: {
DBEGIN: null,
DFACT: null,
NDURATION_MEAS: 0,
SLAB_MEAS: null,
NINCLUDE_DEF: null,
NIDENT: state.ident
}
});
setState(pv => ({ ...pv, init: true, ident: data.NIDENT }));
}
}, [state.init, state.ident, executeStored]);
//При смене идентификатора процесса
useEffect(() => {
if (state.ident) loadProjects();
}, [state.ident, loadProjects]);
//При смене выбранного проекта
useEffect(() => {
if (state.selectedProject) loadProjectJobs(false);
}, [state.selectedProject, loadProjectJobs]);
//При подключении компонента к странице
useEffect(() => {
initJobs();
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
//Обработка нажатия на элемент в списке проектов
const handleProjectClick = project => {
if (state.selectedProject != project.NRN) {
setState(pv => ({
...pv,
selectedProject: project.NRN,
selectedProjectDocRn: project.NPROJECT,
selectedProjectJobsLoaded: false,
selectedProjectTasks: [],
selectedProjectGanttDef: {},
showProjectsList: false
}));
} else
setState(pv => ({
...pv,
selectedProjectJobsLoaded: false,
selectedProject: null,
selectedProjectDocRn: null,
selectedProjectTasks: [],
selectedProjectGanttDef: {},
showProjectsList: false
}));
};
//Отработка нажатия на заголовок плана-графика
const handleTitleClick = () =>
state.selectedProjectDocRn ? pOnlineShowDocument({ unitCode: "Projects", document: state.selectedProjectDocRn }) : null;
//Обработка измненения сроков задачи в диаграмме Гантта
const handleTaskDatesChange = ({ task, start, end, isMain }) => {
console.log("ПОМЕНЯЛИ ДАТЫ");
console.log(task);
console.log(start);
console.log(end);
if (isMain) {
console.log("ЭТО - ГЛАВНОЕ. ПОЙДЁМ НА СЕРВЕР...");
loadProjectJobs(true);
}
};
//Обработка изменения прогресса задачи в диаграмме Гантта
const handleTaskProgressChange = ({ task, progress }) => {
console.log("ПОМЕНЯЛИ % ГОТОВНОСТИ");
console.log(task);
console.log(progress);
};
//Генерация кастомных представлений атрибутов задачи в редакторе
const taskAttributeRenderer = ({ task, attribute }) => {
switch (attribute.name) {
case "type":
return task.type === 1 ? "Этап проекта" : "Работа проекта";
case "state":
return task.type === 1 ? formatStageStatusValue(task[attribute.name]) : formatJobStatusValue(task[attribute.name]);
default:
return null;
}
};
//Генерация содержимого
return (
setState(pv => ({ ...pv, showProjectsList: !pv.showProjectsList }))}>
Проекты
setState(pv => ({ ...pv, showProjectsList: false }))}
sx={STYLES.PROJECTS_DRAWER}
>
{state.projectsLoaded ? (
) : null}
{state.init == true ? (
{state.selectedProjectJobsLoaded ? (
) : !state.selectedProject ? (
) : null}
) : null}
);
};
//----------------
//Интерфейс модуля
//----------------
export { PrjJobs };