forked from CITKParus/P8-Panels
WEB APP: Панель "Работы проектов" - детализация фактической трудоёмкости по "Планам и отчетам подразделений", генерация представлений отдельных элементов данных вынесена в отдельный модуль
This commit is contained in:
parent
79c11ab366
commit
cfb66b92df
125
app/panels/prj_jobs/lab_fact_rpt_dtl.js
Normal file
125
app/panels/prj_jobs/lab_fact_rpt_dtl.js
Normal file
@ -0,0 +1,125 @@
|
|||||||
|
/*
|
||||||
|
Парус 8 - Панели мониторинга - ПУП - Работы проектов
|
||||||
|
Компонент панели: Детализация фактической трудоёмкости по "Планам и отчетам подразделений"
|
||||||
|
*/
|
||||||
|
|
||||||
|
//---------------------
|
||||||
|
//Подключение библиотек
|
||||||
|
//---------------------
|
||||||
|
|
||||||
|
import React, { useContext, useState, useCallback, useEffect } from "react"; //Классы React
|
||||||
|
import PropTypes from "prop-types"; //Контроль свойств компонента
|
||||||
|
import { Dialog, DialogContent, DialogActions, Button, DialogTitle } from "@mui/material"; //Интерфейсные элементы
|
||||||
|
import { BackEndСtx } from "../../context/backend"; //Контекст взаимодействия с сервером
|
||||||
|
import { ApplicationСtx } from "../../context/application"; //Контекст приложения
|
||||||
|
import { object2Base64XML } from "../../core/utils"; //Вспомогательные функции
|
||||||
|
import { BUTTONS } from "../../../app.text"; //Текстовые ресурсы
|
||||||
|
import { P8P_DATA_GRID_CONFIG_PROPS } from "../../config_wrapper"; //Подключение компонентов к настройкам приложения
|
||||||
|
import { P8PDataGrid, P8P_DATA_GRID_SIZE } from "../../components/p8p_data_grid"; //Таблица данных
|
||||||
|
import { factRptDtlValueFormatter, factRptDtlHeadCellRender } from "./layouts"; //Дополнительная разметка и вёрстка клиентских элементов
|
||||||
|
|
||||||
|
//-----------
|
||||||
|
//Тело модуля
|
||||||
|
//-----------
|
||||||
|
|
||||||
|
//Детализация фактической трудоёмкости по "Планам и отчетам подразделений"
|
||||||
|
const LabFactRptDtl = ({ periodId, title, onHide }) => {
|
||||||
|
//Состояние таблицы детализации плановой трудоёмкости по графику
|
||||||
|
const [factRptDtl, setFactRptDtl] = useState({
|
||||||
|
dataLoaded: false,
|
||||||
|
columnsDef: [],
|
||||||
|
orders: [],
|
||||||
|
rows: [],
|
||||||
|
reload: true,
|
||||||
|
pageNumber: 1,
|
||||||
|
morePages: true
|
||||||
|
});
|
||||||
|
|
||||||
|
//Подключение к контексту приложения
|
||||||
|
const { configSystemPageSize } = useContext(ApplicationСtx);
|
||||||
|
|
||||||
|
//Подключение к контексту взаимодействия с сервером
|
||||||
|
const { executeStored, SERV_DATA_TYPE_CLOB } = useContext(BackEndСtx);
|
||||||
|
|
||||||
|
//Загрузка детализации фактической трудоёмкости по отчетам для ресурса
|
||||||
|
const loadFactRptDtl = useCallback(async () => {
|
||||||
|
if (factRptDtl.reload) {
|
||||||
|
const data = await executeStored({
|
||||||
|
stored: "PKG_P8PANELS_PROJECTS.JB_PERIODS_LIST_FACT_RPT",
|
||||||
|
args: {
|
||||||
|
NJB_PERIODS: periodId,
|
||||||
|
CORDERS: { VALUE: object2Base64XML(factRptDtl.orders, { arrayNodeName: "orders" }), SDATA_TYPE: SERV_DATA_TYPE_CLOB },
|
||||||
|
NPAGE_NUMBER: factRptDtl.pageNumber,
|
||||||
|
NPAGE_SIZE: configSystemPageSize,
|
||||||
|
NINCLUDE_DEF: factRptDtl.dataLoaded ? 0 : 1
|
||||||
|
},
|
||||||
|
respArg: "COUT"
|
||||||
|
});
|
||||||
|
setFactRptDtl(pv => ({
|
||||||
|
...pv,
|
||||||
|
columnsDef: data.XCOLUMNS_DEF ? [...data.XCOLUMNS_DEF] : pv.columnsDef,
|
||||||
|
rows: pv.pageNumber == 1 ? [...(data.XROWS || [])] : [...pv.rows, ...(data.XROWS || [])],
|
||||||
|
dataLoaded: true,
|
||||||
|
reload: false,
|
||||||
|
morePages: (data.XROWS || []).length >= configSystemPageSize
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}, [
|
||||||
|
periodId,
|
||||||
|
factRptDtl.reload,
|
||||||
|
factRptDtl.orders,
|
||||||
|
factRptDtl.dataLoaded,
|
||||||
|
factRptDtl.pageNumber,
|
||||||
|
executeStored,
|
||||||
|
configSystemPageSize,
|
||||||
|
SERV_DATA_TYPE_CLOB
|
||||||
|
]);
|
||||||
|
|
||||||
|
//При изменении состояния сортировки в детализации факта по "Планам и отчетам в подразделении"
|
||||||
|
const handlePlanJobsDtlDGOrderChanged = ({ orders }) => setFactRptDtl(pv => ({ ...pv, orders, pageNumber: 1, reload: true }));
|
||||||
|
|
||||||
|
//При изменении количества отображаемых страниц в факта по "Планам и отчетам в подразделении"
|
||||||
|
const handlePlanJobsDtlDGPagesCountChanged = () => setFactRptDtl(pv => ({ ...pv, pageNumber: pv.pageNumber + 1, reload: true }));
|
||||||
|
|
||||||
|
//При необходимости обновить данные
|
||||||
|
useEffect(() => {
|
||||||
|
loadFactRptDtl();
|
||||||
|
}, [factRptDtl.reload, loadFactRptDtl]);
|
||||||
|
|
||||||
|
//Генерация содержимого
|
||||||
|
return factRptDtl.dataLoaded ? (
|
||||||
|
<Dialog open onClose={onHide} fullWidth maxWidth="xl">
|
||||||
|
<DialogTitle>{title}</DialogTitle>
|
||||||
|
<DialogContent>
|
||||||
|
<P8PDataGrid
|
||||||
|
{...P8P_DATA_GRID_CONFIG_PROPS}
|
||||||
|
columnsDef={factRptDtl.columnsDef}
|
||||||
|
rows={factRptDtl.rows}
|
||||||
|
size={P8P_DATA_GRID_SIZE.SMALL}
|
||||||
|
morePages={factRptDtl.morePages}
|
||||||
|
reloading={factRptDtl.reload}
|
||||||
|
valueFormatter={factRptDtlValueFormatter}
|
||||||
|
headCellRender={factRptDtlHeadCellRender}
|
||||||
|
onOrderChanged={handlePlanJobsDtlDGOrderChanged}
|
||||||
|
onPagesCountChanged={handlePlanJobsDtlDGPagesCountChanged}
|
||||||
|
/>
|
||||||
|
</DialogContent>
|
||||||
|
<DialogActions>
|
||||||
|
<Button onClick={onHide}>{BUTTONS.CLOSE}</Button>
|
||||||
|
</DialogActions>
|
||||||
|
</Dialog>
|
||||||
|
) : null;
|
||||||
|
};
|
||||||
|
|
||||||
|
//Контроль свойств - Детализация фактической трудоёмкости по "Планам и отчетам подразделений"
|
||||||
|
LabFactRptDtl.propTypes = {
|
||||||
|
periodId: PropTypes.number.isRequired,
|
||||||
|
title: PropTypes.string.isRequired,
|
||||||
|
onHide: PropTypes.func.isRequired
|
||||||
|
};
|
||||||
|
|
||||||
|
//----------------
|
||||||
|
//Интерфейс модуля
|
||||||
|
//----------------
|
||||||
|
|
||||||
|
export { LabFactRptDtl };
|
@ -9,87 +9,19 @@
|
|||||||
|
|
||||||
import React, { useContext, useState, useCallback, useEffect } from "react"; //Классы React
|
import React, { useContext, useState, useCallback, useEffect } from "react"; //Классы React
|
||||||
import PropTypes from "prop-types"; //Контроль свойств компонента
|
import PropTypes from "prop-types"; //Контроль свойств компонента
|
||||||
import { Dialog, DialogContent, DialogActions, Button, DialogTitle, Stack, Icon, Link } from "@mui/material"; //Интерфейсные элементы
|
import { Dialog, DialogContent, DialogActions, Button, DialogTitle } from "@mui/material"; //Интерфейсные элементы
|
||||||
import { BackEndСtx } from "../../context/backend"; //Контекст взаимодействия с сервером
|
import { BackEndСtx } from "../../context/backend"; //Контекст взаимодействия с сервером
|
||||||
import { ApplicationСtx } from "../../context/application"; //Контекст приложения
|
import { ApplicationСtx } from "../../context/application"; //Контекст приложения
|
||||||
import { object2Base64XML, formatDateRF } from "../../core/utils"; //Вспомогательные функции
|
import { object2Base64XML } from "../../core/utils"; //Вспомогательные функции
|
||||||
import { BUTTONS } from "../../../app.text"; //Текстовые ресурсы
|
import { BUTTONS } from "../../../app.text"; //Текстовые ресурсы
|
||||||
import { P8P_DATA_GRID_CONFIG_PROPS } from "../../config_wrapper"; //Подключение компонентов к настройкам приложения
|
import { P8P_DATA_GRID_CONFIG_PROPS } from "../../config_wrapper"; //Подключение компонентов к настройкам приложения
|
||||||
import { P8PDataGrid, P8P_DATA_GRID_SIZE } from "../../components/p8p_data_grid"; //Таблица данных
|
import { P8PDataGrid, P8P_DATA_GRID_SIZE } from "../../components/p8p_data_grid"; //Таблица данных
|
||||||
|
import { planJobsDtlValueFormatter, planJobsDtlHeadCellRender, planJobsDtlDataCellRender } from "./layouts"; //Дополнительная разметка и вёрстка клиентских элементов
|
||||||
|
|
||||||
//------------------------------------
|
//------------------------------------
|
||||||
//Вспомогательные функции и компоненты
|
//Вспомогательные функции и компоненты
|
||||||
//------------------------------------
|
//------------------------------------
|
||||||
|
|
||||||
//Формирование значения для колонки "Состояние" этапа
|
|
||||||
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 (
|
|
||||||
<Stack direction="row" gap={0.5} alignItems="center" justifyContent="center">
|
|
||||||
<Icon title={text}>{icon}</Icon>
|
|
||||||
</Stack>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
//Форматирование значений колонок в таблице детализации трудоёмкости по графику
|
|
||||||
const planJobsDtlValueFormatter = ({ value, columnDef }) => {
|
|
||||||
switch (columnDef.name) {
|
|
||||||
case "NJOB_STATE":
|
|
||||||
return formatJobStatusValue(value);
|
|
||||||
case "DJOB_BEG":
|
|
||||||
case "DJOB_END":
|
|
||||||
return formatDateRF(value);
|
|
||||||
}
|
|
||||||
return value;
|
|
||||||
};
|
|
||||||
|
|
||||||
//Генерация представления ячейки заголовка в таблице детализации трудоёмкости по графику
|
|
||||||
const planJobsDtlHeadCellRender = ({ columnDef }) => {
|
|
||||||
switch (columnDef.name) {
|
|
||||||
case "NJOB_STATE":
|
|
||||||
return {
|
|
||||||
stackProps: { justifyContent: "center" },
|
|
||||||
cellProps: { align: "center" }
|
|
||||||
};
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
//Генерация представления ячейки c данными в таблице детализации трудоёмкости по графику
|
|
||||||
const planJobsDtlDataCellRender = ({ row, columnDef, onProjectClick }) => {
|
|
||||||
switch (columnDef.name) {
|
|
||||||
case "SPRJ":
|
|
||||||
return {
|
|
||||||
data: row[columnDef.name] ? (
|
|
||||||
<Link
|
|
||||||
component="button"
|
|
||||||
variant="body2"
|
|
||||||
align="left"
|
|
||||||
underline="hover"
|
|
||||||
onClick={() => (onProjectClick ? onProjectClick({ sender: row }) : null)}
|
|
||||||
>
|
|
||||||
{row[columnDef.name]}
|
|
||||||
</Link>
|
|
||||||
) : (
|
|
||||||
row[columnDef.name]
|
|
||||||
)
|
|
||||||
};
|
|
||||||
case "NSTATE":
|
|
||||||
return {
|
|
||||||
cellProps: { align: "center" },
|
|
||||||
data: formatJobStatusValue(row[columnDef.name])
|
|
||||||
};
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
//-----------
|
//-----------
|
||||||
//Тело модуля
|
//Тело модуля
|
||||||
//-----------
|
//-----------
|
||||||
@ -113,8 +45,8 @@ const LabPlanJobsDtl = ({ periodId, title, onHide, onProjectClick }) => {
|
|||||||
//Подключение к контексту взаимодействия с сервером
|
//Подключение к контексту взаимодействия с сервером
|
||||||
const { executeStored, SERV_DATA_TYPE_CLOB } = useContext(BackEndСtx);
|
const { executeStored, SERV_DATA_TYPE_CLOB } = useContext(BackEndСtx);
|
||||||
|
|
||||||
//Загрузка детализации плановой трудоёмкости по ФОТ для ресурса
|
//Загрузка детализации плановой трудоёмкости по графику для ресурса
|
||||||
const loadPlanFOTDtl = useCallback(async () => {
|
const loadPlanJobsDtl = useCallback(async () => {
|
||||||
if (planJobsDtl.reload) {
|
if (planJobsDtl.reload) {
|
||||||
const data = await executeStored({
|
const data = await executeStored({
|
||||||
stored: "PKG_P8PANELS_PROJECTS.JB_PERIODS_LIST_PLAN_JOBS",
|
stored: "PKG_P8PANELS_PROJECTS.JB_PERIODS_LIST_PLAN_JOBS",
|
||||||
@ -147,19 +79,19 @@ const LabPlanJobsDtl = ({ periodId, title, onHide, onProjectClick }) => {
|
|||||||
SERV_DATA_TYPE_CLOB
|
SERV_DATA_TYPE_CLOB
|
||||||
]);
|
]);
|
||||||
|
|
||||||
//При изменении состояния сортировки в детализации плана ФОТ по строке ресурса
|
//При изменении состояния сортировки в детализации плановой трудоёмкости по графику
|
||||||
const handlePlanJobsDtlDGOrderChanged = ({ orders }) => setPlanJobsDtl(pv => ({ ...pv, orders, pageNumber: 1, reload: true }));
|
const handlePlanJobsDtlDGOrderChanged = ({ orders }) => setPlanJobsDtl(pv => ({ ...pv, orders, pageNumber: 1, reload: true }));
|
||||||
|
|
||||||
//При изменении количества отображаемых страниц в в детализации плана ФОТ по строке ресурса
|
//При изменении количества отображаемых страниц в детализации плановой трудоёмкости по графику
|
||||||
const handlePlanJobsDtlDGPagesCountChanged = () => setPlanJobsDtl(pv => ({ ...pv, pageNumber: pv.pageNumber + 1, reload: true }));
|
const handlePlanJobsDtlDGPagesCountChanged = () => setPlanJobsDtl(pv => ({ ...pv, pageNumber: pv.pageNumber + 1, reload: true }));
|
||||||
|
|
||||||
//При нажатии на проект в таблице детализацц
|
//При нажатии на проект в таблице детализаци
|
||||||
const handleProjectClick = ({ sender }) => (onProjectClick ? onProjectClick({ sender }) : null);
|
const handleProjectClick = ({ sender }) => (onProjectClick ? onProjectClick({ sender }) : null);
|
||||||
|
|
||||||
//При необходимости обновить данные
|
//При необходимости обновить данные
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
loadPlanFOTDtl();
|
loadPlanJobsDtl();
|
||||||
}, [planJobsDtl.reload, loadPlanFOTDtl]);
|
}, [planJobsDtl.reload, loadPlanJobsDtl]);
|
||||||
|
|
||||||
//Генерация содержимого
|
//Генерация содержимого
|
||||||
return planJobsDtl.dataLoaded ? (
|
return planJobsDtl.dataLoaded ? (
|
||||||
|
187
app/panels/prj_jobs/layouts.js
Normal file
187
app/panels/prj_jobs/layouts.js
Normal file
@ -0,0 +1,187 @@
|
|||||||
|
/*
|
||||||
|
Парус 8 - Панели мониторинга - ПУП - Экономика проектов
|
||||||
|
Дополнительная разметка и вёрстка клиентских элементов
|
||||||
|
*/
|
||||||
|
|
||||||
|
//---------------------
|
||||||
|
//Подключение библиотек
|
||||||
|
//---------------------
|
||||||
|
|
||||||
|
import React from "react"; //Классы React
|
||||||
|
import { Icon, Stack, Link } from "@mui/material"; //Интерфейсные компоненты
|
||||||
|
import { formatDateRF } from "../../core/utils"; //Вспомогательные функции
|
||||||
|
|
||||||
|
//-----------
|
||||||
|
//Тело модуля
|
||||||
|
//-----------
|
||||||
|
|
||||||
|
//Формирование значения для колонки "Состояние" этапа
|
||||||
|
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 (
|
||||||
|
<Stack direction="row" gap={0.5} alignItems="center">
|
||||||
|
<Icon title={text}>{icon}</Icon>
|
||||||
|
{text}
|
||||||
|
</Stack>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
//Формирование значения для колонки "Состояние" работы
|
||||||
|
const formatJobStatusValue = (value, addText = false, justifyContent = null) => {
|
||||||
|
const [text, icon] =
|
||||||
|
value == 0
|
||||||
|
? ["Не начата", "not_started"]
|
||||||
|
: value == 1
|
||||||
|
? ["Выполняется", "loop"]
|
||||||
|
: value == 2
|
||||||
|
? ["Выполнена", "task_alt"]
|
||||||
|
: value == 3
|
||||||
|
? ["Остановлена", "do_not_disturb_on"]
|
||||||
|
: ["Отменена", "cancel"];
|
||||||
|
return (
|
||||||
|
<Stack direction="row" gap={0.5} alignItems="center" {...(justifyContent ? { justifyContent } : {})}>
|
||||||
|
<Icon title={text}>{icon}</Icon>
|
||||||
|
{addText == true ? text : null}
|
||||||
|
</Stack>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
//Генерация кастомных представлений атрибутов задачи в редакторе
|
||||||
|
export 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], true);
|
||||||
|
default:
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
//Форматирование значений колонок в таблице детализации трудоёмкости по графику
|
||||||
|
export const planJobsDtlValueFormatter = ({ value, columnDef }) => {
|
||||||
|
switch (columnDef.name) {
|
||||||
|
case "NJOB_STATE":
|
||||||
|
return formatJobStatusValue(value, false, "center");
|
||||||
|
case "DJOB_BEG":
|
||||||
|
case "DJOB_END":
|
||||||
|
return formatDateRF(value);
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
};
|
||||||
|
|
||||||
|
//Генерация представления ячейки заголовка в таблице детализации трудоёмкости по графику
|
||||||
|
export const planJobsDtlHeadCellRender = ({ columnDef }) => {
|
||||||
|
switch (columnDef.name) {
|
||||||
|
case "NJOB_STATE":
|
||||||
|
return {
|
||||||
|
stackProps: { justifyContent: "center" },
|
||||||
|
cellProps: { align: "center" }
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
//Генерация представления ячейки c данными в таблице детализации трудоёмкости по графику
|
||||||
|
export const planJobsDtlDataCellRender = ({ row, columnDef, onProjectClick }) => {
|
||||||
|
switch (columnDef.name) {
|
||||||
|
case "SPRJ":
|
||||||
|
return {
|
||||||
|
data: row[columnDef.name] ? (
|
||||||
|
<Link
|
||||||
|
component="button"
|
||||||
|
variant="body2"
|
||||||
|
align="left"
|
||||||
|
underline="hover"
|
||||||
|
onClick={() => (onProjectClick ? onProjectClick({ sender: row }) : null)}
|
||||||
|
>
|
||||||
|
{row[columnDef.name]}
|
||||||
|
</Link>
|
||||||
|
) : (
|
||||||
|
row[columnDef.name]
|
||||||
|
)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
//Форматирование значений колонок в таблице детализации трудоёмкости по отчетам
|
||||||
|
export const factRptDtlValueFormatter = ({ value, columnDef }) => {
|
||||||
|
switch (columnDef.name) {
|
||||||
|
case "NJOB_STATE":
|
||||||
|
return formatJobStatusValue(value, false, "center");
|
||||||
|
case "DJOB_BEG":
|
||||||
|
case "DJOB_END":
|
||||||
|
return formatDateRF(value);
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
};
|
||||||
|
|
||||||
|
//Генерация представления ячейки заголовка в таблице детализации трудоёмкости по отчетам
|
||||||
|
export const factRptDtlHeadCellRender = ({ columnDef }) => {
|
||||||
|
switch (columnDef.name) {
|
||||||
|
case "NJOB_STATE":
|
||||||
|
return {
|
||||||
|
stackProps: { justifyContent: "center" },
|
||||||
|
cellProps: { align: "center" }
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
//Генерация представления ячейки c данными в таблице периодов балансировки
|
||||||
|
export const periodsDataCellRender = ({ row, columnDef, onLabPlanFOTClick, onLabFactRptClick, onLabPlanJobsClick }) => {
|
||||||
|
switch (columnDef.name) {
|
||||||
|
case "NLAB_PLAN_FOT":
|
||||||
|
case "NLAB_FACT_RPT":
|
||||||
|
case "NLAB_PLAN_JOBS":
|
||||||
|
return {
|
||||||
|
data: row[columnDef.name] ? (
|
||||||
|
<Link
|
||||||
|
component="button"
|
||||||
|
variant="body2"
|
||||||
|
align="left"
|
||||||
|
underline="hover"
|
||||||
|
onClick={() =>
|
||||||
|
columnDef.name === "NLAB_PLAN_FOT"
|
||||||
|
? onLabPlanFOTClick
|
||||||
|
? onLabPlanFOTClick({ sender: row })
|
||||||
|
: null
|
||||||
|
: columnDef.name === "NLAB_FACT_RPT"
|
||||||
|
? onLabFactRptClick
|
||||||
|
? onLabFactRptClick({ sender: row })
|
||||||
|
: null
|
||||||
|
: columnDef.name === "NLAB_PLAN_JOBS"
|
||||||
|
? onLabPlanJobsClick
|
||||||
|
? onLabPlanJobsClick({ sender: row })
|
||||||
|
: null
|
||||||
|
: null
|
||||||
|
}
|
||||||
|
>
|
||||||
|
{row[columnDef.name]}
|
||||||
|
</Link>
|
||||||
|
) : (
|
||||||
|
row[columnDef.name]
|
||||||
|
)
|
||||||
|
};
|
||||||
|
case "NLAB_DIFF_RPT_FOT":
|
||||||
|
return { data: <div style={{ color: row[columnDef.name] <= 0 ? "green" : "red" }}>{row[columnDef.name]}</div> };
|
||||||
|
case "NLAB_DIFF_JOBS_FOT":
|
||||||
|
return {
|
||||||
|
data: (
|
||||||
|
<Stack direction="row" gap={0.5} alignItems="center" justifyContent="right">
|
||||||
|
<div style={{ color: row[columnDef.name] <= 0 ? "green" : "red" }}>{row[columnDef.name]}</div>
|
||||||
|
<Icon sx={{ color: row[columnDef.name] <= 0 ? "green" : "red" }}>{row[columnDef.name] <= 0 ? "done" : "error"}</Icon>
|
||||||
|
</Stack>
|
||||||
|
)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
@ -9,7 +9,7 @@
|
|||||||
|
|
||||||
import React, { useContext, useState, useCallback, useEffect } from "react"; //Классы React
|
import React, { useContext, useState, useCallback, useEffect } from "react"; //Классы React
|
||||||
import PropTypes from "prop-types"; //Контроль свойств компонента
|
import PropTypes from "prop-types"; //Контроль свойств компонента
|
||||||
import { Drawer, Fab, Box, Grid, List, ListItemButton, ListItemText, ListItemIcon, Icon, Typography, Stack } from "@mui/material"; //Интерфейсные элементы
|
import { Drawer, Fab, Box, Grid, List, ListItemButton, ListItemText, ListItemIcon, Icon, Typography } from "@mui/material"; //Интерфейсные элементы
|
||||||
import { BackEndСtx } from "../../context/backend"; //Контекст взаимодействия с сервером
|
import { BackEndСtx } from "../../context/backend"; //Контекст взаимодействия с сервером
|
||||||
import { MessagingСtx } from "../../context/messaging"; //Контекст сообщений
|
import { MessagingСtx } from "../../context/messaging"; //Контекст сообщений
|
||||||
import { ApplicationСtx } from "../../context/application"; //Контекст приложения
|
import { ApplicationСtx } from "../../context/application"; //Контекст приложения
|
||||||
@ -17,6 +17,7 @@ import { formatDateJSONDateOnly } from "../../core/utils"; //Вспомогат
|
|||||||
import { P8P_GANTT_CONFIG_PROPS } from "../../config_wrapper"; //Подключение компонентов к настройкам приложения
|
import { P8P_GANTT_CONFIG_PROPS } from "../../config_wrapper"; //Подключение компонентов к настройкам приложения
|
||||||
import { P8PGantt } from "../../components/p8p_gantt"; //Диаграмма Ганта
|
import { P8PGantt } from "../../components/p8p_gantt"; //Диаграмма Ганта
|
||||||
import { ResMon } from "./res_mon"; //Монитор ресурсов
|
import { ResMon } from "./res_mon"; //Монитор ресурсов
|
||||||
|
import { taskAttributeRenderer } from "./layouts"; //Дополнительная разметка и вёрстка клиентских элементов
|
||||||
|
|
||||||
//---------
|
//---------
|
||||||
//Константы
|
//Константы
|
||||||
@ -42,55 +43,13 @@ const STYLES = {
|
|||||||
GANTT_CONTAINER: { height: GANTT_HEIGHT, width: GANTT_WIDTH },
|
GANTT_CONTAINER: { height: GANTT_HEIGHT, width: GANTT_WIDTH },
|
||||||
GANTT_TITLE: { paddingLeft: "100px", paddingRight: "120px" },
|
GANTT_TITLE: { paddingLeft: "100px", paddingRight: "120px" },
|
||||||
PERIODS_BUTTON: { position: "absolute", right: "20px" },
|
PERIODS_BUTTON: { position: "absolute", right: "20px" },
|
||||||
PERIODS_DRAWER: { width: "1000px", flexShrink: 0, [`& .MuiDrawer-paper`]: { width: "1000px", boxSizing: "border-box" } }
|
PERIODS_DRAWER: { width: "1200px", flexShrink: 0, [`& .MuiDrawer-paper`]: { width: "1200px", boxSizing: "border-box" } }
|
||||||
};
|
};
|
||||||
|
|
||||||
//------------------------------------
|
//------------------------------------
|
||||||
//Вспомогательные функции и компоненты
|
//Вспомогательные функции и компоненты
|
||||||
//------------------------------------
|
//------------------------------------
|
||||||
|
|
||||||
//Формирование значения для колонки "Состояние" этапа
|
|
||||||
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 (
|
|
||||||
<Stack direction="row" gap={0.5} alignItems="center">
|
|
||||||
<Icon title={text}>{icon}</Icon>
|
|
||||||
{text}
|
|
||||||
</Stack>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
//Формирование значения для колонки "Состояние" работы
|
|
||||||
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 (
|
|
||||||
<Stack direction="row" gap={0.5} alignItems="center">
|
|
||||||
<Icon title={text}>{icon}</Icon>
|
|
||||||
{text}
|
|
||||||
</Stack>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
//Список проектов
|
//Список проектов
|
||||||
const ProjectsList = ({ projects = [], selectedProject, onClick } = {}) => {
|
const ProjectsList = ({ projects = [], selectedProject, onClick } = {}) => {
|
||||||
//Подключение к контексту сообщений
|
//Подключение к контексту сообщений
|
||||||
@ -333,18 +292,6 @@ const PrjJobs = () => {
|
|||||||
if (isMain) modifyJob(task.rn, new Date(start), new Date(end), new Date(state.dateBegin), new Date(state.dateFact), state.durationMeas);
|
if (isMain) modifyJob(task.rn, new Date(start), new Date(end), new Date(state.dateBegin), new Date(state.dateFact), state.durationMeas);
|
||||||
};
|
};
|
||||||
|
|
||||||
//Генерация кастомных представлений атрибутов задачи в редакторе
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
//Обработка нажатия на сохранение данных в проект
|
//Обработка нажатия на сохранение данных в проект
|
||||||
const handleSaveToProjectsClick = () => saveProjects();
|
const handleSaveToProjectsClick = () => saveProjects();
|
||||||
|
|
||||||
|
@ -9,67 +9,15 @@
|
|||||||
|
|
||||||
import React, { useContext, useState, useCallback, useEffect } from "react"; //Классы React
|
import React, { useContext, useState, useCallback, useEffect } from "react"; //Классы React
|
||||||
import PropTypes from "prop-types"; //Контроль свойств компонента
|
import PropTypes from "prop-types"; //Контроль свойств компонента
|
||||||
import { Icon, Stack, Link } from "@mui/material"; //Интерфейсные элементы
|
|
||||||
import { BackEndСtx } from "../../context/backend"; //Контекст взаимодействия с сервером
|
import { BackEndСtx } from "../../context/backend"; //Контекст взаимодействия с сервером
|
||||||
import { ApplicationСtx } from "../../context/application"; //Контекст приложения
|
import { ApplicationСtx } from "../../context/application"; //Контекст приложения
|
||||||
import { object2Base64XML } from "../../core/utils"; //Вспомогательные функции
|
import { object2Base64XML } from "../../core/utils"; //Вспомогательные функции
|
||||||
import { P8P_DATA_GRID_CONFIG_PROPS } from "../../config_wrapper"; //Подключение компонентов к настройкам приложения
|
import { P8P_DATA_GRID_CONFIG_PROPS } from "../../config_wrapper"; //Подключение компонентов к настройкам приложения
|
||||||
import { P8PDataGrid, P8P_DATA_GRID_SIZE } from "../../components/p8p_data_grid"; //Таблица данных
|
import { P8PDataGrid, P8P_DATA_GRID_SIZE } from "../../components/p8p_data_grid"; //Таблица данных
|
||||||
import { LabPlanFOTDtl } from "./lab_plan_fot_dtl"; //Детализация плановой трудоёмкости по ФОТ
|
import { LabPlanFOTDtl } from "./lab_plan_fot_dtl"; //Детализация плановой трудоёмкости по ФОТ
|
||||||
|
import { LabFactRptDtl } from "./lab_fact_rpt_dtl"; //Детализация фактической трудоёмкости по "Планам и отчетам подразделений"
|
||||||
import { LabPlanJobsDtl } from "./lab_plan_jobs_dtl"; //Детализация плановой трудоёмкости по графику
|
import { LabPlanJobsDtl } from "./lab_plan_jobs_dtl"; //Детализация плановой трудоёмкости по графику
|
||||||
|
import { periodsDataCellRender } from "./layouts"; //Дополнительная разметка и вёрстка клиентских элементов
|
||||||
//------------------------------------
|
|
||||||
//Вспомогательные функции и компоненты
|
|
||||||
//------------------------------------
|
|
||||||
|
|
||||||
//Генерация представления ячейки c данными в таблице периодов балансировки
|
|
||||||
const periodsDataCellRender = ({ row, columnDef, onLabPlanFOTClick, onLabPlanJobsClick }) => {
|
|
||||||
switch (columnDef.name) {
|
|
||||||
case "NLAB_PLAN_FOT":
|
|
||||||
return {
|
|
||||||
data: row[columnDef.name] ? (
|
|
||||||
<Link
|
|
||||||
component="button"
|
|
||||||
variant="body2"
|
|
||||||
align="left"
|
|
||||||
underline="hover"
|
|
||||||
onClick={() => (onLabPlanFOTClick ? onLabPlanFOTClick({ sender: row }) : null)}
|
|
||||||
>
|
|
||||||
{row[columnDef.name]}
|
|
||||||
</Link>
|
|
||||||
) : (
|
|
||||||
row[columnDef.name]
|
|
||||||
)
|
|
||||||
};
|
|
||||||
case "NLAB_DIFF_RPT_FOT":
|
|
||||||
return { data: <div style={{ color: row[columnDef.name] <= 0 ? "green" : "red" }}>{row[columnDef.name]}</div> };
|
|
||||||
case "NLAB_PLAN_JOBS":
|
|
||||||
return {
|
|
||||||
data: row[columnDef.name] ? (
|
|
||||||
<Link
|
|
||||||
component="button"
|
|
||||||
variant="body2"
|
|
||||||
align="left"
|
|
||||||
underline="hover"
|
|
||||||
onClick={() => (onLabPlanJobsClick ? onLabPlanJobsClick({ sender: row }) : null)}
|
|
||||||
>
|
|
||||||
{row[columnDef.name]}
|
|
||||||
</Link>
|
|
||||||
) : (
|
|
||||||
row[columnDef.name]
|
|
||||||
)
|
|
||||||
};
|
|
||||||
case "NLAB_DIFF_JOBS_FOT":
|
|
||||||
return {
|
|
||||||
data: (
|
|
||||||
<Stack direction="row" gap={0.5} alignItems="center" justifyContent="right">
|
|
||||||
<div style={{ color: row[columnDef.name] <= 0 ? "green" : "red" }}>{row[columnDef.name]}</div>
|
|
||||||
<Icon sx={{ color: row[columnDef.name] <= 0 ? "green" : "red" }}>{row[columnDef.name] <= 0 ? "done" : "error"}</Icon>
|
|
||||||
</Stack>
|
|
||||||
)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
//-----------
|
//-----------
|
||||||
//Тело модуля
|
//Тело модуля
|
||||||
@ -78,7 +26,14 @@ const periodsDataCellRender = ({ row, columnDef, onLabPlanFOTClick, onLabPlanJob
|
|||||||
//Монитор ресурсов
|
//Монитор ресурсов
|
||||||
const ResMon = ({ ident, onPlanJobsDtlProjectClick }) => {
|
const ResMon = ({ ident, onPlanJobsDtlProjectClick }) => {
|
||||||
//Собственное состояние
|
//Собственное состояние
|
||||||
const [state, setState] = useState({ displayPlanFOTDtl: null, titlePlanFOTDtl: null, displayPlanJobsDtl: null, titlePlanJobsDtl: null });
|
const [state, setState] = useState({
|
||||||
|
displayPlanFOTDtl: null,
|
||||||
|
titlePlanFOTDtl: null,
|
||||||
|
displayFactRptDtl: null,
|
||||||
|
titleFactRptDtl: null,
|
||||||
|
displayPlanJobsDtl: null,
|
||||||
|
titlePlanJobsDtl: null
|
||||||
|
});
|
||||||
|
|
||||||
//Состояние таблицы периодов монитора ресурсов
|
//Состояние таблицы периодов монитора ресурсов
|
||||||
const [peridos, setPeriods] = useState({
|
const [peridos, setPeriods] = useState({
|
||||||
@ -125,7 +80,15 @@ const ResMon = ({ ident, onPlanJobsDtlProjectClick }) => {
|
|||||||
|
|
||||||
//При сокрытии детализации
|
//При сокрытии детализации
|
||||||
const handleHideDtl = () =>
|
const handleHideDtl = () =>
|
||||||
setState(pv => ({ ...pv, displayPlanFOTDtl: null, titlePlanFOTDtl: null, displayPlanJobsDtl: null, titlePlanJobsDtl: null }));
|
setState(pv => ({
|
||||||
|
...pv,
|
||||||
|
displayPlanFOTDtl: null,
|
||||||
|
titlePlanFOTDtl: null,
|
||||||
|
displayFactRptDtl: null,
|
||||||
|
titleFactRptDtl: null,
|
||||||
|
displayPlanJobsDtl: null,
|
||||||
|
titlePlanJobsDtl: null
|
||||||
|
}));
|
||||||
|
|
||||||
//При нажатии на плановую трудоёмкость по ФОТ
|
//При нажатии на плановую трудоёмкость по ФОТ
|
||||||
const handleLabPlanFOTClick = ({ sender }) =>
|
const handleLabPlanFOTClick = ({ sender }) =>
|
||||||
@ -135,6 +98,14 @@ const ResMon = ({ ident, onPlanJobsDtlProjectClick }) => {
|
|||||||
titlePlanFOTDtl: `${sender.SPERIOD} - ${sender.SINS_DEPARTMENT} - ${sender.SFCMANPOWER} - ${sender.NLAB_PLAN_FOT}`
|
titlePlanFOTDtl: `${sender.SPERIOD} - ${sender.SINS_DEPARTMENT} - ${sender.SFCMANPOWER} - ${sender.NLAB_PLAN_FOT}`
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
//При нажатии на фактическую трудоёмкость по отчетам
|
||||||
|
const handleLabFactRptClick = ({ sender }) =>
|
||||||
|
setState(pv => ({
|
||||||
|
...pv,
|
||||||
|
displayFactRptDtl: sender.NRN,
|
||||||
|
titleFactRptDtl: `${sender.SPERIOD} - ${sender.SINS_DEPARTMENT} - ${sender.SFCMANPOWER} - ${sender.NLAB_FACT_RPT}`
|
||||||
|
}));
|
||||||
|
|
||||||
//При нажатии на проект в списке детализации плановой трудоёмкости по графику
|
//При нажатии на проект в списке детализации плановой трудоёмкости по графику
|
||||||
const handleLabPlanJobsClick = ({ sender }) =>
|
const handleLabPlanJobsClick = ({ sender }) =>
|
||||||
setState(pv => ({
|
setState(pv => ({
|
||||||
@ -171,13 +142,21 @@ const ResMon = ({ ident, onPlanJobsDtlProjectClick }) => {
|
|||||||
onOrderChanged={handlePeriodsOrderChanged}
|
onOrderChanged={handlePeriodsOrderChanged}
|
||||||
onPagesCountChanged={handlePeriodsPagesCountChanged}
|
onPagesCountChanged={handlePeriodsPagesCountChanged}
|
||||||
dataCellRender={prms =>
|
dataCellRender={prms =>
|
||||||
periodsDataCellRender({ ...prms, onLabPlanFOTClick: handleLabPlanFOTClick, onLabPlanJobsClick: handleLabPlanJobsClick })
|
periodsDataCellRender({
|
||||||
|
...prms,
|
||||||
|
onLabPlanFOTClick: handleLabPlanFOTClick,
|
||||||
|
onLabFactRptClick: handleLabFactRptClick,
|
||||||
|
onLabPlanJobsClick: handleLabPlanJobsClick
|
||||||
|
})
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
) : null}
|
) : null}
|
||||||
{state.displayPlanFOTDtl ? (
|
{state.displayPlanFOTDtl ? (
|
||||||
<LabPlanFOTDtl periodId={state.displayPlanFOTDtl} title={state.titlePlanFOTDtl} onHide={handleHideDtl} />
|
<LabPlanFOTDtl periodId={state.displayPlanFOTDtl} title={state.titlePlanFOTDtl} onHide={handleHideDtl} />
|
||||||
) : null}
|
) : null}
|
||||||
|
{state.displayFactRptDtl ? (
|
||||||
|
<LabFactRptDtl periodId={state.displayFactRptDtl} title={state.titleFactRptDtl} onHide={handleHideDtl} />
|
||||||
|
) : null}
|
||||||
{state.displayPlanJobsDtl ? (
|
{state.displayPlanJobsDtl ? (
|
||||||
<LabPlanJobsDtl
|
<LabPlanJobsDtl
|
||||||
periodId={state.displayPlanJobsDtl}
|
periodId={state.displayPlanJobsDtl}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user