Merge pull request 'main' (#1) from CITKParus/P8-Panels:main into main
Reviewed-on: #1
130
README.md
@ -65,6 +65,17 @@
|
|||||||
|
|
||||||
1. Установите сервер приложений "ПАРУС 8 Онлайн" согласно документации (см. "Парус-Онлайн 2. Часть 1. Установка ГГГГ.ММ.docx"), требуется релиз от октября 2023 года и позднее.
|
1. Установите сервер приложений "ПАРУС 8 Онлайн" согласно документации (см. "Парус-Онлайн 2. Часть 1. Установка ГГГГ.ММ.docx"), требуется релиз от октября 2023 года и позднее.
|
||||||
2. Разместите на диске сервера приложений библиотеку расширения "P8-Panels-ParusOnlineExt", для этого скопируйте содержимое папки "bin" из [репозитория расширения "P8-Panels-ParusOnlineExt"](https://git.citpb.ru/CITKParus/P8-Panels-ParusOnlineExt), например, в каталог "C:\p8web20\Ext\P8-Panels-ParusOnlineExt".
|
2. Разместите на диске сервера приложений библиотеку расширения "P8-Panels-ParusOnlineExt", для этого скопируйте содержимое папки "bin" из [репозитория расширения "P8-Panels-ParusOnlineExt"](https://git.citpb.ru/CITKParus/P8-Panels-ParusOnlineExt), например, в каталог "C:\p8web20\Ext\P8-Panels-ParusOnlineExt".
|
||||||
|
|
||||||
|
> **Внимание:**
|
||||||
|
>
|
||||||
|
> - **Для релиза "ПАРУС 8 Онлайн" от 30.08.2024**
|
||||||
|
>
|
||||||
|
> Требуется [патч до промежуточной сборки 02.09.2024 или старше](https://cloud.mail.ru/public/nEZb/y4oQa1N6D). Установка расширения на данный релиз не рекомендуется, по возможности - пропустите его.
|
||||||
|
>
|
||||||
|
> - **Для релизов "ПАРУС 8 Онлайн" до 30.08.2024**
|
||||||
|
>
|
||||||
|
> Содержимое папки "bin" следует брать из специальной сборки расширения - [Для сборок Парус-Онлайн до 30.08.2024](https://git.citpb.ru/CITKParus/P8-Panels-ParusOnlineExt/releases/tag/FOR_PARUS_ONLINE_BEFORE_20240830)
|
||||||
|
|
||||||
3. Подключите библиотеку расширения к серверу приложений "ПАРУС 8 Онлайн". Для этого добавьте ссылку на библиотеку в файл "Config\extensions.config" сервера приложений:
|
3. Подключите библиотеку расширения к серверу приложений "ПАРУС 8 Онлайн". Для этого добавьте ссылку на библиотеку в файл "Config\extensions.config" сервера приложений:
|
||||||
|
|
||||||
```
|
```
|
||||||
@ -235,9 +246,9 @@ WEB-приложение "ПАРУС 8 Онлайн" поддерживает в
|
|||||||
</Desktop>
|
</Desktop>
|
||||||
```
|
```
|
||||||
|
|
||||||
### Интеграция в разделы - вызов из действия
|
### Интеграция в разделы - вызов из КОР-действия
|
||||||
|
|
||||||
Панель может быть вызвана из действия раздела Системы (только для WEB-клиента). Для это необходимо зарегистрировать в разделе метод с кодом "P8PANELS_OPEN", при этом метод обязательно должен иметь "Тип метода" - "Встроенный", а "Доступность" - "Клиентский". Для метода необходимо настроить параметры:
|
Панель может быть вызвана из действия раздела Системы (только для WEB-клиента). Для это необходимо зарегистрировать (здесь и далее - настройка выполняется в приложении "Контрусктор отраслевых расширений" для соответствующих классов Системы) в разделе метод с кодом "P8PANELS_OPEN", при этом метод обязательно должен иметь "Тип метода" - "Встроенный", а "Доступность" - "Клиентский". Для метода необходимо настроить параметры:
|
||||||
|
|
||||||
- `SPANEL` - строка, обязательный, уникальное имя (`name`) той панели из "p8panels.config", которая должна быть открыта действием
|
- `SPANEL` - строка, обязательный, уникальное имя (`name`) той панели из "p8panels.config", которая должна быть открыта действием
|
||||||
- `SCAPTION` - строка, необязательный, заголовок вкладки WEB-приложения "ПАРУС 8 Онлайн", в которой будет открыта панель, если не задан - будет использовано видимое наименование панели (`caption`) из "p8panels.config"
|
- `SCAPTION` - строка, необязательный, заголовок вкладки WEB-приложения "ПАРУС 8 Онлайн", в которой будет открыта панель, если не задан - будет использовано видимое наименование панели (`caption`) из "p8panels.config"
|
||||||
@ -273,6 +284,119 @@ const MyPanel = () => {
|
|||||||
- Реализовать в КОР-действии параметр с выпадающим списком (или иным интерфейсным элементом), позволяющим пользователю выбрать какую именно панель ему необходимо открыть сейчас
|
- Реализовать в КОР-действии параметр с выпадающим списком (или иным интерфейсным элементом), позволяющим пользователю выбрать какую именно панель ему необходимо открыть сейчас
|
||||||
- Определять значение параметра `SPANEL` КОР-метода "P8PANELS_OPEN" из контекста (документа, атрибута, каталога и т.п.), таким образом автоматически определяя открываемую панель
|
- Определять значение параметра `SPANEL` КОР-метода "P8PANELS_OPEN" из контекста (документа, атрибута, каталога и т.п.), таким образом автоматически определяя открываемую панель
|
||||||
|
|
||||||
|
#### Настройка КОР-действия для вызова панели "Выдача сменного задания" из раздела "Сменные задания"
|
||||||
|
|
||||||
|
Входящая в состав поставки фреймворка панель "Выдача сменного задания" доступна для вызова из раздела "Сменные задания" (приложение "Планирование и учёт в дискретном производстве", главное меню > "Документы" > "Сменные задания").
|
||||||
|
|
||||||
|
Для настройки этой возможности:
|
||||||
|
|
||||||
|
1. Откройте раздел "Классы" приложения "Конструктор отраслевых расширений" (главное меню > "Учёт" > "Классы")
|
||||||
|
2. В дереве классов выберите "Сменные задания", а в списке классов - класс с кодом "CostJobs"
|
||||||
|
3. В спецификации "Методы", выбранного класса, зарегистрируйте новый метод со следующими атрибутами:
|
||||||
|
|
||||||
|
- `Мнемокод` - P8PANELS_OPEN
|
||||||
|
- `Наименование` - P8PANELS_OPEN
|
||||||
|
- `Тип метода` - Встроенный
|
||||||
|
- `Доступность` - Клиентский
|
||||||
|
|
||||||
|
4. Для добавленного метода `P8PANELS_OPEN` в спецификации "Параметры" зарегистрируйте следующий набор параметров:
|
||||||
|
|
||||||
|
| Имя | Наименование | Тип | Домен | Обязательный | Тип привязки | Контекст | Параметр действия |
|
||||||
|
| -------- | ------------------- | ------- | ------- | ------------ | ----------------- | -------------------- | ----------------- |
|
||||||
|
| NRN | Рег. номер записи | Входной | TRN | Нет | Контекст | Идентификатор записи | |
|
||||||
|
| SPANEL | Наименование панели | Входной | TSTRING | Да | Параметр действия | | SPANEL |
|
||||||
|
| SCAPTION | Заголовок вкладки | Входной | TSTRING | Нет | Параметр действия | | SCAPTION |
|
||||||
|
|
||||||
|
5. В спецификации "Действия", выбранного класса, зарегистрируйте новое действие со следующими атрибутами:
|
||||||
|
|
||||||
|
- `Тип` - Нестандартное
|
||||||
|
- `Код` - FCJOBS_OPEN_JOBS_MANAGE
|
||||||
|
- `Наименование` - Открытие панели "Выдача сменного задания"
|
||||||
|
- `Технология производства` - Конструктор
|
||||||
|
- `Реализующий метод` - P8PANELS_OPEN
|
||||||
|
- `Обработка записей` - Для одной текущей записи
|
||||||
|
- `Завершение транзакции` - После каждого вызова действия
|
||||||
|
- `Обновление выборки` - Не обновлять
|
||||||
|
|
||||||
|
6. Для добавленного действия `FCJOBS_OPEN_JOBS_MANAGE` в спецификации "Параметры" зарегистрируйте следующий набор параметров:
|
||||||
|
|
||||||
|
| Имя | Домен | Тип привязки | Значение |
|
||||||
|
| -------- | ------- | ------------ | ----------------------- |
|
||||||
|
| SPANEL | TSTRING | Значение | MechRecCostJobsManage |
|
||||||
|
| SCAPTION | TSTRING | Значение | Выдача сменного задания |
|
||||||
|
|
||||||
|
7. Откройте редактор формы представления данных класса "CostJobs" ("Сменные задания").
|
||||||
|
|
||||||
|
Для этого отметьте в списке классов запись с кодом "CostJobs", перейдите на закладку "Методы вызова", укажите метод вызова "main", в его контекстном меню укажите "Формы", в появившемся списке форм выполните действие "Редактор" для формы с наименованием "Форма просмотра".
|
||||||
|
|
||||||
|
В открывшемся редакторе формы перейдите в режим редактирования всплывающего меню заголовка (закладка "Таблицы", таблица "CostJobs", затем кнопка "Редактор источника", установить фокус на форме представления данных щелчком мыши, затем пункт "Всплывающее меню" в "Инспекторе объектов"). Найдите в меню пункт, созданный Системой для действия, зарегистрированного на шаге 5 (как правило имеет метку, совпадающую с наименованием действия). Расположите (перетаскиванием) этот пункт меню сразу после пункта "Отработать исполнение по штрих-кодам". Укажите для этого пункта следующие параметры в "Инспекторе объектов":
|
||||||
|
|
||||||
|
- `Заголовок` - Выдать сменное задание…
|
||||||
|
|
||||||
|
Закройте окна редакторов с сохранением изменений.
|
||||||
|
|
||||||
|
8. Выдайте права но новое действие в "Администраторе", при необходимости - начните новый сеанс в "ПАРУС 8 Онлайн" с очисткой системного кэша.
|
||||||
|
|
||||||
|
#### Настройка КОР-действия для вызова панели "Производственная программа" из раздела "Планы и отчеты производства изделий"
|
||||||
|
|
||||||
|
Входящая в состав поставки фреймворка панель "Производственная программа" доступна для вызова из спецификации "Выпуск" раздела "Планы и отчеты производства изделий" (приложение "Планирование и учёт в дискретном производстве", главное меню > "Документы" > "Планы и отчеты производства изделий").
|
||||||
|
|
||||||
|
Для настройки этой возможности:
|
||||||
|
|
||||||
|
1. Откройте раздел "Классы" приложения "Конструктор отраслевых расширений" (главное меню > "Учёт" > "Классы")
|
||||||
|
2. В дереве классов выберите "Планы и отчеты производства изделий (спецификация)", а в списке классов - класс с кодом "CostProductPlansSpecs"
|
||||||
|
3. В спецификации "Методы", выбранного класса, зарегистрируйте новый метод со следующими атрибутами:
|
||||||
|
|
||||||
|
- `Мнемокод` - P8PANELS_OPEN
|
||||||
|
- `Наименование` - P8PANELS_OPEN
|
||||||
|
- `Тип метода` - Встроенный
|
||||||
|
- `Доступность` - Клиентский
|
||||||
|
|
||||||
|
4. Для добавленного метода `P8PANELS_OPEN` в спецификации "Параметры" зарегистрируйте следующий набор параметров:
|
||||||
|
|
||||||
|
| Имя | Наименование | Тип | Домен | Обязательный | Тип привязки | Контекст | Параметр действия |
|
||||||
|
| -------- | ------------------- | ------- | ------- | ------------ | ----------------- | -------------------- | ----------------- |
|
||||||
|
| NSPRN | Рег. номер записи | Входной | TRN | Нет | Контекст | Идентификатор записи | |
|
||||||
|
| SPANEL | Наименование панели | Входной | TSTRING | Да | Параметр действия | | SPANEL |
|
||||||
|
| SCAPTION | Заголовок вкладки | Входной | TSTRING | Нет | Параметр действия | | SCAPTION |
|
||||||
|
|
||||||
|
5. В спецификации "Действия", выбранного класса, зарегистрируйте новое действие со следующими атрибутами:
|
||||||
|
|
||||||
|
- `Тип` - Нестандартное
|
||||||
|
- `Код` - FCPRODPLANSP_OPEN_COST_PROD_PLANS
|
||||||
|
- `Наименование` - Открытие панели "Производственная программа"
|
||||||
|
- `Технология производства` - Конструктор
|
||||||
|
- `Реализующий метод` - P8PANELS_OPEN
|
||||||
|
- `Обработка записей` - Для одной текущей записи
|
||||||
|
- `Завершение транзакции` - После каждого вызова действия
|
||||||
|
- `Обновление выборки` - Не обновлять
|
||||||
|
|
||||||
|
6. Для добавленного действия `FCPRODPLANSP_OPEN_COST_PROD_PLANS` в спецификации "Параметры" зарегистрируйте следующий набор параметров:
|
||||||
|
|
||||||
|
| Имя | Домен | Тип привязки | Значение |
|
||||||
|
| -------- | ------- | ------------ | -------------------------- |
|
||||||
|
| SPANEL | TSTRING | Значение | MechRecCostProdPlans |
|
||||||
|
| SCAPTION | TSTRING | Значение | Производственная программа |
|
||||||
|
|
||||||
|
7. Откройте редактор формы представления данных класса "CostProductPlans" ("Планы и отчеты производства изделий") - родительский для того, в который добавили действие.
|
||||||
|
|
||||||
|
Для этого отметьте в списке классов запись с кодом "CostProductPlans", перейдите на закладку "Методы вызова", укажите метод вызова "main", в его контекстном меню укажите "Формы", в появившемся списке форм выполните действие "Редактор" для формы с наименованием "Форма просмотра".
|
||||||
|
|
||||||
|
В открывшемся редакторе формы перейдите в режим редактирования всплывающего меню спецификации (закладка "Таблицы", таблица "CostProductPlansSpecs", затем кнопка "Редактор источника", установить фокус на форме представления данных щелчком мыши, затем пункт "Всплывающее меню" в "Инспекторе объектов"). Найдите в меню пункт, созданный Системой для действия, зарегистрированного на шаге 5 (как правило имеет метку, совпадающую с наименованием действия). Расположите (перетаскиванием) этот пункт меню сразу после пункта "Формирование". Укажите для этого пункта следующие параметры в "Инспекторе объектов":
|
||||||
|
|
||||||
|
- `Заголовок` - Открыть диаграмму…
|
||||||
|
- `Правило доступности` - @nCATEGORY = 1 and @nSTATUS = 2
|
||||||
|
|
||||||
|
Закройте окна редакторов с сохранением изменений.
|
||||||
|
|
||||||
|
8. Выдайте права но новое действие в "Администраторе", при необходимости - начните новый сеанс в "ПАРУС 8 Онлайн" с очисткой системного кэша.
|
||||||
|
|
||||||
|
#### Настройка КОР-действия для вызова панели "Редактор настройки регламентированного отчёта" из раздела "Настройки форм регламентированных отчетов"
|
||||||
|
|
||||||
|
Начиная с релиза Системы "сентябрь 2024" настройка данного действия включена в штатную поставку Системы. Корректная работа панели "Редактор настройки регламентированного отчёта" на релизах до "сентябрь 2024" не обеспечивается.
|
||||||
|
|
||||||
|
Для настройки необходимых метаданных следует выполнить импорт "Управляемых разделов", поставляемых с Системой или импорт метаданных "Сервиса регламентированной и управленческой отчётости" (путь в каталоге релиза "/ЦИТК/Регламентированная отчетность/rrp_units.zip", см. подробнее документацию к сервису - "/ЦИТК/Регламентированная отчетность/Пользовательские инструкции").
|
||||||
|
|
||||||
## VI. Разработка панелей
|
## VI. Разработка панелей
|
||||||
|
|
||||||
> **Внимание:** данное руководство не является обучающим курсом по WEB-разработке как таковой. Изложенные ниже сведения о порядке реализации пользовательских панелей, даны с учётом приведённых ранее требований к разработчику.
|
> **Внимание:** данное руководство не является обучающим курсом по WEB-разработке как таковой. Изложенные ниже сведения о порядке реализации пользовательских панелей, даны с учётом приведённых ранее требований к разработчику.
|
||||||
@ -1810,7 +1934,7 @@ const MyPanel = () => {
|
|||||||
|
|
||||||
**Свойства**
|
**Свойства**
|
||||||
|
|
||||||
`height` - обязательный, число, высота области диаграммы на панели (может быть задана в разных единицах измерения - `height="100px"`, `height="50vh"`, `height="500pt"`)\
|
`containerStyle` - необязательный, объект, стили, которые будут применены к компонету `div`, являющемуся контейнером диаграммы\
|
||||||
`title` - необязательный, строка, заголовок диаграммы (если не указан - не отображается)\
|
`title` - необязательный, строка, заголовок диаграммы (если не указан - не отображается)\
|
||||||
`titleStyle` - необязательный, объект, стили, которые будут применены к компонету `Typography` заголовка диаграммы\
|
`titleStyle` - необязательный, объект, стили, которые будут применены к компонету `Typography` заголовка диаграммы\
|
||||||
`onTitleClick` - необязательный, функция, будет вызвана при нажатии пользователем на заголовок (если указана - заголовок формируется в виде гиперссылки), сигнатура функции `f()`, результат функции не интерпретируется\
|
`onTitleClick` - необязательный, функция, будет вызвана при нажатии пользователем на заголовок (если указана - заголовок формируется в виде гиперссылки), сигнатура функции `f()`, результат функции не интерпретируется\
|
||||||
|
29
app.styles.js
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
/*
|
||||||
|
Парус 8 - Панели мониторинга
|
||||||
|
Типовые стили
|
||||||
|
*/
|
||||||
|
|
||||||
|
//----------------
|
||||||
|
//Интерфейс модуля
|
||||||
|
//----------------
|
||||||
|
|
||||||
|
//Стили
|
||||||
|
export const APP_STYLES = {
|
||||||
|
SCROLL: {
|
||||||
|
"&::-webkit-scrollbar": {
|
||||||
|
height: "8px",
|
||||||
|
width: "8px"
|
||||||
|
},
|
||||||
|
"&::-webkit-scrollbar-track": {
|
||||||
|
borderRadius: "8px",
|
||||||
|
backgroundColor: "#EBEBEB"
|
||||||
|
},
|
||||||
|
"&::-webkit-scrollbar-thumb": {
|
||||||
|
borderRadius: "8px",
|
||||||
|
backgroundColor: "#b4b4b4"
|
||||||
|
},
|
||||||
|
"&::-webkit-scrollbar-thumb:hover": {
|
||||||
|
backgroundColor: "#808080"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
@ -29,6 +29,9 @@ import { P8PPanelsMenuDrawer, P8P_PANELS_MENU_PANEL_SHAPE } from "./p8p_panels_m
|
|||||||
//Константы
|
//Константы
|
||||||
//---------
|
//---------
|
||||||
|
|
||||||
|
//Высота главного меню
|
||||||
|
const APP_BAR_HEIGHT = "64px";
|
||||||
|
|
||||||
//Стили
|
//Стили
|
||||||
const STYLES = {
|
const STYLES = {
|
||||||
ROOT_BOX: { display: "flex" },
|
ROOT_BOX: { display: "flex" },
|
||||||
@ -125,4 +128,4 @@ P8PAppWorkspace.propTypes = {
|
|||||||
//Интерфейс модуля
|
//Интерфейс модуля
|
||||||
//----------------
|
//----------------
|
||||||
|
|
||||||
export { P8PAppWorkspace };
|
export { APP_BAR_HEIGHT, P8PAppWorkspace };
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
|
|
||||||
import React, { useState, useEffect } from "react"; //Классы React
|
import React, { useState, useEffect } from "react"; //Классы React
|
||||||
import PropTypes from "prop-types"; //Контроль свойств компонента
|
import PropTypes from "prop-types"; //Контроль свойств компонента
|
||||||
import { P8PTable, P8P_TABLE_SIZE, P8P_TABLE_DATA_TYPE, P8P_TABLE_FILTER_SHAPE } from "./p8p_table"; //Таблица
|
import { P8PTable, P8P_TABLE_SIZE, P8P_TABLE_DATA_TYPE, P8P_TABLE_FILTER_SHAPE, P8P_TABLE_MORE_HEIGHT, P8P_TABLE_FILTERS_HEIGHT } from "./p8p_table"; //Таблица
|
||||||
|
|
||||||
//---------
|
//---------
|
||||||
//Константы
|
//Константы
|
||||||
@ -24,6 +24,12 @@ const P8P_DATA_GRID_DATA_TYPE = P8P_TABLE_DATA_TYPE;
|
|||||||
//Формат фильтра
|
//Формат фильтра
|
||||||
const P8P_DATA_GRID_FILTER_SHAPE = P8P_TABLE_FILTER_SHAPE;
|
const P8P_DATA_GRID_FILTER_SHAPE = P8P_TABLE_FILTER_SHAPE;
|
||||||
|
|
||||||
|
//Высота кнопки догрузки данных
|
||||||
|
const P8P_DATA_GRID_MORE_HEIGHT = P8P_TABLE_MORE_HEIGHT;
|
||||||
|
|
||||||
|
//Высота фильтров таблицы
|
||||||
|
const P8P_DATA_GRID_FILTERS_HEIGHT = P8P_TABLE_FILTERS_HEIGHT;
|
||||||
|
|
||||||
//-----------
|
//-----------
|
||||||
//Тело модуля
|
//Тело модуля
|
||||||
//-----------
|
//-----------
|
||||||
@ -187,4 +193,11 @@ P8PDataGrid.propTypes = {
|
|||||||
//Интерфейс модуля
|
//Интерфейс модуля
|
||||||
//----------------
|
//----------------
|
||||||
|
|
||||||
export { P8P_DATA_GRID_DATA_TYPE, P8P_DATA_GRID_SIZE, P8P_DATA_GRID_FILTER_SHAPE, P8PDataGrid };
|
export {
|
||||||
|
P8P_DATA_GRID_DATA_TYPE,
|
||||||
|
P8P_DATA_GRID_SIZE,
|
||||||
|
P8P_DATA_GRID_FILTER_SHAPE,
|
||||||
|
P8P_DATA_GRID_MORE_HEIGHT,
|
||||||
|
P8P_DATA_GRID_FILTERS_HEIGHT,
|
||||||
|
P8PDataGrid
|
||||||
|
};
|
||||||
|
@ -78,10 +78,22 @@ const P8P_GANTT_TASK_COLOR_SHAPE = PropTypes.shape({
|
|||||||
desc: PropTypes.string.isRequired
|
desc: PropTypes.string.isRequired
|
||||||
});
|
});
|
||||||
|
|
||||||
|
//Высота заголовка
|
||||||
|
const TITLE_HEIGHT = "44px";
|
||||||
|
|
||||||
|
//Высота панели масштабирования
|
||||||
|
const ZOOM_HEIGHT = "56px";
|
||||||
|
|
||||||
//Стили
|
//Стили
|
||||||
const STYLES = {
|
const STYLES = {
|
||||||
TASK_EDITOR_CONTENT: { minWidth: 400, overflowX: "auto" },
|
TASK_EDITOR_CONTENT: { minWidth: 400, overflowX: "auto" },
|
||||||
TASK_EDITOR_LIST: { width: "100%", minWidth: 300, maxWidth: 700, bgcolor: "background.paper" }
|
TASK_EDITOR_LIST: { width: "100%", minWidth: 300, maxWidth: 700, bgcolor: "background.paper" },
|
||||||
|
GANTT_TITLE: { height: TITLE_HEIGHT },
|
||||||
|
GANTT_ZOOM: { height: ZOOM_HEIGHT },
|
||||||
|
GANTT: (noData, title, zoomBar) => ({
|
||||||
|
height: `calc(100% - ${zoomBar ? ZOOM_HEIGHT : "0px"} - ${title ? TITLE_HEIGHT : "0px"})`,
|
||||||
|
display: noData ? "none" : ""
|
||||||
|
})
|
||||||
};
|
};
|
||||||
|
|
||||||
//--------------------------------
|
//--------------------------------
|
||||||
@ -318,7 +330,7 @@ P8PGanttTaskEditor.propTypes = {
|
|||||||
|
|
||||||
//Диаграмма Ганта
|
//Диаграмма Ганта
|
||||||
const P8PGantt = ({
|
const P8PGantt = ({
|
||||||
height,
|
containerStyle,
|
||||||
title,
|
title,
|
||||||
titleStyle,
|
titleStyle,
|
||||||
onTitleClick,
|
onTitleClick,
|
||||||
@ -408,10 +420,16 @@ const P8PGantt = ({
|
|||||||
|
|
||||||
//Генерация содержимого
|
//Генерация содержимого
|
||||||
return (
|
return (
|
||||||
<div>
|
<div style={{ ...(containerStyle ? containerStyle : {}) }}>
|
||||||
{state.gantt && state.noData ? <P8PAppInlineError text={noDataFoundText} /> : null}
|
{state.gantt && state.noData ? <P8PAppInlineError text={noDataFoundText} /> : null}
|
||||||
{state.gantt && !state.noData && title ? (
|
{state.gantt && !state.noData && title ? (
|
||||||
<Typography p={1} sx={{ ...(titleStyle ? titleStyle : {}) }} align="center" color="textSecondary" variant="subtitle1">
|
<Typography
|
||||||
|
p={1}
|
||||||
|
sx={{ ...STYLES.GANTT_TITLE, ...(titleStyle ? titleStyle : {}) }}
|
||||||
|
align="center"
|
||||||
|
color="textSecondary"
|
||||||
|
variant="subtitle1"
|
||||||
|
>
|
||||||
{onTitleClick ? (
|
{onTitleClick ? (
|
||||||
<Link component="button" variant="body2" underline="hover" onClick={() => onTitleClick()}>
|
<Link component="button" variant="body2" underline="hover" onClick={() => onTitleClick()}>
|
||||||
{title}
|
{title}
|
||||||
@ -422,7 +440,7 @@ const P8PGantt = ({
|
|||||||
</Typography>
|
</Typography>
|
||||||
) : null}
|
) : null}
|
||||||
{state.gantt && !state.noData && zoomBar ? (
|
{state.gantt && !state.noData && zoomBar ? (
|
||||||
<Box p={1}>
|
<Box p={1} sx={STYLES.GANTT_ZOOM}>
|
||||||
<IconButton onClick={() => handleZoomChange(-1)} disabled={state.zoom == 0}>
|
<IconButton onClick={() => handleZoomChange(-1)} disabled={state.zoom == 0}>
|
||||||
<Icon>zoom_in</Icon>
|
<Icon>zoom_in</Icon>
|
||||||
</IconButton>
|
</IconButton>
|
||||||
@ -450,7 +468,7 @@ const P8PGantt = ({
|
|||||||
cancelBtnCaption={cancelTaskEditorBtnCaption}
|
cancelBtnCaption={cancelTaskEditorBtnCaption}
|
||||||
/>
|
/>
|
||||||
) : null}
|
) : null}
|
||||||
<div style={{ height, display: state.noData ? "none" : "" }}>
|
<div style={STYLES.GANTT(state.noData, title, zoomBar)}>
|
||||||
<svg id="__gantt__" width="100%"></svg>
|
<svg id="__gantt__" width="100%"></svg>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -459,7 +477,7 @@ const P8PGantt = ({
|
|||||||
|
|
||||||
//Контроль свойств - Диаграмма Ганта
|
//Контроль свойств - Диаграмма Ганта
|
||||||
P8PGantt.propTypes = {
|
P8PGantt.propTypes = {
|
||||||
height: PropTypes.string.isRequired,
|
containerStyle: PropTypes.object,
|
||||||
title: PropTypes.string,
|
title: PropTypes.string,
|
||||||
titleStyle: PropTypes.object,
|
titleStyle: PropTypes.object,
|
||||||
onTitleClick: PropTypes.func,
|
onTitleClick: PropTypes.func,
|
||||||
|
@ -58,7 +58,8 @@ const STYLES = {
|
|||||||
GRID: { maxWidth: 1200, direction: "row", justifyContent: "left", alignItems: "stretch" },
|
GRID: { maxWidth: 1200, direction: "row", justifyContent: "left", alignItems: "stretch" },
|
||||||
GRID_PANEL_CARD: { maxWidth: 400, height: "100%", flexDirection: "column", display: "flex" },
|
GRID_PANEL_CARD: { maxWidth: 400, height: "100%", flexDirection: "column", display: "flex" },
|
||||||
GRID_PANEL_CARD_MEDIA: { height: 140 },
|
GRID_PANEL_CARD_MEDIA: { height: 140 },
|
||||||
GRID_PANEL_CARD_CONTENT_TITLE: { alignItems: "center" },
|
GRID_PANEL_CARD_CONTENT_TITLE: { alignItems: "flex-start" },
|
||||||
|
GRID_PANEL_CARD_CONTENT_TITLE_ICON: { paddingTop: "4px" },
|
||||||
GRID_PANEL_CARD_ACTIONS: { marginTop: "auto", display: "flex", justifyContent: "flex-end", alignItems: "flex-start" },
|
GRID_PANEL_CARD_ACTIONS: { marginTop: "auto", display: "flex", justifyContent: "flex-end", alignItems: "flex-start" },
|
||||||
DESKTOP_GROUP_HEADER: { fontWeight: "bold", fontFamily: "tahoma, arial, verdana, sans-serif!important", fontSize: "13px!important" },
|
DESKTOP_GROUP_HEADER: { fontWeight: "bold", fontFamily: "tahoma, arial, verdana, sans-serif!important", fontSize: "13px!important" },
|
||||||
DESKTOP_ITEM_BUTTON: { fontSize: "12px", textTransform: "none", "&:hover": { backgroundColor: "#c3e1ff" }, maxWidth: "150px" },
|
DESKTOP_ITEM_BUTTON: { fontSize: "12px", textTransform: "none", "&:hover": { backgroundColor: "#c3e1ff" }, maxWidth: "150px" },
|
||||||
@ -130,7 +131,7 @@ const getPanelsLinks = ({ variant, panels, selectedPanel, group, defaultGroupTyt
|
|||||||
) : null}
|
) : null}
|
||||||
<CardContent>
|
<CardContent>
|
||||||
<Stack gap={1} direction="row" sx={STYLES.GRID_PANEL_CARD_CONTENT_TITLE}>
|
<Stack gap={1} direction="row" sx={STYLES.GRID_PANEL_CARD_CONTENT_TITLE}>
|
||||||
{panel.icon ? <Icon>{panel.icon}</Icon> : null}
|
{panel.icon ? <Icon sx={STYLES.GRID_PANEL_CARD_CONTENT_TITLE_ICON}>{panel.icon}</Icon> : null}
|
||||||
<Typography variant="h5">{panel.caption}</Typography>
|
<Typography variant="h5">{panel.caption}</Typography>
|
||||||
</Stack>
|
</Stack>
|
||||||
<Typography variant="body2" color="text.secondary">
|
<Typography variant="body2" color="text.secondary">
|
||||||
|
@ -81,6 +81,12 @@ const P8P_TABLE_FILTER_SHAPE = PropTypes.shape({
|
|||||||
to: PropTypes.any
|
to: PropTypes.any
|
||||||
});
|
});
|
||||||
|
|
||||||
|
//Высота кнопки догрузки данных
|
||||||
|
const P8P_TABLE_MORE_HEIGHT = "49px";
|
||||||
|
|
||||||
|
//Высота фильтров таблицы
|
||||||
|
const P8P_TABLE_FILTERS_HEIGHT = "48px";
|
||||||
|
|
||||||
//Стили
|
//Стили
|
||||||
const STYLES = {
|
const STYLES = {
|
||||||
TABLE: {
|
TABLE: {
|
||||||
@ -434,7 +440,7 @@ P8PTableColumnFilterDialog.propTypes = {
|
|||||||
//Сводный фильтр
|
//Сводный фильтр
|
||||||
const P8PTableFiltersChips = ({ filters, columnsDef, valueFromCaption, valueToCaption, onFilterChipClick, onFilterChipDelete, valueFormatter }) => {
|
const P8PTableFiltersChips = ({ filters, columnsDef, valueFromCaption, valueToCaption, onFilterChipClick, onFilterChipDelete, valueFormatter }) => {
|
||||||
return (
|
return (
|
||||||
<Stack direction="row" spacing={1} pb={2}>
|
<Stack direction="row" spacing={1} p={1}>
|
||||||
{filters.map((filter, i) => {
|
{filters.map((filter, i) => {
|
||||||
const columnDef = columnsDef.find(columnDef => columnDef.name == filter.name);
|
const columnDef = columnsDef.find(columnDef => columnDef.name == filter.name);
|
||||||
return (
|
return (
|
||||||
@ -956,4 +962,4 @@ P8PTable.propTypes = {
|
|||||||
//Интерфейс модуля
|
//Интерфейс модуля
|
||||||
//----------------
|
//----------------
|
||||||
|
|
||||||
export { P8P_TABLE_DATA_TYPE, P8P_TABLE_SIZE, P8P_TABLE_FILTER_SHAPE, P8PTable };
|
export { P8P_TABLE_DATA_TYPE, P8P_TABLE_SIZE, P8P_TABLE_FILTER_SHAPE, P8P_TABLE_MORE_HEIGHT, P8P_TABLE_FILTERS_HEIGHT, P8PTable };
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
//---------------------
|
//---------------------
|
||||||
|
|
||||||
import React, { useState, useContext, useCallback, useEffect } from "react"; //Классы React
|
import React, { useState, useContext, useCallback, useEffect } from "react"; //Классы React
|
||||||
import { Grid, Paper, Box } from "@mui/material"; //Интерфейсные компоненты
|
import { Box } from "@mui/material"; //Интерфейсные компоненты
|
||||||
import { P8PDataGrid, P8P_DATA_GRID_SIZE } from "../../components/p8p_data_grid"; //Таблица данных
|
import { P8PDataGrid, P8P_DATA_GRID_SIZE } from "../../components/p8p_data_grid"; //Таблица данных
|
||||||
import { P8P_DATA_GRID_CONFIG_PROPS } from "../../config_wrapper"; //Подключение компонентов к настройкам приложения
|
import { P8P_DATA_GRID_CONFIG_PROPS } from "../../config_wrapper"; //Подключение компонентов к настройкам приложения
|
||||||
import { BackEndСtx } from "../../context/backend"; //Контекст взаимодействия с сервером
|
import { BackEndСtx } from "../../context/backend"; //Контекст взаимодействия с сервером
|
||||||
@ -18,6 +18,33 @@ import { headCellRender, dataCellRender, groupCellRender, DIGITS_REG_EXP, MONTH_
|
|||||||
import { TEXTS } from "../../../app.text"; //Тектовые ресурсы и константы
|
import { TEXTS } from "../../../app.text"; //Тектовые ресурсы и константы
|
||||||
import { Filter } from "./filter"; //Компонент фильтра
|
import { Filter } from "./filter"; //Компонент фильтра
|
||||||
import { FilterDialog } from "./filter_dialog"; //Компонент диалогового окна фильтра отбора
|
import { FilterDialog } from "./filter_dialog"; //Компонент диалогового окна фильтра отбора
|
||||||
|
import { useWindowResize } from "./hooks"; //Пользовательские хуки
|
||||||
|
|
||||||
|
//---------
|
||||||
|
//Константы
|
||||||
|
//---------
|
||||||
|
|
||||||
|
//Высота меню Парус (пиксели)
|
||||||
|
const pxOuterMenuH = 53;
|
||||||
|
//Высота заголовка панели (пиксели)
|
||||||
|
const pxPanelHeaderH = 64;
|
||||||
|
//Минимальная ширина таблицы (пиксели)
|
||||||
|
const minGridW = 800;
|
||||||
|
//Минимальная высота таблицы (пиксели)
|
||||||
|
const minGridH = 200;
|
||||||
|
|
||||||
|
//Стили
|
||||||
|
const STYLES = {
|
||||||
|
BOX_ROW: { display: "flex", justifyContent: "center", alignItems: "center" },
|
||||||
|
GRID_PADDING: { paddingTop: 1, paddingBottom: 1 },
|
||||||
|
GRID_SIZES: (width, height) => ({
|
||||||
|
padding: "0px",
|
||||||
|
minWidth: minGridW,
|
||||||
|
maxWidth: width * 0.975 > minGridW ? width * 0.975 : minGridW,
|
||||||
|
minHeight: minGridH,
|
||||||
|
maxHeight: (height - pxOuterMenuH - pxPanelHeaderH) * 0.975 > minGridH ? (height - pxOuterMenuH - pxPanelHeaderH) * 0.975 : minGridH
|
||||||
|
})
|
||||||
|
};
|
||||||
|
|
||||||
//-----------
|
//-----------
|
||||||
//Тело модуля
|
//Тело модуля
|
||||||
@ -31,6 +58,8 @@ const EqsPrfrm = () => {
|
|||||||
columnsDef: [],
|
columnsDef: [],
|
||||||
groups: [],
|
groups: [],
|
||||||
rows: [],
|
rows: [],
|
||||||
|
fixedHeader: false,
|
||||||
|
fixedColumns: 0,
|
||||||
reload: false
|
reload: false
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -39,6 +68,7 @@ const EqsPrfrm = () => {
|
|||||||
isOpen: false,
|
isOpen: false,
|
||||||
isDefault: false,
|
isDefault: false,
|
||||||
isSetByUser: false,
|
isSetByUser: false,
|
||||||
|
needSave: false,
|
||||||
values: {
|
values: {
|
||||||
belong: "",
|
belong: "",
|
||||||
prodObj: "",
|
prodObj: "",
|
||||||
@ -128,6 +158,8 @@ const EqsPrfrm = () => {
|
|||||||
...pv,
|
...pv,
|
||||||
columnsDef: data.XCOLUMNS_DEF ? [...data.XCOLUMNS_DEF] : pv.columnsDef,
|
columnsDef: data.XCOLUMNS_DEF ? [...data.XCOLUMNS_DEF] : pv.columnsDef,
|
||||||
rows: [...(data.XROWS || [])],
|
rows: [...(data.XROWS || [])],
|
||||||
|
fixedHeader: data.XDATA_GRID.fixedHeader,
|
||||||
|
fixedColumns: data.XDATA_GRID.fixedColumns,
|
||||||
groups: [...(data.XGROUPS || [])],
|
groups: [...(data.XGROUPS || [])],
|
||||||
dataLoaded: true,
|
dataLoaded: true,
|
||||||
reload: false
|
reload: false
|
||||||
@ -135,7 +167,7 @@ const EqsPrfrm = () => {
|
|||||||
}
|
}
|
||||||
}, [dataGrid.reload, filter, executeStored]);
|
}, [dataGrid.reload, filter, executeStored]);
|
||||||
|
|
||||||
//Загрузка значений фильра по умолчанию
|
//Загрузка значений фильтра по умолчанию
|
||||||
const loadDefaultFilter = useCallback(async () => {
|
const loadDefaultFilter = useCallback(async () => {
|
||||||
const data = await executeStored({
|
const data = await executeStored({
|
||||||
stored: "PKG_P8PANELS_EQUIPSRV.GET_DEFAULT_FP",
|
stored: "PKG_P8PANELS_EQUIPSRV.GET_DEFAULT_FP",
|
||||||
@ -148,6 +180,17 @@ const EqsPrfrm = () => {
|
|||||||
}));
|
}));
|
||||||
}, [executeStored]);
|
}, [executeStored]);
|
||||||
|
|
||||||
|
//Загрузка значений фильтра из локального хранилища браузера
|
||||||
|
const loadLocalFilter = useCallback(async () => {
|
||||||
|
let vs = filter.values;
|
||||||
|
Object.keys(vs).map(function (k) {
|
||||||
|
vs[k] =
|
||||||
|
k == "fromMonth" || k == "fromYear" || k == "toMonth" || k == "toYear" ? Number(localStorage.getItem(k)) : localStorage.getItem(k);
|
||||||
|
});
|
||||||
|
setFilter(pv => ({ ...pv, isDefault: true, values: { ...vs } }));
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
|
}, []);
|
||||||
|
|
||||||
//Отбор документа (ТОиР или Ремонтных ведомостей) по ячейке даты
|
//Отбор документа (ТОиР или Ремонтных ведомостей) по ячейке даты
|
||||||
const showEquipSrv = async ({ date, workType, info }) => {
|
const showEquipSrv = async ({ date, workType, info }) => {
|
||||||
const [techName, servKind] = info.split("_");
|
const [techName, servKind] = info.split("_");
|
||||||
@ -180,7 +223,7 @@ const EqsPrfrm = () => {
|
|||||||
const setFilterOpen = isOpen => setFilter(pv => ({ ...pv, isOpen }));
|
const setFilterOpen = isOpen => setFilter(pv => ({ ...pv, isOpen }));
|
||||||
|
|
||||||
//Установить значение фильтра
|
//Установить значение фильтра
|
||||||
const setFilterValues = values => setFilter(pv => ({ ...pv, isSetByUser: true, values: { ...values } }));
|
const setFilterValues = values => setFilter(pv => ({ ...pv, isSetByUser: true, needSave: true, values: { ...values } }));
|
||||||
|
|
||||||
//Отработка события скрытия/раскрытия ячейки даты
|
//Отработка события скрытия/раскрытия ячейки даты
|
||||||
const handleClick = (e, ref) => {
|
const handleClick = (e, ref) => {
|
||||||
@ -223,16 +266,26 @@ const EqsPrfrm = () => {
|
|||||||
//eslint-disable-next-line react-hooks/exhaustive-deps
|
//eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, [refIsDeprecated]);
|
}, [refIsDeprecated]);
|
||||||
|
|
||||||
|
//При закрытии панели
|
||||||
|
useEffect(() => {
|
||||||
|
filter.needSave
|
||||||
|
? window.addEventListener("beforeunload", function () {
|
||||||
|
Object.keys(filter.values).map(function (k) {
|
||||||
|
localStorage.setItem(k, filter.values[k]);
|
||||||
|
});
|
||||||
|
})
|
||||||
|
: null;
|
||||||
|
}, [filter.needSave, filter.values]);
|
||||||
|
|
||||||
//При загрузке фильтра по умолчанию
|
//При загрузке фильтра по умолчанию
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (filter.isDefault) setFilterOpen(true);
|
if (filter.isDefault) setFilterOpen(true);
|
||||||
}, [filter.isDefault]);
|
}, [filter.isDefault]);
|
||||||
|
|
||||||
//При подключении к страницк
|
//При подключении к странице
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
loadDefaultFilter();
|
localStorage.getItem("belong") ? loadLocalFilter() : loadDefaultFilter();
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
}, [loadDefaultFilter, loadLocalFilter]);
|
||||||
}, []);
|
|
||||||
|
|
||||||
//При открытии диалога фильтра
|
//При открытии диалога фильтра
|
||||||
const handleFilterClick = () => setFilterOpen(true);
|
const handleFilterClick = () => setFilterOpen(true);
|
||||||
@ -246,32 +299,37 @@ const EqsPrfrm = () => {
|
|||||||
//При закрытии диалога фильтра
|
//При закрытии диалога фильтра
|
||||||
const handleFilterCancel = () => setFilterOpen(false);
|
const handleFilterCancel = () => setFilterOpen(false);
|
||||||
|
|
||||||
|
//Состояние ширины и высоты рабочей области окна
|
||||||
|
const [width, height] = useWindowResize();
|
||||||
|
|
||||||
//Генерация содержимого
|
//Генерация содержимого
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
{filter.isOpen ? <FilterDialog initial={filter.values} onOk={handleFilterOk} onCancel={handleFilterCancel} /> : null}
|
{filter.isOpen ? <FilterDialog initial={filter.values} onOk={handleFilterOk} onCancel={handleFilterCancel} /> : null}
|
||||||
<Filter filter={filter.values} onClick={handleFilterClick} />
|
<Filter filter={filter.values} onClick={handleFilterClick} />
|
||||||
{dataGrid.dataLoaded ? (
|
{dataGrid.dataLoaded ? (
|
||||||
<Paper variant="outlined">
|
<Box sx={{ ...STYLES.GRID_PADDING, ...STYLES.BOX_ROW }}>
|
||||||
<Grid container spacing={1}>
|
|
||||||
<Grid item xs={12}>
|
|
||||||
<Box p={1}>
|
|
||||||
<P8PDataGrid
|
<P8PDataGrid
|
||||||
{...P8P_DATA_GRID_CONFIG_PROPS}
|
{...P8P_DATA_GRID_CONFIG_PROPS}
|
||||||
|
containerComponentProps={{
|
||||||
|
elevation: 6,
|
||||||
|
style: {
|
||||||
|
...STYLES.GRID_SIZES(width, height)
|
||||||
|
}
|
||||||
|
}}
|
||||||
columnsDef={dataGrid.columnsDef}
|
columnsDef={dataGrid.columnsDef}
|
||||||
groups={dataGrid.groups}
|
groups={dataGrid.groups}
|
||||||
rows={dataGrid.rows}
|
rows={dataGrid.rows}
|
||||||
|
fixedHeader={dataGrid.fixedHeader}
|
||||||
|
fixedColumns={dataGrid.fixedColumns}
|
||||||
size={P8P_DATA_GRID_SIZE.LARGE}
|
size={P8P_DATA_GRID_SIZE.LARGE}
|
||||||
reloading={dataGrid.reload}
|
reloading={dataGrid.reload}
|
||||||
headCellRender={prms => headCellRender({ ...prms }, handleClick)}
|
headCellRender={prms => headCellRender({ ...prms }, handleClick)}
|
||||||
dataCellRender={prms => dataCellRender({ ...prms }, showEquipSrv)}
|
dataCellRender={prms => dataCellRender({ ...prms }, width * 0.2, showEquipSrv)}
|
||||||
groupCellRender={prms => groupCellRender({ ...prms })}
|
groupCellRender={prms => groupCellRender({ ...prms })}
|
||||||
showCellRightBorder={true}
|
showCellRightBorder={true}
|
||||||
/>
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
</Grid>
|
|
||||||
</Grid>
|
|
||||||
</Paper>
|
|
||||||
) : null}
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
36
app/panels/eqs_prfrm/hooks.js
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
/*
|
||||||
|
Парус 8 - Панели мониторинга - ТОиР - Выполнение работ
|
||||||
|
Пользовательские хуки
|
||||||
|
*/
|
||||||
|
|
||||||
|
//---------------------
|
||||||
|
//Подключение библиотек
|
||||||
|
//---------------------
|
||||||
|
|
||||||
|
import { useState, useLayoutEffect } from "react"; //Классы React
|
||||||
|
|
||||||
|
//-----------
|
||||||
|
//Тело модуля
|
||||||
|
//-----------
|
||||||
|
|
||||||
|
//Хук для отработки изменений ширины и высоты рабочей области окна
|
||||||
|
const useWindowResize = () => {
|
||||||
|
//Состояние размера рабочей области
|
||||||
|
const [size, setSize] = useState([0, 0]);
|
||||||
|
//При изменении размера
|
||||||
|
useLayoutEffect(() => {
|
||||||
|
function updateSize() {
|
||||||
|
setSize([document.documentElement.clientWidth, document.documentElement.clientHeight]);
|
||||||
|
}
|
||||||
|
window.addEventListener("resize", updateSize);
|
||||||
|
updateSize();
|
||||||
|
return () => window.removeEventListener("resize", updateSize);
|
||||||
|
}, []);
|
||||||
|
return size;
|
||||||
|
};
|
||||||
|
|
||||||
|
//--------------
|
||||||
|
//Интерфейс хука
|
||||||
|
//--------------
|
||||||
|
|
||||||
|
export { useWindowResize };
|
@ -20,7 +20,7 @@ export const MONTH_NAME_REG_EXP = /_\d{4}_\d{1,2}/;
|
|||||||
export const DAY_NAME_REG_EXP = /_\d{4}_\d{1,2}_\d{1,2}/;
|
export const DAY_NAME_REG_EXP = /_\d{4}_\d{1,2}_\d{1,2}/;
|
||||||
|
|
||||||
//Стили
|
//Стили
|
||||||
export const STYLES = {
|
const STYLES = {
|
||||||
HIDE_CELL_STYLE: { display: "none" },
|
HIDE_CELL_STYLE: { display: "none" },
|
||||||
HCR_MAIN_STYLE: { border: "1px solid rgba(0, 0, 0)", textAlign: "center" },
|
HCR_MAIN_STYLE: { border: "1px solid rgba(0, 0, 0)", textAlign: "center" },
|
||||||
HCR_DATE_STYLE: { padding: "5px", minWidth: "25px", maxWidth: "25px" },
|
HCR_DATE_STYLE: { padding: "5px", minWidth: "25px", maxWidth: "25px" },
|
||||||
@ -31,7 +31,12 @@ export const STYLES = {
|
|||||||
DCR_FACT_NOT_RELATED_CELL_STYLE: { cursor: "pointer", backgroundColor: "crimson", border: "1px solid rgba(0, 0, 0) !important" },
|
DCR_FACT_NOT_RELATED_CELL_STYLE: { cursor: "pointer", backgroundColor: "crimson", border: "1px solid rgba(0, 0, 0) !important" },
|
||||||
DCR_DOUBLE_CELL: { padding: "unset" },
|
DCR_DOUBLE_CELL: { padding: "unset" },
|
||||||
DCR_DOUBLE_CELL_GRID_ITEM: backgroundColor => ({ cursor: "pointer", backgroundColor }),
|
DCR_DOUBLE_CELL_GRID_ITEM: backgroundColor => ({ cursor: "pointer", backgroundColor }),
|
||||||
HIDDEN_PARAGRAPH: { display: "none" }
|
HIDDEN_PARAGRAPH: { display: "none" },
|
||||||
|
STICKY_WIDTH_UNSET: { minWidth: "unset", maxWidth: "unset" },
|
||||||
|
FIRST_STICKY_CELL: { left: "0px" },
|
||||||
|
OBJINFO_WIDTH: width => ({ minWidth: width, maxWidth: width }),
|
||||||
|
OBJINFO_WRKNAME_WIDTH: width => ({ minWidth: width * 0.6, maxWidth: width * 0.6 }),
|
||||||
|
WRKTYPE_WIDTH: width => ({ left: width * 0.6, minWidth: width - width * 0.4, maxWidth: width - width * 0.4 })
|
||||||
};
|
};
|
||||||
|
|
||||||
//-----------
|
//-----------
|
||||||
@ -71,7 +76,11 @@ export const headCellRender = ({ columnDef }, hClick) => {
|
|||||||
//Объединение нужных колонок и строк
|
//Объединение нужных колонок и строк
|
||||||
if (columnDef.name == "SINFO" || columnDef.name == "SWRKTYPE") {
|
if (columnDef.name == "SINFO" || columnDef.name == "SWRKTYPE") {
|
||||||
cellProps = { colSpan: 2 };
|
cellProps = { colSpan: 2 };
|
||||||
if (columnDef.name == "SINFO") cellProps = { ...cellProps, rowSpan: 2 };
|
cellStyle = { ...cellStyle, ...STYLES.STICKY_WIDTH_UNSET };
|
||||||
|
if (columnDef.name == "SINFO") {
|
||||||
|
cellProps = { ...cellProps, rowSpan: 2 };
|
||||||
|
cellStyle = { ...cellStyle, ...STYLES.FIRST_STICKY_CELL };
|
||||||
|
}
|
||||||
}
|
}
|
||||||
//Изменения в заголовках с датами
|
//Изменения в заголовках с датами
|
||||||
if (columnDef.visible && DAY_NAME_REG_EXP.test(columnDef.name)) {
|
if (columnDef.visible && DAY_NAME_REG_EXP.test(columnDef.name)) {
|
||||||
@ -82,7 +91,7 @@ export const headCellRender = ({ columnDef }, hClick) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
//Генерация представления ячейки
|
//Генерация представления ячейки
|
||||||
export const dataCellRender = ({ row, columnDef }, showEquipSrv) => {
|
export const dataCellRender = ({ row, columnDef }, width, showEquipSrv) => {
|
||||||
let curParent = "";
|
let curParent = "";
|
||||||
let cellDate;
|
let cellDate;
|
||||||
let cellStyle = STYLES.DCR_MAIN_STYLE;
|
let cellStyle = STYLES.DCR_MAIN_STYLE;
|
||||||
@ -93,10 +102,10 @@ export const dataCellRender = ({ row, columnDef }, showEquipSrv) => {
|
|||||||
//Ячейка "Информация по объекту ремонта"
|
//Ячейка "Информация по объекту ремонта"
|
||||||
if (columnDef.name == "SOBJINFO") {
|
if (columnDef.name == "SOBJINFO") {
|
||||||
cellProps = { colSpan: 2 };
|
cellProps = { colSpan: 2 };
|
||||||
cellStyle = { ...cellStyle, ...STYLES.DCR_OBJECT_INFO_STYLE };
|
cellStyle = { ...cellStyle, ...STYLES.DCR_OBJECT_INFO_STYLE, ...STYLES.OBJINFO_WIDTH(width) };
|
||||||
}
|
}
|
||||||
//Ячейка "Тип работ"
|
//Ячейка "Тип работ"
|
||||||
if (columnDef.name == "SWRKTYPE") cellStyle = STYLES.HIDE_CELL_STYLE;
|
if (columnDef.name == "SWRKTYPE") cellStyle = { ...STYLES.HIDE_CELL_STYLE };
|
||||||
//Ячейки колонок месяцев
|
//Ячейки колонок месяцев
|
||||||
if (columnDef.parent == "" && columnDef.expandable == true && columnDef.expanded == false) {
|
if (columnDef.parent == "" && columnDef.expandable == true && columnDef.expanded == false) {
|
||||||
curParent = columnDef.name;
|
curParent = columnDef.name;
|
||||||
@ -118,13 +127,17 @@ export const dataCellRender = ({ row, columnDef }, showEquipSrv) => {
|
|||||||
}
|
}
|
||||||
//Строка плана по объекту ремонта
|
//Строка плана по объекту ремонта
|
||||||
if (columnDef.name == "SOBJINFO" && row["SWRKTYPE"] == "План") {
|
if (columnDef.name == "SOBJINFO" && row["SWRKTYPE"] == "План") {
|
||||||
cellStyle = { ...cellStyle };
|
cellStyle = { ...cellStyle, ...STYLES.FIRST_STICKY_CELL, ...STYLES.OBJINFO_WRKNAME_WIDTH(width) };
|
||||||
cellProps = { rowSpan: 2 };
|
cellProps = { rowSpan: 2 };
|
||||||
}
|
}
|
||||||
//Строка факта по объекту ремонта
|
//Строка факта по объекту ремонта
|
||||||
if (columnDef.name == "SOBJINFO" && row["SWRKTYPE"] == "Факт") {
|
if (columnDef.name == "SOBJINFO" && row["SWRKTYPE"] == "Факт") {
|
||||||
cellStyle = { display: "none" };
|
cellStyle = { display: "none" };
|
||||||
}
|
}
|
||||||
|
//Ячейка план/факт
|
||||||
|
if (columnDef.name == "SWRKTYPE") {
|
||||||
|
cellStyle = { ...cellStyle, ...STYLES.WRKTYPE_WIDTH(width) };
|
||||||
|
}
|
||||||
//Закрашивание ячеек
|
//Закрашивание ячеек
|
||||||
switch (row[columnDef.name]) {
|
switch (row[columnDef.name]) {
|
||||||
case "blue":
|
case "blue":
|
||||||
|
@ -9,26 +9,63 @@
|
|||||||
|
|
||||||
import React, { useState } from "react"; //Классы React
|
import React, { useState } from "react"; //Классы React
|
||||||
import PropTypes from "prop-types"; //Контроль свойств компонента
|
import PropTypes from "prop-types"; //Контроль свойств компонента
|
||||||
import { Typography, Box, Checkbox, Grid, Icon, Button, Dialog, DialogContent, TextField, DialogActions, Tooltip } from "@mui/material"; //Интерфейсные элементы
|
import {
|
||||||
import { P8PDataGrid, P8P_DATA_GRID_SIZE } from "../../components/p8p_data_grid"; //Таблица данных
|
Typography,
|
||||||
|
Box,
|
||||||
|
Checkbox,
|
||||||
|
Grid,
|
||||||
|
Icon,
|
||||||
|
Button,
|
||||||
|
Dialog,
|
||||||
|
DialogContent,
|
||||||
|
TextField,
|
||||||
|
DialogActions,
|
||||||
|
Tooltip,
|
||||||
|
Stack,
|
||||||
|
DialogTitle
|
||||||
|
} from "@mui/material"; //Интерфейсные элементы
|
||||||
|
import { BUTTONS } from "../../../app.text"; //Текстовые ресурсы
|
||||||
|
import { APP_BAR_HEIGHT } from "../../components/p8p_app_workspace"; //Заголовок страницы
|
||||||
|
import { P8PDataGrid, P8P_DATA_GRID_SIZE, P8P_DATA_GRID_MORE_HEIGHT } from "../../components/p8p_data_grid"; //Таблица данных
|
||||||
|
import { APP_STYLES } from "../../../app.styles"; //Типовые стили
|
||||||
import { P8P_DATA_GRID_CONFIG_PROPS } from "../../config_wrapper"; //Подключение компонентов к настройкам приложения
|
import { P8P_DATA_GRID_CONFIG_PROPS } from "../../config_wrapper"; //Подключение компонентов к настройкам приложения
|
||||||
import { useCostJobsSpecs, useEquipConfiguration } from "./hooks"; //Собственные хуки таблиц
|
import { useCostJobsSpecs, useEquipConfiguration } from "./hooks"; //Собственные хуки таблиц
|
||||||
|
import { MAIN_HEADER_HEIGHT, SUB_HEADER_HEIGHT } from "./mech_rec_cost_jobs_manage"; //Заглавный компонент панели
|
||||||
|
|
||||||
//---------
|
//---------
|
||||||
//Константы
|
//Константы
|
||||||
//---------
|
//---------
|
||||||
const sUnitCostJobsSpecs = "CostJobsSpecs"; //Мнемокод раздела операций
|
|
||||||
const sUnitCostEquipment = "CostEquipment"; //Мнемокод раздела рабочих центров
|
//Мнемокод раздела операций
|
||||||
|
const UNIT_COST_JOBS_SPECS = "CostJobsSpecs";
|
||||||
|
|
||||||
|
//Мнемокод раздела рабочих центров
|
||||||
|
const UNIT_COST_EQUIPMENT = "CostEquipment";
|
||||||
|
|
||||||
|
//Высота заголовка таблицы
|
||||||
|
const TABLE_HEADER_HEIGHT = "35px";
|
||||||
|
|
||||||
|
//Высота панели кнопок таблицы
|
||||||
|
const TABLE_BUTTONS_HEIGHT = "35px";
|
||||||
|
|
||||||
|
//Отступ таблицы
|
||||||
|
const TABLE_PADDING_TOP = "15px";
|
||||||
|
|
||||||
//Стили
|
//Стили
|
||||||
const STYLES = {
|
const STYLES = {
|
||||||
CONTAINER: { textAlign: "center" },
|
CONTAINER: { textAlign: "center" },
|
||||||
DATA_GRID_CONTAINER: { minHeight: "65vh", maxHeight: "65vh" },
|
DATA_GRID_CONTAINER: morePages => ({
|
||||||
TABLE: { paddingTop: "15px" },
|
height: `calc(100vh - ${APP_BAR_HEIGHT} - ${MAIN_HEADER_HEIGHT} - ${SUB_HEADER_HEIGHT} - ${TABLE_HEADER_HEIGHT} - ${TABLE_BUTTONS_HEIGHT} - ${TABLE_PADDING_TOP} - 32px - ${
|
||||||
TABLE_BUTTONS: { display: "flex", justifyContent: "flex-end" },
|
morePages ? P8P_DATA_GRID_MORE_HEIGHT : "0px"
|
||||||
|
})`,
|
||||||
|
...APP_STYLES.SCROLL
|
||||||
|
}),
|
||||||
|
TABLE: { paddingTop: TABLE_PADDING_TOP },
|
||||||
|
TABLE_HEADER: { height: TABLE_HEADER_HEIGHT, overflow: "hidden" },
|
||||||
|
TABLE_BUTTONS: { display: "flex", justifyContent: "flex-end", height: TABLE_BUTTONS_HEIGHT, overflow: "hidden" },
|
||||||
CHECK_BOX: { textAlign: "center" },
|
CHECK_BOX: { textAlign: "center" },
|
||||||
JOBS_INFO: { minWidth: "60%", maxWidth: "60%", textAlign: "center" },
|
JOBS_INFO: { textAlign: "center" },
|
||||||
EQUIPMENT_INFO: { minWidth: "40%", maxWidth: "40%", textAlign: "center" }
|
EQUIPMENT_INFO: { textAlign: "center" }
|
||||||
};
|
};
|
||||||
|
|
||||||
//Цвета
|
//Цвета
|
||||||
@ -47,7 +84,7 @@ const dataCellRender = ({ row, columnDef, handleSelectChange, sUnit, selectedRow
|
|||||||
//Стиль
|
//Стиль
|
||||||
let cellStyle = {};
|
let cellStyle = {};
|
||||||
//Если это рабочие центры
|
//Если это рабочие центры
|
||||||
if (sUnit === sUnitCostEquipment) {
|
if (sUnit === UNIT_COST_EQUIPMENT) {
|
||||||
//Признак недоступности
|
//Признак недоступности
|
||||||
let disabled = true;
|
let disabled = true;
|
||||||
//Если в выбранной строке смены указано рабочее место
|
//Если в выбранной строке смены указано рабочее место
|
||||||
@ -98,7 +135,7 @@ const dataCellRender = ({ row, columnDef, handleSelectChange, sUnit, selectedRow
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
//Если это сменное задание
|
//Если это сменное задание
|
||||||
if (sUnit === sUnitCostJobsSpecs) {
|
if (sUnit === UNIT_COST_JOBS_SPECS) {
|
||||||
//Если указан станок
|
//Если указан станок
|
||||||
if (row["SEQCONFIG"]) {
|
if (row["SEQCONFIG"]) {
|
||||||
//Подсвечиваем сменное задание зеленым
|
//Подсвечиваем сменное задание зеленым
|
||||||
@ -193,6 +230,7 @@ const CostJobsSpecsInclude = ({ includeEquipment, setIncludeEquipment, setCostJo
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Dialog open onClose={() => handlePriorEditClose()}>
|
<Dialog open onClose={() => handlePriorEditClose()}>
|
||||||
|
<DialogTitle>Включить в задание</DialogTitle>
|
||||||
<DialogContent>
|
<DialogContent>
|
||||||
<Box>
|
<Box>
|
||||||
<TextField
|
<TextField
|
||||||
@ -219,15 +257,12 @@ const CostJobsSpecsInclude = ({ includeEquipment, setIncludeEquipment, setCostJo
|
|||||||
setState(value);
|
setState(value);
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<Box>
|
<Box></Box>
|
||||||
<Button onClick={costJobsSpecIncludeCostEquipment} variant="contained" sx={STYLES.DIALOG_BUTTONS}>
|
|
||||||
Включить в задание
|
|
||||||
</Button>
|
|
||||||
</Box>
|
|
||||||
</Box>
|
</Box>
|
||||||
</DialogContent>
|
</DialogContent>
|
||||||
<DialogActions>
|
<DialogActions>
|
||||||
<Button onClick={() => handlePriorEditClose(null)}>Закрыть</Button>
|
<Button onClick={costJobsSpecIncludeCostEquipment}>{BUTTONS.OK}</Button>
|
||||||
|
<Button onClick={() => handlePriorEditClose(null)}>{BUTTONS.CANCEL}</Button>
|
||||||
</DialogActions>
|
</DialogActions>
|
||||||
</Dialog>
|
</Dialog>
|
||||||
);
|
);
|
||||||
@ -247,7 +282,7 @@ CostJobsSpecsInclude.propTypes = {
|
|||||||
//-----------
|
//-----------
|
||||||
|
|
||||||
//Таблица информации о строках сменного задания
|
//Таблица информации о строках сменного задания
|
||||||
const CostJobsSpecsDataGrid = ({ task, haveNote }) => {
|
const CostJobsSpecsDataGrid = ({ task, haveNote, fromAction }) => {
|
||||||
//Собственное состояние - Включение в задание
|
//Собственное состояние - Включение в задание
|
||||||
const [includeEquipment, setIncludeEquipment] = useState({ NFCJOBSSP: null, NEQCONFIG: null, NVALUE: 0 });
|
const [includeEquipment, setIncludeEquipment] = useState({ NFCJOBSSP: null, NEQCONFIG: null, NVALUE: 0 });
|
||||||
|
|
||||||
@ -255,7 +290,7 @@ const CostJobsSpecsDataGrid = ({ task, haveNote }) => {
|
|||||||
const [costJobsSpecs, setCostJobsSpecs, issueCostJobsSpecs] = useCostJobsSpecs(task);
|
const [costJobsSpecs, setCostJobsSpecs, issueCostJobsSpecs] = useCostJobsSpecs(task);
|
||||||
|
|
||||||
//Собственное состояние - таблица рабочих центров
|
//Собственное состояние - таблица рабочих центров
|
||||||
const [equipConfiguration, setEquipConfiguration, includeEquipConfiguration, excludeEquipConfiguration] = useEquipConfiguration(task);
|
const [equipConfiguration, setEquipConfiguration, includeEquipConfiguration, excludeEquipConfiguration] = useEquipConfiguration(task, fromAction);
|
||||||
|
|
||||||
//При изменении состояния сортировки операций
|
//При изменении состояния сортировки операций
|
||||||
const costJobsSpecOrderChanged = ({ orders }) => setCostJobsSpecs(pv => ({ ...pv, orders: [...orders], pageNumber: 1, reload: true }));
|
const costJobsSpecOrderChanged = ({ orders }) => setCostJobsSpecs(pv => ({ ...pv, orders: [...orders], pageNumber: 1, reload: true }));
|
||||||
@ -314,7 +349,7 @@ const CostJobsSpecsDataGrid = ({ task, haveNote }) => {
|
|||||||
//Исходим от раздела
|
//Исходим от раздела
|
||||||
switch (prms.SUNIT) {
|
switch (prms.SUNIT) {
|
||||||
//Сменное задание
|
//Сменное задание
|
||||||
case sUnitCostJobsSpecs:
|
case UNIT_COST_JOBS_SPECS:
|
||||||
//Определяем это новое отмеченное сменное задание или сброс старого
|
//Определяем это новое отмеченное сменное задание или сброс старого
|
||||||
selectedRow = costJobsSpecs.selectedRow.NRN ? (costJobsSpecs.selectedRow.NRN === prms.NRN ? null : prms.NRN) : prms.NRN;
|
selectedRow = costJobsSpecs.selectedRow.NRN ? (costJobsSpecs.selectedRow.NRN === prms.NRN ? null : prms.NRN) : prms.NRN;
|
||||||
//Актуализируем строки
|
//Актуализируем строки
|
||||||
@ -327,7 +362,7 @@ const CostJobsSpecsDataGrid = ({ task, haveNote }) => {
|
|||||||
//Выходим
|
//Выходим
|
||||||
break;
|
break;
|
||||||
//Рабочие центры
|
//Рабочие центры
|
||||||
case sUnitCostEquipment:
|
case UNIT_COST_EQUIPMENT:
|
||||||
//Определяем это новое отмеченное сменное задание или сброс старого
|
//Определяем это новое отмеченное сменное задание или сброс старого
|
||||||
selectedRow = equipConfiguration.selectedRow.NRN ? (equipConfiguration.selectedRow.NRN === prms.NRN ? null : prms.NRN) : prms.NRN;
|
selectedRow = equipConfiguration.selectedRow.NRN ? (equipConfiguration.selectedRow.NRN === prms.NRN ? null : prms.NRN) : prms.NRN;
|
||||||
//Актуализируем строки
|
//Актуализируем строки
|
||||||
@ -356,23 +391,23 @@ const CostJobsSpecsDataGrid = ({ task, haveNote }) => {
|
|||||||
return (
|
return (
|
||||||
<div style={STYLES.CONTAINER}>
|
<div style={STYLES.CONTAINER}>
|
||||||
<Grid container spacing={2}>
|
<Grid container spacing={2}>
|
||||||
<Grid item sx={STYLES.JOBS_INFO}>
|
<Grid item sx={STYLES.JOBS_INFO} xs={6}>
|
||||||
<Typography variant={"h6"}>Сменное задание</Typography>
|
<Typography sx={STYLES.TABLE_HEADER} variant={"h6"} color={"text.secondary"}>
|
||||||
|
Сменное задание
|
||||||
|
</Typography>
|
||||||
{costJobsSpecs.dataLoaded ? (
|
{costJobsSpecs.dataLoaded ? (
|
||||||
<>
|
<>
|
||||||
<Box sx={STYLES.TABLE_BUTTONS}>
|
<Box sx={STYLES.TABLE_BUTTONS}>
|
||||||
<Tooltip title={haveNote ? "Сменное задание имеет строку с примечанием" : null}>
|
<Tooltip title={haveNote ? "Сменное задание имеет строку с примечанием" : null}>
|
||||||
<Box>
|
|
||||||
<Button variant="contained" size="small" disabled={haveNote} onClick={costJobsSpecIssue}>
|
<Button variant="contained" size="small" disabled={haveNote} onClick={costJobsSpecIssue}>
|
||||||
Выдать задания
|
Выдать задания
|
||||||
</Button>
|
</Button>
|
||||||
</Box>
|
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
</Box>
|
</Box>
|
||||||
<Box sx={STYLES.TABLE}>
|
<Box sx={STYLES.TABLE}>
|
||||||
<P8PDataGrid
|
<P8PDataGrid
|
||||||
{...P8P_DATA_GRID_CONFIG_PROPS}
|
{...P8P_DATA_GRID_CONFIG_PROPS}
|
||||||
containerComponentProps={{ sx: STYLES.DATA_GRID_CONTAINER, elevation: 1 }}
|
containerComponentProps={{ sx: STYLES.DATA_GRID_CONTAINER(costJobsSpecs.morePages), elevation: 1 }}
|
||||||
columnsDef={costJobsSpecs.columnsDef}
|
columnsDef={costJobsSpecs.columnsDef}
|
||||||
rows={costJobsSpecs.rows}
|
rows={costJobsSpecs.rows}
|
||||||
size={P8P_DATA_GRID_SIZE.SMALL}
|
size={P8P_DATA_GRID_SIZE.SMALL}
|
||||||
@ -384,7 +419,7 @@ const CostJobsSpecsDataGrid = ({ task, haveNote }) => {
|
|||||||
dataCellRender({
|
dataCellRender({
|
||||||
...prms,
|
...prms,
|
||||||
handleSelectChange,
|
handleSelectChange,
|
||||||
sUnit: sUnitCostJobsSpecs,
|
sUnit: UNIT_COST_JOBS_SPECS,
|
||||||
selectedRow: costJobsSpecs.selectedRow.NRN,
|
selectedRow: costJobsSpecs.selectedRow.NRN,
|
||||||
selectedJobSpec: costJobsSpecs.selectedRow
|
selectedJobSpec: costJobsSpecs.selectedRow
|
||||||
})
|
})
|
||||||
@ -396,11 +431,14 @@ const CostJobsSpecsDataGrid = ({ task, haveNote }) => {
|
|||||||
</>
|
</>
|
||||||
) : null}
|
) : null}
|
||||||
</Grid>
|
</Grid>
|
||||||
<Grid item sx={STYLES.EQUIPMENT_INFO}>
|
<Grid item sx={STYLES.EQUIPMENT_INFO} xs={6}>
|
||||||
<Typography variant={"h6"}>Рабочие центры</Typography>
|
<Typography sx={STYLES.TABLE_HEADER} variant={"h6"} color={"text.secondary"}>
|
||||||
|
Рабочие центры
|
||||||
|
</Typography>
|
||||||
{equipConfiguration.dataLoaded ? (
|
{equipConfiguration.dataLoaded ? (
|
||||||
<>
|
<>
|
||||||
<Box sx={STYLES.TABLE_BUTTONS}>
|
<Box sx={STYLES.TABLE_BUTTONS}>
|
||||||
|
<Stack direction={"row"} spacing={1}>
|
||||||
<Button
|
<Button
|
||||||
variant="contained"
|
variant="contained"
|
||||||
size="small"
|
size="small"
|
||||||
@ -413,7 +451,6 @@ const CostJobsSpecsDataGrid = ({ task, haveNote }) => {
|
|||||||
>
|
>
|
||||||
Включить в задание
|
Включить в задание
|
||||||
</Button>
|
</Button>
|
||||||
<Box ml={1}>
|
|
||||||
<Button
|
<Button
|
||||||
variant="contained"
|
variant="contained"
|
||||||
size="small"
|
size="small"
|
||||||
@ -422,12 +459,12 @@ const CostJobsSpecsDataGrid = ({ task, haveNote }) => {
|
|||||||
>
|
>
|
||||||
Исключить из задания
|
Исключить из задания
|
||||||
</Button>
|
</Button>
|
||||||
</Box>
|
</Stack>
|
||||||
</Box>
|
</Box>
|
||||||
<Box sx={STYLES.TABLE}>
|
<Box sx={STYLES.TABLE}>
|
||||||
<P8PDataGrid
|
<P8PDataGrid
|
||||||
{...P8P_DATA_GRID_CONFIG_PROPS}
|
{...P8P_DATA_GRID_CONFIG_PROPS}
|
||||||
containerComponentProps={{ sx: STYLES.DATA_GRID_CONTAINER, elevation: 1 }}
|
containerComponentProps={{ sx: STYLES.DATA_GRID_CONTAINER(equipConfiguration.morePages), elevation: 1 }}
|
||||||
columnsDef={equipConfiguration.columnsDef}
|
columnsDef={equipConfiguration.columnsDef}
|
||||||
rows={equipConfiguration.rows}
|
rows={equipConfiguration.rows}
|
||||||
size={P8P_DATA_GRID_SIZE.SMALL}
|
size={P8P_DATA_GRID_SIZE.SMALL}
|
||||||
@ -439,7 +476,7 @@ const CostJobsSpecsDataGrid = ({ task, haveNote }) => {
|
|||||||
dataCellRender({
|
dataCellRender({
|
||||||
...prms,
|
...prms,
|
||||||
handleSelectChange,
|
handleSelectChange,
|
||||||
sUnit: sUnitCostEquipment,
|
sUnit: UNIT_COST_EQUIPMENT,
|
||||||
selectedRow: equipConfiguration.selectedRow.NRN,
|
selectedRow: equipConfiguration.selectedRow.NRN,
|
||||||
selectedJobSpec: costJobsSpecs.selectedRow
|
selectedJobSpec: costJobsSpecs.selectedRow
|
||||||
})
|
})
|
||||||
@ -468,7 +505,8 @@ const CostJobsSpecsDataGrid = ({ task, haveNote }) => {
|
|||||||
//Контроль свойств - Таблица информации о строках сменного задания
|
//Контроль свойств - Таблица информации о строках сменного задания
|
||||||
CostJobsSpecsDataGrid.propTypes = {
|
CostJobsSpecsDataGrid.propTypes = {
|
||||||
task: PropTypes.number.isRequired,
|
task: PropTypes.number.isRequired,
|
||||||
haveNote: PropTypes.bool.isRequired
|
haveNote: PropTypes.bool.isRequired,
|
||||||
|
fromAction: PropTypes.bool.isRequired
|
||||||
};
|
};
|
||||||
|
|
||||||
//----------------
|
//----------------
|
||||||
|
@ -1,9 +1,15 @@
|
|||||||
|
/*
|
||||||
|
Парус 8 - Панели мониторинга - ПУП - Выдача сменного задания
|
||||||
|
Кастомные хуки
|
||||||
|
*/
|
||||||
|
|
||||||
//---------------------
|
//---------------------
|
||||||
//Подключение библиотек
|
//Подключение библиотек
|
||||||
//---------------------
|
//---------------------
|
||||||
|
|
||||||
import React, { useState, useCallback, useEffect, useContext } from "react"; //Классы React
|
import React, { useState, useCallback, useEffect, useContext } from "react"; //Классы React
|
||||||
import { BackEndСtx } from "../../context/backend"; //Контекст взаимодействия с сервером
|
import { BackEndСtx } from "../../context/backend"; //Контекст взаимодействия с сервером
|
||||||
|
import { NavigationCtx } from "../../context/navigation"; //Контекст навигации
|
||||||
import { object2Base64XML } from "../../core/utils"; //Вспомогательные функции
|
import { object2Base64XML } from "../../core/utils"; //Вспомогательные функции
|
||||||
|
|
||||||
//---------
|
//---------
|
||||||
@ -39,18 +45,20 @@ const useCostJobs = () => {
|
|||||||
jobList: [],
|
jobList: [],
|
||||||
jobListLoaded: false,
|
jobListLoaded: false,
|
||||||
selectedJob: {},
|
selectedJob: {},
|
||||||
dataLoaded: false
|
fromAction: false
|
||||||
});
|
});
|
||||||
|
|
||||||
//Подключение к контексту взаимодействия с сервером
|
//Подключение к контексту взаимодействия с сервером
|
||||||
const { executeStored } = useContext(BackEndСtx);
|
const { executeStored } = useContext(BackEndСtx);
|
||||||
|
//Подключение к контексту навигации
|
||||||
|
const { getNavigationSearch } = useContext(NavigationCtx);
|
||||||
|
|
||||||
//При подключении компонента к странице
|
//При подключении компонента к странице
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const initPlans = async () => {
|
const initPlans = async fcJob => {
|
||||||
const data = await executeStored({
|
const data = await executeStored({
|
||||||
stored: "PKG_P8PANELS_MECHREC.FCJOBS_INIT",
|
stored: "PKG_P8PANELS_MECHREC.FCJOBS_INIT",
|
||||||
args: {},
|
args: { NFCJOBS: fcJob ? parseInt(fcJob) : null },
|
||||||
respArg: "COUT",
|
respArg: "COUT",
|
||||||
isArray: name => name === "XFCJOBS",
|
isArray: name => name === "XFCJOBS",
|
||||||
attributeValueProcessor: (name, val) => (["NHAVE_NOTE"].includes(name) ? val == 1 : val)
|
attributeValueProcessor: (name, val) => (["NHAVE_NOTE"].includes(name) ? val == 1 : val)
|
||||||
@ -59,11 +67,16 @@ const useCostJobs = () => {
|
|||||||
...pv,
|
...pv,
|
||||||
init: true,
|
init: true,
|
||||||
jobList: [...(data.XFCJOBS || [])],
|
jobList: [...(data.XFCJOBS || [])],
|
||||||
jobListLoaded: true
|
selectedJob: data.XFCJOBS_SELECTED ? data.XFCJOBS_SELECTED : {},
|
||||||
|
jobListLoaded: true,
|
||||||
|
fromAction: fcJob ? true : false
|
||||||
}));
|
}));
|
||||||
};
|
};
|
||||||
if (!state.init) {
|
if (!state.init) {
|
||||||
initPlans();
|
//Считаем параметры, переданные из действия
|
||||||
|
const actionPrms = getNavigationSearch();
|
||||||
|
//Иницализируем планы
|
||||||
|
initPlans(actionPrms.NRN);
|
||||||
}
|
}
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, []);
|
}, []);
|
||||||
@ -163,7 +176,7 @@ const useCostJobsSpecs = task => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
//Хук для таблицы рабочих центров
|
//Хук для таблицы рабочих центров
|
||||||
const useEquipConfiguration = task => {
|
const useEquipConfiguration = (task, fromAction) => {
|
||||||
//Собственное состояние - таблица данных
|
//Собственное состояние - таблица данных
|
||||||
const [equipConfiguration, setEquipConfiguration] = useState({
|
const [equipConfiguration, setEquipConfiguration] = useState({
|
||||||
task: null,
|
task: null,
|
||||||
@ -232,6 +245,7 @@ const useEquipConfiguration = task => {
|
|||||||
stored: "PKG_P8PANELS_MECHREC.EQCONFIG_DG_GET",
|
stored: "PKG_P8PANELS_MECHREC.EQCONFIG_DG_GET",
|
||||||
args: {
|
args: {
|
||||||
NFCJOBS: task,
|
NFCJOBS: task,
|
||||||
|
NFROM_ACTION: fromAction ? 1 : 0,
|
||||||
CORDERS: { VALUE: object2Base64XML(equipConfiguration.orders, { arrayNodeName: "orders" }), SDATA_TYPE: SERV_DATA_TYPE_CLOB },
|
CORDERS: { VALUE: object2Base64XML(equipConfiguration.orders, { arrayNodeName: "orders" }), SDATA_TYPE: SERV_DATA_TYPE_CLOB },
|
||||||
NPAGE_NUMBER: equipConfiguration.pageNumber,
|
NPAGE_NUMBER: equipConfiguration.pageNumber,
|
||||||
NPAGE_SIZE: DATA_GRID_PAGE_SIZE,
|
NPAGE_SIZE: DATA_GRID_PAGE_SIZE,
|
||||||
@ -261,7 +275,8 @@ const useEquipConfiguration = task => {
|
|||||||
equipConfiguration.selectedRow,
|
equipConfiguration.selectedRow,
|
||||||
equipConfiguration.task,
|
equipConfiguration.task,
|
||||||
task,
|
task,
|
||||||
executeStored
|
executeStored,
|
||||||
|
fromAction
|
||||||
]);
|
]);
|
||||||
|
|
||||||
return [equipConfiguration, setEquipConfiguration, includeEquipConfiguration, excludeEquipConfiguration];
|
return [equipConfiguration, setEquipConfiguration, includeEquipConfiguration, excludeEquipConfiguration];
|
||||||
|
@ -18,8 +18,16 @@ import { useCostJobs, useFilteredFcjobs } from "./hooks"; //Вспомогате
|
|||||||
//Константы
|
//Константы
|
||||||
//---------
|
//---------
|
||||||
|
|
||||||
|
//Высота основного заголовка
|
||||||
|
const MAIN_HEADER_HEIGHT = "35px";
|
||||||
|
|
||||||
|
//Высота подзаголовка
|
||||||
|
const SUB_HEADER_HEIGHT = "35px";
|
||||||
|
|
||||||
//Стили
|
//Стили
|
||||||
const STYLES = {
|
const STYLES = {
|
||||||
|
MAIN_HEADER: { height: MAIN_HEADER_HEIGHT, overflow: "hidden" },
|
||||||
|
SUB_HEADER: { height: SUB_HEADER_HEIGHT, overflow: "hidden" },
|
||||||
JOBS_FINDER: { marginTop: "10px", marginLeft: "10px", width: "93%" },
|
JOBS_FINDER: { marginTop: "10px", marginLeft: "10px", width: "93%" },
|
||||||
JOBS_LIST_ITEM_PRIMARY: { wordWrap: "break-word" },
|
JOBS_LIST_ITEM_PRIMARY: { wordWrap: "break-word" },
|
||||||
JOBS_BUTTON: { position: "absolute" },
|
JOBS_BUTTON: { position: "absolute" },
|
||||||
@ -96,8 +104,7 @@ const MechRecCostJobs = () => {
|
|||||||
setState(pv => ({
|
setState(pv => ({
|
||||||
...pv,
|
...pv,
|
||||||
selectedJob: job,
|
selectedJob: job,
|
||||||
showJobList: false,
|
showJobList: false
|
||||||
dataLoaded: false
|
|
||||||
}));
|
}));
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -107,8 +114,7 @@ const MechRecCostJobs = () => {
|
|||||||
setState(pv => ({
|
setState(pv => ({
|
||||||
...pv,
|
...pv,
|
||||||
selectedJob: {},
|
selectedJob: {},
|
||||||
showJobList: false,
|
showJobList: false
|
||||||
dataLoaded: false
|
|
||||||
}));
|
}));
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -130,9 +136,12 @@ const MechRecCostJobs = () => {
|
|||||||
<div style={STYLES.CONTAINER}>
|
<div style={STYLES.CONTAINER}>
|
||||||
{state.selectedJob.NRN ? (
|
{state.selectedJob.NRN ? (
|
||||||
<>
|
<>
|
||||||
<Typography variant={"h6"}>{`Сменное задание №${state.selectedJob.SDOC_NUMB} на ${state.selectedJob.SPERIOD}`}</Typography>
|
<Typography
|
||||||
<Typography variant={"h6"}>{`${state.selectedJob.SSUBDIV}`}</Typography>
|
sx={STYLES.MAIN_HEADER}
|
||||||
<CostJobsSpecsDataGrid task={state.selectedJob.NRN} haveNote={state.selectedJob.NHAVE_NOTE} />
|
variant={"h6"}
|
||||||
|
>{`Сменное задание №${state.selectedJob.SDOC_NUMB} на ${state.selectedJob.SPERIOD}`}</Typography>
|
||||||
|
<Typography sx={STYLES.SUB_HEADER} variant={"h6"}>{`${state.selectedJob.SSUBDIV}`}</Typography>
|
||||||
|
<CostJobsSpecsDataGrid task={state.selectedJob.NRN} haveNote={state.selectedJob.NHAVE_NOTE} fromAction={state.fromAction} />
|
||||||
</>
|
</>
|
||||||
) : !state.selectedJob.NRN ? (
|
) : !state.selectedJob.NRN ? (
|
||||||
<InlineMsgInfo okBtn={false} text={"Укажите сменное задание для отображения информации"} />
|
<InlineMsgInfo okBtn={false} text={"Укажите сменное задание для отображения информации"} />
|
||||||
@ -146,4 +155,4 @@ const MechRecCostJobs = () => {
|
|||||||
//Интерфейс модуля
|
//Интерфейс модуля
|
||||||
//----------------
|
//----------------
|
||||||
|
|
||||||
export { MechRecCostJobs };
|
export { MAIN_HEADER_HEIGHT, SUB_HEADER_HEIGHT, MechRecCostJobs };
|
||||||
|
@ -20,7 +20,8 @@ import { useCostDeliveryLists } from "./backend_dg"; //Собственные х
|
|||||||
|
|
||||||
//Стили
|
//Стили
|
||||||
const STYLES = {
|
const STYLES = {
|
||||||
CONTAINER: { margin: "5px 0px", textAlign: "center" }
|
CONTAINER: { margin: "5px 0px", textAlign: "center" },
|
||||||
|
DATA_GRID_CELL_COVERED: { backgroundColor: "lightblue" }
|
||||||
};
|
};
|
||||||
|
|
||||||
//------------------------------------
|
//------------------------------------
|
||||||
@ -32,7 +33,7 @@ const dataCellRender = ({ row, columnDef }) => {
|
|||||||
//Если "Количество план" равно или меньше "Остаток"
|
//Если "Количество план" равно или меньше "Остаток"
|
||||||
if (row["NQUANT_PLAN"] <= row["NREST"]) {
|
if (row["NQUANT_PLAN"] <= row["NREST"]) {
|
||||||
return {
|
return {
|
||||||
cellStyle: { backgroundColor: "lightblue" },
|
cellStyle: { ...STYLES.DATA_GRID_CELL_COVERED },
|
||||||
data: row[columnDef]
|
data: row[columnDef]
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
|
@ -20,7 +20,8 @@ import { useGoodsParties } from "./backend_dg"; //Собственные хук
|
|||||||
|
|
||||||
//Стили
|
//Стили
|
||||||
const STYLES = {
|
const STYLES = {
|
||||||
CONTAINER: { margin: "5px 0px", textAlign: "center" }
|
CONTAINER: { margin: "5px 0px", textAlign: "center" },
|
||||||
|
DATA_GRID_CELL_COVERED: { backgroundColor: "lightblue" }
|
||||||
};
|
};
|
||||||
|
|
||||||
//------------------------------------
|
//------------------------------------
|
||||||
@ -32,7 +33,7 @@ const dataCellRender = ({ row, columnDef, quantPlanSum }) => {
|
|||||||
//Если остаток больше суммы "Выдать по норме" - закрашиваем голубым
|
//Если остаток больше суммы "Выдать по норме" - закрашиваем голубым
|
||||||
if (row["NRESTFACT"] >= quantPlanSum) {
|
if (row["NRESTFACT"] >= quantPlanSum) {
|
||||||
return {
|
return {
|
||||||
cellStyle: { backgroundColor: "lightblue" },
|
cellStyle: { ...STYLES.DATA_GRID_CELL_COVERED },
|
||||||
data: row[columnDef]
|
data: row[columnDef]
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
|
@ -40,7 +40,9 @@ import {
|
|||||||
} from "@mui/material"; //Интерфейсные элементы
|
} 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 { NavigationCtx } from "../../context/navigation"; //Контекст навигации
|
||||||
import { P8P_GANTT_CONFIG_PROPS } from "../../config_wrapper"; //Подключение компонентов к настройкам приложения
|
import { P8P_GANTT_CONFIG_PROPS } from "../../config_wrapper"; //Подключение компонентов к настройкам приложения
|
||||||
|
import { APP_BAR_HEIGHT } from "../../components/p8p_app_workspace"; //Заголовок страницы
|
||||||
import { P8PGantt, taskLegendDesc } from "../../components/p8p_gantt"; //Диаграмма Ганта
|
import { P8PGantt, taskLegendDesc } from "../../components/p8p_gantt"; //Диаграмма Ганта
|
||||||
import { xml2JSON, formatDateJSONDateOnly, formatDateRF, hasValue } from "../../core/utils"; //Вспомогательные функции
|
import { xml2JSON, formatDateJSONDateOnly, formatDateRF, hasValue } from "../../core/utils"; //Вспомогательные функции
|
||||||
import { useFilteredPlanCtlgs } from "./hooks"; //Вспомогательные хуки
|
import { useFilteredPlanCtlgs } from "./hooks"; //Вспомогательные хуки
|
||||||
@ -58,12 +60,6 @@ const DECLINATIONS = ["план", "плана", "планов"];
|
|||||||
const SORT_REP_DATE = "DREP_DATE";
|
const SORT_REP_DATE = "DREP_DATE";
|
||||||
const SORT_REP_DATE_TO = "DREP_DATE_TO";
|
const SORT_REP_DATE_TO = "DREP_DATE_TO";
|
||||||
|
|
||||||
//Высота диаграммы Ганта
|
|
||||||
const GANTT_HEIGHT = "75vh";
|
|
||||||
|
|
||||||
//Ширина диаграммы Ганта
|
|
||||||
const GANTT_WIDTH = "98vw";
|
|
||||||
|
|
||||||
//Стили
|
//Стили
|
||||||
const STYLES = {
|
const STYLES = {
|
||||||
PLANS_FINDER: { marginTop: "10px", marginLeft: "10px", width: "93%" },
|
PLANS_FINDER: { marginTop: "10px", marginLeft: "10px", width: "93%" },
|
||||||
@ -71,20 +67,23 @@ const STYLES = {
|
|||||||
PLANS_LIST_ITEM_ZERODOCS: { backgroundColor: "#ebecec" },
|
PLANS_LIST_ITEM_ZERODOCS: { backgroundColor: "#ebecec" },
|
||||||
PLANS_LIST_ITEM_PRIMARY: { wordWrap: "break-word" },
|
PLANS_LIST_ITEM_PRIMARY: { wordWrap: "break-word" },
|
||||||
PLANS_LIST_ITEM_SECONDARY: { wordWrap: "break-word", fontSize: "0.6rem", textTransform: "uppercase" },
|
PLANS_LIST_ITEM_SECONDARY: { wordWrap: "break-word", fontSize: "0.6rem", textTransform: "uppercase" },
|
||||||
PLANS_BUTTON: { position: "absolute" },
|
PLANS_BUTTON: { position: "absolute", top: `calc(${APP_BAR_HEIGHT} + 16px)`, left: "16px" },
|
||||||
PLANS_DRAWER: {
|
PLANS_DRAWER: {
|
||||||
width: "350px",
|
width: "350px",
|
||||||
display: "inline-block",
|
display: "inline-block",
|
||||||
flexShrink: 0,
|
flexShrink: 0,
|
||||||
[`& .MuiDrawer-paper`]: { width: "350px", display: "inline-block", boxSizing: "border-box" }
|
[`& .MuiDrawer-paper`]: { width: "350px", display: "inline-block", boxSizing: "border-box" }
|
||||||
},
|
},
|
||||||
GANTT_CONTAINER: { height: GANTT_HEIGHT, width: GANTT_WIDTH },
|
GANTT_CONTAINER: { height: `calc(100vh - ${APP_BAR_HEIGHT})`, width: "100vw", paddingTop: "24px" },
|
||||||
GANTT_TITLE: { paddingLeft: "100px", paddingRight: "120px" },
|
GANTT_TITLE: { paddingLeft: "250px", paddingRight: "250px" },
|
||||||
SECOND_TABLE: { paddingTop: "30px" },
|
SECOND_TABLE: { paddingTop: "30px" },
|
||||||
TASK_DIALOG_CARD_CONTAINER: { padding: "0px" },
|
TASK_DIALOG_CARD_CONTAINER: { padding: "0px" },
|
||||||
TASK_DIALOG_LIST_ITEM_ICON: { justifyContent: "center" },
|
TASK_DIALOG_LIST_ITEM_ICON: { justifyContent: "center" },
|
||||||
TASK_DIALOG_ICON: { fontSize: "2rem" },
|
TASK_DIALOG_ICON: { fontSize: "2rem" },
|
||||||
TASK_DIALOG_ACTION_CONTAINER: { border: 1, borderColor: "text.primary", borderRadius: "5px", width: "100%" }
|
TASK_DIALOG_ACTION_CONTAINER: { border: 1, borderColor: "text.primary", borderRadius: "5px", width: "100%" },
|
||||||
|
FILTERS: { display: "table", float: "right" },
|
||||||
|
FILTERS_DATE: { display: "table-cell", verticalAlign: "middle" },
|
||||||
|
FILTERS_LEVEL: { display: "table-cell", verticalAlign: "middle", paddingLeft: "15px" }
|
||||||
};
|
};
|
||||||
|
|
||||||
//------------------------------------
|
//------------------------------------
|
||||||
@ -148,7 +147,7 @@ const PlanCtlgsList = ({ planCtlgs = [], selectedPlanCtlg, filter, setFilter, on
|
|||||||
>
|
>
|
||||||
<ListItemText
|
<ListItemText
|
||||||
primary={<Typography sx={STYLES.PLANS_LIST_ITEM_PRIMARY}>{p.SNAME}</Typography>}
|
primary={<Typography sx={STYLES.PLANS_LIST_ITEM_PRIMARY}>{p.SNAME}</Typography>}
|
||||||
secondary={<Typography sx={{ ...STYLES.PLANS_LIST_ITEM_SECONDARY }}>{formatCountDocs(p.NCOUNT_DOCS)}</Typography>}
|
secondary={<Typography sx={STYLES.PLANS_LIST_ITEM_SECONDARY}>{formatCountDocs(p.NCOUNT_DOCS)}</Typography>}
|
||||||
/>
|
/>
|
||||||
</ListItemButton>
|
</ListItemButton>
|
||||||
))}
|
))}
|
||||||
@ -210,7 +209,9 @@ const taskDialogRenderer = ({ task, taskColors, close, handleTaskDetailOpen }) =
|
|||||||
{task["detail_list"]}
|
{task["detail_list"]}
|
||||||
</Button>
|
</Button>
|
||||||
) : (
|
) : (
|
||||||
<Typography color="textSecondary">{`Анализ отклонений недоступен: ${task["detail_list"]}`}</Typography>
|
<Typography color="textSecondary">{`Анализ отклонений недоступен${
|
||||||
|
task["detail_list"] ? `: ${task["detail_list"]}` : ""
|
||||||
|
}`}</Typography>
|
||||||
)}
|
)}
|
||||||
</Box>
|
</Box>
|
||||||
</CardActions>
|
</CardActions>
|
||||||
@ -239,7 +240,8 @@ const MechRecCostProdPlans = () => {
|
|||||||
selectedPlanCtlgGanttDef: {},
|
selectedPlanCtlgGanttDef: {},
|
||||||
selectedPlanCtlgSpecs: [],
|
selectedPlanCtlgSpecs: [],
|
||||||
selectedTaskDetail: null,
|
selectedTaskDetail: null,
|
||||||
selectedTaskDetailType: null
|
selectedTaskDetailType: null,
|
||||||
|
planSpec: null
|
||||||
});
|
});
|
||||||
//Состояние для фильтра каталогов
|
//Состояние для фильтра каталогов
|
||||||
const [filter, setFilter] = useState({ ctlgName: "", haveDocs: false });
|
const [filter, setFilter] = useState({ ctlgName: "", haveDocs: false });
|
||||||
@ -253,7 +255,10 @@ const MechRecCostProdPlans = () => {
|
|||||||
//Подключение к контексту взаимодействия с сервером
|
//Подключение к контексту взаимодействия с сервером
|
||||||
const { executeStored } = useContext(BackEndСtx);
|
const { executeStored } = useContext(BackEndСtx);
|
||||||
|
|
||||||
// Инициализация каталогов планов
|
//Подключение к контексту навигации
|
||||||
|
const { getNavigationSearch } = useContext(NavigationCtx);
|
||||||
|
|
||||||
|
//Инициализация каталогов планов
|
||||||
const initPlanCtlgs = useCallback(async () => {
|
const initPlanCtlgs = useCallback(async () => {
|
||||||
if (!state.init) {
|
if (!state.init) {
|
||||||
const data = await executeStored({
|
const data = await executeStored({
|
||||||
@ -307,7 +312,7 @@ const MechRecCostProdPlans = () => {
|
|||||||
async (level = null, sort = null) => {
|
async (level = null, sort = null) => {
|
||||||
const data = await executeStored({
|
const data = await executeStored({
|
||||||
stored: "PKG_P8PANELS_MECHREC.FCPRODPLANSP_GET",
|
stored: "PKG_P8PANELS_MECHREC.FCPRODPLANSP_GET",
|
||||||
args: { NCRN: state.selectedPlanCtlg, NLEVEL: level, SSORT_FIELD: sort }
|
args: { NCRN: state.selectedPlanCtlg, NLEVEL: level, SSORT_FIELD: sort, NFCPRODPLANSP: state.planSpec }
|
||||||
});
|
});
|
||||||
let doc = await parseProdPlanSpXML(data.COUT);
|
let doc = await parseProdPlanSpXML(data.COUT);
|
||||||
setState(pv => ({
|
setState(pv => ({
|
||||||
@ -324,7 +329,7 @@ const MechRecCostProdPlans = () => {
|
|||||||
}));
|
}));
|
||||||
},
|
},
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
[executeStored, state.ident, state.selectedPlanCtlg]
|
[executeStored, state.ident, state.selectedPlanCtlg, state.planSpec]
|
||||||
);
|
);
|
||||||
|
|
||||||
//Обработка нажатия на элемент в списке каталогов планов
|
//Обработка нажатия на элемент в списке каталогов планов
|
||||||
@ -335,14 +340,16 @@ const MechRecCostProdPlans = () => {
|
|||||||
|
|
||||||
//При подключении компонента к странице
|
//При подключении компонента к странице
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
initPlanCtlgs();
|
const actionPrms = getNavigationSearch();
|
||||||
|
if (actionPrms.NSPRN) setState(pv => ({ ...pv, planSpec: parseInt(actionPrms.NSPRN), init: true }));
|
||||||
|
else initPlanCtlgs();
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
//При смене выбранного каталога плана
|
//При смене выбранного каталога плана или при явном указании позиции спецификации плана
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (state.selectedPlanCtlg) loadPlanCtglSpecs(null, SORT_REP_DATE_TO);
|
if (state.selectedPlanCtlg || state.planSpec) loadPlanCtglSpecs(null, SORT_REP_DATE_TO);
|
||||||
}, [state.selectedPlanCtlg, loadPlanCtglSpecs]);
|
}, [state.selectedPlanCtlg, state.planSpec, loadPlanCtglSpecs]);
|
||||||
|
|
||||||
//Выбор уровня
|
//Выбор уровня
|
||||||
const handleChangeSelectLevel = selectedLevel => {
|
const handleChangeSelectLevel = selectedLevel => {
|
||||||
@ -368,7 +375,9 @@ const MechRecCostProdPlans = () => {
|
|||||||
|
|
||||||
//Генерация содержимого
|
//Генерация содержимого
|
||||||
return (
|
return (
|
||||||
<Box p={2}>
|
<Box>
|
||||||
|
{!state.planSpec ? (
|
||||||
|
<>
|
||||||
<Fab variant="extended" sx={STYLES.PLANS_BUTTON} onClick={() => setState(pv => ({ ...pv, showPlanList: !pv.showPlanList }))}>
|
<Fab variant="extended" sx={STYLES.PLANS_BUTTON} onClick={() => setState(pv => ({ ...pv, showPlanList: !pv.showPlanList }))}>
|
||||||
Каталоги планов
|
Каталоги планов
|
||||||
</Fab>
|
</Fab>
|
||||||
@ -386,17 +395,28 @@ const MechRecCostProdPlans = () => {
|
|||||||
onClick={handleProjectClick}
|
onClick={handleProjectClick}
|
||||||
/>
|
/>
|
||||||
</Drawer>
|
</Drawer>
|
||||||
|
</>
|
||||||
|
) : null}
|
||||||
{state.init == true ? (
|
{state.init == true ? (
|
||||||
<Grid container spacing={1}>
|
<Grid container>
|
||||||
<Grid item xs={12}>
|
<Grid item xs={12}>
|
||||||
{state.selectedPlanCtlgSpecsLoaded ? (
|
{state.selectedPlanCtlgSpecsLoaded ? (
|
||||||
state.selectedPlanCtlgSpecs.length === 0 ? (
|
state.selectedPlanCtlgSpecs.length === 0 ? (
|
||||||
<InlineMsgInfo okBtn={false} text={"В каталоге планов отсутствуют записи спецификации"} />
|
<Box pt={3}>
|
||||||
|
<InlineMsgInfo
|
||||||
|
okBtn={false}
|
||||||
|
text={
|
||||||
|
state.planSpec
|
||||||
|
? "Не найдено данных для выбранной позиции плана"
|
||||||
|
: "В каталоге планов отсутствуют записи спецификации"
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
) : (
|
) : (
|
||||||
<Box sx={STYLES.GANTT_CONTAINER} p={1}>
|
<Box>
|
||||||
{state.selectedPlanCtlgMaxLevel ? (
|
{state.selectedPlanCtlgMaxLevel ? (
|
||||||
<Box sx={{ display: "table", float: "right" }}>
|
<Box sx={STYLES.FILTERS} p={1}>
|
||||||
<Box sx={{ display: "table-cell", verticalAlign: "middle" }}>
|
<Box sx={STYLES.FILTERS_DATE}>
|
||||||
<InputLabel id="select-label-sort">Сортировка</InputLabel>
|
<InputLabel id="select-label-sort">Сортировка</InputLabel>
|
||||||
<Select
|
<Select
|
||||||
labelId="select-label-sort"
|
labelId="select-label-sort"
|
||||||
@ -416,7 +436,7 @@ const MechRecCostProdPlans = () => {
|
|||||||
</MenuItem>
|
</MenuItem>
|
||||||
</Select>
|
</Select>
|
||||||
</Box>
|
</Box>
|
||||||
<Box sx={{ display: "table-cell", verticalAlign: "middle", paddingLeft: "15px" }}>
|
<Box sx={STYLES.FILTERS_LEVEL}>
|
||||||
<InputLabel id="select-label-level">До уровня</InputLabel>
|
<InputLabel id="select-label-level">До уровня</InputLabel>
|
||||||
<Select
|
<Select
|
||||||
labelId="select-label-level"
|
labelId="select-label-level"
|
||||||
@ -440,7 +460,7 @@ const MechRecCostProdPlans = () => {
|
|||||||
<P8PGantt
|
<P8PGantt
|
||||||
{...P8P_GANTT_CONFIG_PROPS}
|
{...P8P_GANTT_CONFIG_PROPS}
|
||||||
{...state.selectedPlanCtlgGanttDef}
|
{...state.selectedPlanCtlgGanttDef}
|
||||||
height={GANTT_HEIGHT}
|
containerStyle={STYLES.GANTT_CONTAINER}
|
||||||
titleStyle={STYLES.GANTT_TITLE}
|
titleStyle={STYLES.GANTT_TITLE}
|
||||||
tasks={state.selectedPlanCtlgSpecs}
|
tasks={state.selectedPlanCtlgSpecs}
|
||||||
taskDialogRenderer={prms => taskDialogRenderer({ ...prms, handleTaskDetailOpen })}
|
taskDialogRenderer={prms => taskDialogRenderer({ ...prms, handleTaskDetailOpen })}
|
||||||
@ -448,7 +468,16 @@ const MechRecCostProdPlans = () => {
|
|||||||
</Box>
|
</Box>
|
||||||
)
|
)
|
||||||
) : !state.selectedPlanCtlg ? (
|
) : !state.selectedPlanCtlg ? (
|
||||||
<InlineMsgInfo okBtn={false} text={"Укажите каталог планов для отображения их спецификаций"} />
|
<Box pt={3}>
|
||||||
|
<InlineMsgInfo
|
||||||
|
okBtn={false}
|
||||||
|
text={
|
||||||
|
state.planSpec
|
||||||
|
? "Загружаю график для выбранной позиции плана..."
|
||||||
|
: "Укажите каталог планов для отображения их спецификаций"
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
) : null}
|
) : null}
|
||||||
</Grid>
|
</Grid>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
@ -34,9 +34,20 @@ const currentDate = new Date();
|
|||||||
const currentMonth = currentDate.getUTCMonth() + 1;
|
const currentMonth = currentDate.getUTCMonth() + 1;
|
||||||
const currentYear = currentDate.getUTCFullYear();
|
const currentYear = currentDate.getUTCFullYear();
|
||||||
|
|
||||||
|
//Высота фильтра
|
||||||
|
const FILTER_HEIGHT = "68px";
|
||||||
|
|
||||||
//Стили
|
//Стили
|
||||||
const STYLES = {
|
const STYLES = {
|
||||||
FILTER_BLOCK: { maxWidth: "200px" }
|
FILTER_CONTAINER: {
|
||||||
|
height: FILTER_HEIGHT,
|
||||||
|
overflow: "hidden",
|
||||||
|
display: "flex",
|
||||||
|
flexDirection: "row",
|
||||||
|
justifyContent: "flex-start",
|
||||||
|
alignItems: "flex-end"
|
||||||
|
},
|
||||||
|
FILTER_BLOCK: { maxWidth: "200px", display: "flex" }
|
||||||
};
|
};
|
||||||
|
|
||||||
//------------------------------------
|
//------------------------------------
|
||||||
@ -71,7 +82,7 @@ DepartmentsDataGrid.propTypes = {
|
|||||||
//Компонент фильтра
|
//Компонент фильтра
|
||||||
const FilterComponent = ({ filter, setFilter, handleMonthChange, handleSelectDeparture }) => {
|
const FilterComponent = ({ filter, setFilter, handleMonthChange, handleSelectDeparture }) => {
|
||||||
return (
|
return (
|
||||||
<Box display="flex" flexDirection="row" justifyContent="flex-start" alignItems="flex-end" pt={1.5} pl={1}>
|
<Box sx={STYLES.FILTER_CONTAINER} pt={1.5} pl={1}>
|
||||||
<FormControl sx={STYLES.FILTER_BLOCK} readOnly fullWidth variant="outlined">
|
<FormControl sx={STYLES.FILTER_BLOCK} readOnly fullWidth variant="outlined">
|
||||||
<InputLabel required={!filter.department.SCODE} htmlFor="department-outlined">
|
<InputLabel required={!filter.department.SCODE} htmlFor="department-outlined">
|
||||||
Цех
|
Цех
|
||||||
@ -95,7 +106,7 @@ const FilterComponent = ({ filter, setFilter, handleMonthChange, handleSelectDep
|
|||||||
label="Цех"
|
label="Цех"
|
||||||
/>
|
/>
|
||||||
</FormControl>
|
</FormControl>
|
||||||
<Box sx={STYLES.FILTER_BLOCK} display="flex" pb={1}>
|
<Box sx={STYLES.FILTER_BLOCK} pb={1}>
|
||||||
<Box>
|
<Box>
|
||||||
<IconButton onClick={() => handleMonthChange(-1)}>
|
<IconButton onClick={() => handleMonthChange(-1)}>
|
||||||
<Icon>navigate_before</Icon>
|
<Icon>navigate_before</Icon>
|
||||||
@ -134,4 +145,4 @@ FilterComponent.propTypes = {
|
|||||||
//Интерфейс модуля
|
//Интерфейс модуля
|
||||||
//----------------
|
//----------------
|
||||||
|
|
||||||
export { FilterComponent };
|
export { FILTER_HEIGHT, FilterComponent };
|
||||||
|
@ -20,7 +20,8 @@ import { useInsDepartment } from "../hooks"; //Состояние таблицы
|
|||||||
|
|
||||||
//Стили
|
//Стили
|
||||||
const STYLES = {
|
const STYLES = {
|
||||||
CONTAINER: { margin: "5px 0px", textAlign: "center" }
|
CONTAINER: { margin: "5px 0px", textAlign: "center" },
|
||||||
|
DATA_GRID_CELL_DEFAULT: { cursor: "pointer", backgroundColor: "#ADD8E6" }
|
||||||
};
|
};
|
||||||
|
|
||||||
//------------------------------------
|
//------------------------------------
|
||||||
@ -30,7 +31,7 @@ const STYLES = {
|
|||||||
//Генерация ссылок на строках
|
//Генерация ссылок на строках
|
||||||
const dataCellRender = ({ row, columnDef, handleSelectDeparture }) => {
|
const dataCellRender = ({ row, columnDef, handleSelectDeparture }) => {
|
||||||
return {
|
return {
|
||||||
cellStyle: { cursor: "pointer", backgroundColor: "#ADD8E6" },
|
cellStyle: { ...STYLES.DATA_GRID_CELL_DEFAULT },
|
||||||
cellProps: {
|
cellProps: {
|
||||||
onClick: () => {
|
onClick: () => {
|
||||||
handleSelectDeparture({ NRN: row["NRN"], SCODE: row["SCODE"].toString(), SNAME: row["SNAME"] });
|
handleSelectDeparture({ NRN: row["NRN"], SCODE: row["SCODE"].toString(), SNAME: row["SNAME"] });
|
||||||
|
@ -178,7 +178,7 @@ const useFilter = (currentMonth, currentYear) => {
|
|||||||
openedDepartment: false,
|
openedDepartment: false,
|
||||||
department: { ...department },
|
department: { ...department },
|
||||||
workHours: data.NWORKHOURS,
|
workHours: data.NWORKHOURS,
|
||||||
totalWorkHours: filter.workDays * data.NWORKHOURS
|
totalWorkHours: Math.round(filter.workDays * data.NWORKHOURS)
|
||||||
}));
|
}));
|
||||||
},
|
},
|
||||||
[executeStored, filter.workDays]
|
[executeStored, filter.workDays]
|
||||||
|
@ -10,9 +10,11 @@
|
|||||||
import React from "react"; //Классы React
|
import React from "react"; //Классы React
|
||||||
import { Typography, Box } from "@mui/material"; //Интерфейсные элементы
|
import { Typography, Box } from "@mui/material"; //Интерфейсные элементы
|
||||||
import { P8PDataGrid, P8P_DATA_GRID_SIZE } from "../../components/p8p_data_grid"; //Таблица данных
|
import { P8PDataGrid, P8P_DATA_GRID_SIZE } from "../../components/p8p_data_grid"; //Таблица данных
|
||||||
|
import { APP_STYLES } from "../../../app.styles"; //Типовые стили
|
||||||
|
import { APP_BAR_HEIGHT } from "../../components/p8p_app_workspace"; //Заголовок страницы
|
||||||
import { P8P_DATA_GRID_CONFIG_PROPS } from "../../config_wrapper"; //Подключение компонентов к настройкам приложения
|
import { P8P_DATA_GRID_CONFIG_PROPS } from "../../config_wrapper"; //Подключение компонентов к настройкам приложения
|
||||||
import { useMechRecDeptCostJobs, useFilter } from "./hooks"; //Кастомные состояния
|
import { useMechRecDeptCostJobs, useFilter } from "./hooks"; //Кастомные состояния
|
||||||
import { FilterComponent } from "./components/filter"; //Компонент фильтра
|
import { FILTER_HEIGHT, FilterComponent } from "./components/filter"; //Компонент фильтра
|
||||||
|
|
||||||
//---------
|
//---------
|
||||||
//Константы
|
//Константы
|
||||||
@ -24,21 +26,26 @@ const currentMonth = currentDate.getUTCMonth() + 1;
|
|||||||
const currentYear = currentDate.getUTCFullYear();
|
const currentYear = currentDate.getUTCFullYear();
|
||||||
|
|
||||||
//Кастомные цвета
|
//Кастомные цвета
|
||||||
const colors = {
|
const COLORS = {
|
||||||
lightred: "#ef8989",
|
LIGHTRED: "#ef8989",
|
||||||
lightyellow: "#f5f5b0",
|
LIGHTYELLOW: "#f5f5b0",
|
||||||
blue: "#0097ff"
|
BLUE: "#0097ff"
|
||||||
};
|
};
|
||||||
|
|
||||||
|
//Высота заголовка
|
||||||
|
const TITLE_HEIGHT = "35px";
|
||||||
|
|
||||||
|
//Нижний отступ заголовка
|
||||||
|
const TITLE_PADDING_BOTTOM = "15px";
|
||||||
|
|
||||||
//Стили
|
//Стили
|
||||||
const STYLES = {
|
const STYLES = {
|
||||||
CONTAINER: { textAlign: "center", paddingTop: "10px" },
|
CONTAINER: { textAlign: "center", paddingTop: "10px" },
|
||||||
TITLE: { paddingBottom: "15px" },
|
TITLE: { height: TITLE_HEIGHT, overflow: "hidden", paddingBottom: TITLE_PADDING_BOTTOM },
|
||||||
DATA_GRID_CONTAINER: {
|
DATA_GRID_CONTAINER: {
|
||||||
minWidth: "700px",
|
height: `calc(100vh - ${APP_BAR_HEIGHT} - ${TITLE_HEIGHT} - ${TITLE_PADDING_BOTTOM} - ${FILTER_HEIGHT} - 10px)`,
|
||||||
maxWidth: "100vw",
|
width: "99vw",
|
||||||
minHeight: "calc(100vh - 250px)",
|
...APP_STYLES.SCROLL
|
||||||
maxHeight: "calc(100vh - 250px)"
|
|
||||||
},
|
},
|
||||||
DATA_GRID_CELL: (row, columnDef) => {
|
DATA_GRID_CELL: (row, columnDef) => {
|
||||||
//Определяем тип дня
|
//Определяем тип дня
|
||||||
@ -53,12 +60,12 @@ const STYLES = {
|
|||||||
...(dayType
|
...(dayType
|
||||||
? {
|
? {
|
||||||
backgroundColor: [1, 3].includes(dayType) ? "lightgrey" : dayType === 4 ? "lightgreen" : null,
|
backgroundColor: [1, 3].includes(dayType) ? "lightgrey" : dayType === 4 ? "lightgreen" : null,
|
||||||
color: [2, 3].includes(dayType) ? colors.blue : null
|
color: [2, 3].includes(dayType) ? COLORS.BLUE : null
|
||||||
}
|
}
|
||||||
: procentLoad || procentLoad === 0
|
: procentLoad || procentLoad === 0
|
||||||
? {
|
? {
|
||||||
backgroundColor:
|
backgroundColor:
|
||||||
procentLoad >= 85 ? "lightgreen" : procentLoad >= 50 ? colors.lightyellow : procentLoad > 0 ? colors.lightred : "lightgrey"
|
procentLoad >= 85 ? "lightgreen" : procentLoad >= 50 ? COLORS.LIGHTYELLOW : procentLoad > 0 ? COLORS.LIGHTRED : "lightgrey"
|
||||||
}
|
}
|
||||||
: {})
|
: {})
|
||||||
};
|
};
|
||||||
@ -141,7 +148,7 @@ const MechRecDeptCostJobs = () => {
|
|||||||
{costJobs.dataLoaded ? (
|
{costJobs.dataLoaded ? (
|
||||||
<P8PDataGrid
|
<P8PDataGrid
|
||||||
{...P8P_DATA_GRID_CONFIG_PROPS}
|
{...P8P_DATA_GRID_CONFIG_PROPS}
|
||||||
containerComponentProps={{ elevation: 6, style: STYLES.DATA_GRID_CONTAINER }}
|
containerComponentProps={{ elevation: 6, sx: STYLES.DATA_GRID_CONTAINER }}
|
||||||
fixedHeader={costJobs.fixedHeader}
|
fixedHeader={costJobs.fixedHeader}
|
||||||
fixedColumns={costJobs.fixedColumns}
|
fixedColumns={costJobs.fixedColumns}
|
||||||
columnsDef={costJobs.columnsDef}
|
columnsDef={costJobs.columnsDef}
|
||||||
|
@ -10,6 +10,8 @@
|
|||||||
import React, { useContext, useState } from "react"; //Классы React
|
import React, { useContext, useState } from "react"; //Классы React
|
||||||
import PropTypes from "prop-types"; //Контроль свойств компонента
|
import PropTypes from "prop-types"; //Контроль свойств компонента
|
||||||
import { Drawer, Fab, Box, List, ListItemButton, ListItemText, Typography, TextField, Link, Grid } from "@mui/material"; //Интерфейсные элементы
|
import { Drawer, Fab, Box, List, ListItemButton, ListItemText, Typography, TextField, Link, Grid } from "@mui/material"; //Интерфейсные элементы
|
||||||
|
import { APP_STYLES } from "../../../app.styles"; //Типовые стили
|
||||||
|
import { APP_BAR_HEIGHT } from "../../components/p8p_app_workspace"; //Заголовок страницы
|
||||||
import { useDeptCostProdPlans, useFilteredPlans } from "./hooks"; //Вспомогательные хуки
|
import { useDeptCostProdPlans, useFilteredPlans } from "./hooks"; //Вспомогательные хуки
|
||||||
import { P8PDataGrid, P8P_DATA_GRID_SIZE } from "../../components/p8p_data_grid"; //Таблица данных
|
import { P8PDataGrid, P8P_DATA_GRID_SIZE } from "../../components/p8p_data_grid"; //Таблица данных
|
||||||
import { P8P_DATA_GRID_CONFIG_PROPS } from "../../config_wrapper"; //Подключение компонентов к настройкам приложения
|
import { P8P_DATA_GRID_CONFIG_PROPS } from "../../config_wrapper"; //Подключение компонентов к настройкам приложения
|
||||||
@ -21,6 +23,15 @@ import { CostRouteListsDataGridDialog } from "./fcroutlst"; //Диалог ма
|
|||||||
//Константы
|
//Константы
|
||||||
//---------
|
//---------
|
||||||
|
|
||||||
|
//Высота заголовка
|
||||||
|
const TITLE_HEIGHT = "35px";
|
||||||
|
|
||||||
|
//Верхний отступ заголовка
|
||||||
|
const TITLE_PADDING_TOP = "10px";
|
||||||
|
|
||||||
|
//Нижний отступ заголовка
|
||||||
|
const TITLE_PADDING_BOTTOM = "20px";
|
||||||
|
|
||||||
//Стили
|
//Стили
|
||||||
const STYLES = {
|
const STYLES = {
|
||||||
PLANS_FINDER: { marginTop: "10px", marginLeft: "10px", width: "93%" },
|
PLANS_FINDER: { marginTop: "10px", marginLeft: "10px", width: "93%" },
|
||||||
@ -33,7 +44,12 @@ const STYLES = {
|
|||||||
[`& .MuiDrawer-paper`]: { width: "350px", display: "inline-block", boxSizing: "border-box" }
|
[`& .MuiDrawer-paper`]: { width: "350px", display: "inline-block", boxSizing: "border-box" }
|
||||||
},
|
},
|
||||||
CONTAINER: { textAlign: "center" },
|
CONTAINER: { textAlign: "center" },
|
||||||
DATA_GRID_CONTAINER: { minWidth: "95vw", maxWidth: "95vw", minHeight: "80vh", maxHeight: "80vh" },
|
TITLE: { height: TITLE_HEIGHT, overflow: "hidden", paddingTop: TITLE_PADDING_TOP, paddingBottom: TITLE_PADDING_BOTTOM, display: "inline-table" },
|
||||||
|
DATA_GRID_CONTAINER: {
|
||||||
|
height: `calc(100vh - ${APP_BAR_HEIGHT} - ${TITLE_HEIGHT} - ${TITLE_PADDING_TOP} - ${TITLE_PADDING_BOTTOM} - 29px)`,
|
||||||
|
width: "98vw",
|
||||||
|
...APP_STYLES.SCROLL
|
||||||
|
},
|
||||||
DATA_GRID_GROUP_CELL: { padding: "2px" },
|
DATA_GRID_GROUP_CELL: { padding: "2px" },
|
||||||
DATA_GRID_CELL: { padding: "8px", maxWidth: "300px", textOverflow: "ellipsis", overflow: "hidden", whiteSpace: "pre" },
|
DATA_GRID_CELL: { padding: "8px", maxWidth: "300px", textOverflow: "ellipsis", overflow: "hidden", whiteSpace: "pre" },
|
||||||
DATA_GRID_CELL_STATUS: (currentStyle, row) => ({ backgroundColor: getRowBackgroudColor(row), ...currentStyle }),
|
DATA_GRID_CELL_STATUS: (currentStyle, row) => ({ backgroundColor: getRowBackgroudColor(row), ...currentStyle }),
|
||||||
@ -263,7 +279,7 @@ const MechRecDeptCostProdPlans = () => {
|
|||||||
onClick={handlePlanClick}
|
onClick={handlePlanClick}
|
||||||
/>
|
/>
|
||||||
</Drawer>
|
</Drawer>
|
||||||
<Grid container spacing={1}>
|
<Grid container>
|
||||||
<Grid item xs={12}>
|
<Grid item xs={12}>
|
||||||
<Box display="flex" justifyContent="center" alignItems="center">
|
<Box display="flex" justifyContent="center" alignItems="center">
|
||||||
{state.dataLoaded ? (
|
{state.dataLoaded ? (
|
||||||
@ -271,13 +287,13 @@ const MechRecDeptCostProdPlans = () => {
|
|||||||
<InlineMsgInfo okBtn={false} text={"В плане отсутствуют записи спецификации"} />
|
<InlineMsgInfo okBtn={false} text={"В плане отсутствуют записи спецификации"} />
|
||||||
) : (
|
) : (
|
||||||
<Box sx={STYLES.CONTAINER}>
|
<Box sx={STYLES.CONTAINER}>
|
||||||
<Typography pt={1} variant={"h6"}>
|
<Typography sx={STYLES.TITLE} variant={"h6"}>
|
||||||
{`Производственный план цеха №${state.selectedPlan.SSUBDIV} на ${state.selectedPlan.SPERIOD}`}
|
{`Производственный план цеха №${state.selectedPlan.SSUBDIV} на ${state.selectedPlan.SPERIOD}`}
|
||||||
</Typography>
|
</Typography>
|
||||||
<Box pt={2.5}>
|
<Box>
|
||||||
<P8PDataGrid
|
<P8PDataGrid
|
||||||
{...P8P_DATA_GRID_CONFIG_PROPS}
|
{...P8P_DATA_GRID_CONFIG_PROPS}
|
||||||
containerComponentProps={{ elevation: 6, style: STYLES.DATA_GRID_CONTAINER }}
|
containerComponentProps={{ elevation: 6, sx: STYLES.DATA_GRID_CONTAINER }}
|
||||||
fixedHeader={state.fixedHeader}
|
fixedHeader={state.fixedHeader}
|
||||||
fixedColumns={state.fixedColumns}
|
fixedColumns={state.fixedColumns}
|
||||||
columnsDef={state.columnsDef}
|
columnsDef={state.columnsDef}
|
||||||
|
BIN
app/panels/mech_rec_help/img/1_1.png
Normal file
After Width: | Height: | Size: 86 KiB |
BIN
app/panels/mech_rec_help/img/1_2.png
Normal file
After Width: | Height: | Size: 101 KiB |
BIN
app/panels/mech_rec_help/img/1_3.png
Normal file
After Width: | Height: | Size: 64 KiB |
BIN
app/panels/mech_rec_help/img/1_4.png
Normal file
After Width: | Height: | Size: 44 KiB |
BIN
app/panels/mech_rec_help/img/1_5.png
Normal file
After Width: | Height: | Size: 114 KiB |
BIN
app/panels/mech_rec_help/img/21_1.png
Normal file
After Width: | Height: | Size: 60 KiB |
BIN
app/panels/mech_rec_help/img/21_2.png
Normal file
After Width: | Height: | Size: 172 KiB |
BIN
app/panels/mech_rec_help/img/21_3.png
Normal file
After Width: | Height: | Size: 37 KiB |
BIN
app/panels/mech_rec_help/img/2_1.png
Normal file
After Width: | Height: | Size: 32 KiB |
BIN
app/panels/mech_rec_help/img/2_2.png
Normal file
After Width: | Height: | Size: 118 KiB |
BIN
app/panels/mech_rec_help/img/2_3.png
Normal file
After Width: | Height: | Size: 66 KiB |
BIN
app/panels/mech_rec_help/img/2_4.png
Normal file
After Width: | Height: | Size: 125 KiB |
BIN
app/panels/mech_rec_help/img/2_5.png
Normal file
After Width: | Height: | Size: 85 KiB |
BIN
app/panels/mech_rec_help/img/31_1.png
Normal file
After Width: | Height: | Size: 57 KiB |
BIN
app/panels/mech_rec_help/img/31_10.png
Normal file
After Width: | Height: | Size: 37 KiB |
BIN
app/panels/mech_rec_help/img/31_2.png
Normal file
After Width: | Height: | Size: 19 KiB |
BIN
app/panels/mech_rec_help/img/31_3.png
Normal file
After Width: | Height: | Size: 74 KiB |
BIN
app/panels/mech_rec_help/img/31_4.png
Normal file
After Width: | Height: | Size: 35 KiB |
BIN
app/panels/mech_rec_help/img/31_5.png
Normal file
After Width: | Height: | Size: 65 KiB |
BIN
app/panels/mech_rec_help/img/31_6.png
Normal file
After Width: | Height: | Size: 26 KiB |
BIN
app/panels/mech_rec_help/img/31_7.png
Normal file
After Width: | Height: | Size: 90 KiB |
BIN
app/panels/mech_rec_help/img/31_8.png
Normal file
After Width: | Height: | Size: 70 KiB |
BIN
app/panels/mech_rec_help/img/31_9.png
Normal file
After Width: | Height: | Size: 64 KiB |
BIN
app/panels/mech_rec_help/img/32_1.png
Normal file
After Width: | Height: | Size: 82 KiB |
BIN
app/panels/mech_rec_help/img/32_2.png
Normal file
After Width: | Height: | Size: 57 KiB |
BIN
app/panels/mech_rec_help/img/32_3.png
Normal file
After Width: | Height: | Size: 106 KiB |
BIN
app/panels/mech_rec_help/img/33_1.png
Normal file
After Width: | Height: | Size: 129 KiB |
BIN
app/panels/mech_rec_help/img/33_2.png
Normal file
After Width: | Height: | Size: 16 KiB |
BIN
app/panels/mech_rec_help/img/33_3.png
Normal file
After Width: | Height: | Size: 48 KiB |
BIN
app/panels/mech_rec_help/img/33_4.png
Normal file
After Width: | Height: | Size: 113 KiB |
BIN
app/panels/mech_rec_help/img/34_1.png
Normal file
After Width: | Height: | Size: 35 KiB |
BIN
app/panels/mech_rec_help/img/34_2.png
Normal file
After Width: | Height: | Size: 88 KiB |
BIN
app/panels/mech_rec_help/img/34_3.png
Normal file
After Width: | Height: | Size: 30 KiB |
BIN
app/panels/mech_rec_help/img/34_4.png
Normal file
After Width: | Height: | Size: 94 KiB |
BIN
app/panels/mech_rec_help/img/34_5.png
Normal file
After Width: | Height: | Size: 68 KiB |
BIN
app/panels/mech_rec_help/img/34_6.png
Normal file
After Width: | Height: | Size: 122 KiB |
BIN
app/panels/mech_rec_help/img/34_7.png
Normal file
After Width: | Height: | Size: 17 KiB |
BIN
app/panels/mech_rec_help/img/34_8.png
Normal file
After Width: | Height: | Size: 52 KiB |
BIN
app/panels/mech_rec_help/img/35_1.png
Normal file
After Width: | Height: | Size: 93 KiB |
BIN
app/panels/mech_rec_help/img/3_1.png
Normal file
After Width: | Height: | Size: 40 KiB |
BIN
app/panels/mech_rec_help/img/410_1.png
Normal file
After Width: | Height: | Size: 86 KiB |
BIN
app/panels/mech_rec_help/img/410_2.png
Normal file
After Width: | Height: | Size: 119 KiB |
BIN
app/panels/mech_rec_help/img/410_3.png
Normal file
After Width: | Height: | Size: 43 KiB |
BIN
app/panels/mech_rec_help/img/410_4.png
Normal file
After Width: | Height: | Size: 75 KiB |
BIN
app/panels/mech_rec_help/img/410_5.png
Normal file
After Width: | Height: | Size: 31 KiB |
BIN
app/panels/mech_rec_help/img/410_6.png
Normal file
After Width: | Height: | Size: 63 KiB |
BIN
app/panels/mech_rec_help/img/410_7.png
Normal file
After Width: | Height: | Size: 65 KiB |
BIN
app/panels/mech_rec_help/img/411_1.png
Normal file
After Width: | Height: | Size: 83 KiB |
BIN
app/panels/mech_rec_help/img/411_2.png
Normal file
After Width: | Height: | Size: 158 KiB |
BIN
app/panels/mech_rec_help/img/411_3.png
Normal file
After Width: | Height: | Size: 89 KiB |
BIN
app/panels/mech_rec_help/img/411_4.png
Normal file
After Width: | Height: | Size: 99 KiB |
BIN
app/panels/mech_rec_help/img/412_1.png
Normal file
After Width: | Height: | Size: 116 KiB |
BIN
app/panels/mech_rec_help/img/412_2.png
Normal file
After Width: | Height: | Size: 26 KiB |
BIN
app/panels/mech_rec_help/img/412_3.png
Normal file
After Width: | Height: | Size: 66 KiB |
BIN
app/panels/mech_rec_help/img/412_4.png
Normal file
After Width: | Height: | Size: 57 KiB |
BIN
app/panels/mech_rec_help/img/413_1.png
Normal file
After Width: | Height: | Size: 67 KiB |
BIN
app/panels/mech_rec_help/img/413_2.png
Normal file
After Width: | Height: | Size: 131 KiB |
BIN
app/panels/mech_rec_help/img/413_3.png
Normal file
After Width: | Height: | Size: 66 KiB |
BIN
app/panels/mech_rec_help/img/413_4.png
Normal file
After Width: | Height: | Size: 48 KiB |
BIN
app/panels/mech_rec_help/img/413_5.png
Normal file
After Width: | Height: | Size: 64 KiB |
BIN
app/panels/mech_rec_help/img/414_1.png
Normal file
After Width: | Height: | Size: 28 KiB |
BIN
app/panels/mech_rec_help/img/414_2.png
Normal file
After Width: | Height: | Size: 22 KiB |
BIN
app/panels/mech_rec_help/img/414_3.png
Normal file
After Width: | Height: | Size: 105 KiB |
BIN
app/panels/mech_rec_help/img/41_1.png
Normal file
After Width: | Height: | Size: 155 KiB |
BIN
app/panels/mech_rec_help/img/41_10.png
Normal file
After Width: | Height: | Size: 100 KiB |
BIN
app/panels/mech_rec_help/img/41_11.png
Normal file
After Width: | Height: | Size: 77 KiB |
BIN
app/panels/mech_rec_help/img/41_12.png
Normal file
After Width: | Height: | Size: 73 KiB |
BIN
app/panels/mech_rec_help/img/41_2.png
Normal file
After Width: | Height: | Size: 42 KiB |
BIN
app/panels/mech_rec_help/img/41_3.png
Normal file
After Width: | Height: | Size: 48 KiB |
BIN
app/panels/mech_rec_help/img/41_4.png
Normal file
After Width: | Height: | Size: 72 KiB |
BIN
app/panels/mech_rec_help/img/41_5.png
Normal file
After Width: | Height: | Size: 64 KiB |
BIN
app/panels/mech_rec_help/img/41_6.png
Normal file
After Width: | Height: | Size: 72 KiB |
BIN
app/panels/mech_rec_help/img/41_7.png
Normal file
After Width: | Height: | Size: 74 KiB |
BIN
app/panels/mech_rec_help/img/41_8.png
Normal file
After Width: | Height: | Size: 91 KiB |
BIN
app/panels/mech_rec_help/img/41_9.png
Normal file
After Width: | Height: | Size: 81 KiB |
BIN
app/panels/mech_rec_help/img/42_1.png
Normal file
After Width: | Height: | Size: 99 KiB |
BIN
app/panels/mech_rec_help/img/42_2.png
Normal file
After Width: | Height: | Size: 39 KiB |
BIN
app/panels/mech_rec_help/img/42_3.png
Normal file
After Width: | Height: | Size: 38 KiB |
BIN
app/panels/mech_rec_help/img/42_4.png
Normal file
After Width: | Height: | Size: 39 KiB |