forked from CITKParus/P8-Panels
ЦИТК-1076 - Добавлен единый стиль P8P* компонентов
This commit is contained in:
parent
55ec11dc55
commit
e243a85a4a
@ -19,7 +19,13 @@ import Button from "@mui/material/Button"; //Кнопки
|
|||||||
import Container from "@mui/material/Container"; //Контейнер
|
import Container from "@mui/material/Container"; //Контейнер
|
||||||
import Box from "@mui/material/Box"; //Обёртка
|
import Box from "@mui/material/Box"; //Обёртка
|
||||||
import { BUTTONS, STATE } from "../../app.text"; //Типовые текстовые ресурсы и константы
|
import { BUTTONS, STATE } from "../../app.text"; //Типовые текстовые ресурсы и константы
|
||||||
import { APP_COLORS } from "../../app.styles"; //Типовые стили
|
import { useTheme } from "@mui/material"; //Тема
|
||||||
|
import { P8P_TYPOGRAPHY_VARIANT } from "../theme/p8p_typography"; //Варианты шрифтов
|
||||||
|
import { P8P_DIALOG_TITLE_VARIANT } from "../theme/variants/p8p_dialog_title_variants"; //Варианты заголовков диалога
|
||||||
|
import { P8P_BUTTON_VARIANT } from "../theme/variants/p8p_button_variants"; //Варианты кнопок
|
||||||
|
import { P8P_CONTAINER_VARIANT } from "../theme/variants/p8p_container_variants"; //Варианты контейнеров
|
||||||
|
import { P8P_DIALOG_CONTENT_VARIANT } from "../theme/variants/p8p_dialog_content_variants"; //Варианты содержимого диалогов
|
||||||
|
import { P8P_DIALOG_CONTENT_TEXT_VARIANT } from "../theme/variants/p8p_dialog_content_text_variants"; //Варианты текста содержимого диалога
|
||||||
|
|
||||||
//---------
|
//---------
|
||||||
//Константы
|
//Константы
|
||||||
@ -32,44 +38,6 @@ const P8P_APP_MESSAGE_VARIANT = {
|
|||||||
ERR: STATE.ERR
|
ERR: STATE.ERR
|
||||||
};
|
};
|
||||||
|
|
||||||
//Стили
|
|
||||||
const STYLES = {
|
|
||||||
DEFAULT: {
|
|
||||||
wordBreak: "break-word"
|
|
||||||
},
|
|
||||||
INFO: {
|
|
||||||
titleText: {
|
|
||||||
color: APP_COLORS[STATE.INFO].contrColor
|
|
||||||
},
|
|
||||||
bodyText: {
|
|
||||||
color: APP_COLORS[STATE.INFO].contrColor
|
|
||||||
}
|
|
||||||
},
|
|
||||||
WARN: {
|
|
||||||
titleText: {
|
|
||||||
color: APP_COLORS[STATE.WARN].contrColor
|
|
||||||
},
|
|
||||||
bodyText: {
|
|
||||||
color: APP_COLORS[STATE.WARN].contrColor
|
|
||||||
}
|
|
||||||
},
|
|
||||||
ERR: {
|
|
||||||
titleText: {
|
|
||||||
color: APP_COLORS[STATE.ERR].contrColor
|
|
||||||
},
|
|
||||||
bodyText: {
|
|
||||||
color: APP_COLORS[STATE.ERR].contrColor
|
|
||||||
}
|
|
||||||
},
|
|
||||||
INLINE_MESSAGE: {
|
|
||||||
with: "100%",
|
|
||||||
textAlign: "center"
|
|
||||||
},
|
|
||||||
FULL_ERROR_TEXT_BUTTON: {
|
|
||||||
color: APP_COLORS[STATE.WARN].contrColor
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
//-----------
|
//-----------
|
||||||
//Тело модуля
|
//Тело модуля
|
||||||
//-----------
|
//-----------
|
||||||
@ -94,37 +62,50 @@ const P8PAppMessage = ({
|
|||||||
//Состояние подробной информации об ошибке
|
//Состояние подробной информации об ошибке
|
||||||
const [showFullErrorText, setShowFullErrorText] = useState(false);
|
const [showFullErrorText, setShowFullErrorText] = useState(false);
|
||||||
|
|
||||||
//Подбор стиля и ресурсов
|
//Определяем вариант стилизации
|
||||||
let style = STYLES.INFO;
|
let titleVariant = P8P_DIALOG_TITLE_VARIANT.INFO;
|
||||||
|
let contentVariant = P8P_DIALOG_CONTENT_TEXT_VARIANT.INFO;
|
||||||
switch (variant) {
|
switch (variant) {
|
||||||
case P8P_APP_MESSAGE_VARIANT.INFO: {
|
case P8P_APP_MESSAGE_VARIANT.INFO: {
|
||||||
style = STYLES.INFO;
|
titleVariant = P8P_DIALOG_TITLE_VARIANT.INFO;
|
||||||
|
contentVariant = P8P_DIALOG_CONTENT_TEXT_VARIANT.INFO;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case P8P_APP_MESSAGE_VARIANT.WARN: {
|
case P8P_APP_MESSAGE_VARIANT.WARN: {
|
||||||
style = STYLES.WARN;
|
titleVariant = P8P_DIALOG_TITLE_VARIANT.WARN;
|
||||||
|
contentVariant = P8P_DIALOG_CONTENT_TEXT_VARIANT.WARN;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case P8P_APP_MESSAGE_VARIANT.ERR: {
|
case P8P_APP_MESSAGE_VARIANT.ERR: {
|
||||||
style = STYLES.ERR;
|
titleVariant = P8P_DIALOG_TITLE_VARIANT.ERROR;
|
||||||
|
contentVariant = P8P_DIALOG_CONTENT_TEXT_VARIANT.ERROR;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//Заголовок
|
//Заголовок
|
||||||
let titlePart;
|
let titlePart;
|
||||||
if (title && titleText) titlePart = <DialogTitle style={{ ...style.DEFAULT, ...style.titleText }}>{titleText}</DialogTitle>;
|
if (title && titleText)
|
||||||
|
titlePart = (
|
||||||
|
<DialogTitle variant={titleVariant}>
|
||||||
|
<Typography variant={P8P_TYPOGRAPHY_VARIANT.H7}>{titleText}</Typography>
|
||||||
|
</DialogTitle>
|
||||||
|
);
|
||||||
|
|
||||||
//Кнопка Отмена
|
//Кнопка Отмена
|
||||||
let cancelBtnPart;
|
let cancelBtnPart;
|
||||||
if (cancelBtn && cancelBtnCaption && variant === P8P_APP_MESSAGE_VARIANT.WARN)
|
if (cancelBtn && cancelBtnCaption && variant === P8P_APP_MESSAGE_VARIANT.WARN)
|
||||||
cancelBtnPart = <Button onClick={() => (onCancel ? onCancel() : null)}>{cancelBtnCaption}</Button>;
|
cancelBtnPart = (
|
||||||
|
<Button variant={P8P_BUTTON_VARIANT.TEXT} onClick={() => (onCancel ? onCancel() : null)}>
|
||||||
|
{cancelBtnCaption}
|
||||||
|
</Button>
|
||||||
|
);
|
||||||
|
|
||||||
//Кнопка OK
|
//Кнопка OK
|
||||||
let okBtnPart;
|
let okBtnPart;
|
||||||
if (okBtn && okBtnCaption)
|
if (okBtn && okBtnCaption)
|
||||||
okBtnPart = (
|
okBtnPart = (
|
||||||
<Button onClick={() => (onOk ? onOk() : null)} autoFocus>
|
<Button variant={P8P_BUTTON_VARIANT.TEXT} onClick={() => (onOk ? onOk() : null)} autoFocus>
|
||||||
{okBtnCaption}
|
{okBtnCaption}
|
||||||
</Button>
|
</Button>
|
||||||
);
|
);
|
||||||
@ -133,7 +114,7 @@ const P8PAppMessage = ({
|
|||||||
let fullErrorTextBtn;
|
let fullErrorTextBtn;
|
||||||
if (fullErrorText && showErrMoreCaption && hideErrMoreCaption && variant === P8P_APP_MESSAGE_VARIANT.ERR)
|
if (fullErrorText && showErrMoreCaption && hideErrMoreCaption && variant === P8P_APP_MESSAGE_VARIANT.ERR)
|
||||||
fullErrorTextBtn = (
|
fullErrorTextBtn = (
|
||||||
<Button onClick={() => setShowFullErrorText(!showFullErrorText)} sx={STYLES.FULL_ERROR_TEXT_BUTTON} autoFocus>
|
<Button variant={P8P_BUTTON_VARIANT.TEXT} color="P8PWarning" onClick={() => setShowFullErrorText(!showFullErrorText)} autoFocus>
|
||||||
{!showFullErrorText ? showErrMoreCaption : hideErrMoreCaption}
|
{!showFullErrorText ? showErrMoreCaption : hideErrMoreCaption}
|
||||||
</Button>
|
</Button>
|
||||||
);
|
);
|
||||||
@ -154,7 +135,7 @@ const P8PAppMessage = ({
|
|||||||
<Dialog open={open || false} onClose={() => (onCancel ? onCancel() : null)}>
|
<Dialog open={open || false} onClose={() => (onCancel ? onCancel() : null)}>
|
||||||
{titlePart}
|
{titlePart}
|
||||||
<DialogContent>
|
<DialogContent>
|
||||||
<DialogContentText style={style.bodyText}>{!showFullErrorText ? text : fullErrorText}</DialogContentText>
|
<DialogContentText variant={contentVariant}>{!showFullErrorText ? text : fullErrorText}</DialogContentText>
|
||||||
</DialogContent>
|
</DialogContent>
|
||||||
{actionsPart}
|
{actionsPart}
|
||||||
</Dialog>
|
</Dialog>
|
||||||
@ -181,24 +162,28 @@ P8PAppMessage.propTypes = {
|
|||||||
|
|
||||||
//Встроенное сообщение
|
//Встроенное сообщение
|
||||||
const P8PAppInlineMessage = ({ variant, text, okBtn, onOk, okBtnCaption }) => {
|
const P8PAppInlineMessage = ({ variant, text, okBtn, onOk, okBtnCaption }) => {
|
||||||
|
//Определяем тему
|
||||||
|
const theme = useTheme();
|
||||||
|
|
||||||
//Генерация содержимого
|
//Генерация содержимого
|
||||||
return (
|
return (
|
||||||
<Container style={STYLES.INLINE_MESSAGE}>
|
<Container variant={P8P_CONTAINER_VARIANT.INLINE_MSG}>
|
||||||
<Box p={1}>
|
<Box p={1}>
|
||||||
<Typography
|
<Typography
|
||||||
|
variant={P8P_TYPOGRAPHY_VARIANT.BODY1}
|
||||||
color={
|
color={
|
||||||
variant === P8P_APP_MESSAGE_VARIANT.ERR
|
variant === P8P_APP_MESSAGE_VARIANT.ERR
|
||||||
? APP_COLORS[STATE.ERR].contrColor
|
? theme.palette.P8PError.main
|
||||||
: variant === P8P_APP_MESSAGE_VARIANT.WARN
|
: variant === P8P_APP_MESSAGE_VARIANT.WARN
|
||||||
? APP_COLORS[STATE.WARN].contrColor
|
? theme.palette.P8PWarning.main
|
||||||
: APP_COLORS[STATE.INFO].contrColor
|
: theme.palette.P8PText.primary
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
{text}
|
{text}
|
||||||
</Typography>
|
</Typography>
|
||||||
{okBtn && okBtnCaption ? (
|
{okBtn && okBtnCaption ? (
|
||||||
<Box pt={1}>
|
<Box pt={1}>
|
||||||
<Button onClick={() => (onOk ? onOk() : null)} autoFocus>
|
<Button variant={P8P_BUTTON_VARIANT.TEXT} onClick={() => (onOk ? onOk() : null)} autoFocus>
|
||||||
{okBtnCaption}
|
{okBtnCaption}
|
||||||
</Button>
|
</Button>
|
||||||
</Box>
|
</Box>
|
||||||
@ -254,12 +239,14 @@ const P8PAppInlineInfo = props => buildVariantInlineMessage(props, P8P_APP_MESSA
|
|||||||
const P8PHintDialog = ({ title, hint, onOk }) => {
|
const P8PHintDialog = ({ title, hint, onOk }) => {
|
||||||
return (
|
return (
|
||||||
<Dialog open={true} onClose={e => (onOk ? onOk(e) : null)}>
|
<Dialog open={true} onClose={e => (onOk ? onOk(e) : null)}>
|
||||||
<DialogTitle>{title}</DialogTitle>
|
<DialogTitle variant={P8P_DIALOG_TITLE_VARIANT.PRIMARY}>{title}</DialogTitle>
|
||||||
<DialogContent>
|
<DialogContent variant={P8P_DIALOG_CONTENT_VARIANT.HINT}>
|
||||||
<div dangerouslySetInnerHTML={{ __html: hint }}></div>
|
<div dangerouslySetInnerHTML={{ __html: hint }}></div>
|
||||||
</DialogContent>
|
</DialogContent>
|
||||||
<DialogActions>
|
<DialogActions>
|
||||||
<Button onClick={e => (onOk ? onOk(e) : null)}>{BUTTONS.OK}</Button>
|
<Button variant={P8P_BUTTON_VARIANT.SECONDARY} onClick={e => (onOk ? onOk(e) : null)}>
|
||||||
|
{BUTTONS.OK}
|
||||||
|
</Button>
|
||||||
</DialogActions>
|
</DialogActions>
|
||||||
</Dialog>
|
</Dialog>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -14,6 +14,8 @@ import DialogTitle from "@mui/material/DialogTitle"; //Заголовок диа
|
|||||||
import DialogContent from "@mui/material/DialogContent"; //Содержимое диалога
|
import DialogContent from "@mui/material/DialogContent"; //Содержимое диалога
|
||||||
import DialogContentText from "@mui/material/DialogContentText"; //Текст содержимого диалога
|
import DialogContentText from "@mui/material/DialogContentText"; //Текст содержимого диалога
|
||||||
import LinearProgress from "@mui/material/LinearProgress"; //Индикатор
|
import LinearProgress from "@mui/material/LinearProgress"; //Индикатор
|
||||||
|
import { P8P_DIALOG_TITLE_VARIANT } from "../theme/variants/p8p_dialog_title_variants"; //Варианты заголовков диалога
|
||||||
|
import { P8P_DIALOG_CONTENT_TEXT_VARIANT } from "../theme/variants/p8p_dialog_content_text_variants"; //Варианты текста содержимого диалога
|
||||||
|
|
||||||
//-----------
|
//-----------
|
||||||
//Тело модуля
|
//Тело модуля
|
||||||
@ -28,9 +30,15 @@ const P8PAppProgress = props => {
|
|||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<Dialog open={open || false} aria-labelledby="progress-dialog-title" aria-describedby="progress-dialog-description">
|
<Dialog open={open || false} aria-labelledby="progress-dialog-title" aria-describedby="progress-dialog-description">
|
||||||
{title ? <DialogTitle id="progress-dialog-title">{title}</DialogTitle> : null}
|
{title ? (
|
||||||
|
<DialogTitle id="progress-dialog-title" variant={P8P_DIALOG_TITLE_VARIANT.PRIMARY}>
|
||||||
|
{title}
|
||||||
|
</DialogTitle>
|
||||||
|
) : null}
|
||||||
<DialogContent>
|
<DialogContent>
|
||||||
<DialogContentText id="progress-dialog-description">{text}</DialogContentText>
|
<DialogContentText id="progress-dialog-description" variant={P8P_DIALOG_CONTENT_TEXT_VARIANT.PRIMARY}>
|
||||||
|
{text}
|
||||||
|
</DialogContentText>
|
||||||
<LinearProgress />
|
<LinearProgress />
|
||||||
</DialogContent>
|
</DialogContent>
|
||||||
</Dialog>
|
</Dialog>
|
||||||
|
|||||||
@ -25,7 +25,13 @@ import {
|
|||||||
Divider
|
Divider
|
||||||
} from "@mui/material"; //Интерфейсные компоненты
|
} from "@mui/material"; //Интерфейсные компоненты
|
||||||
import { P8PPanelsMenuDrawer, P8P_PANELS_MENU_PANEL_SHAPE } from "./p8p_panels_menu"; //Меню
|
import { P8PPanelsMenuDrawer, P8P_PANELS_MENU_PANEL_SHAPE } from "./p8p_panels_menu"; //Меню
|
||||||
import { APP_STYLES } from "../../app.styles"; //Типовые стили
|
import { P8P_TYPOGRAPHY_VARIANT } from "../theme/p8p_typography"; //Варианты шрифтов
|
||||||
|
import { P8P_ICON_BUTTON_VARIANT } from "../theme/variants/p8p_icon_button_variants"; //Варианты кнопок-иконок
|
||||||
|
import { P8P_APP_BAR_VARIANT } from "../theme/variants/p8p_app_bar_variants"; //Варианты областей заголовка
|
||||||
|
import { P8P_DRAWER_VARIANT } from "../theme/variants/p8p_drawer_variants"; //Варианты выезжающих областей
|
||||||
|
import { P8P_BOX_CENTER_START, P8P_BOX_CENTER_END, P8P_BOX_FLEX, P8P_BOX_APP_WORKSPACE } from "../theme/styles/box"; //Стили контейнеров
|
||||||
|
import { P8P_MAIN_APP_WORKSPACE } from "../theme/styles/main"; //Стили содержимого страницы
|
||||||
|
import { P8P_LIST_ITEM_TEXT_VARIANT } from "../theme/variants/p8p_list_item_text_variants"; //Варианты значений списков
|
||||||
|
|
||||||
//---------
|
//---------
|
||||||
//Константы
|
//Константы
|
||||||
@ -34,18 +40,6 @@ import { APP_STYLES } from "../../app.styles"; //Типовые стили
|
|||||||
//Высота главного меню
|
//Высота главного меню
|
||||||
const APP_BAR_HEIGHT = "64px";
|
const APP_BAR_HEIGHT = "64px";
|
||||||
|
|
||||||
//Стили
|
|
||||||
const STYLES = {
|
|
||||||
DRAWER: { [`& .MuiDrawer-paper`]: { ...APP_STYLES.SCROLL } },
|
|
||||||
ROOT_BOX: { display: "flex" },
|
|
||||||
APP_BAR: { position: "fixed" },
|
|
||||||
APP_BAR_MAIN_BOX: { display: "flex", width: "100vw", alignItems: "center", justifyContent: "space-between" },
|
|
||||||
APP_BAR_LEFT_SIDE: { display: "flex", alignItems: "center", justifyContent: "flex-start" },
|
|
||||||
APP_BAR_RIGHT_SIDE: { display: "flex", alignItems: "center", justifyContent: "flex-end" },
|
|
||||||
APP_BAR_BUTTON: { mr: 2 },
|
|
||||||
MAIN: { flexGrow: 1 }
|
|
||||||
};
|
|
||||||
|
|
||||||
//-----------
|
//-----------
|
||||||
//Тело модуля
|
//Тело модуля
|
||||||
//-----------
|
//-----------
|
||||||
@ -92,35 +86,35 @@ const P8PAppWorkspace = ({
|
|||||||
|
|
||||||
//Генерация содержимого
|
//Генерация содержимого
|
||||||
return (
|
return (
|
||||||
<Box sx={STYLES.ROOT_BOX}>
|
<Box sx={P8P_BOX_FLEX}>
|
||||||
{showAppBar && (
|
{showAppBar && (
|
||||||
<>
|
<>
|
||||||
<CssBaseline />
|
<CssBaseline />
|
||||||
<AppBar sx={STYLES.APP_BAR}>
|
<AppBar variant={P8P_APP_BAR_VARIANT.FIXED}>
|
||||||
<Toolbar>
|
<Toolbar>
|
||||||
<Box sx={STYLES.APP_BAR_MAIN_BOX}>
|
<Box sx={P8P_BOX_APP_WORKSPACE}>
|
||||||
<Box sx={STYLES.APP_BAR_LEFT_SIDE}>
|
<Box sx={P8P_BOX_CENTER_START}>
|
||||||
<IconButton
|
<IconButton
|
||||||
color="inherit"
|
color="inherit"
|
||||||
aria-label="open drawer"
|
aria-label="open drawer"
|
||||||
onClick={open ? handleDrawerClose : handleDrawerOpen}
|
onClick={open ? handleDrawerClose : handleDrawerOpen}
|
||||||
edge="start"
|
edge="start"
|
||||||
sx={STYLES.APP_BAR_BUTTON}
|
variant={P8P_ICON_BUTTON_VARIANT.APP_BAR_BUTTON}
|
||||||
>
|
>
|
||||||
<Icon>{open ? "chevron_left" : "menu"}</Icon>
|
<Icon>{open ? "chevron_left" : "menu"}</Icon>
|
||||||
</IconButton>
|
</IconButton>
|
||||||
<Typography variant="h6" noWrap component="div">
|
<Typography variant={P8P_TYPOGRAPHY_VARIANT.H6} noWrap component="div">
|
||||||
{caption || selectedPanel?.caption}
|
{caption || selectedPanel?.caption}
|
||||||
</Typography>
|
</Typography>
|
||||||
</Box>
|
</Box>
|
||||||
<Box sx={STYLES.APP_BAR_RIGHT_SIDE}>
|
<Box sx={P8P_BOX_CENTER_END}>
|
||||||
{showAppBarSettings && selectedPanel.showUserSettings ? (
|
{showAppBarSettings && selectedPanel.showUserSettings ? (
|
||||||
<IconButton
|
<IconButton
|
||||||
color="inherit"
|
color="inherit"
|
||||||
aria-label="open drawer"
|
aria-label="open drawer"
|
||||||
onClick={() => handleSettingsDialog(selectedPanel.name)}
|
onClick={() => handleSettingsDialog(selectedPanel.name)}
|
||||||
edge="end"
|
edge="end"
|
||||||
sx={STYLES.APP_BAR_BUTTON}
|
variant={P8P_ICON_BUTTON_VARIANT.APP_BAR_BUTTON}
|
||||||
>
|
>
|
||||||
<Icon>settings</Icon>
|
<Icon>settings</Icon>
|
||||||
</IconButton>
|
</IconButton>
|
||||||
@ -129,33 +123,33 @@ const P8PAppWorkspace = ({
|
|||||||
</Box>
|
</Box>
|
||||||
</Toolbar>
|
</Toolbar>
|
||||||
</AppBar>
|
</AppBar>
|
||||||
<Drawer anchor="left" open={open} onClose={handleDrawerClose} sx={STYLES.DRAWER}>
|
<Drawer anchor="left" open={open} onClose={handleDrawerClose} data-variant={P8P_DRAWER_VARIANT.PRIMARY}>
|
||||||
<List>
|
<List>
|
||||||
<ListItemButton onClick={handleDrawerClose}>
|
<ListItemButton onClick={handleDrawerClose}>
|
||||||
<ListItemIcon>
|
<ListItemIcon>
|
||||||
<Icon>close</Icon>
|
<Icon>close</Icon>
|
||||||
</ListItemIcon>
|
</ListItemIcon>
|
||||||
<ListItemText primary={closeCaption} />
|
<ListItemText variant={P8P_LIST_ITEM_TEXT_VARIANT.PRIMARY} primary={closeCaption} />
|
||||||
</ListItemButton>
|
</ListItemButton>
|
||||||
<ListItemButton onClick={handleHomeClick}>
|
<ListItemButton onClick={handleHomeClick}>
|
||||||
<ListItemIcon>
|
<ListItemIcon>
|
||||||
<Icon>home</Icon>
|
<Icon>home</Icon>
|
||||||
</ListItemIcon>
|
</ListItemIcon>
|
||||||
<ListItemText primary={homeCaption} />
|
<ListItemText variant={P8P_LIST_ITEM_TEXT_VARIANT.PRIMARY} primary={homeCaption} />
|
||||||
</ListItemButton>
|
</ListItemButton>
|
||||||
<Divider component="li" />
|
<Divider component="li" />
|
||||||
<ListItemButton onClick={() => handleSettingsDialog()}>
|
<ListItemButton onClick={() => handleSettingsDialog()}>
|
||||||
<ListItemIcon>
|
<ListItemIcon>
|
||||||
<Icon>settings</Icon>
|
<Icon>settings</Icon>
|
||||||
</ListItemIcon>
|
</ListItemIcon>
|
||||||
<ListItemText primary={settingsCaption} />
|
<ListItemText variant={P8P_LIST_ITEM_TEXT_VARIANT.PRIMARY} primary={settingsCaption} />
|
||||||
</ListItemButton>
|
</ListItemButton>
|
||||||
</List>
|
</List>
|
||||||
<P8PPanelsMenuDrawer panels={panels} selectedPanel={selectedPanel} onItemNavigate={handleItemNavigate} />
|
<P8PPanelsMenuDrawer panels={panels} selectedPanel={selectedPanel} onItemNavigate={handleItemNavigate} />
|
||||||
</Drawer>
|
</Drawer>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
<main style={STYLES.MAIN}>
|
<main style={P8P_MAIN_APP_WORKSPACE}>
|
||||||
{showAppBar && <Toolbar />}
|
{showAppBar && <Toolbar />}
|
||||||
{children}
|
{children}
|
||||||
</main>
|
</main>
|
||||||
|
|||||||
@ -9,604 +9,32 @@
|
|||||||
|
|
||||||
import React, { useEffect, useState, useRef } from "react"; //Классы React
|
import React, { useEffect, useState, useRef } from "react"; //Классы React
|
||||||
import PropTypes from "prop-types"; //Контроль свойств компонента
|
import PropTypes from "prop-types"; //Контроль свойств компонента
|
||||||
import {
|
import { Box, Typography, Link, IconButton, Icon } from "@mui/material"; //Интерфейсные компоненты
|
||||||
Box,
|
|
||||||
Typography,
|
|
||||||
Dialog,
|
|
||||||
DialogActions,
|
|
||||||
DialogContent,
|
|
||||||
Button,
|
|
||||||
List,
|
|
||||||
ListItem,
|
|
||||||
ListItemText,
|
|
||||||
Link,
|
|
||||||
Divider,
|
|
||||||
IconButton,
|
|
||||||
Icon
|
|
||||||
} from "@mui/material"; //Интерфейсные компоненты
|
|
||||||
import { P8PAppInlineError } from "./p8p_app_message"; //Встраиваемое сообщение об ошибке
|
import { P8PAppInlineError } from "./p8p_app_message"; //Встраиваемое сообщение об ошибке
|
||||||
import { hasValue } from "../core/utils"; //Вспомогательный функции
|
|
||||||
import { useP8PCyclogram } from "./p8p_cyclogram_hooks"; //Хук для циклограммы
|
import { useP8PCyclogram } from "./p8p_cyclogram_hooks"; //Хук для циклограммы
|
||||||
|
import { P8PCyclogramTaskEditor } from "./p8p_cyclogram/p8p_cyclogram_task_editor"; //Редактор задачи
|
||||||
|
import { P8P_TYPOGRAPHY_VARIANT } from "../theme/p8p_typography"; //Варианты шрифтов
|
||||||
|
import { P8P_COMPONENT_HEIGHT } from "../theme/styles/common"; //Стили - общие
|
||||||
|
import { P8P_BOX_CYCLOGRAM } from "../theme/styles/box"; //Стили контейнеров
|
||||||
|
import { getShift } from "./p8p_cyclogram/p8p_cyclogram_utils"; //Вспомогательные функции циклограммы
|
||||||
|
import {
|
||||||
|
P8P_CYCLOGRAM_ZOOM,
|
||||||
|
NDEFAULT_LINE_HEIGHT,
|
||||||
|
NDEFAULT_HEADER_HEIGHT,
|
||||||
|
TITLE_HEIGHT,
|
||||||
|
ZOOM_HEIGHT,
|
||||||
|
P8P_CYCLOGRAM_COLUMN_SHAPE,
|
||||||
|
P8P_CYCLOGRAM_GROUP_SHAPE,
|
||||||
|
P8P_CYCLOGRAM_TASK_SHAPE,
|
||||||
|
P8P_CYCLOGRAM_TASK_ATTRIBUTE_SHAPE
|
||||||
|
} from "./p8p_cyclogram/p8p_cyclogram_constants"; //Константы циклограммы
|
||||||
|
import { P8PCyclogramGrid } from "./p8p_cyclogram/p8p_cyclogram_grid"; //Фон таблицы циклограммы
|
||||||
|
import { P8PCyclogramView } from "./p8p_cyclogram/p8p_cyclogram_view"; //Представление циклограммы
|
||||||
|
import { P8P_TYPOGRAPHY_TITLE } from "../theme/styles/typography"; //Стили текста
|
||||||
|
|
||||||
//---------
|
//-----------
|
||||||
//Константы
|
//Тело модуля
|
||||||
//---------
|
//-----------
|
||||||
|
|
||||||
//Уровни масштаба
|
|
||||||
const P8P_CYCLOGRAM_ZOOM = [0.2, 0.4, 0.7, 1, 1.5, 2, 2.5];
|
|
||||||
|
|
||||||
//Параметры элементов циклограммы
|
|
||||||
const NDEFAULT_LINE_HEIGHT = 20;
|
|
||||||
const NDEFAULT_HEADER_HEIGHT = 35;
|
|
||||||
|
|
||||||
//Высота заголовка
|
|
||||||
const TITLE_HEIGHT = "44px";
|
|
||||||
|
|
||||||
//Высота панели масштабирования
|
|
||||||
const ZOOM_HEIGHT = "56px";
|
|
||||||
|
|
||||||
//Стили
|
|
||||||
const STYLES = {
|
|
||||||
CYCLOGRAM_TITLE: { height: TITLE_HEIGHT },
|
|
||||||
CYCLOGRAM_ZOOM: { height: ZOOM_HEIGHT },
|
|
||||||
HEADER_COLUMN: {
|
|
||||||
fontSize: "12px",
|
|
||||||
textOverflow: "ellipsis",
|
|
||||||
overflow: "hidden",
|
|
||||||
whiteSpace: "pre",
|
|
||||||
textAlign: "center",
|
|
||||||
lineHeight: "3",
|
|
||||||
padding: "0px 5px"
|
|
||||||
},
|
|
||||||
CYCLOGRAM_BOX: (noData, title, zoomBar) => ({
|
|
||||||
position: "relative",
|
|
||||||
overflow: "auto",
|
|
||||||
padding: "0px 8px",
|
|
||||||
height: `calc(100% - ${zoomBar ? ZOOM_HEIGHT : "0px"} - ${title ? TITLE_HEIGHT : "0px"})`,
|
|
||||||
display: noData ? "none" : ""
|
|
||||||
}),
|
|
||||||
GRID_ROW: index => (index % 2 === 0 ? { backgroundColor: "#ffffff" } : { backgroundColor: "#f5f5f5" }),
|
|
||||||
GROUP_HEADER_BOX: {
|
|
||||||
border: "1px solid",
|
|
||||||
backgroundColor: "#ebebeb",
|
|
||||||
display: "flex",
|
|
||||||
alignItems: "center",
|
|
||||||
justifyContent: "center"
|
|
||||||
},
|
|
||||||
GROUP_HEADER: {
|
|
||||||
fontSize: "14px",
|
|
||||||
textAlign: "center",
|
|
||||||
wordWrap: "break-word"
|
|
||||||
},
|
|
||||||
TASK_EDITOR_CONTENT: { minWidth: 400, overflowX: "auto" },
|
|
||||||
TASK_EDITOR_LIST: { width: "100%", minWidth: 300, maxWidth: 700, bgcolor: "background.paper" },
|
|
||||||
TASK_BOX: (lineHeight, bgColor, textColor, highlightColor) => ({
|
|
||||||
display: "flex",
|
|
||||||
alignItems: "center",
|
|
||||||
backgroundColor: bgColor ? bgColor : "#b4b9bf",
|
|
||||||
...(textColor ? { color: textColor } : {}),
|
|
||||||
height: lineHeight,
|
|
||||||
"&:hover": {
|
|
||||||
...(highlightColor
|
|
||||||
? { backgroundColor: `${highlightColor} !important`, filter: "brightness(1) !important" }
|
|
||||||
: { filter: "brightness(1.25) !important" }),
|
|
||||||
cursor: "pointer !important"
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
TASK: lineHeight => {
|
|
||||||
const availableLines = Math.floor(lineHeight / 18);
|
|
||||||
return {
|
|
||||||
width: "100%",
|
|
||||||
fontSize: "12px",
|
|
||||||
overflowWrap: "break-word",
|
|
||||||
wordBreak: "break-all",
|
|
||||||
overflow: "hidden",
|
|
||||||
textOverflow: "ellipsis",
|
|
||||||
display: "-webkit-box",
|
|
||||||
lineHeight: "18px",
|
|
||||||
maxHeight: lineHeight,
|
|
||||||
WebkitLineClamp: availableLines < 1 ? 1 : availableLines,
|
|
||||||
WebkitBoxOrient: "vertical"
|
|
||||||
};
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
//Структура колонки
|
|
||||||
const P8P_CYCLOGRAM_COLUMN_SHAPE = PropTypes.shape({
|
|
||||||
name: PropTypes.string.isRequired,
|
|
||||||
start: PropTypes.number.isRequired,
|
|
||||||
end: PropTypes.number.isRequired
|
|
||||||
});
|
|
||||||
|
|
||||||
//Структура группы
|
|
||||||
const P8P_CYCLOGRAM_GROUP_SHAPE = PropTypes.shape({
|
|
||||||
name: PropTypes.string.isRequired,
|
|
||||||
height: PropTypes.number.isRequired,
|
|
||||||
width: PropTypes.number.isRequired,
|
|
||||||
visible: PropTypes.bool.isRequired
|
|
||||||
});
|
|
||||||
|
|
||||||
//Структура задачи
|
|
||||||
const P8P_CYCLOGRAM_TASK_SHAPE = PropTypes.shape({
|
|
||||||
id: PropTypes.string.isRequired,
|
|
||||||
rn: PropTypes.number.isRequired,
|
|
||||||
name: PropTypes.string.isRequired,
|
|
||||||
fullName: PropTypes.string.isRequired,
|
|
||||||
lineNumb: PropTypes.number.isRequired,
|
|
||||||
start: PropTypes.number.isRequired,
|
|
||||||
end: PropTypes.number.isRequired,
|
|
||||||
group: PropTypes.string,
|
|
||||||
bgColor: PropTypes.string,
|
|
||||||
textColor: PropTypes.string,
|
|
||||||
highlightColor: PropTypes.string
|
|
||||||
});
|
|
||||||
|
|
||||||
//Структура динамического атрибута задачи
|
|
||||||
const P8P_CYCLOGRAM_TASK_ATTRIBUTE_SHAPE = PropTypes.shape({
|
|
||||||
name: PropTypes.string.isRequired,
|
|
||||||
caption: PropTypes.string.isRequired,
|
|
||||||
visible: PropTypes.bool.isRequired
|
|
||||||
});
|
|
||||||
|
|
||||||
//--------------------------------
|
|
||||||
//Вспомогательные классы и функции
|
|
||||||
//--------------------------------
|
|
||||||
|
|
||||||
//Определение сдвига для максимальной ширины колонок
|
|
||||||
const getShift = (columns, currentColumnsMaxWidth, maxCyclogramWidth) => {
|
|
||||||
//Определяем доступное пространство для расширения
|
|
||||||
let maxWidthDiff = maxCyclogramWidth - currentColumnsMaxWidth;
|
|
||||||
//Инициализируем значение сдвига
|
|
||||||
let shift = 1;
|
|
||||||
//Если доступно больше ширины и есть пространство для расширения
|
|
||||||
if (maxCyclogramWidth > currentColumnsMaxWidth && maxCyclogramWidth - maxWidthDiff > columns.length) {
|
|
||||||
//Определяем доступный сдвиг колонок
|
|
||||||
shift = maxCyclogramWidth / currentColumnsMaxWidth;
|
|
||||||
}
|
|
||||||
//Возвращаем сдвиг
|
|
||||||
return shift;
|
|
||||||
};
|
|
||||||
|
|
||||||
//Формирование стилей для группы
|
|
||||||
const getGroupStyles = (indexGrp, highlightColor) => {
|
|
||||||
return `.main .TaskGrp${indexGrp}:hover .TaskGrp${indexGrp} {
|
|
||||||
${highlightColor ? `background: ${highlightColor};` : `filter: brightness(1.15);`}
|
|
||||||
}
|
|
||||||
.main:has(.TaskGrp${indexGrp}:hover) .TaskGrpHeader${indexGrp} {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
//cursor: pointer;
|
|
||||||
};
|
|
||||||
|
|
||||||
//Фон строк таблицы
|
|
||||||
const P8PCyclogramRowsGrid = ({ rows, maxWidth, lineHeight }) => {
|
|
||||||
return (
|
|
||||||
<g>
|
|
||||||
{rows.map((el, index) => (
|
|
||||||
<foreignObject x="0" y={NDEFAULT_HEADER_HEIGHT + index * lineHeight} width={maxWidth} height={lineHeight} key={index}>
|
|
||||||
<Box sx={STYLES.GRID_ROW(index)} height={lineHeight} />
|
|
||||||
</foreignObject>
|
|
||||||
))}
|
|
||||||
</g>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
//Контроль свойств - Фон строк таблицы
|
|
||||||
P8PCyclogramRowsGrid.propTypes = {
|
|
||||||
rows: PropTypes.array.isRequired,
|
|
||||||
maxWidth: PropTypes.number.isRequired,
|
|
||||||
lineHeight: PropTypes.number.isRequired
|
|
||||||
};
|
|
||||||
|
|
||||||
//Линии строк таблицы
|
|
||||||
const P8PCyclogramRowsLines = ({ rows, maxWidth, lineHeight }) => {
|
|
||||||
return (
|
|
||||||
<g>
|
|
||||||
{rows.map((el, index) => (
|
|
||||||
<line
|
|
||||||
x1="0"
|
|
||||||
y1={NDEFAULT_HEADER_HEIGHT + lineHeight + index * lineHeight}
|
|
||||||
x2={maxWidth}
|
|
||||||
y2={NDEFAULT_HEADER_HEIGHT + lineHeight + index * lineHeight}
|
|
||||||
key={index}
|
|
||||||
></line>
|
|
||||||
))}
|
|
||||||
</g>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
//Контроль свойств - Линии строк таблицы
|
|
||||||
P8PCyclogramRowsLines.propTypes = {
|
|
||||||
rows: PropTypes.array.isRequired,
|
|
||||||
maxWidth: PropTypes.number.isRequired,
|
|
||||||
lineHeight: PropTypes.number.isRequired
|
|
||||||
};
|
|
||||||
|
|
||||||
//Линии колонок таблицы
|
|
||||||
const P8PCyclogramColumnsLines = ({ columns, shift, y1, y2 }) => {
|
|
||||||
//Инициализируем старт текущей колонки
|
|
||||||
let prevColumnEnd = 0;
|
|
||||||
return (
|
|
||||||
<g>
|
|
||||||
{columns.map((column, index) => {
|
|
||||||
//Аккумулируем окончание последней колонки с учетом сдвига
|
|
||||||
prevColumnEnd = index !== 0 ? prevColumnEnd + (columns[index - 1].end - columns[index - 1].start) * shift : 0;
|
|
||||||
return <line x1={prevColumnEnd} y1={y1} x2={prevColumnEnd} y2={y2} stroke="#e0e0e0" key={index} />;
|
|
||||||
})}
|
|
||||||
<line
|
|
||||||
x1={prevColumnEnd + (columns[columns.length - 1].end - columns[columns.length - 1].start) * shift}
|
|
||||||
y1={y1}
|
|
||||||
x2={prevColumnEnd + (columns[columns.length - 1].end - columns[columns.length - 1].start) * shift}
|
|
||||||
y2={y2}
|
|
||||||
stroke="#e0e0e0"
|
|
||||||
/>
|
|
||||||
</g>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
//Контроль свойств - Линии колонок таблицы
|
|
||||||
P8PCyclogramColumnsLines.propTypes = {
|
|
||||||
columns: PropTypes.array.isRequired,
|
|
||||||
shift: PropTypes.number.isRequired,
|
|
||||||
y1: PropTypes.number.isRequired,
|
|
||||||
y2: PropTypes.number.isRequired
|
|
||||||
};
|
|
||||||
|
|
||||||
//Фон таблицы циклограммы
|
|
||||||
const P8PCyclogramGrid = ({ tasks, columns, shift, maxWidth, maxHeight, lineHeight }) => {
|
|
||||||
//Формируем массив строк исходя из максимального значения строки задачи
|
|
||||||
const rows = Array.from(Array(Math.max(...tasks.map(o => o.lineNumb)) + 1).keys());
|
|
||||||
return (
|
|
||||||
<g className="grid">
|
|
||||||
<rect x="0" y="0" width={maxWidth} height={maxHeight}></rect>
|
|
||||||
<P8PCyclogramRowsGrid rows={rows} maxWidth={maxWidth} lineHeight={lineHeight} />
|
|
||||||
<P8PCyclogramRowsLines rows={rows} maxWidth={maxWidth} lineHeight={lineHeight} />
|
|
||||||
<P8PCyclogramColumnsLines columns={columns} shift={shift} y1={NDEFAULT_HEADER_HEIGHT} y2={maxHeight} />
|
|
||||||
</g>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
//Контроль свойств - Фон таблицы циклограммы
|
|
||||||
P8PCyclogramGrid.propTypes = {
|
|
||||||
tasks: PropTypes.array.isRequired,
|
|
||||||
columns: PropTypes.array.isRequired,
|
|
||||||
shift: PropTypes.number.isRequired,
|
|
||||||
maxWidth: PropTypes.number.isRequired,
|
|
||||||
maxHeight: PropTypes.number.isRequired,
|
|
||||||
lineHeight: PropTypes.number.isRequired
|
|
||||||
};
|
|
||||||
|
|
||||||
//Колонка заголовка циклограммы
|
|
||||||
const P8PCyclogramHeaderColumn = ({ column, start, shift, columnRenderer }) => {
|
|
||||||
//Рассчитываем ширину колонки
|
|
||||||
const columnWidth = column.end - column.start;
|
|
||||||
//Формируем собственное отображение, если требуется
|
|
||||||
const customView = columnRenderer ? columnRenderer({ column }) : null;
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<foreignObject x={start} y="0" width={columnWidth * shift} height={NDEFAULT_HEADER_HEIGHT}>
|
|
||||||
{customView ? (
|
|
||||||
customView
|
|
||||||
) : (
|
|
||||||
<Typography sx={{ ...STYLES.HEADER_COLUMN, height: NDEFAULT_HEADER_HEIGHT }} title={column.name}>
|
|
||||||
{column.name}
|
|
||||||
</Typography>
|
|
||||||
)}
|
|
||||||
</foreignObject>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
//Контроль свойств - Колонка заголовка циклограммы
|
|
||||||
P8PCyclogramHeaderColumn.propTypes = {
|
|
||||||
column: PropTypes.object.isRequired,
|
|
||||||
start: PropTypes.number.isRequired,
|
|
||||||
shift: PropTypes.number.isRequired,
|
|
||||||
maxHeight: PropTypes.number.isRequired,
|
|
||||||
lastElement: PropTypes.bool,
|
|
||||||
columnRenderer: PropTypes.func
|
|
||||||
};
|
|
||||||
|
|
||||||
//Заголовок циклограммы
|
|
||||||
const P8PCyclogramHeader = ({ columns, shift, maxWidth, maxHeight, columnRenderer, headerBlock }) => {
|
|
||||||
//Инициализируем старт текущей колонки
|
|
||||||
let prevColumnEnd = 0;
|
|
||||||
return (
|
|
||||||
<g className="header" ref={headerBlock}>
|
|
||||||
<rect x="0" y="0" width={maxWidth} height={NDEFAULT_HEADER_HEIGHT} fill="#ffffff" stroke="#e0e0e0" strokeWidth="1.4"></rect>
|
|
||||||
{columns.map((column, index) => {
|
|
||||||
//Аккумулируем окончание последней колонки с учетом сдвига
|
|
||||||
prevColumnEnd = index !== 0 ? prevColumnEnd + (columns[index - 1].end - columns[index - 1].start) * shift : 0;
|
|
||||||
return (
|
|
||||||
<P8PCyclogramHeaderColumn
|
|
||||||
column={column}
|
|
||||||
shift={shift}
|
|
||||||
start={prevColumnEnd}
|
|
||||||
maxHeight={maxHeight}
|
|
||||||
lastElement={columns.length - 1 === index}
|
|
||||||
columnRenderer={columnRenderer}
|
|
||||||
key={index}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
<g className="columnsDividers">
|
|
||||||
<P8PCyclogramColumnsLines columns={columns} shift={shift} y1={0} y2={NDEFAULT_HEADER_HEIGHT} />
|
|
||||||
</g>
|
|
||||||
</g>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
//Контроль свойств - Заголовок циклограммы
|
|
||||||
P8PCyclogramHeader.propTypes = {
|
|
||||||
columns: PropTypes.array.isRequired,
|
|
||||||
shift: PropTypes.number.isRequired,
|
|
||||||
maxWidth: PropTypes.number.isRequired,
|
|
||||||
maxHeight: PropTypes.number.isRequired,
|
|
||||||
columnRenderer: PropTypes.func,
|
|
||||||
headerBlock: PropTypes.object
|
|
||||||
};
|
|
||||||
|
|
||||||
//Задача циклограммы
|
|
||||||
const P8PCyclogramTask = ({ task, indexGrp, shift, lineHeight, openTaskEditor, taskRenderer }) => {
|
|
||||||
//Рассчитываем ширину задачи
|
|
||||||
const width = task.end !== 0 ? (task.end - task.start) * shift : 0;
|
|
||||||
//Формируем собственное отображение, если требуется
|
|
||||||
const customView = taskRenderer ? taskRenderer({ task, taskHeight: lineHeight, taskWidth: width }) || {} : {};
|
|
||||||
return (
|
|
||||||
<foreignObject
|
|
||||||
x={task.start !== 0 ? task.start * shift : 0}
|
|
||||||
y={NDEFAULT_HEADER_HEIGHT + task.lineNumb * lineHeight}
|
|
||||||
width={width}
|
|
||||||
height={lineHeight}
|
|
||||||
>
|
|
||||||
<Box
|
|
||||||
className={hasValue(indexGrp) ? `TaskGrp${indexGrp}` : null}
|
|
||||||
sx={{ ...STYLES.TASK_BOX(lineHeight, task.bgColor, task.textColor, task.highlightColor), ...customView.taskStyle }}
|
|
||||||
{...customView.taskProps}
|
|
||||||
onClick={() => openTaskEditor(task)}
|
|
||||||
>
|
|
||||||
{customView.data ? (
|
|
||||||
customView.data
|
|
||||||
) : (
|
|
||||||
<Typography sx={STYLES.TASK(lineHeight)} title={task.name}>
|
|
||||||
{task.name}
|
|
||||||
</Typography>
|
|
||||||
)}
|
|
||||||
</Box>
|
|
||||||
</foreignObject>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
//Контроль свойств - Группы циклограммы
|
|
||||||
P8PCyclogramTask.propTypes = {
|
|
||||||
task: PropTypes.object.isRequired,
|
|
||||||
indexGrp: PropTypes.number,
|
|
||||||
shift: PropTypes.number.isRequired,
|
|
||||||
lineHeight: PropTypes.number.isRequired,
|
|
||||||
openTaskEditor: PropTypes.func.isRequired,
|
|
||||||
taskRenderer: PropTypes.func
|
|
||||||
};
|
|
||||||
|
|
||||||
//Основная информация циклограммы
|
|
||||||
const P8PCyclogramMain = ({
|
|
||||||
columns,
|
|
||||||
groups,
|
|
||||||
tasks,
|
|
||||||
shift,
|
|
||||||
lineHeight,
|
|
||||||
maxWidth,
|
|
||||||
maxHeight,
|
|
||||||
openTaskEditor,
|
|
||||||
groupHeaderRenderer,
|
|
||||||
taskRenderer,
|
|
||||||
columnRenderer,
|
|
||||||
headerBlock
|
|
||||||
}) => {
|
|
||||||
//Инициализируем коллекцию тасков с группами
|
|
||||||
const tasksWithGroup = tasks.filter(task => hasValue(task.groupName));
|
|
||||||
//Инициализируем коллекцию тасков без групп
|
|
||||||
const tasksWithoutGroup = tasks.filter(task => !hasValue(task.groupName));
|
|
||||||
//Инициализируем коллекцию отображаемых групп
|
|
||||||
const visibleGroups = groups ? groups.filter(group => group.visible) : [];
|
|
||||||
return (
|
|
||||||
<g className="main">
|
|
||||||
<g className="tasks">
|
|
||||||
{visibleGroups.length !== 0
|
|
||||||
? visibleGroups.map((grp, indexGrp) => {
|
|
||||||
//Считываем задачи группы
|
|
||||||
let groupTasks = tasksWithGroup.filter(task => task.groupName === grp.name);
|
|
||||||
//Если по данной группе нет тасков - ничего не выводим
|
|
||||||
if (groupTasks.length === 0) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return (
|
|
||||||
<g className={`TaskGrp${indexGrp}`} key={indexGrp}>
|
|
||||||
{groupTasks.map((task, index) => (
|
|
||||||
<P8PCyclogramTask
|
|
||||||
task={task}
|
|
||||||
indexGrp={indexGrp}
|
|
||||||
shift={shift}
|
|
||||||
lineHeight={lineHeight}
|
|
||||||
openTaskEditor={openTaskEditor}
|
|
||||||
taskRenderer={taskRenderer}
|
|
||||||
key={index}
|
|
||||||
/>
|
|
||||||
))}
|
|
||||||
<style>{getGroupStyles(indexGrp, grp.highlightColor)}</style>
|
|
||||||
</g>
|
|
||||||
);
|
|
||||||
})
|
|
||||||
: null}
|
|
||||||
<g className={`TasksWithoutGroups`}>
|
|
||||||
{tasksWithoutGroup.map((task, index) => {
|
|
||||||
return (
|
|
||||||
<P8PCyclogramTask
|
|
||||||
task={task}
|
|
||||||
shift={shift}
|
|
||||||
lineHeight={lineHeight}
|
|
||||||
openTaskEditor={openTaskEditor}
|
|
||||||
taskRenderer={taskRenderer}
|
|
||||||
key={index}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</g>
|
|
||||||
</g>
|
|
||||||
<P8PCyclogramHeader
|
|
||||||
columns={columns}
|
|
||||||
shift={shift}
|
|
||||||
maxWidth={maxWidth}
|
|
||||||
maxHeight={maxHeight}
|
|
||||||
columnRenderer={columnRenderer}
|
|
||||||
headerBlock={headerBlock}
|
|
||||||
/>
|
|
||||||
{visibleGroups.length !== 0 ? (
|
|
||||||
<g className="groups">
|
|
||||||
{visibleGroups.map((grp, indexGrp) => {
|
|
||||||
//Инициализируем параметры группы
|
|
||||||
let defaultView = null;
|
|
||||||
let customView = null;
|
|
||||||
let groupHeaderX = 0;
|
|
||||||
let groupHeaderY = 0;
|
|
||||||
let groupTasks = tasksWithGroup.filter(task => task.groupName === grp.name);
|
|
||||||
//Если по данной группе нет тасков - ничего не выводим
|
|
||||||
if (groupTasks.length === 0) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
//Если требуется отображать заголовок группы
|
|
||||||
if (grp.visible) {
|
|
||||||
//Формируем отображение по умолчанию
|
|
||||||
defaultView = (
|
|
||||||
<Box sx={{ ...STYLES.GROUP_HEADER_BOX, height: grp.height }}>
|
|
||||||
<Typography sx={{ ...STYLES.GROUP_HEADER, maxWidth: grp.width, maxHeight: grp.height }}>{grp.name}</Typography>
|
|
||||||
</Box>
|
|
||||||
);
|
|
||||||
//Формируем собственное отображение, если требуется
|
|
||||||
customView = groupHeaderRenderer ? groupHeaderRenderer({ group: grp }) : null;
|
|
||||||
//Рассчитываем координаты заголовка группы
|
|
||||||
groupHeaderX = Math.min(...groupTasks.map(o => o.start)) * shift;
|
|
||||||
groupHeaderY = NDEFAULT_HEADER_HEIGHT + Math.min(...groupTasks.map(o => o.lineNumb)) * lineHeight - grp.height - 5;
|
|
||||||
}
|
|
||||||
return (
|
|
||||||
<foreignObject
|
|
||||||
x={groupHeaderX}
|
|
||||||
y={groupHeaderY}
|
|
||||||
width={grp.width}
|
|
||||||
height={grp.height}
|
|
||||||
className={`TaskGrpHeader${indexGrp}`}
|
|
||||||
display="none"
|
|
||||||
key={indexGrp}
|
|
||||||
>
|
|
||||||
{customView ? customView : defaultView}
|
|
||||||
</foreignObject>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</g>
|
|
||||||
) : null}
|
|
||||||
</g>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
//Контроль свойств - Основная информация циклограммы
|
|
||||||
P8PCyclogramMain.propTypes = {
|
|
||||||
columns: PropTypes.array.isRequired,
|
|
||||||
groups: PropTypes.array,
|
|
||||||
tasks: PropTypes.array.isRequired,
|
|
||||||
shift: PropTypes.number.isRequired,
|
|
||||||
lineHeight: PropTypes.number.isRequired,
|
|
||||||
maxWidth: PropTypes.number.isRequired,
|
|
||||||
maxHeight: PropTypes.number.isRequired,
|
|
||||||
openTaskEditor: PropTypes.func.isRequired,
|
|
||||||
groupHeaderRenderer: PropTypes.func,
|
|
||||||
taskRenderer: PropTypes.func,
|
|
||||||
columnRenderer: PropTypes.func,
|
|
||||||
headerBlock: PropTypes.object
|
|
||||||
};
|
|
||||||
|
|
||||||
//Редактор задачи
|
|
||||||
const P8PCyclogramTaskEditor = ({
|
|
||||||
task,
|
|
||||||
taskAttributes,
|
|
||||||
onOk,
|
|
||||||
onCancel,
|
|
||||||
taskAttributeRenderer,
|
|
||||||
taskDialogRenderer,
|
|
||||||
nameCaption,
|
|
||||||
okBtnCaption,
|
|
||||||
cancelBtnCaption
|
|
||||||
}) => {
|
|
||||||
//Собственное состояние
|
|
||||||
const [state] = useState({
|
|
||||||
start: task.start,
|
|
||||||
end: task.end
|
|
||||||
});
|
|
||||||
|
|
||||||
//Отображаемые атрибуты
|
|
||||||
const dispTaskAttributes =
|
|
||||||
Array.isArray(taskAttributes) && taskAttributes.length > 0 ? taskAttributes.filter(attr => attr.visible && hasValue(task[attr.name])) : [];
|
|
||||||
|
|
||||||
//При сохранении
|
|
||||||
const handleOk = () => (onOk && state.start && state.end ? onOk() : null);
|
|
||||||
|
|
||||||
//При отмене
|
|
||||||
const handleCancel = () => (onCancel ? onCancel() : null);
|
|
||||||
|
|
||||||
//Генерация содержимого
|
|
||||||
return (
|
|
||||||
<Dialog open onClose={handleCancel}>
|
|
||||||
{taskDialogRenderer ? (
|
|
||||||
taskDialogRenderer({ task, taskAttributes, close: handleCancel })
|
|
||||||
) : (
|
|
||||||
<>
|
|
||||||
<DialogContent sx={STYLES.TASK_EDITOR_CONTENT}>
|
|
||||||
<List sx={STYLES.TASK_EDITOR_LIST}>
|
|
||||||
<ListItem alignItems="flex-start">
|
|
||||||
<ListItemText primary={nameCaption} secondary={task.fullName} />
|
|
||||||
</ListItem>
|
|
||||||
{dispTaskAttributes.length > 0 ? <Divider component="li" /> : null}
|
|
||||||
{dispTaskAttributes.length > 0
|
|
||||||
? dispTaskAttributes.map((attr, i) => {
|
|
||||||
const defaultView = task[attr.name];
|
|
||||||
const customView = taskAttributeRenderer ? taskAttributeRenderer({ task, attribute: attr }) : null;
|
|
||||||
return (
|
|
||||||
<React.Fragment key={i}>
|
|
||||||
<ListItem alignItems="flex-start">
|
|
||||||
<ListItemText
|
|
||||||
primary={attr.caption}
|
|
||||||
secondaryTypographyProps={{ component: "span" }}
|
|
||||||
secondary={customView ? customView : defaultView}
|
|
||||||
/>
|
|
||||||
</ListItem>
|
|
||||||
{i < dispTaskAttributes.length - 1 ? <Divider component="li" /> : null}
|
|
||||||
</React.Fragment>
|
|
||||||
);
|
|
||||||
})
|
|
||||||
: null}
|
|
||||||
</List>
|
|
||||||
</DialogContent>
|
|
||||||
<DialogActions>
|
|
||||||
<Button onClick={handleOk}>{okBtnCaption}</Button>
|
|
||||||
<Button onClick={handleCancel}>{cancelBtnCaption}</Button>
|
|
||||||
</DialogActions>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</Dialog>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
//Контроль свойств - Редактор задачи
|
|
||||||
P8PCyclogramTaskEditor.propTypes = {
|
|
||||||
task: P8P_CYCLOGRAM_TASK_SHAPE,
|
|
||||||
taskAttributes: PropTypes.arrayOf(P8P_CYCLOGRAM_TASK_ATTRIBUTE_SHAPE),
|
|
||||||
onOk: PropTypes.func,
|
|
||||||
onCancel: PropTypes.func,
|
|
||||||
taskAttributeRenderer: PropTypes.func,
|
|
||||||
taskDialogRenderer: PropTypes.func,
|
|
||||||
nameCaption: PropTypes.string.isRequired,
|
|
||||||
okBtnCaption: PropTypes.string.isRequired,
|
|
||||||
cancelBtnCaption: PropTypes.string.isRequired
|
|
||||||
};
|
|
||||||
|
|
||||||
//Циклограмма
|
//Циклограмма
|
||||||
const P8PCyclogram = ({
|
const P8PCyclogram = ({
|
||||||
@ -716,13 +144,14 @@ const P8PCyclogram = ({
|
|||||||
{title ? (
|
{title ? (
|
||||||
<Typography
|
<Typography
|
||||||
p={1}
|
p={1}
|
||||||
sx={{ ...STYLES.CYCLOGRAM_TITLE, ...(titleStyle ? titleStyle : {}) }}
|
sx={{ ...P8P_TYPOGRAPHY_TITLE, ...(titleStyle ? titleStyle : {}) }}
|
||||||
align="center"
|
align="center"
|
||||||
color="textSecondary"
|
color="textSecondary"
|
||||||
variant="subtitle1"
|
variant={P8P_TYPOGRAPHY_VARIANT.TITLE}
|
||||||
|
component="h6"
|
||||||
>
|
>
|
||||||
{onTitleClick ? (
|
{onTitleClick ? (
|
||||||
<Link component="button" variant="body2" underline="hover" onClick={() => onTitleClick()}>
|
<Link component="button" variant={P8P_TYPOGRAPHY_VARIANT.BODY3} underline="hover" onClick={() => onTitleClick()}>
|
||||||
{title}
|
{title}
|
||||||
</Link>
|
</Link>
|
||||||
) : (
|
) : (
|
||||||
@ -731,7 +160,7 @@ const P8PCyclogram = ({
|
|||||||
</Typography>
|
</Typography>
|
||||||
) : null}
|
) : null}
|
||||||
{zoomBar ? (
|
{zoomBar ? (
|
||||||
<Box p={1} sx={STYLES.CYCLOGRAM_ZOOM}>
|
<Box p={1} sx={P8P_COMPONENT_HEIGHT({ height: ZOOM_HEIGHT })}>
|
||||||
<IconButton
|
<IconButton
|
||||||
onClick={() => handleZoomChange(1)}
|
onClick={() => handleZoomChange(1)}
|
||||||
disabled={state.zoom == P8P_CYCLOGRAM_ZOOM[P8P_CYCLOGRAM_ZOOM.length - 1]}
|
disabled={state.zoom == P8P_CYCLOGRAM_ZOOM[P8P_CYCLOGRAM_ZOOM.length - 1]}
|
||||||
@ -743,7 +172,16 @@ const P8PCyclogram = ({
|
|||||||
</IconButton>
|
</IconButton>
|
||||||
</Box>
|
</Box>
|
||||||
) : null}
|
) : null}
|
||||||
<Box className="scroll" sx={STYLES.CYCLOGRAM_BOX(state.noData, title, zoomBar)} onScroll={handleScroll}>
|
<Box
|
||||||
|
className="scroll"
|
||||||
|
//sx={STYLES.CYCLOGRAM_BOX(state.noData, title, zoomBar)}
|
||||||
|
sx={P8P_BOX_CYCLOGRAM({
|
||||||
|
noData: state.noData,
|
||||||
|
zoomBarHeight: zoomBar ? ZOOM_HEIGHT : null,
|
||||||
|
titleHeight: title ? TITLE_HEIGHT : null
|
||||||
|
})}
|
||||||
|
onScroll={handleScroll}
|
||||||
|
>
|
||||||
<svg id="cyclogram" width={state.maxWidth} height={state.maxHeight}>
|
<svg id="cyclogram" width={state.maxWidth} height={state.maxHeight}>
|
||||||
<P8PCyclogramGrid
|
<P8PCyclogramGrid
|
||||||
tasks={state.tasks}
|
tasks={state.tasks}
|
||||||
@ -753,7 +191,7 @@ const P8PCyclogram = ({
|
|||||||
maxHeight={state.maxHeight}
|
maxHeight={state.maxHeight}
|
||||||
lineHeight={state.lineHeight}
|
lineHeight={state.lineHeight}
|
||||||
/>
|
/>
|
||||||
<P8PCyclogramMain
|
<P8PCyclogramView
|
||||||
columns={columns}
|
columns={columns}
|
||||||
groups={groups}
|
groups={groups}
|
||||||
tasks={state.tasks}
|
tasks={state.tasks}
|
||||||
|
|||||||
56
app/components/p8p_cyclogram/p8p_cyclogram_column.js
Normal file
56
app/components/p8p_cyclogram/p8p_cyclogram_column.js
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
/*
|
||||||
|
Парус 8 - Панели мониторинга - Циклограмма
|
||||||
|
Компонент: Колонка
|
||||||
|
*/
|
||||||
|
|
||||||
|
//---------------------
|
||||||
|
//Подключение библиотек
|
||||||
|
//---------------------
|
||||||
|
|
||||||
|
import React from "react"; //Классы React
|
||||||
|
import PropTypes from "prop-types"; //Контроль свойств компонента
|
||||||
|
import { Typography } from "@mui/material"; //Интерфейсные компоненты
|
||||||
|
import { P8P_TYPOGRAPHY_VARIANT } from "../../theme/p8p_typography"; //Варианты шрифтов
|
||||||
|
import { NDEFAULT_HEADER_HEIGHT } from "./p8p_cyclogram_constants"; //Константы циклограммы
|
||||||
|
import { P8P_TYPOGRAPHY_CG_HEADER } from "../../theme/styles/typography"; //Стили текста
|
||||||
|
|
||||||
|
//-----------
|
||||||
|
//Тело модуля
|
||||||
|
//-----------
|
||||||
|
|
||||||
|
//Колонка
|
||||||
|
const P8PCyclogramHeaderColumn = ({ column, start, shift, columnRenderer }) => {
|
||||||
|
//Рассчитываем ширину колонки
|
||||||
|
const columnWidth = column.end - column.start;
|
||||||
|
//Формируем собственное отображение, если требуется
|
||||||
|
const customView = columnRenderer ? columnRenderer({ column }) : null;
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<foreignObject x={start} y="0" width={columnWidth * shift} height={NDEFAULT_HEADER_HEIGHT}>
|
||||||
|
{customView ? (
|
||||||
|
customView
|
||||||
|
) : (
|
||||||
|
<Typography variant={P8P_TYPOGRAPHY_VARIANT.COLUMN} sx={P8P_TYPOGRAPHY_CG_HEADER} title={column.name} component={"p"}>
|
||||||
|
{column.name}
|
||||||
|
</Typography>
|
||||||
|
)}
|
||||||
|
</foreignObject>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
//Контроль свойств - Колонка
|
||||||
|
P8PCyclogramHeaderColumn.propTypes = {
|
||||||
|
column: PropTypes.object.isRequired,
|
||||||
|
start: PropTypes.number.isRequired,
|
||||||
|
shift: PropTypes.number.isRequired,
|
||||||
|
maxHeight: PropTypes.number.isRequired,
|
||||||
|
lastElement: PropTypes.bool,
|
||||||
|
columnRenderer: PropTypes.func
|
||||||
|
};
|
||||||
|
|
||||||
|
//----------------
|
||||||
|
//Интерфейс модуля
|
||||||
|
//----------------
|
||||||
|
|
||||||
|
export { P8PCyclogramHeaderColumn };
|
||||||
51
app/components/p8p_cyclogram/p8p_cyclogram_column_lines.js
Normal file
51
app/components/p8p_cyclogram/p8p_cyclogram_column_lines.js
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
/*
|
||||||
|
Парус 8 - Панели мониторинга - Циклограмма
|
||||||
|
Компонент: Линии колонки таблицы
|
||||||
|
*/
|
||||||
|
|
||||||
|
//---------------------
|
||||||
|
//Подключение библиотек
|
||||||
|
//---------------------
|
||||||
|
|
||||||
|
import React from "react"; //Классы React
|
||||||
|
import PropTypes from "prop-types"; //Контроль свойств компонента
|
||||||
|
|
||||||
|
//-----------
|
||||||
|
//Тело модуля
|
||||||
|
//-----------
|
||||||
|
|
||||||
|
//Линии колонок таблицы
|
||||||
|
const P8PCyclogramColumnsLines = ({ columns, shift, y1, y2 }) => {
|
||||||
|
//Инициализируем старт текущей колонки
|
||||||
|
let prevColumnEnd = 0;
|
||||||
|
return (
|
||||||
|
<g>
|
||||||
|
{columns.map((column, index) => {
|
||||||
|
//Аккумулируем окончание последней колонки с учетом сдвига
|
||||||
|
prevColumnEnd = index !== 0 ? prevColumnEnd + (columns[index - 1].end - columns[index - 1].start) * shift : 0;
|
||||||
|
return <line x1={prevColumnEnd} y1={y1} x2={prevColumnEnd} y2={y2} stroke="#e0e0e0" key={index} />;
|
||||||
|
})}
|
||||||
|
<line
|
||||||
|
x1={prevColumnEnd + (columns[columns.length - 1].end - columns[columns.length - 1].start) * shift}
|
||||||
|
y1={y1}
|
||||||
|
x2={prevColumnEnd + (columns[columns.length - 1].end - columns[columns.length - 1].start) * shift}
|
||||||
|
y2={y2}
|
||||||
|
stroke="#e0e0e0"
|
||||||
|
/>
|
||||||
|
</g>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
//Контроль свойств - Линии колонок таблицы
|
||||||
|
P8PCyclogramColumnsLines.propTypes = {
|
||||||
|
columns: PropTypes.array.isRequired,
|
||||||
|
shift: PropTypes.number.isRequired,
|
||||||
|
y1: PropTypes.number.isRequired,
|
||||||
|
y2: PropTypes.number.isRequired
|
||||||
|
};
|
||||||
|
|
||||||
|
//----------------
|
||||||
|
//Интерфейс модуля
|
||||||
|
//----------------
|
||||||
|
|
||||||
|
export { P8PCyclogramColumnsLines };
|
||||||
80
app/components/p8p_cyclogram/p8p_cyclogram_constants.js
Normal file
80
app/components/p8p_cyclogram/p8p_cyclogram_constants.js
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
/*
|
||||||
|
Парус 8 - Панели мониторинга - Циклограмма
|
||||||
|
Компонент: Константы
|
||||||
|
*/
|
||||||
|
|
||||||
|
//---------------------
|
||||||
|
//Подключение библиотек
|
||||||
|
//---------------------
|
||||||
|
|
||||||
|
import PropTypes from "prop-types"; //Контроль свойств компонента
|
||||||
|
|
||||||
|
//-----------
|
||||||
|
//Тело модуля
|
||||||
|
//-----------
|
||||||
|
|
||||||
|
//Уровни масштаба
|
||||||
|
const P8P_CYCLOGRAM_ZOOM = [0.2, 0.4, 0.7, 1, 1.5, 2, 2.5];
|
||||||
|
|
||||||
|
//Параметры элементов циклограммы
|
||||||
|
const NDEFAULT_LINE_HEIGHT = 20;
|
||||||
|
const NDEFAULT_HEADER_HEIGHT = 35;
|
||||||
|
|
||||||
|
//Высота заголовка
|
||||||
|
const TITLE_HEIGHT = "44px";
|
||||||
|
|
||||||
|
//Высота панели масштабирования
|
||||||
|
const ZOOM_HEIGHT = "56px";
|
||||||
|
|
||||||
|
//Структура колонки
|
||||||
|
const P8P_CYCLOGRAM_COLUMN_SHAPE = PropTypes.shape({
|
||||||
|
name: PropTypes.string.isRequired,
|
||||||
|
start: PropTypes.number.isRequired,
|
||||||
|
end: PropTypes.number.isRequired
|
||||||
|
});
|
||||||
|
|
||||||
|
//Структура группы
|
||||||
|
const P8P_CYCLOGRAM_GROUP_SHAPE = PropTypes.shape({
|
||||||
|
name: PropTypes.string.isRequired,
|
||||||
|
height: PropTypes.number.isRequired,
|
||||||
|
width: PropTypes.number.isRequired,
|
||||||
|
visible: PropTypes.bool.isRequired
|
||||||
|
});
|
||||||
|
|
||||||
|
//Структура задачи
|
||||||
|
const P8P_CYCLOGRAM_TASK_SHAPE = PropTypes.shape({
|
||||||
|
id: PropTypes.string.isRequired,
|
||||||
|
rn: PropTypes.number.isRequired,
|
||||||
|
name: PropTypes.string.isRequired,
|
||||||
|
fullName: PropTypes.string.isRequired,
|
||||||
|
lineNumb: PropTypes.number.isRequired,
|
||||||
|
start: PropTypes.number.isRequired,
|
||||||
|
end: PropTypes.number.isRequired,
|
||||||
|
group: PropTypes.string,
|
||||||
|
bgColor: PropTypes.string,
|
||||||
|
textColor: PropTypes.string,
|
||||||
|
highlightColor: PropTypes.string
|
||||||
|
});
|
||||||
|
|
||||||
|
//Структура динамического атрибута задачи
|
||||||
|
const P8P_CYCLOGRAM_TASK_ATTRIBUTE_SHAPE = PropTypes.shape({
|
||||||
|
name: PropTypes.string.isRequired,
|
||||||
|
caption: PropTypes.string.isRequired,
|
||||||
|
visible: PropTypes.bool.isRequired
|
||||||
|
});
|
||||||
|
|
||||||
|
//----------------
|
||||||
|
//Интерфейс модуля
|
||||||
|
//----------------
|
||||||
|
|
||||||
|
export {
|
||||||
|
P8P_CYCLOGRAM_ZOOM,
|
||||||
|
NDEFAULT_LINE_HEIGHT,
|
||||||
|
NDEFAULT_HEADER_HEIGHT,
|
||||||
|
TITLE_HEIGHT,
|
||||||
|
ZOOM_HEIGHT,
|
||||||
|
P8P_CYCLOGRAM_COLUMN_SHAPE,
|
||||||
|
P8P_CYCLOGRAM_GROUP_SHAPE,
|
||||||
|
P8P_CYCLOGRAM_TASK_SHAPE,
|
||||||
|
P8P_CYCLOGRAM_TASK_ATTRIBUTE_SHAPE
|
||||||
|
};
|
||||||
49
app/components/p8p_cyclogram/p8p_cyclogram_grid.js
Normal file
49
app/components/p8p_cyclogram/p8p_cyclogram_grid.js
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
/*
|
||||||
|
Парус 8 - Панели мониторинга - Циклограмма
|
||||||
|
Компонент: Фон таблицы
|
||||||
|
*/
|
||||||
|
|
||||||
|
//---------------------
|
||||||
|
//Подключение библиотек
|
||||||
|
//---------------------
|
||||||
|
|
||||||
|
import React from "react"; //Классы React
|
||||||
|
import PropTypes from "prop-types"; //Контроль свойств компонента
|
||||||
|
import { P8PCyclogramRowsGrid } from "./p8p_cyclogram_rows_grid"; //Фон строк таблицы
|
||||||
|
import { P8PCyclogramRowsLines } from "./p8p_cyclogram_row_lines"; //Линии строк таблицы
|
||||||
|
import { P8PCyclogramColumnsLines } from "./p8p_cyclogram_column_lines"; //Линии колонок таблицы
|
||||||
|
import { NDEFAULT_HEADER_HEIGHT } from "./p8p_cyclogram_constants"; //Константы циклограммы
|
||||||
|
|
||||||
|
//-----------
|
||||||
|
//Тело модуля
|
||||||
|
//-----------
|
||||||
|
|
||||||
|
//Фон таблицы
|
||||||
|
const P8PCyclogramGrid = ({ tasks, columns, shift, maxWidth, maxHeight, lineHeight }) => {
|
||||||
|
//Формируем массив строк исходя из максимального значения строки задачи
|
||||||
|
const rows = Array.from(Array(Math.max(...tasks.map(o => o.lineNumb)) + 1).keys());
|
||||||
|
return (
|
||||||
|
<g className="grid">
|
||||||
|
<rect x="0" y="0" width={maxWidth} height={maxHeight}></rect>
|
||||||
|
<P8PCyclogramRowsGrid rows={rows} maxWidth={maxWidth} lineHeight={lineHeight} />
|
||||||
|
<P8PCyclogramRowsLines rows={rows} maxWidth={maxWidth} lineHeight={lineHeight} />
|
||||||
|
<P8PCyclogramColumnsLines columns={columns} shift={shift} y1={NDEFAULT_HEADER_HEIGHT} y2={maxHeight} />
|
||||||
|
</g>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
//Контроль свойств - Фон таблицы
|
||||||
|
P8PCyclogramGrid.propTypes = {
|
||||||
|
tasks: PropTypes.array.isRequired,
|
||||||
|
columns: PropTypes.array.isRequired,
|
||||||
|
shift: PropTypes.number.isRequired,
|
||||||
|
maxWidth: PropTypes.number.isRequired,
|
||||||
|
maxHeight: PropTypes.number.isRequired,
|
||||||
|
lineHeight: PropTypes.number.isRequired
|
||||||
|
};
|
||||||
|
|
||||||
|
//----------------
|
||||||
|
//Интерфейс модуля
|
||||||
|
//----------------
|
||||||
|
|
||||||
|
export { P8PCyclogramGrid };
|
||||||
63
app/components/p8p_cyclogram/p8p_cyclogram_header.js
Normal file
63
app/components/p8p_cyclogram/p8p_cyclogram_header.js
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
/*
|
||||||
|
Парус 8 - Панели мониторинга - Циклограмма
|
||||||
|
Компонент: Заголовок
|
||||||
|
*/
|
||||||
|
|
||||||
|
//---------------------
|
||||||
|
//Подключение библиотек
|
||||||
|
//---------------------
|
||||||
|
|
||||||
|
import React from "react"; //Классы React
|
||||||
|
import PropTypes from "prop-types"; //Контроль свойств компонента
|
||||||
|
import { NDEFAULT_HEADER_HEIGHT } from "./p8p_cyclogram_constants"; //Константы циклограммы
|
||||||
|
import { P8PCyclogramHeaderColumn } from "./p8p_cyclogram_column"; //Колонка циклограммы
|
||||||
|
import { P8PCyclogramColumnsLines } from "./p8p_cyclogram_column_lines"; //Линии колонок таблицы
|
||||||
|
|
||||||
|
//-----------
|
||||||
|
//Тело модуля
|
||||||
|
//-----------
|
||||||
|
|
||||||
|
//Заголовок
|
||||||
|
const P8PCyclogramHeader = ({ columns, shift, maxWidth, maxHeight, columnRenderer, headerBlock }) => {
|
||||||
|
//Инициализируем старт текущей колонки
|
||||||
|
let prevColumnEnd = 0;
|
||||||
|
return (
|
||||||
|
<g className="header" ref={headerBlock}>
|
||||||
|
<rect x="0" y="0" width={maxWidth} height={NDEFAULT_HEADER_HEIGHT} fill="#ffffff" stroke="#e0e0e0" strokeWidth="1.4"></rect>
|
||||||
|
{columns.map((column, index) => {
|
||||||
|
//Аккумулируем окончание последней колонки с учетом сдвига
|
||||||
|
prevColumnEnd = index !== 0 ? prevColumnEnd + (columns[index - 1].end - columns[index - 1].start) * shift : 0;
|
||||||
|
return (
|
||||||
|
<P8PCyclogramHeaderColumn
|
||||||
|
column={column}
|
||||||
|
shift={shift}
|
||||||
|
start={prevColumnEnd}
|
||||||
|
maxHeight={maxHeight}
|
||||||
|
lastElement={columns.length - 1 === index}
|
||||||
|
columnRenderer={columnRenderer}
|
||||||
|
key={index}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
<g className="columnsDividers">
|
||||||
|
<P8PCyclogramColumnsLines columns={columns} shift={shift} y1={0} y2={NDEFAULT_HEADER_HEIGHT} />
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
//Контроль свойств - Заголовок
|
||||||
|
P8PCyclogramHeader.propTypes = {
|
||||||
|
columns: PropTypes.array.isRequired,
|
||||||
|
shift: PropTypes.number.isRequired,
|
||||||
|
maxWidth: PropTypes.number.isRequired,
|
||||||
|
maxHeight: PropTypes.number.isRequired,
|
||||||
|
columnRenderer: PropTypes.func,
|
||||||
|
headerBlock: PropTypes.object
|
||||||
|
};
|
||||||
|
|
||||||
|
//----------------
|
||||||
|
//Интерфейс модуля
|
||||||
|
//----------------
|
||||||
|
|
||||||
|
export { P8PCyclogramHeader };
|
||||||
42
app/components/p8p_cyclogram/p8p_cyclogram_row_lines.js
Normal file
42
app/components/p8p_cyclogram/p8p_cyclogram_row_lines.js
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
/*
|
||||||
|
Парус 8 - Панели мониторинга - Циклограмма
|
||||||
|
Компонент: Линии строк таблицы
|
||||||
|
*/
|
||||||
|
|
||||||
|
//---------------------
|
||||||
|
//Подключение библиотек
|
||||||
|
//---------------------
|
||||||
|
|
||||||
|
import React from "react"; //Классы React
|
||||||
|
import PropTypes from "prop-types"; //Контроль свойств компонента
|
||||||
|
import { NDEFAULT_HEADER_HEIGHT } from "./p8p_cyclogram_constants"; //Константы циклограммы
|
||||||
|
|
||||||
|
//Линии строк таблицы
|
||||||
|
const P8PCyclogramRowsLines = ({ rows, maxWidth, lineHeight }) => {
|
||||||
|
return (
|
||||||
|
<g>
|
||||||
|
{rows.map((el, index) => (
|
||||||
|
<line
|
||||||
|
x1="0"
|
||||||
|
y1={NDEFAULT_HEADER_HEIGHT + lineHeight + index * lineHeight}
|
||||||
|
x2={maxWidth}
|
||||||
|
y2={NDEFAULT_HEADER_HEIGHT + lineHeight + index * lineHeight}
|
||||||
|
key={index}
|
||||||
|
></line>
|
||||||
|
))}
|
||||||
|
</g>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
//Контроль свойств - Линии строк таблицы
|
||||||
|
P8PCyclogramRowsLines.propTypes = {
|
||||||
|
rows: PropTypes.array.isRequired,
|
||||||
|
maxWidth: PropTypes.number.isRequired,
|
||||||
|
lineHeight: PropTypes.number.isRequired
|
||||||
|
};
|
||||||
|
|
||||||
|
//----------------
|
||||||
|
//Интерфейс модуля
|
||||||
|
//----------------
|
||||||
|
|
||||||
|
export { P8PCyclogramRowsLines };
|
||||||
44
app/components/p8p_cyclogram/p8p_cyclogram_rows_grid.js
Normal file
44
app/components/p8p_cyclogram/p8p_cyclogram_rows_grid.js
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
/*
|
||||||
|
Парус 8 - Панели мониторинга - Циклограмма
|
||||||
|
Компонент: Фон строк таблицы
|
||||||
|
*/
|
||||||
|
|
||||||
|
//---------------------
|
||||||
|
//Подключение библиотек
|
||||||
|
//---------------------
|
||||||
|
|
||||||
|
import React from "react"; //Классы React
|
||||||
|
import PropTypes from "prop-types"; //Контроль свойств компонента
|
||||||
|
import { Box } from "@mui/material"; //Интерфейсные компоненты
|
||||||
|
import { P8P_BOX_CYCLOGRAM_ROW } from "../../theme/styles/box"; //Стили контейнеров
|
||||||
|
import { NDEFAULT_HEADER_HEIGHT } from "./p8p_cyclogram_constants"; //Константы циклограммы
|
||||||
|
|
||||||
|
//-----------
|
||||||
|
//Тело модуля
|
||||||
|
//-----------
|
||||||
|
|
||||||
|
//Фон строк таблицы
|
||||||
|
const P8PCyclogramRowsGrid = ({ rows, maxWidth, lineHeight }) => {
|
||||||
|
return (
|
||||||
|
<g>
|
||||||
|
{rows.map((el, index) => (
|
||||||
|
<foreignObject x="0" y={NDEFAULT_HEADER_HEIGHT + index * lineHeight} width={maxWidth} height={lineHeight} key={index}>
|
||||||
|
<Box sx={P8P_BOX_CYCLOGRAM_ROW({ index })} height={lineHeight} />
|
||||||
|
</foreignObject>
|
||||||
|
))}
|
||||||
|
</g>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
//Контроль свойств - Фон строк таблицы
|
||||||
|
P8PCyclogramRowsGrid.propTypes = {
|
||||||
|
rows: PropTypes.array.isRequired,
|
||||||
|
maxWidth: PropTypes.number.isRequired,
|
||||||
|
lineHeight: PropTypes.number.isRequired
|
||||||
|
};
|
||||||
|
|
||||||
|
//----------------
|
||||||
|
//Интерфейс модуля
|
||||||
|
//----------------
|
||||||
|
|
||||||
|
export { P8PCyclogramRowsGrid };
|
||||||
77
app/components/p8p_cyclogram/p8p_cyclogram_task.js
Normal file
77
app/components/p8p_cyclogram/p8p_cyclogram_task.js
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
/*
|
||||||
|
Парус 8 - Панели мониторинга - Циклограмма
|
||||||
|
Компонент: Задача
|
||||||
|
*/
|
||||||
|
|
||||||
|
//---------------------
|
||||||
|
//Подключение библиотек
|
||||||
|
//---------------------
|
||||||
|
|
||||||
|
import React from "react"; //Классы React
|
||||||
|
import PropTypes from "prop-types"; //Контроль свойств компонента
|
||||||
|
import { Box, Typography } from "@mui/material"; //Интерфейсные компоненты
|
||||||
|
import { hasValue } from "../../core/utils"; //Вспомогательный функции
|
||||||
|
import { P8P_TYPOGRAPHY_VARIANT } from "../../theme/p8p_typography"; //Варианты шрифтов
|
||||||
|
import { P8P_BOX_CYCLOGRAM_TASK } from "../../theme/styles/box"; //Стили контейнеров
|
||||||
|
import { NDEFAULT_HEADER_HEIGHT } from "./p8p_cyclogram_constants"; //Константы циклограммы
|
||||||
|
import { P8P_TYPOGRAPHY_CG_TASK } from "../../theme/styles/typography"; //Стили текста
|
||||||
|
|
||||||
|
//-----------
|
||||||
|
//Тело модуля
|
||||||
|
//-----------
|
||||||
|
|
||||||
|
//Задача
|
||||||
|
const P8PCyclogramTask = ({ task, indexGrp, shift, lineHeight, openTaskEditor, taskRenderer }) => {
|
||||||
|
//Рассчитываем ширину задачи
|
||||||
|
const width = task.end !== 0 ? (task.end - task.start) * shift : 0;
|
||||||
|
//Формируем собственное отображение, если требуется
|
||||||
|
const customView = taskRenderer ? taskRenderer({ task, taskHeight: lineHeight, taskWidth: width }) || {} : {};
|
||||||
|
//Определение количества доступных строк
|
||||||
|
const availableLines = Math.floor(lineHeight / 18);
|
||||||
|
return (
|
||||||
|
<foreignObject
|
||||||
|
x={task.start !== 0 ? task.start * shift : 0}
|
||||||
|
y={NDEFAULT_HEADER_HEIGHT + task.lineNumb * lineHeight}
|
||||||
|
width={width}
|
||||||
|
height={lineHeight}
|
||||||
|
>
|
||||||
|
<Box
|
||||||
|
className={hasValue(indexGrp) ? `TaskGrp${indexGrp}` : null}
|
||||||
|
sx={{
|
||||||
|
...P8P_BOX_CYCLOGRAM_TASK({ lineHeight, bgColor: task.bgColor, textColor: task.textColor, highlightColor: task.highlightColor }),
|
||||||
|
...customView.taskStyle
|
||||||
|
}}
|
||||||
|
{...customView.taskProps}
|
||||||
|
onClick={() => openTaskEditor(task)}
|
||||||
|
>
|
||||||
|
{customView.data ? (
|
||||||
|
customView.data
|
||||||
|
) : (
|
||||||
|
<Typography
|
||||||
|
sx={P8P_TYPOGRAPHY_CG_TASK({ maxHeight: lineHeight, availableLines })}
|
||||||
|
variant={P8P_TYPOGRAPHY_VARIANT.BODY2_LIGHT}
|
||||||
|
title={task.name}
|
||||||
|
>
|
||||||
|
{task.name}
|
||||||
|
</Typography>
|
||||||
|
)}
|
||||||
|
</Box>
|
||||||
|
</foreignObject>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
//Контроль свойств - Задача
|
||||||
|
P8PCyclogramTask.propTypes = {
|
||||||
|
task: PropTypes.object.isRequired,
|
||||||
|
indexGrp: PropTypes.number,
|
||||||
|
shift: PropTypes.number.isRequired,
|
||||||
|
lineHeight: PropTypes.number.isRequired,
|
||||||
|
openTaskEditor: PropTypes.func.isRequired,
|
||||||
|
taskRenderer: PropTypes.func
|
||||||
|
};
|
||||||
|
|
||||||
|
//----------------
|
||||||
|
//Интерфейс модуля
|
||||||
|
//----------------
|
||||||
|
|
||||||
|
export { P8PCyclogramTask };
|
||||||
117
app/components/p8p_cyclogram/p8p_cyclogram_task_editor.js
Normal file
117
app/components/p8p_cyclogram/p8p_cyclogram_task_editor.js
Normal file
@ -0,0 +1,117 @@
|
|||||||
|
/*
|
||||||
|
Парус 8 - Панели мониторинга - Циклограмма
|
||||||
|
Компонент: Редактор задачи
|
||||||
|
*/
|
||||||
|
|
||||||
|
//---------------------
|
||||||
|
//Подключение библиотек
|
||||||
|
//---------------------
|
||||||
|
|
||||||
|
import React, { useState } from "react"; //Классы React
|
||||||
|
import PropTypes from "prop-types"; //Контроль свойств компонента
|
||||||
|
import { Dialog, DialogActions, DialogContent, Button, List, ListItem, ListItemText, Divider } from "@mui/material"; //Интерфейсные компоненты
|
||||||
|
import { hasValue } from "../../core/utils"; //Вспомогательный функции
|
||||||
|
import { P8P_DIALOG_CONTENT_VARIANT } from "../../theme/variants/p8p_dialog_content_variants"; //Варианты диалогов (содержимое)
|
||||||
|
import { P8P_LIST_VARIANT } from "../../theme/variants/p8p_list_variants"; //Варианты списков
|
||||||
|
import { P8P_LIST_ITEM_TEXT_VARIANT } from "../../theme/variants/p8p_list_item_text_variants"; //Варианты значений списков
|
||||||
|
import { P8P_BUTTON_VARIANT } from "../../theme/variants/p8p_button_variants"; //Варианты кнопок
|
||||||
|
import { P8P_CYCLOGRAM_TASK_SHAPE, P8P_CYCLOGRAM_TASK_ATTRIBUTE_SHAPE } from "./p8p_cyclogram_constants"; //Константы циклограммы
|
||||||
|
|
||||||
|
//-----------
|
||||||
|
//Тело модуля
|
||||||
|
//-----------
|
||||||
|
|
||||||
|
//Редактор задачи
|
||||||
|
const P8PCyclogramTaskEditor = ({
|
||||||
|
task,
|
||||||
|
taskAttributes,
|
||||||
|
onOk,
|
||||||
|
onCancel,
|
||||||
|
taskAttributeRenderer,
|
||||||
|
taskDialogRenderer,
|
||||||
|
nameCaption,
|
||||||
|
okBtnCaption,
|
||||||
|
cancelBtnCaption
|
||||||
|
}) => {
|
||||||
|
//Собственное состояние
|
||||||
|
const [state] = useState({
|
||||||
|
start: task.start,
|
||||||
|
end: task.end
|
||||||
|
});
|
||||||
|
|
||||||
|
//Отображаемые атрибуты
|
||||||
|
const dispTaskAttributes =
|
||||||
|
Array.isArray(taskAttributes) && taskAttributes.length > 0 ? taskAttributes.filter(attr => attr.visible && hasValue(task[attr.name])) : [];
|
||||||
|
|
||||||
|
//При сохранении
|
||||||
|
const handleOk = () => (onOk && state.start && state.end ? onOk() : null);
|
||||||
|
|
||||||
|
//При отмене
|
||||||
|
const handleCancel = () => (onCancel ? onCancel() : null);
|
||||||
|
|
||||||
|
//Генерация содержимого
|
||||||
|
return (
|
||||||
|
<Dialog open onClose={handleCancel}>
|
||||||
|
{taskDialogRenderer ? (
|
||||||
|
taskDialogRenderer({ task, taskAttributes, close: handleCancel })
|
||||||
|
) : (
|
||||||
|
<>
|
||||||
|
<DialogContent variant={P8P_DIALOG_CONTENT_VARIANT.TASK}>
|
||||||
|
<List variant={P8P_LIST_VARIANT.GANTT_TASK}>
|
||||||
|
<ListItem alignItems="flex-start">
|
||||||
|
<ListItemText variant={P8P_LIST_ITEM_TEXT_VARIANT.PRIMARY} primary={nameCaption} secondary={task.fullName} />
|
||||||
|
</ListItem>
|
||||||
|
{dispTaskAttributes.length > 0 ? <Divider component="li" /> : null}
|
||||||
|
{dispTaskAttributes.length > 0
|
||||||
|
? dispTaskAttributes.map((attr, i) => {
|
||||||
|
const defaultView = task[attr.name];
|
||||||
|
const customView = taskAttributeRenderer ? taskAttributeRenderer({ task, attribute: attr }) : null;
|
||||||
|
return (
|
||||||
|
<React.Fragment key={i}>
|
||||||
|
<ListItem alignItems="flex-start">
|
||||||
|
<ListItemText
|
||||||
|
variant={P8P_LIST_ITEM_TEXT_VARIANT.PRIMARY}
|
||||||
|
primary={attr.caption}
|
||||||
|
secondaryTypographyProps={{ component: "span" }}
|
||||||
|
secondary={customView ? customView : defaultView}
|
||||||
|
/>
|
||||||
|
</ListItem>
|
||||||
|
{i < dispTaskAttributes.length - 1 ? <Divider component="li" /> : null}
|
||||||
|
</React.Fragment>
|
||||||
|
);
|
||||||
|
})
|
||||||
|
: null}
|
||||||
|
</List>
|
||||||
|
</DialogContent>
|
||||||
|
<DialogActions>
|
||||||
|
<Button variant={P8P_BUTTON_VARIANT.SECONDARY} onClick={handleCancel}>
|
||||||
|
{cancelBtnCaption}
|
||||||
|
</Button>
|
||||||
|
<Button variant={P8P_BUTTON_VARIANT.PRIMARY} onClick={handleOk}>
|
||||||
|
{okBtnCaption}
|
||||||
|
</Button>
|
||||||
|
</DialogActions>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</Dialog>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
//Контроль свойств - Редактор задачи
|
||||||
|
P8PCyclogramTaskEditor.propTypes = {
|
||||||
|
task: P8P_CYCLOGRAM_TASK_SHAPE,
|
||||||
|
taskAttributes: PropTypes.arrayOf(P8P_CYCLOGRAM_TASK_ATTRIBUTE_SHAPE),
|
||||||
|
onOk: PropTypes.func,
|
||||||
|
onCancel: PropTypes.func,
|
||||||
|
taskAttributeRenderer: PropTypes.func,
|
||||||
|
taskDialogRenderer: PropTypes.func,
|
||||||
|
nameCaption: PropTypes.string.isRequired,
|
||||||
|
okBtnCaption: PropTypes.string.isRequired,
|
||||||
|
cancelBtnCaption: PropTypes.string.isRequired
|
||||||
|
};
|
||||||
|
|
||||||
|
//----------------
|
||||||
|
//Интерфейс модуля
|
||||||
|
//----------------
|
||||||
|
|
||||||
|
export { P8PCyclogramTaskEditor };
|
||||||
34
app/components/p8p_cyclogram/p8p_cyclogram_utils.js
Normal file
34
app/components/p8p_cyclogram/p8p_cyclogram_utils.js
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
/*
|
||||||
|
Парус 8 - Панели мониторинга - Циклограмма
|
||||||
|
Ядро: Вспомогательные функции
|
||||||
|
*/
|
||||||
|
|
||||||
|
//-----------
|
||||||
|
//Тело модуля
|
||||||
|
//-----------
|
||||||
|
|
||||||
|
//Определение сдвига для максимальной ширины колонок
|
||||||
|
export const getShift = (columns, currentColumnsMaxWidth, maxCyclogramWidth) => {
|
||||||
|
//Определяем доступное пространство для расширения
|
||||||
|
let maxWidthDiff = maxCyclogramWidth - currentColumnsMaxWidth;
|
||||||
|
//Инициализируем значение сдвига
|
||||||
|
let shift = 1;
|
||||||
|
//Если доступно больше ширины и есть пространство для расширения
|
||||||
|
if (maxCyclogramWidth > currentColumnsMaxWidth && maxCyclogramWidth - maxWidthDiff > columns.length) {
|
||||||
|
//Определяем доступный сдвиг колонок
|
||||||
|
shift = maxCyclogramWidth / currentColumnsMaxWidth;
|
||||||
|
}
|
||||||
|
//Возвращаем сдвиг
|
||||||
|
return shift;
|
||||||
|
};
|
||||||
|
|
||||||
|
//Формирование стилей для группы
|
||||||
|
export const getGroupStyles = (indexGrp, highlightColor) => {
|
||||||
|
return `.main .TaskGrp${indexGrp}:hover .TaskGrp${indexGrp} {
|
||||||
|
${highlightColor ? `background: ${highlightColor};` : `filter: brightness(1.15);`}
|
||||||
|
}
|
||||||
|
.main:has(.TaskGrp${indexGrp}:hover) .TaskGrpHeader${indexGrp} {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
};
|
||||||
171
app/components/p8p_cyclogram/p8p_cyclogram_view.js
Normal file
171
app/components/p8p_cyclogram/p8p_cyclogram_view.js
Normal file
@ -0,0 +1,171 @@
|
|||||||
|
/*
|
||||||
|
Парус 8 - Панели мониторинга - Циклограмма
|
||||||
|
Компонент: Представление циклограммы
|
||||||
|
*/
|
||||||
|
|
||||||
|
//---------------------
|
||||||
|
//Подключение библиотек
|
||||||
|
//---------------------
|
||||||
|
|
||||||
|
import React from "react"; //Классы React
|
||||||
|
import PropTypes from "prop-types"; //Контроль свойств компонента
|
||||||
|
import { Box, Typography } from "@mui/material"; //Интерфейсные компоненты
|
||||||
|
import { hasValue } from "../../core/utils"; //Вспомогательный функции
|
||||||
|
import { P8P_TYPOGRAPHY_VARIANT } from "../../theme/p8p_typography"; //Варианты шрифтов
|
||||||
|
import { P8P_BOX_CYCLOGRAM_GROUP } from "../../theme/styles/box"; //Стили контейнеров
|
||||||
|
import { NDEFAULT_HEADER_HEIGHT } from "./p8p_cyclogram_constants"; //Константы циклограммы
|
||||||
|
import { P8PCyclogramTask } from "./p8p_cyclogram_task"; //Задача циклограммы
|
||||||
|
import { P8PCyclogramHeader } from "./p8p_cyclogram_header"; //Заголовок циклограммы
|
||||||
|
import { getGroupStyles } from "./p8p_cyclogram_utils"; //Вспомогательные функции циклограммы
|
||||||
|
import { P8P_TYPOGRAPHY_CG_GROUP } from "../../theme/styles/typography"; //Стили текста
|
||||||
|
|
||||||
|
//-----------
|
||||||
|
//Тело модуля
|
||||||
|
//-----------
|
||||||
|
|
||||||
|
//Представление циклограммы
|
||||||
|
const P8PCyclogramView = ({
|
||||||
|
columns,
|
||||||
|
groups,
|
||||||
|
tasks,
|
||||||
|
shift,
|
||||||
|
lineHeight,
|
||||||
|
maxWidth,
|
||||||
|
maxHeight,
|
||||||
|
openTaskEditor,
|
||||||
|
groupHeaderRenderer,
|
||||||
|
taskRenderer,
|
||||||
|
columnRenderer,
|
||||||
|
headerBlock
|
||||||
|
}) => {
|
||||||
|
//Инициализируем коллекцию тасков с группами
|
||||||
|
const tasksWithGroup = tasks.filter(task => hasValue(task.groupName));
|
||||||
|
//Инициализируем коллекцию тасков без групп
|
||||||
|
const tasksWithoutGroup = tasks.filter(task => !hasValue(task.groupName));
|
||||||
|
//Инициализируем коллекцию отображаемых групп
|
||||||
|
const visibleGroups = groups ? groups.filter(group => group.visible) : [];
|
||||||
|
return (
|
||||||
|
<g className="main">
|
||||||
|
<g className="tasks">
|
||||||
|
{visibleGroups.length !== 0
|
||||||
|
? visibleGroups.map((grp, indexGrp) => {
|
||||||
|
//Считываем задачи группы
|
||||||
|
let groupTasks = tasksWithGroup.filter(task => task.groupName === grp.name);
|
||||||
|
//Если по данной группе нет тасков - ничего не выводим
|
||||||
|
if (groupTasks.length === 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<g className={`TaskGrp${indexGrp}`} key={indexGrp}>
|
||||||
|
{groupTasks.map((task, index) => (
|
||||||
|
<P8PCyclogramTask
|
||||||
|
task={task}
|
||||||
|
indexGrp={indexGrp}
|
||||||
|
shift={shift}
|
||||||
|
lineHeight={lineHeight}
|
||||||
|
openTaskEditor={openTaskEditor}
|
||||||
|
taskRenderer={taskRenderer}
|
||||||
|
key={index}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
<style>{getGroupStyles(indexGrp, grp.highlightColor)}</style>
|
||||||
|
</g>
|
||||||
|
);
|
||||||
|
})
|
||||||
|
: null}
|
||||||
|
<g className={`TasksWithoutGroups`}>
|
||||||
|
{tasksWithoutGroup.map((task, index) => {
|
||||||
|
return (
|
||||||
|
<P8PCyclogramTask
|
||||||
|
task={task}
|
||||||
|
shift={shift}
|
||||||
|
lineHeight={lineHeight}
|
||||||
|
openTaskEditor={openTaskEditor}
|
||||||
|
taskRenderer={taskRenderer}
|
||||||
|
key={index}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
<P8PCyclogramHeader
|
||||||
|
columns={columns}
|
||||||
|
shift={shift}
|
||||||
|
maxWidth={maxWidth}
|
||||||
|
maxHeight={maxHeight}
|
||||||
|
columnRenderer={columnRenderer}
|
||||||
|
headerBlock={headerBlock}
|
||||||
|
/>
|
||||||
|
{visibleGroups.length !== 0 ? (
|
||||||
|
<g className="groups">
|
||||||
|
{visibleGroups.map((grp, indexGrp) => {
|
||||||
|
//Инициализируем параметры группы
|
||||||
|
let defaultView = null;
|
||||||
|
let customView = null;
|
||||||
|
let groupHeaderX = 0;
|
||||||
|
let groupHeaderY = 0;
|
||||||
|
let groupTasks = tasksWithGroup.filter(task => task.groupName === grp.name);
|
||||||
|
//Если по данной группе нет тасков - ничего не выводим
|
||||||
|
if (groupTasks.length === 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
//Если требуется отображать заголовок группы
|
||||||
|
if (grp.visible) {
|
||||||
|
//Формируем отображение по умолчанию
|
||||||
|
defaultView = (
|
||||||
|
<Box sx={P8P_BOX_CYCLOGRAM_GROUP({ height: grp.height })}>
|
||||||
|
<Typography
|
||||||
|
sx={P8P_TYPOGRAPHY_CG_GROUP({ maxWidth: grp.width, maxHeight: grp.height })}
|
||||||
|
variant={P8P_TYPOGRAPHY_VARIANT.BODY3_LIGHT}
|
||||||
|
>
|
||||||
|
{grp.name}
|
||||||
|
</Typography>
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
//Формируем собственное отображение, если требуется
|
||||||
|
customView = groupHeaderRenderer ? groupHeaderRenderer({ group: grp }) : null;
|
||||||
|
//Рассчитываем координаты заголовка группы
|
||||||
|
groupHeaderX = Math.min(...groupTasks.map(o => o.start)) * shift;
|
||||||
|
groupHeaderY = NDEFAULT_HEADER_HEIGHT + Math.min(...groupTasks.map(o => o.lineNumb)) * lineHeight - grp.height - 5;
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<foreignObject
|
||||||
|
x={groupHeaderX}
|
||||||
|
y={groupHeaderY}
|
||||||
|
width={grp.width}
|
||||||
|
height={grp.height}
|
||||||
|
className={`TaskGrpHeader${indexGrp}`}
|
||||||
|
display="none"
|
||||||
|
key={indexGrp}
|
||||||
|
>
|
||||||
|
{customView ? customView : defaultView}
|
||||||
|
</foreignObject>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</g>
|
||||||
|
) : null}
|
||||||
|
</g>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
//Контроль свойств - Представление циклограммы
|
||||||
|
P8PCyclogramView.propTypes = {
|
||||||
|
columns: PropTypes.array.isRequired,
|
||||||
|
groups: PropTypes.array,
|
||||||
|
tasks: PropTypes.array.isRequired,
|
||||||
|
shift: PropTypes.number.isRequired,
|
||||||
|
lineHeight: PropTypes.number.isRequired,
|
||||||
|
maxWidth: PropTypes.number.isRequired,
|
||||||
|
maxHeight: PropTypes.number.isRequired,
|
||||||
|
openTaskEditor: PropTypes.func.isRequired,
|
||||||
|
groupHeaderRenderer: PropTypes.func,
|
||||||
|
taskRenderer: PropTypes.func,
|
||||||
|
columnRenderer: PropTypes.func,
|
||||||
|
headerBlock: PropTypes.object
|
||||||
|
};
|
||||||
|
|
||||||
|
//----------------
|
||||||
|
//Интерфейс модуля
|
||||||
|
//----------------
|
||||||
|
|
||||||
|
export { P8PCyclogramView };
|
||||||
@ -19,7 +19,7 @@ import {
|
|||||||
P8P_TABLE_FILTERS_HEIGHT,
|
P8P_TABLE_FILTERS_HEIGHT,
|
||||||
P8P_TABLE_PAGINATOR_ALIGN,
|
P8P_TABLE_PAGINATOR_ALIGN,
|
||||||
P8P_TABLE_PAGINATOR_POSITION
|
P8P_TABLE_PAGINATOR_POSITION
|
||||||
} from "./p8p_table"; //Таблица
|
} from "./p8p_table/p8p_table"; //Таблица
|
||||||
import { useP8PDataGrid } from "./p8p_data_grid_hooks"; //Хук для таблицы данных
|
import { useP8PDataGrid } from "./p8p_data_grid_hooks"; //Хук для таблицы данных
|
||||||
|
|
||||||
//---------
|
//---------
|
||||||
@ -92,6 +92,7 @@ const P8PDataGrid = ({
|
|||||||
valueFormatter,
|
valueFormatter,
|
||||||
containerComponent,
|
containerComponent,
|
||||||
containerComponentProps,
|
containerComponentProps,
|
||||||
|
headExpandCellStyle,
|
||||||
onOrderChanged,
|
onOrderChanged,
|
||||||
onFilterChanged,
|
onFilterChanged,
|
||||||
onPagesCountChanged,
|
onPagesCountChanged,
|
||||||
@ -187,6 +188,7 @@ const P8PDataGrid = ({
|
|||||||
containerComponent={containerComponent}
|
containerComponent={containerComponent}
|
||||||
containerComponentProps={containerComponentProps}
|
containerComponentProps={containerComponentProps}
|
||||||
morePagesBtnProps={morePagesBtnProps}
|
morePagesBtnProps={morePagesBtnProps}
|
||||||
|
headExpandCellStyle={headExpandCellStyle}
|
||||||
onOrderChanged={handleOrderChanged}
|
onOrderChanged={handleOrderChanged}
|
||||||
onFilterChanged={handleFilterChanged}
|
onFilterChanged={handleFilterChanged}
|
||||||
onPagesCountChanged={handlePagesCountChanged}
|
onPagesCountChanged={handlePagesCountChanged}
|
||||||
@ -233,6 +235,7 @@ P8PDataGrid.propTypes = {
|
|||||||
valueFormatter: PropTypes.func,
|
valueFormatter: PropTypes.func,
|
||||||
containerComponent: PropTypes.oneOfType([PropTypes.elementType, PropTypes.string]),
|
containerComponent: PropTypes.oneOfType([PropTypes.elementType, PropTypes.string]),
|
||||||
containerComponentProps: PropTypes.object,
|
containerComponentProps: PropTypes.object,
|
||||||
|
headExpandCellStyle: PropTypes.object,
|
||||||
onOrderChanged: PropTypes.func,
|
onOrderChanged: PropTypes.func,
|
||||||
onFilterChanged: PropTypes.func,
|
onFilterChanged: PropTypes.func,
|
||||||
onPagesCountChanged: PropTypes.func,
|
onPagesCountChanged: PropTypes.func,
|
||||||
|
|||||||
@ -12,7 +12,9 @@ import PropTypes from "prop-types"; //Контроль свойств компо
|
|||||||
import { Dialog, DialogTitle, DialogContent, DialogActions, Button } from "@mui/material"; //Интерфейсные компоненты
|
import { Dialog, DialogTitle, DialogContent, DialogActions, Button } from "@mui/material"; //Интерфейсные компоненты
|
||||||
import { BUTTONS } from "../../app.text"; //Общие текстовые ресурсы
|
import { BUTTONS } from "../../app.text"; //Общие текстовые ресурсы
|
||||||
import { P8P_INPUT, P8PInput } from "./p8p_input"; //Поле ввода
|
import { P8P_INPUT, P8PInput } from "./p8p_input"; //Поле ввода
|
||||||
import { APP_STYLES } from "../../app.styles"; //Типовые стили
|
import { P8P_DIALOG_CONTENT_VARIANT } from "../theme/variants/p8p_dialog_content_variants"; //Варианты содержимого диалога
|
||||||
|
import { P8P_BUTTON_VARIANT } from "../theme/variants/p8p_button_variants"; //Варианты кнопок
|
||||||
|
import { P8P_DIALOG_TITLE_VARIANT } from "../theme/variants/p8p_dialog_title_variants"; //Варианты заголовков диалога
|
||||||
|
|
||||||
//---------
|
//---------
|
||||||
//Константы
|
//Константы
|
||||||
@ -27,12 +29,6 @@ const P8P_DIALOG_WIDTH = {
|
|||||||
XL: "xl"
|
XL: "xl"
|
||||||
};
|
};
|
||||||
|
|
||||||
//Стили
|
|
||||||
const STYLES = {
|
|
||||||
SCROLL: display =>
|
|
||||||
display === true ? { overflow: "auto", ...APP_STYLES.SCROLL } : { overflow: "hidden", display: "flex", flexDirection: "column" }
|
|
||||||
};
|
|
||||||
|
|
||||||
//-----------------------
|
//-----------------------
|
||||||
//Вспомогательные функции
|
//Вспомогательные функции
|
||||||
//-----------------------
|
//-----------------------
|
||||||
@ -93,22 +89,29 @@ const P8PDialog = ({
|
|||||||
//Формирование представления
|
//Формирование представления
|
||||||
return (
|
return (
|
||||||
<Dialog onClose={handleClose} open {...{ ...(width ? { maxWidth: width } : {}), ...(fullWidth === true ? { fullWidth: true } : {}) }}>
|
<Dialog onClose={handleClose} open {...{ ...(width ? { maxWidth: width } : {}), ...(fullWidth === true ? { fullWidth: true } : {}) }}>
|
||||||
<DialogTitle>{title}</DialogTitle>
|
<DialogTitle variant={P8P_DIALOG_TITLE_VARIANT.PRIMARY}>{title}</DialogTitle>
|
||||||
<DialogContent sx={STYLES.SCROLL(scrollContent)}>
|
<DialogContent variant={scrollContent ? P8P_DIALOG_CONTENT_VARIANT.PRIMARY : P8P_DIALOG_CONTENT_VARIANT.HIDDEN}>
|
||||||
{inputsState.map((input, i) => (
|
{inputsState.map((input, i) => (
|
||||||
<P8PInput key={i} {...input} formValues={formValues} onChange={handleInputChange} />
|
<P8PInput key={i} {...input} formValues={formValues} onChange={handleInputChange} />
|
||||||
))}
|
))}
|
||||||
|
|
||||||
{children}
|
{children}
|
||||||
</DialogContent>
|
</DialogContent>
|
||||||
<DialogActions>
|
<DialogActions>
|
||||||
|
{onClose && (
|
||||||
|
<Button variant={P8P_BUTTON_VARIANT.OUTLINED} onClick={handleClose}>
|
||||||
|
{BUTTONS.CLOSE}
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
{onCancel && (
|
||||||
|
<Button variant={P8P_BUTTON_VARIANT.SECONDARY} onClick={handleCancel}>
|
||||||
|
{BUTTONS.CANCEL}
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
{onOk && (
|
{onOk && (
|
||||||
<Button disabled={okDisabled} onClick={handleOk}>
|
<Button variant={P8P_BUTTON_VARIANT.PRIMARY} disabled={okDisabled} onClick={handleOk}>
|
||||||
{BUTTONS.OK}
|
{BUTTONS.OK}
|
||||||
</Button>
|
</Button>
|
||||||
)}
|
)}
|
||||||
{onCancel && <Button onClick={handleCancel}>{BUTTONS.CANCEL}</Button>}
|
|
||||||
{onClose && <Button onClick={handleClose}>{BUTTONS.CLOSE}</Button>}
|
|
||||||
</DialogActions>
|
</DialogActions>
|
||||||
</Dialog>
|
</Dialog>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -10,17 +10,10 @@
|
|||||||
import React from "react"; //Классы React
|
import React from "react"; //Классы React
|
||||||
import PropTypes from "prop-types"; //Контроль свойств компонента
|
import PropTypes from "prop-types"; //Контроль свойств компонента
|
||||||
import { Dialog, AppBar, Toolbar, IconButton, Typography, Icon, DialogContent, DialogTitle } from "@mui/material"; //Интерфейсные компоненты
|
import { Dialog, AppBar, Toolbar, IconButton, Typography, Icon, DialogContent, DialogTitle } from "@mui/material"; //Интерфейсные компоненты
|
||||||
|
import { P8P_APP_BAR_VARIANT } from "../theme/variants/p8p_app_bar_variants"; //Варианты областей заголовка
|
||||||
//---------
|
import { P8P_TYPOGRAPHY_VARIANT } from "../theme/p8p_typography"; //Варианты шрифтов
|
||||||
//Константы
|
import { P8P_COMPONENT_ZERO_PADDING } from "../theme/styles/common"; //Стили - общие
|
||||||
//---------
|
import { P8P_TYPOGRAPHY_DIALOG_TITLE } from "../theme/styles/typography"; //Стили текста
|
||||||
|
|
||||||
//Стили
|
|
||||||
const STYLES = {
|
|
||||||
DIALOG_TITLE: { padding: 0 },
|
|
||||||
APP_BAR: { position: "relative" },
|
|
||||||
TITLE_TYPOGRAPHY: { ml: 2, flex: 1 }
|
|
||||||
};
|
|
||||||
|
|
||||||
//-----------
|
//-----------
|
||||||
//Тело модуля
|
//Тело модуля
|
||||||
@ -33,14 +26,14 @@ const P8PFullScreenDialog = ({ title, onClose, contentProps, children }) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Dialog fullScreen open onClose={handleClose} scroll="paper">
|
<Dialog fullScreen open onClose={handleClose} scroll="paper" p={0}>
|
||||||
<DialogTitle sx={STYLES.DIALOG_TITLE}>
|
<DialogTitle sx={P8P_COMPONENT_ZERO_PADDING}>
|
||||||
<AppBar sx={STYLES.APP_BAR}>
|
<AppBar variant={P8P_APP_BAR_VARIANT.RELATIVE}>
|
||||||
<Toolbar>
|
<Toolbar>
|
||||||
<IconButton edge="start" color="inherit" onClick={handleClose} aria-label="close">
|
<IconButton edge="start" color="inherit" onClick={handleClose} aria-label="close">
|
||||||
<Icon>close</Icon>
|
<Icon>close</Icon>
|
||||||
</IconButton>
|
</IconButton>
|
||||||
<Typography sx={STYLES.TITLE_TYPOGRAPHY} variant="h6" component="div">
|
<Typography variant={P8P_TYPOGRAPHY_VARIANT.H6} sx={P8P_TYPOGRAPHY_DIALOG_TITLE} component="div">
|
||||||
{title}
|
{title}
|
||||||
</Typography>
|
</Typography>
|
||||||
</Toolbar>
|
</Toolbar>
|
||||||
|
|||||||
@ -9,324 +9,23 @@
|
|||||||
|
|
||||||
import React, { useEffect, useState, useCallback, useRef } from "react"; //Классы React
|
import React, { useEffect, useState, useCallback, useRef } from "react"; //Классы React
|
||||||
import PropTypes from "prop-types"; //Контроль свойств компонента
|
import PropTypes from "prop-types"; //Контроль свойств компонента
|
||||||
import {
|
import { Box, IconButton, Icon, Typography, Link } from "@mui/material"; //Интерфейсные компоненты
|
||||||
Box,
|
|
||||||
IconButton,
|
|
||||||
Icon,
|
|
||||||
Typography,
|
|
||||||
Dialog,
|
|
||||||
DialogActions,
|
|
||||||
DialogContent,
|
|
||||||
TextField,
|
|
||||||
Button,
|
|
||||||
List,
|
|
||||||
ListItem,
|
|
||||||
ListItemText,
|
|
||||||
Divider,
|
|
||||||
Slider,
|
|
||||||
Link
|
|
||||||
} from "@mui/material"; //Интерфейсные компоненты
|
|
||||||
import { P8PAppInlineError } from "./p8p_app_message"; //Встраиваемое сообщение об ошибке
|
import { P8PAppInlineError } from "./p8p_app_message"; //Встраиваемое сообщение об ошибке
|
||||||
import { useP8PGantt } from "./p8p_gantt_hooks"; //Хук для диаграммы Ганта
|
import { useP8PGantt } from "./p8p_gantt/p8p_gantt_hooks"; //Хук для диаграммы Ганта
|
||||||
|
import {
|
||||||
//---------
|
P8P_GANTT_ZOOM,
|
||||||
//Константы
|
P8P_GANTT_ZOOM_VIEW_MODES,
|
||||||
//---------
|
P8P_GANTT_TASK_SHAPE,
|
||||||
|
P8P_GANTT_TASK_ATTRIBUTE_SHAPE,
|
||||||
//Уровни масштаба
|
P8P_GANTT_TASK_COLOR_SHAPE,
|
||||||
const P8P_GANTT_ZOOM = [0, 1, 2, 3, 4, 5];
|
TITLE_HEIGHT,
|
||||||
|
ZOOM_HEIGHT
|
||||||
//Уровни масштаба (строковые наименования в терминах библиотеки)
|
} from "./p8p_gantt/p8p_gantt_constants"; //Константы диаграммы Ганта
|
||||||
const P8P_GANTT_ZOOM_VIEW_MODES = {
|
import { P8PGanttTaskEditor, taskLegendDesc } from "./p8p_gantt/p8p_gantt_task_editor"; //Редактор задачи
|
||||||
0: "Quarter Day",
|
import { P8P_TYPOGRAPHY_VARIANT } from "../theme/p8p_typography"; //Варианты шрифтов
|
||||||
1: "Half Day",
|
import { P8P_COMPONENT_HEIGHT } from "../theme/styles/common"; //Стили - общие
|
||||||
2: "Day",
|
import { P8P_BOX_GANTT } from "../theme/styles/box"; //Стили контейнеров
|
||||||
3: "Week",
|
import { P8P_TYPOGRAPHY_TITLE } from "../theme/styles/typography"; //Стили текста
|
||||||
4: "Month",
|
|
||||||
5: "Year"
|
|
||||||
};
|
|
||||||
|
|
||||||
//Структура задачи
|
|
||||||
const P8P_GANTT_TASK_SHAPE = PropTypes.shape({
|
|
||||||
id: PropTypes.string.isRequired,
|
|
||||||
rn: PropTypes.number.isRequired,
|
|
||||||
numb: PropTypes.string.isRequired,
|
|
||||||
name: PropTypes.string.isRequired,
|
|
||||||
fullName: PropTypes.string.isRequired,
|
|
||||||
start: PropTypes.string.isRequired,
|
|
||||||
end: PropTypes.string.isRequired,
|
|
||||||
progress: PropTypes.number,
|
|
||||||
dependencies: PropTypes.array,
|
|
||||||
readOnly: PropTypes.bool,
|
|
||||||
readOnlyDates: PropTypes.bool,
|
|
||||||
readOnlyProgress: PropTypes.bool,
|
|
||||||
bgColor: PropTypes.string,
|
|
||||||
textColor: PropTypes.string,
|
|
||||||
bgProgressColor: PropTypes.string
|
|
||||||
});
|
|
||||||
|
|
||||||
//Структура динамического атрибута задачи
|
|
||||||
const P8P_GANTT_TASK_ATTRIBUTE_SHAPE = PropTypes.shape({
|
|
||||||
name: PropTypes.string.isRequired,
|
|
||||||
caption: PropTypes.string.isRequired,
|
|
||||||
visible: PropTypes.bool.isRequired
|
|
||||||
});
|
|
||||||
|
|
||||||
//Структура описания цвета задачи
|
|
||||||
const P8P_GANTT_TASK_COLOR_SHAPE = PropTypes.shape({
|
|
||||||
bgColor: PropTypes.string,
|
|
||||||
textColor: PropTypes.string,
|
|
||||||
bgProgressColor: PropTypes.string,
|
|
||||||
desc: PropTypes.string.isRequired
|
|
||||||
});
|
|
||||||
|
|
||||||
//Высота заголовка
|
|
||||||
const TITLE_HEIGHT = "44px";
|
|
||||||
|
|
||||||
//Высота панели масштабирования
|
|
||||||
const ZOOM_HEIGHT = "56px";
|
|
||||||
|
|
||||||
//Стили
|
|
||||||
const STYLES = {
|
|
||||||
TASK_EDITOR_CONTENT: { minWidth: 400, overflowX: "auto" },
|
|
||||||
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" : ""
|
|
||||||
})
|
|
||||||
};
|
|
||||||
|
|
||||||
//--------------------------------
|
|
||||||
//Вспомогательные классы и функции
|
|
||||||
//--------------------------------
|
|
||||||
|
|
||||||
//Проверка существования значения
|
|
||||||
const hasValue = value => typeof value !== "undefined" && value !== null && value !== "";
|
|
||||||
|
|
||||||
//Формирование описания для легенды
|
|
||||||
const taskLegendDesc = ({ task, taskColors }) => {
|
|
||||||
if (Array.isArray(taskColors) && taskColors.length > 0) {
|
|
||||||
const colorDesc = taskColors.find(
|
|
||||||
color => task.bgColor === color.bgColor && task.textColor === color.textColor && task.bgProgressColor === color.bgProgressColor
|
|
||||||
);
|
|
||||||
if (colorDesc)
|
|
||||||
return {
|
|
||||||
text: colorDesc.desc,
|
|
||||||
style: {
|
|
||||||
...(colorDesc.bgProgressColor
|
|
||||||
? {
|
|
||||||
background: `linear-gradient(to right, ${colorDesc.bgProgressColor} ,${
|
|
||||||
colorDesc.bgColor ? colorDesc.bgColor : "transparent"
|
|
||||||
})`
|
|
||||||
}
|
|
||||||
: colorDesc.bgColor
|
|
||||||
? { backgroundColor: colorDesc.bgColor }
|
|
||||||
: {}),
|
|
||||||
...(colorDesc.textColor ? { color: colorDesc.textColor } : {})
|
|
||||||
}
|
|
||||||
};
|
|
||||||
else return null;
|
|
||||||
} else return null;
|
|
||||||
};
|
|
||||||
|
|
||||||
//Редактор задачи
|
|
||||||
const P8PGanttTaskEditor = ({
|
|
||||||
task,
|
|
||||||
taskAttributes,
|
|
||||||
taskColors,
|
|
||||||
onOk,
|
|
||||||
onCancel,
|
|
||||||
taskAttributeRenderer,
|
|
||||||
taskDialogRenderer,
|
|
||||||
taskDialogProps,
|
|
||||||
numbCaption,
|
|
||||||
nameCaption,
|
|
||||||
startCaption,
|
|
||||||
endCaption,
|
|
||||||
progressCaption,
|
|
||||||
legendCaption,
|
|
||||||
okBtnCaption,
|
|
||||||
cancelBtnCaption
|
|
||||||
}) => {
|
|
||||||
//Собственное состояние
|
|
||||||
const [state, setState] = useState({
|
|
||||||
start: task.start,
|
|
||||||
end: task.end,
|
|
||||||
progress: task.progress
|
|
||||||
});
|
|
||||||
|
|
||||||
//Отображаемые атрибуты
|
|
||||||
const dispTaskAttributes =
|
|
||||||
Array.isArray(taskAttributes) && taskAttributes.length > 0 ? taskAttributes.filter(attr => attr.visible && hasValue(task[attr.name])) : [];
|
|
||||||
|
|
||||||
//При сохранении
|
|
||||||
const handleOk = () => (onOk && state.start && state.end ? onOk({ task, start: state.start, end: state.end, progress: state.progress }) : null);
|
|
||||||
|
|
||||||
//При отмене
|
|
||||||
const handleCancel = () => (onCancel ? onCancel() : null);
|
|
||||||
|
|
||||||
//При изменении сроков
|
|
||||||
const handlePeriodChanged = e => setState(prev => ({ ...prev, [e.target.name]: e.target.value }));
|
|
||||||
|
|
||||||
//При изменении прогресса
|
|
||||||
const handleProgressChanged = (e, newValue) => setState(prev => ({ ...prev, progress: newValue }));
|
|
||||||
|
|
||||||
//Описание легенды для задачи
|
|
||||||
const legendDesc = taskLegendDesc({ task, taskColors });
|
|
||||||
let legend = legendDesc ? (
|
|
||||||
<ListItemText
|
|
||||||
secondaryTypographyProps={{
|
|
||||||
p: 1,
|
|
||||||
sx: legendDesc.style
|
|
||||||
}}
|
|
||||||
primary={legendCaption}
|
|
||||||
secondary={legendDesc.text}
|
|
||||||
/>
|
|
||||||
) : null;
|
|
||||||
|
|
||||||
//Генерация содержимого
|
|
||||||
return (
|
|
||||||
<Dialog open onClose={handleCancel} {...(taskDialogProps ? taskDialogProps : {})}>
|
|
||||||
{taskDialogRenderer ? (
|
|
||||||
taskDialogRenderer({ task, taskAttributes, taskColors, close: handleCancel })
|
|
||||||
) : (
|
|
||||||
<>
|
|
||||||
<DialogContent sx={STYLES.TASK_EDITOR_CONTENT}>
|
|
||||||
<List sx={STYLES.TASK_EDITOR_LIST}>
|
|
||||||
<ListItem alignItems="flex-start">
|
|
||||||
<ListItemText primary={numbCaption} secondary={task.numb} />
|
|
||||||
</ListItem>
|
|
||||||
<Divider component="li" />
|
|
||||||
<ListItem alignItems="flex-start">
|
|
||||||
<ListItemText primary={nameCaption} secondary={task.fullName} />
|
|
||||||
</ListItem>
|
|
||||||
<Divider component="li" />
|
|
||||||
<ListItem alignItems="flex-start">
|
|
||||||
<ListItemText
|
|
||||||
secondaryTypographyProps={{ component: "span" }}
|
|
||||||
primary={startCaption}
|
|
||||||
secondary={
|
|
||||||
<TextField
|
|
||||||
error={!state.start}
|
|
||||||
disabled={task.readOnly === true || task.readOnlyDates === true}
|
|
||||||
name="start"
|
|
||||||
fullWidth
|
|
||||||
required
|
|
||||||
InputLabelProps={{ shrink: true }}
|
|
||||||
type={"date"}
|
|
||||||
value={state.start}
|
|
||||||
onChange={handlePeriodChanged}
|
|
||||||
variant="standard"
|
|
||||||
size="small"
|
|
||||||
margin="normal"
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
</ListItem>
|
|
||||||
<Divider component="li" />
|
|
||||||
<ListItem alignItems="flex-start">
|
|
||||||
<ListItemText
|
|
||||||
secondaryTypographyProps={{ component: "span" }}
|
|
||||||
primary={endCaption}
|
|
||||||
secondary={
|
|
||||||
<TextField
|
|
||||||
error={!state.end}
|
|
||||||
disabled={task.readOnly === true || task.readOnlyDates === true}
|
|
||||||
name="end"
|
|
||||||
fullWidth
|
|
||||||
required
|
|
||||||
InputLabelProps={{ shrink: true }}
|
|
||||||
type={"date"}
|
|
||||||
value={state.end}
|
|
||||||
onChange={handlePeriodChanged}
|
|
||||||
variant="standard"
|
|
||||||
size="small"
|
|
||||||
margin="normal"
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
</ListItem>
|
|
||||||
{hasValue(task.progress) || legend || dispTaskAttributes.length > 0 ? <Divider component="li" /> : null}
|
|
||||||
{hasValue(task.progress) ? (
|
|
||||||
<>
|
|
||||||
<ListItem alignItems="flex-start">
|
|
||||||
<ListItemText
|
|
||||||
secondaryTypographyProps={{ component: "span" }}
|
|
||||||
primary={`${progressCaption}${
|
|
||||||
task.readOnly === true || task.readOnlyProgress === true ? ` (${task.progress}%)` : ""
|
|
||||||
}`}
|
|
||||||
secondary={
|
|
||||||
<Slider
|
|
||||||
disabled={task.readOnly === true || task.readOnlyProgress === true}
|
|
||||||
defaultValue={task.progress}
|
|
||||||
valueLabelDisplay="auto"
|
|
||||||
onChange={handleProgressChanged}
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
</ListItem>
|
|
||||||
{legend || dispTaskAttributes.length > 0 ? <Divider component="li" /> : null}
|
|
||||||
</>
|
|
||||||
) : null}
|
|
||||||
{legend ? (
|
|
||||||
<>
|
|
||||||
<ListItem alignItems="flex-start">{legend}</ListItem>
|
|
||||||
{dispTaskAttributes.length > 0 ? <Divider component="li" /> : null}
|
|
||||||
</>
|
|
||||||
) : null}
|
|
||||||
{dispTaskAttributes.length > 0
|
|
||||||
? dispTaskAttributes.map((attr, i) => {
|
|
||||||
const defaultView = task[attr.name];
|
|
||||||
const customView = taskAttributeRenderer ? taskAttributeRenderer({ task, attribute: attr }) : null;
|
|
||||||
return (
|
|
||||||
<React.Fragment key={i}>
|
|
||||||
<ListItem alignItems="flex-start">
|
|
||||||
<ListItemText
|
|
||||||
primary={attr.caption}
|
|
||||||
secondaryTypographyProps={{ component: "span" }}
|
|
||||||
secondary={customView ? customView : defaultView}
|
|
||||||
/>
|
|
||||||
</ListItem>
|
|
||||||
{i < dispTaskAttributes.length - 1 ? <Divider component="li" /> : null}
|
|
||||||
</React.Fragment>
|
|
||||||
);
|
|
||||||
})
|
|
||||||
: null}
|
|
||||||
</List>
|
|
||||||
</DialogContent>
|
|
||||||
<DialogActions>
|
|
||||||
<Button disabled={!state.start || !state.end || task.readOnly} onClick={handleOk}>
|
|
||||||
{okBtnCaption}
|
|
||||||
</Button>
|
|
||||||
<Button onClick={handleCancel}>{cancelBtnCaption}</Button>
|
|
||||||
</DialogActions>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</Dialog>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
//Контроль свойств - Редактор задачи
|
|
||||||
P8PGanttTaskEditor.propTypes = {
|
|
||||||
task: P8P_GANTT_TASK_SHAPE,
|
|
||||||
taskAttributes: PropTypes.arrayOf(P8P_GANTT_TASK_ATTRIBUTE_SHAPE),
|
|
||||||
taskColors: PropTypes.arrayOf(P8P_GANTT_TASK_COLOR_SHAPE),
|
|
||||||
onOk: PropTypes.func,
|
|
||||||
onCancel: PropTypes.func,
|
|
||||||
taskAttributeRenderer: PropTypes.func,
|
|
||||||
taskDialogRenderer: PropTypes.func,
|
|
||||||
taskDialogProps: PropTypes.object,
|
|
||||||
numbCaption: PropTypes.string.isRequired,
|
|
||||||
nameCaption: PropTypes.string.isRequired,
|
|
||||||
startCaption: PropTypes.string.isRequired,
|
|
||||||
endCaption: PropTypes.string.isRequired,
|
|
||||||
progressCaption: PropTypes.string.isRequired,
|
|
||||||
legendCaption: PropTypes.string.isRequired,
|
|
||||||
okBtnCaption: PropTypes.string.isRequired,
|
|
||||||
cancelBtnCaption: PropTypes.string.isRequired
|
|
||||||
};
|
|
||||||
|
|
||||||
//-----------
|
//-----------
|
||||||
//Тело модуля
|
//Тело модуля
|
||||||
@ -359,7 +58,9 @@ const P8PGantt = ({
|
|||||||
progressTaskEditorCaption,
|
progressTaskEditorCaption,
|
||||||
legendTaskEditorCaption,
|
legendTaskEditorCaption,
|
||||||
okTaskEditorBtnCaption,
|
okTaskEditorBtnCaption,
|
||||||
cancelTaskEditorBtnCaption
|
cancelTaskEditorBtnCaption,
|
||||||
|
zoomBarStyle,
|
||||||
|
zoomBarHeight
|
||||||
}) => {
|
}) => {
|
||||||
//Собственное состояние
|
//Собственное состояние
|
||||||
const [state, setState] = useState({
|
const [state, setState] = useState({
|
||||||
@ -438,13 +139,14 @@ const P8PGantt = ({
|
|||||||
{state.gantt && !state.noData && title ? (
|
{state.gantt && !state.noData && title ? (
|
||||||
<Typography
|
<Typography
|
||||||
p={1}
|
p={1}
|
||||||
sx={{ ...STYLES.GANTT_TITLE, ...(titleStyle ? titleStyle : {}) }}
|
sx={{ ...P8P_TYPOGRAPHY_TITLE, ...(titleStyle ? titleStyle : {}) }}
|
||||||
align="center"
|
align="center"
|
||||||
color="textSecondary"
|
color="textSecondary"
|
||||||
variant="subtitle1"
|
variant={P8P_TYPOGRAPHY_VARIANT.TITLE}
|
||||||
|
component="h6"
|
||||||
>
|
>
|
||||||
{onTitleClick ? (
|
{onTitleClick ? (
|
||||||
<Link component="button" variant="body2" underline="hover" onClick={() => onTitleClick()}>
|
<Link component="button" variant={P8P_TYPOGRAPHY_VARIANT.BODY3} underline="hover" onClick={() => onTitleClick()}>
|
||||||
{title}
|
{title}
|
||||||
</Link>
|
</Link>
|
||||||
) : (
|
) : (
|
||||||
@ -453,7 +155,7 @@ const P8PGantt = ({
|
|||||||
</Typography>
|
</Typography>
|
||||||
) : null}
|
) : null}
|
||||||
{state.gantt && !state.noData && zoomBar ? (
|
{state.gantt && !state.noData && zoomBar ? (
|
||||||
<Box p={1} sx={STYLES.GANTT_ZOOM}>
|
<Box p={1} sx={zoomBarStyle ? zoomBarStyle : P8P_COMPONENT_HEIGHT({ height: ZOOM_HEIGHT })}>
|
||||||
<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>
|
||||||
@ -482,7 +184,14 @@ const P8PGantt = ({
|
|||||||
cancelBtnCaption={cancelTaskEditorBtnCaption}
|
cancelBtnCaption={cancelTaskEditorBtnCaption}
|
||||||
/>
|
/>
|
||||||
) : null}
|
) : null}
|
||||||
<div style={STYLES.GANTT(state.noData, title, zoomBar)} ref={svgContainerRef}>
|
<div
|
||||||
|
style={P8P_BOX_GANTT({
|
||||||
|
noData: state.noData,
|
||||||
|
zoomBarHeight: zoomBar ? (zoomBarHeight ? zoomBarHeight : ZOOM_HEIGHT) : null,
|
||||||
|
titleHeight: title ? TITLE_HEIGHT : null
|
||||||
|
})}
|
||||||
|
ref={svgContainerRef}
|
||||||
|
>
|
||||||
<svg id="__gantt__" width="100%"></svg>
|
<svg id="__gantt__" width="100%"></svg>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -516,7 +225,9 @@ P8PGantt.propTypes = {
|
|||||||
progressTaskEditorCaption: PropTypes.string.isRequired,
|
progressTaskEditorCaption: PropTypes.string.isRequired,
|
||||||
legendTaskEditorCaption: PropTypes.string.isRequired,
|
legendTaskEditorCaption: PropTypes.string.isRequired,
|
||||||
okTaskEditorBtnCaption: PropTypes.string.isRequired,
|
okTaskEditorBtnCaption: PropTypes.string.isRequired,
|
||||||
cancelTaskEditorBtnCaption: PropTypes.string.isRequired
|
cancelTaskEditorBtnCaption: PropTypes.string.isRequired,
|
||||||
|
zoomBarStyle: PropTypes.object,
|
||||||
|
zoomBarHeight: PropTypes.string
|
||||||
};
|
};
|
||||||
|
|
||||||
//----------------
|
//----------------
|
||||||
|
|||||||
81
app/components/p8p_gantt/p8p_gantt_constants.js
Normal file
81
app/components/p8p_gantt/p8p_gantt_constants.js
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
/*
|
||||||
|
Парус 8 - Панели мониторинга - Диаграмма Ганта
|
||||||
|
Компонент: Константы
|
||||||
|
*/
|
||||||
|
|
||||||
|
//---------------------
|
||||||
|
//Подключение библиотек
|
||||||
|
//---------------------
|
||||||
|
|
||||||
|
import PropTypes from "prop-types"; //Контроль свойств компонента
|
||||||
|
|
||||||
|
//-----------
|
||||||
|
//Тело модуля
|
||||||
|
//-----------
|
||||||
|
|
||||||
|
//Уровни масштаба
|
||||||
|
const P8P_GANTT_ZOOM = [0, 1, 2, 3, 4, 5];
|
||||||
|
|
||||||
|
//Уровни масштаба (строковые наименования в терминах библиотеки)
|
||||||
|
const P8P_GANTT_ZOOM_VIEW_MODES = {
|
||||||
|
0: "Quarter Day",
|
||||||
|
1: "Half Day",
|
||||||
|
2: "Day",
|
||||||
|
3: "Week",
|
||||||
|
4: "Month",
|
||||||
|
5: "Year"
|
||||||
|
};
|
||||||
|
|
||||||
|
//Структура задачи
|
||||||
|
const P8P_GANTT_TASK_SHAPE = PropTypes.shape({
|
||||||
|
id: PropTypes.string.isRequired,
|
||||||
|
rn: PropTypes.number.isRequired,
|
||||||
|
numb: PropTypes.string.isRequired,
|
||||||
|
name: PropTypes.string.isRequired,
|
||||||
|
fullName: PropTypes.string.isRequired,
|
||||||
|
start: PropTypes.string.isRequired,
|
||||||
|
end: PropTypes.string.isRequired,
|
||||||
|
progress: PropTypes.number,
|
||||||
|
dependencies: PropTypes.array,
|
||||||
|
readOnly: PropTypes.bool,
|
||||||
|
readOnlyDates: PropTypes.bool,
|
||||||
|
readOnlyProgress: PropTypes.bool,
|
||||||
|
bgColor: PropTypes.string,
|
||||||
|
textColor: PropTypes.string,
|
||||||
|
bgProgressColor: PropTypes.string
|
||||||
|
});
|
||||||
|
|
||||||
|
//Структура динамического атрибута задачи
|
||||||
|
const P8P_GANTT_TASK_ATTRIBUTE_SHAPE = PropTypes.shape({
|
||||||
|
name: PropTypes.string.isRequired,
|
||||||
|
caption: PropTypes.string.isRequired,
|
||||||
|
visible: PropTypes.bool.isRequired
|
||||||
|
});
|
||||||
|
|
||||||
|
//Структура описания цвета задачи
|
||||||
|
const P8P_GANTT_TASK_COLOR_SHAPE = PropTypes.shape({
|
||||||
|
bgColor: PropTypes.string,
|
||||||
|
textColor: PropTypes.string,
|
||||||
|
bgProgressColor: PropTypes.string,
|
||||||
|
desc: PropTypes.string.isRequired
|
||||||
|
});
|
||||||
|
|
||||||
|
//Высота заголовка
|
||||||
|
const TITLE_HEIGHT = "44px";
|
||||||
|
|
||||||
|
//Высота панели масштабирования
|
||||||
|
const ZOOM_HEIGHT = "56px";
|
||||||
|
|
||||||
|
//----------------
|
||||||
|
//Интерфейс модуля
|
||||||
|
//----------------
|
||||||
|
|
||||||
|
export {
|
||||||
|
P8P_GANTT_ZOOM,
|
||||||
|
P8P_GANTT_ZOOM_VIEW_MODES,
|
||||||
|
P8P_GANTT_TASK_SHAPE,
|
||||||
|
P8P_GANTT_TASK_ATTRIBUTE_SHAPE,
|
||||||
|
P8P_GANTT_TASK_COLOR_SHAPE,
|
||||||
|
TITLE_HEIGHT,
|
||||||
|
ZOOM_HEIGHT
|
||||||
|
};
|
||||||
@ -8,8 +8,8 @@
|
|||||||
//---------------------
|
//---------------------
|
||||||
|
|
||||||
import { useState, useCallback, useEffect, useContext, useRef, useMemo } from "react"; //Классы React
|
import { useState, useCallback, useEffect, useContext, useRef, useMemo } from "react"; //Классы React
|
||||||
import { BackEndCtx } from "../context/backend"; //Контекст взаимодействия с сервером
|
import { BackEndCtx } from "../../context/backend"; //Контекст взаимодействия с сервером
|
||||||
import { formatDateJSONDateOnly } from "../core/utils"; //Вспомогательные функции
|
import { formatDateJSONDateOnly } from "../../core/utils"; //Вспомогательные функции
|
||||||
|
|
||||||
//---------
|
//---------
|
||||||
//Константы
|
//Константы
|
||||||
267
app/components/p8p_gantt/p8p_gantt_task_editor.js
Normal file
267
app/components/p8p_gantt/p8p_gantt_task_editor.js
Normal file
@ -0,0 +1,267 @@
|
|||||||
|
/*
|
||||||
|
Парус 8 - Панели мониторинга - Диаграмма Ганта
|
||||||
|
Компонент: Редактор задачи
|
||||||
|
*/
|
||||||
|
|
||||||
|
//---------------------
|
||||||
|
//Подключение библиотек
|
||||||
|
//---------------------
|
||||||
|
|
||||||
|
import React, { useState } from "react"; //Классы React
|
||||||
|
import PropTypes from "prop-types"; //Контроль свойств компонента
|
||||||
|
import { Dialog, DialogActions, DialogContent, TextField, Button, List, ListItem, ListItemText, Divider, Slider } from "@mui/material"; //Интерфейсные компоненты
|
||||||
|
import { P8P_GANTT_TASK_SHAPE, P8P_GANTT_TASK_ATTRIBUTE_SHAPE, P8P_GANTT_TASK_COLOR_SHAPE } from "./p8p_gantt_constants"; //Константы диаграммы Ганта
|
||||||
|
import { P8P_DIALOG_CONTENT_VARIANT } from "../../theme/variants/p8p_dialog_content_variants"; //Варианты диалогов (содержимое)
|
||||||
|
import { P8P_LIST_VARIANT } from "../../theme/variants/p8p_list_variants"; //Варианты списков
|
||||||
|
import { P8P_LIST_ITEM_TEXT_VARIANT } from "../../theme/variants/p8p_list_item_text_variants"; //Варианты значений списков
|
||||||
|
import { P8P_TEXT_FIELD_VARIANT } from "../../theme/variants/p8p_text_field_variants"; //Варианты полей ввода
|
||||||
|
import { P8P_BUTTON_VARIANT } from "../../theme/variants/p8p_button_variants"; //Варианты кнопок
|
||||||
|
|
||||||
|
//--------------------------------
|
||||||
|
//Вспомогательные классы и функции
|
||||||
|
//--------------------------------
|
||||||
|
|
||||||
|
//Проверка существования значения
|
||||||
|
const hasValue = value => typeof value !== "undefined" && value !== null && value !== "";
|
||||||
|
|
||||||
|
//Формирование описания для легенды
|
||||||
|
const taskLegendDesc = ({ task, taskColors }) => {
|
||||||
|
if (Array.isArray(taskColors) && taskColors.length > 0) {
|
||||||
|
const colorDesc = taskColors.find(
|
||||||
|
color => task.bgColor === color.bgColor && task.textColor === color.textColor && task.bgProgressColor === color.bgProgressColor
|
||||||
|
);
|
||||||
|
if (colorDesc)
|
||||||
|
return {
|
||||||
|
text: colorDesc.desc,
|
||||||
|
style: {
|
||||||
|
...(colorDesc.bgProgressColor
|
||||||
|
? {
|
||||||
|
background: `linear-gradient(to right, ${colorDesc.bgProgressColor} ,${
|
||||||
|
colorDesc.bgColor ? colorDesc.bgColor : "transparent"
|
||||||
|
})`
|
||||||
|
}
|
||||||
|
: colorDesc.bgColor
|
||||||
|
? { backgroundColor: colorDesc.bgColor }
|
||||||
|
: {}),
|
||||||
|
...(colorDesc.textColor ? { color: colorDesc.textColor } : {})
|
||||||
|
}
|
||||||
|
};
|
||||||
|
else return null;
|
||||||
|
} else return null;
|
||||||
|
};
|
||||||
|
|
||||||
|
//-----------
|
||||||
|
//Тело модуля
|
||||||
|
//-----------
|
||||||
|
|
||||||
|
//Редактор задачи
|
||||||
|
const P8PGanttTaskEditor = ({
|
||||||
|
task,
|
||||||
|
taskAttributes,
|
||||||
|
taskColors,
|
||||||
|
onOk,
|
||||||
|
onCancel,
|
||||||
|
taskAttributeRenderer,
|
||||||
|
taskDialogRenderer,
|
||||||
|
taskDialogProps,
|
||||||
|
numbCaption,
|
||||||
|
nameCaption,
|
||||||
|
startCaption,
|
||||||
|
endCaption,
|
||||||
|
progressCaption,
|
||||||
|
legendCaption,
|
||||||
|
okBtnCaption,
|
||||||
|
cancelBtnCaption
|
||||||
|
}) => {
|
||||||
|
//Собственное состояние
|
||||||
|
const [state, setState] = useState({
|
||||||
|
start: task.start,
|
||||||
|
end: task.end,
|
||||||
|
progress: task.progress
|
||||||
|
});
|
||||||
|
|
||||||
|
//Отображаемые атрибуты
|
||||||
|
const dispTaskAttributes =
|
||||||
|
Array.isArray(taskAttributes) && taskAttributes.length > 0 ? taskAttributes.filter(attr => attr.visible && hasValue(task[attr.name])) : [];
|
||||||
|
|
||||||
|
//При сохранении
|
||||||
|
const handleOk = () => (onOk && state.start && state.end ? onOk({ task, start: state.start, end: state.end, progress: state.progress }) : null);
|
||||||
|
|
||||||
|
//При отмене
|
||||||
|
const handleCancel = () => (onCancel ? onCancel() : null);
|
||||||
|
|
||||||
|
//При изменении сроков
|
||||||
|
const handlePeriodChanged = e => setState(prev => ({ ...prev, [e.target.name]: e.target.value }));
|
||||||
|
|
||||||
|
//При изменении прогресса
|
||||||
|
const handleProgressChanged = (e, newValue) => setState(prev => ({ ...prev, progress: newValue }));
|
||||||
|
|
||||||
|
//Описание легенды для задачи
|
||||||
|
const legendDesc = taskLegendDesc({ task, taskColors });
|
||||||
|
let legend = legendDesc ? (
|
||||||
|
<ListItemText
|
||||||
|
variant={P8P_LIST_ITEM_TEXT_VARIANT.PRIMARY}
|
||||||
|
secondaryTypographyProps={{
|
||||||
|
p: 1,
|
||||||
|
sx: legendDesc.style
|
||||||
|
}}
|
||||||
|
primary={legendCaption}
|
||||||
|
secondary={legendDesc.text}
|
||||||
|
/>
|
||||||
|
) : null;
|
||||||
|
|
||||||
|
//Генерация содержимого
|
||||||
|
return (
|
||||||
|
<Dialog open onClose={handleCancel} {...(taskDialogProps ? taskDialogProps : {})}>
|
||||||
|
{taskDialogRenderer ? (
|
||||||
|
taskDialogRenderer({ task, taskAttributes, taskColors, close: handleCancel })
|
||||||
|
) : (
|
||||||
|
<>
|
||||||
|
<DialogContent variant={P8P_DIALOG_CONTENT_VARIANT.TASK}>
|
||||||
|
<List variant={P8P_LIST_VARIANT.GANTT_TASK}>
|
||||||
|
<ListItem alignItems="flex-start">
|
||||||
|
<ListItemText variant={P8P_LIST_ITEM_TEXT_VARIANT.PRIMARY} primary={numbCaption} secondary={task.numb} />
|
||||||
|
</ListItem>
|
||||||
|
<Divider component="li" />
|
||||||
|
<ListItem alignItems="flex-start">
|
||||||
|
<ListItemText variant={P8P_LIST_ITEM_TEXT_VARIANT.PRIMARY} primary={nameCaption} secondary={task.fullName} />
|
||||||
|
</ListItem>
|
||||||
|
<Divider component="li" />
|
||||||
|
<ListItem alignItems="flex-start">
|
||||||
|
<ListItemText
|
||||||
|
variant={P8P_LIST_ITEM_TEXT_VARIANT.PRIMARY}
|
||||||
|
secondaryTypographyProps={{ component: "span" }}
|
||||||
|
primary={startCaption}
|
||||||
|
secondary={
|
||||||
|
<TextField
|
||||||
|
error={!state.start}
|
||||||
|
disabled={task.readOnly === true || task.readOnlyDates === true}
|
||||||
|
name="start"
|
||||||
|
fullWidth
|
||||||
|
required
|
||||||
|
InputLabelProps={{ shrink: true }}
|
||||||
|
type={"date"}
|
||||||
|
value={state.start}
|
||||||
|
onChange={handlePeriodChanged}
|
||||||
|
variant="standard"
|
||||||
|
data-variant={P8P_TEXT_FIELD_VARIANT.PRIMARY}
|
||||||
|
size="small"
|
||||||
|
margin="normal"
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</ListItem>
|
||||||
|
<Divider component="li" />
|
||||||
|
<ListItem alignItems="flex-start">
|
||||||
|
<ListItemText
|
||||||
|
variant={P8P_LIST_ITEM_TEXT_VARIANT.PRIMARY}
|
||||||
|
secondaryTypographyProps={{ component: "span" }}
|
||||||
|
primary={endCaption}
|
||||||
|
secondary={
|
||||||
|
<TextField
|
||||||
|
error={!state.end}
|
||||||
|
disabled={task.readOnly === true || task.readOnlyDates === true}
|
||||||
|
name="end"
|
||||||
|
fullWidth
|
||||||
|
required
|
||||||
|
InputLabelProps={{ shrink: true }}
|
||||||
|
type={"date"}
|
||||||
|
value={state.end}
|
||||||
|
onChange={handlePeriodChanged}
|
||||||
|
variant="standard"
|
||||||
|
data-variant={P8P_TEXT_FIELD_VARIANT.PRIMARY}
|
||||||
|
size="small"
|
||||||
|
margin="normal"
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</ListItem>
|
||||||
|
{hasValue(task.progress) || legend || dispTaskAttributes.length > 0 ? <Divider component="li" /> : null}
|
||||||
|
{hasValue(task.progress) ? (
|
||||||
|
<>
|
||||||
|
<ListItem alignItems="flex-start">
|
||||||
|
<ListItemText
|
||||||
|
variant={P8P_LIST_ITEM_TEXT_VARIANT.PRIMARY}
|
||||||
|
secondaryTypographyProps={{ component: "span" }}
|
||||||
|
primary={`${progressCaption}${
|
||||||
|
task.readOnly === true || task.readOnlyProgress === true ? ` (${task.progress}%)` : ""
|
||||||
|
}`}
|
||||||
|
secondary={
|
||||||
|
<Slider
|
||||||
|
disabled={task.readOnly === true || task.readOnlyProgress === true}
|
||||||
|
defaultValue={task.progress}
|
||||||
|
valueLabelDisplay="auto"
|
||||||
|
onChange={handleProgressChanged}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</ListItem>
|
||||||
|
{legend || dispTaskAttributes.length > 0 ? <Divider component="li" /> : null}
|
||||||
|
</>
|
||||||
|
) : null}
|
||||||
|
{legend ? (
|
||||||
|
<>
|
||||||
|
<ListItem alignItems="flex-start">{legend}</ListItem>
|
||||||
|
{dispTaskAttributes.length > 0 ? <Divider component="li" /> : null}
|
||||||
|
</>
|
||||||
|
) : null}
|
||||||
|
{dispTaskAttributes.length > 0
|
||||||
|
? dispTaskAttributes.map((attr, i) => {
|
||||||
|
const defaultView = task[attr.name];
|
||||||
|
const customView = taskAttributeRenderer ? taskAttributeRenderer({ task, attribute: attr }) : null;
|
||||||
|
return (
|
||||||
|
<React.Fragment key={i}>
|
||||||
|
<ListItem alignItems="flex-start">
|
||||||
|
<ListItemText
|
||||||
|
variant={P8P_LIST_ITEM_TEXT_VARIANT.PRIMARY}
|
||||||
|
primary={attr.caption}
|
||||||
|
secondaryTypographyProps={{ component: "span" }}
|
||||||
|
secondary={customView ? customView : defaultView}
|
||||||
|
/>
|
||||||
|
</ListItem>
|
||||||
|
{i < dispTaskAttributes.length - 1 ? <Divider component="li" /> : null}
|
||||||
|
</React.Fragment>
|
||||||
|
);
|
||||||
|
})
|
||||||
|
: null}
|
||||||
|
</List>
|
||||||
|
</DialogContent>
|
||||||
|
<DialogActions>
|
||||||
|
<Button variant={P8P_BUTTON_VARIANT.SECONDARY} onClick={handleCancel}>
|
||||||
|
{cancelBtnCaption}
|
||||||
|
</Button>
|
||||||
|
<Button variant={P8P_BUTTON_VARIANT.PRIMARY} disabled={!state.start || !state.end || task.readOnly} onClick={handleOk}>
|
||||||
|
{okBtnCaption}
|
||||||
|
</Button>
|
||||||
|
</DialogActions>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</Dialog>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
//Контроль свойств - Редактор задачи
|
||||||
|
P8PGanttTaskEditor.propTypes = {
|
||||||
|
task: P8P_GANTT_TASK_SHAPE,
|
||||||
|
taskAttributes: PropTypes.arrayOf(P8P_GANTT_TASK_ATTRIBUTE_SHAPE),
|
||||||
|
taskColors: PropTypes.arrayOf(P8P_GANTT_TASK_COLOR_SHAPE),
|
||||||
|
onOk: PropTypes.func,
|
||||||
|
onCancel: PropTypes.func,
|
||||||
|
taskAttributeRenderer: PropTypes.func,
|
||||||
|
taskDialogRenderer: PropTypes.func,
|
||||||
|
taskDialogProps: PropTypes.object,
|
||||||
|
numbCaption: PropTypes.string.isRequired,
|
||||||
|
nameCaption: PropTypes.string.isRequired,
|
||||||
|
startCaption: PropTypes.string.isRequired,
|
||||||
|
endCaption: PropTypes.string.isRequired,
|
||||||
|
progressCaption: PropTypes.string.isRequired,
|
||||||
|
legendCaption: PropTypes.string.isRequired,
|
||||||
|
okBtnCaption: PropTypes.string.isRequired,
|
||||||
|
cancelBtnCaption: PropTypes.string.isRequired
|
||||||
|
};
|
||||||
|
|
||||||
|
//----------------
|
||||||
|
//Интерфейс модуля
|
||||||
|
//----------------
|
||||||
|
|
||||||
|
export { P8PGanttTaskEditor, taskLegendDesc };
|
||||||
@ -12,15 +12,18 @@ import PropTypes from "prop-types"; //Контроль свойств компо
|
|||||||
import { IconButton, Icon, Typography, Paper, Stack } from "@mui/material"; //Интерфейсные компоненты MUI
|
import { IconButton, Icon, Typography, Paper, Stack } from "@mui/material"; //Интерфейсные компоненты MUI
|
||||||
import { P8PHintDialog } from "./p8p_app_message"; //Диалог подсказки
|
import { P8PHintDialog } from "./p8p_app_message"; //Диалог подсказки
|
||||||
import { TEXTS, STATE } from "../../app.text"; //Типовые текстовые ресурсы и константы
|
import { TEXTS, STATE } from "../../app.text"; //Типовые текстовые ресурсы и константы
|
||||||
import { APP_COLORS } from "../../app.styles"; //Типовые стили
|
|
||||||
import { useP8PIndicator } from "./p8p_indicator_hooks"; //Хук для индикатора
|
import { useP8PIndicator } from "./p8p_indicator_hooks"; //Хук для индикатора
|
||||||
|
import { P8P_TYPOGRAPHY_VARIANT } from "../theme/p8p_typography"; //Варианты шрифтов
|
||||||
|
import { P8P_TYPOGRAPHY_CLICKABLE } from "../theme/styles/typography"; //Стили текстовых полей
|
||||||
|
import { P8P_PAPER_INDICATOR } from "../theme/styles/paper"; //Стили выделяемого контейнера
|
||||||
|
import { P8P_STACK_INLINE_HIDDEN } from "../theme/styles/stack"; //Стили для групповой информации
|
||||||
|
import { P8P_ICON_INDICATOR } from "../theme/styles/icon"; //Стили иконок
|
||||||
|
|
||||||
//---------
|
//---------
|
||||||
//Константы
|
//Константы
|
||||||
//---------
|
//---------
|
||||||
|
|
||||||
//Варианты исполнения
|
//Варианты исполнения
|
||||||
|
|
||||||
const P8P_INDICATOR_VARIANT = {
|
const P8P_INDICATOR_VARIANT = {
|
||||||
ELEVATION: "elevation",
|
ELEVATION: "elevation",
|
||||||
OUTLINED: "outlined"
|
OUTLINED: "outlined"
|
||||||
@ -33,70 +36,11 @@ const P8P_INDICATOR_STATE = {
|
|||||||
WARN: STATE.WARN,
|
WARN: STATE.WARN,
|
||||||
ERR: STATE.ERR
|
ERR: STATE.ERR
|
||||||
};
|
};
|
||||||
//Цвета заливки
|
|
||||||
const BG_COLOR = {
|
|
||||||
[STATE.OK]: APP_COLORS[STATE.OK].color,
|
|
||||||
[STATE.ERR]: APP_COLORS[STATE.ERR].color,
|
|
||||||
[STATE.WARN]: APP_COLORS[STATE.WARN].color
|
|
||||||
};
|
|
||||||
|
|
||||||
//Цвета текста и иконок
|
//Ширина для элементов индикатора
|
||||||
const COLOR = {
|
const WIDTH_ICON_VALUE = "1rem"; //Иконка значения индикатора
|
||||||
[STATE.OK]: APP_COLORS[STATE.OK].contrColor,
|
const WIDTH_ICON = "50px"; //Иконка индикатора
|
||||||
[STATE.ERR]: APP_COLORS[STATE.ERR].contrColor,
|
const WIDTH_CAPTION = "99cqw"; //Заголовок индикатора
|
||||||
[STATE.WARN]: APP_COLORS[STATE.WARN].contrColor
|
|
||||||
};
|
|
||||||
|
|
||||||
//Стили
|
|
||||||
const STYLES = {
|
|
||||||
CONTAINER: (state, clickable, userColor, userBackgroundColor) => ({
|
|
||||||
padding: "10px",
|
|
||||||
width: "100%",
|
|
||||||
height: "100%",
|
|
||||||
overflow: "hidden",
|
|
||||||
...getBackgroundColor(state, userBackgroundColor),
|
|
||||||
...getColor(state, userColor),
|
|
||||||
display: "flex",
|
|
||||||
flexDirection: "column",
|
|
||||||
justifyContent: "center",
|
|
||||||
...(clickable
|
|
||||||
? {
|
|
||||||
cursor: "pointer",
|
|
||||||
"&:hover": { filter: "brightness(0.92) !important" },
|
|
||||||
"&:active": { backgroundColor: APP_COLORS.ACTIVE.color }
|
|
||||||
}
|
|
||||||
: {})
|
|
||||||
}),
|
|
||||||
ICON: (state, userColor) => ({ fontSize: "50px", ...getColor(state, userColor) }),
|
|
||||||
HINT_ICON: (state, userColor) => ({ fontSize: "1rem", ...getColor(state, userColor) }),
|
|
||||||
VALUE_CAPTION_STACK: { containerType: "inline-size", width: "100%", overflow: "hidden" },
|
|
||||||
CAPTION_TYPOGRAPHY: clickable => ({
|
|
||||||
width: "99cqw",
|
|
||||||
...(clickable
|
|
||||||
? {
|
|
||||||
cursor: "pointer"
|
|
||||||
}
|
|
||||||
: {})
|
|
||||||
}),
|
|
||||||
VALUE_TYPOGRAPHY: clickable => ({
|
|
||||||
...(clickable
|
|
||||||
? {
|
|
||||||
cursor: "pointer"
|
|
||||||
}
|
|
||||||
: {})
|
|
||||||
})
|
|
||||||
};
|
|
||||||
|
|
||||||
//-----------------------
|
|
||||||
//Вспомогательные функции
|
|
||||||
//-----------------------
|
|
||||||
|
|
||||||
//Подбор цвета заливки
|
|
||||||
const getBackgroundColor = (state, userColor) =>
|
|
||||||
userColor ? { backgroundColor: userColor } : BG_COLOR[state] ? { backgroundColor: BG_COLOR[state] } : {};
|
|
||||||
|
|
||||||
//Подбор цвета текста
|
|
||||||
const getColor = (state, userColor) => (userColor ? { color: userColor } : COLOR[state] ? { color: COLOR[state] } : {});
|
|
||||||
|
|
||||||
//-----------
|
//-----------
|
||||||
//Тело модуля
|
//Тело модуля
|
||||||
@ -150,7 +94,7 @@ const P8PIndicator = ({
|
|||||||
|
|
||||||
//Представление текста значения индикатора
|
//Представление текста значения индикатора
|
||||||
const valueTextView = (
|
const valueTextView = (
|
||||||
<Typography variant={"h4"} sx={STYLES.VALUE_TYPOGRAPHY(onValueClick ? true : false)} onClick={handleValueClick}>
|
<Typography variant={P8P_TYPOGRAPHY_VARIANT.H4} sx={onValueClick ? { ...P8P_TYPOGRAPHY_CLICKABLE } : {}} onClick={handleValueClick}>
|
||||||
{[undefined, null, ""].includes(value) ? TEXTS.NO_DATA_FOUND_SHORT : value}
|
{[undefined, null, ""].includes(value) ? TEXTS.NO_DATA_FOUND_SHORT : value}
|
||||||
</Typography>
|
</Typography>
|
||||||
);
|
);
|
||||||
@ -158,9 +102,10 @@ const P8PIndicator = ({
|
|||||||
//Представление текста подписи индикатора
|
//Представление текста подписи индикатора
|
||||||
const captionView = (
|
const captionView = (
|
||||||
<Typography
|
<Typography
|
||||||
|
variant={P8P_TYPOGRAPHY_VARIANT.BODY3}
|
||||||
align={"left"}
|
align={"left"}
|
||||||
noWrap={true}
|
noWrap={true}
|
||||||
sx={STYLES.CAPTION_TYPOGRAPHY(onCaptionClick ? true : false)}
|
sx={{ width: WIDTH_CAPTION, ...(onCaptionClick ? { ...P8P_TYPOGRAPHY_CLICKABLE } : {}) }}
|
||||||
title={caption}
|
title={caption}
|
||||||
onClick={handleCaptionClick}
|
onClick={handleCaptionClick}
|
||||||
>
|
>
|
||||||
@ -175,7 +120,7 @@ const P8PIndicator = ({
|
|||||||
<Stack direction={"row"} alignItems={"start"}>
|
<Stack direction={"row"} alignItems={"start"}>
|
||||||
{valueTextView}
|
{valueTextView}
|
||||||
<IconButton onClick={handleHintClick}>
|
<IconButton onClick={handleHintClick}>
|
||||||
<Icon sx={STYLES.HINT_ICON(state, color)}>help_outline</Icon>
|
<Icon sx={P8P_ICON_INDICATOR({ state, fontSize: WIDTH_ICON_VALUE, color })}>help_outline</Icon>
|
||||||
</IconButton>
|
</IconButton>
|
||||||
</Stack>
|
</Stack>
|
||||||
</>
|
</>
|
||||||
@ -190,17 +135,17 @@ const P8PIndicator = ({
|
|||||||
return (
|
return (
|
||||||
<Paper
|
<Paper
|
||||||
elevation={variant === P8P_INDICATOR_VARIANT.ELEVATION ? elevation : 0}
|
elevation={variant === P8P_INDICATOR_VARIANT.ELEVATION ? elevation : 0}
|
||||||
sx={STYLES.CONTAINER(state, clickable, color, backgroundColor)}
|
sx={P8P_PAPER_INDICATOR({ state, color, backgroundColor, clickable })}
|
||||||
square={square}
|
square={square}
|
||||||
variant={variant}
|
variant={variant}
|
||||||
onClick={handleClick}
|
onClick={handleClick}
|
||||||
>
|
>
|
||||||
<Stack direction={"row"} alignItems={"center"} justifyContent={"space-between"}>
|
<Stack direction={"row"} alignItems={"center"} justifyContent={"space-between"}>
|
||||||
<Stack direction={"column"} alignItems={"start"} pr={2} sx={STYLES.VALUE_CAPTION_STACK}>
|
<Stack direction={"column"} alignItems={"start"} pr={2} sx={P8P_STACK_INLINE_HIDDEN}>
|
||||||
{valueView}
|
{valueView}
|
||||||
{captionView}
|
{captionView}
|
||||||
</Stack>
|
</Stack>
|
||||||
{icon ? <Icon sx={STYLES.ICON(state, color)}>{icon}</Icon> : null}
|
{icon ? <Icon sx={P8P_ICON_INDICATOR({ state, fontSize: WIDTH_ICON, color })}>{icon}</Icon> : null}
|
||||||
</Stack>
|
</Stack>
|
||||||
</Paper>
|
</Paper>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -10,6 +10,12 @@
|
|||||||
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 { Box, Icon, Input, InputAdornment, FormControl, Select, InputLabel, MenuItem, IconButton, Autocomplete, TextField } from "@mui/material"; //Интерфейсные компоненты
|
import { Box, Icon, Input, InputAdornment, FormControl, Select, InputLabel, MenuItem, IconButton, Autocomplete, TextField } from "@mui/material"; //Интерфейсные компоненты
|
||||||
|
import { P8P_AUTOCOMPLETE_VARIANT } from "../theme/variants/p8p_autocomplete_variants"; //Варианты полей выбора (Autocomplete)
|
||||||
|
import { P8P_INPUT_LABEL_VARIANT } from "../theme/variants/p8p_input_label_variants"; //Варианты меток выбора
|
||||||
|
import { P8P_TEXT_FIELD_VARIANT } from "../theme/variants/p8p_text_field_variants"; //Варианты полей ввода
|
||||||
|
import { P8P_SELECT_VARIANT } from "../theme/variants/p8p_select_variants"; //Варианты полей выбора (Select)
|
||||||
|
import { P8P_MENU_ITEM_VARIANT } from "../theme/variants/p8p_menu_item_variants"; //Варианты элементов меню
|
||||||
|
import { P8P_INPUT_VARIANT } from "../theme/variants/p8p_input_variants"; //Варианты полей ввода (Input)
|
||||||
|
|
||||||
//---------
|
//---------
|
||||||
//Константы
|
//Константы
|
||||||
@ -58,7 +64,7 @@ const P8PInput = ({ name, value, label, onChange, dictionary, list, type, freeSo
|
|||||||
|
|
||||||
//Генерация содержимого
|
//Генерация содержимого
|
||||||
return (
|
return (
|
||||||
<Box p={1}>
|
<Box p={1} minWidth="300px">
|
||||||
<FormControl variant={"standard"} fullWidth {...other}>
|
<FormControl variant={"standard"} fullWidth {...other}>
|
||||||
{list ? (
|
{list ? (
|
||||||
freeSolo ? (
|
freeSolo ? (
|
||||||
@ -71,53 +77,70 @@ const P8PInput = ({ name, value, label, onChange, dictionary, list, type, freeSo
|
|||||||
onChange={(event, newValue) => handleChangeByName(name, newValue)}
|
onChange={(event, newValue) => handleChangeByName(name, newValue)}
|
||||||
onInputChange={(event, newInputValue) => handleChangeByName(name, newInputValue)}
|
onInputChange={(event, newInputValue) => handleChangeByName(name, newInputValue)}
|
||||||
options={list}
|
options={list}
|
||||||
renderInput={params => <TextField {...params} label={label} name={name} variant={"standard"} />}
|
variant={P8P_AUTOCOMPLETE_VARIANT.PRIMARY}
|
||||||
|
renderInput={params => (
|
||||||
|
<TextField {...params} label={label} name={name} variant={"standard"} data-variant={P8P_TEXT_FIELD_VARIANT.PRIMARY} />
|
||||||
|
)}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<>
|
<>
|
||||||
<InputLabel id={`${name}Lable`} shrink>
|
<FormControl variant="standard" fullWidth>
|
||||||
{label}
|
<InputLabel id={`${name}Lable`} shrink data-variant={P8P_INPUT_LABEL_VARIANT.PRIMARY}>
|
||||||
</InputLabel>
|
{label}
|
||||||
<Select
|
</InputLabel>
|
||||||
labelId={`${name}Lable`}
|
<Select
|
||||||
id={name}
|
labelId={`${name}Lable`}
|
||||||
name={name}
|
id={name}
|
||||||
label={label}
|
name={name}
|
||||||
value={[undefined, null].includes(current.value) ? "" : current.value}
|
label={label}
|
||||||
onChange={handleChange}
|
value={[undefined, null].includes(current.value) ? "" : current.value}
|
||||||
disabled={disabled}
|
onChange={handleChange}
|
||||||
displayEmpty
|
disabled={disabled}
|
||||||
>
|
displayEmpty
|
||||||
{list.map((item, i) => (
|
data-variant={P8P_SELECT_VARIANT.PRIMARY}
|
||||||
<MenuItem key={i} value={[undefined, null].includes(item.value) ? "" : item.value}>
|
>
|
||||||
{item.name}
|
{list.map((item, i) => (
|
||||||
</MenuItem>
|
<MenuItem
|
||||||
))}
|
key={i}
|
||||||
</Select>
|
value={[undefined, null].includes(item.value) ? "" : item.value}
|
||||||
|
variant={P8P_MENU_ITEM_VARIANT.PRIMARY}
|
||||||
|
>
|
||||||
|
{item.name}
|
||||||
|
</MenuItem>
|
||||||
|
))}
|
||||||
|
</Select>
|
||||||
|
</FormControl>
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
) : (
|
) : (
|
||||||
<>
|
<>
|
||||||
<InputLabel {...(current.type == "date" ? { shrink: true } : {})} htmlFor={name}>
|
<FormControl variant="standard" fullWidth>
|
||||||
{label}
|
<InputLabel
|
||||||
</InputLabel>
|
{...(current.type == "date" ? { shrink: true } : {})}
|
||||||
<Input
|
htmlFor={name}
|
||||||
id={name}
|
data-variant={P8P_INPUT_LABEL_VARIANT.PRIMARY}
|
||||||
name={name}
|
>
|
||||||
value={current.value ? current.value : ""}
|
{label}
|
||||||
endAdornment={
|
</InputLabel>
|
||||||
dictionary ? (
|
<Input
|
||||||
<InputAdornment position="end">
|
id={name}
|
||||||
<IconButton aria-label={`${name} select`} onClick={handleDictionaryClick} edge="end">
|
name={name}
|
||||||
<Icon>list</Icon>
|
value={current.value ? current.value : ""}
|
||||||
</IconButton>
|
endAdornment={
|
||||||
</InputAdornment>
|
dictionary ? (
|
||||||
) : null
|
<InputAdornment position="end">
|
||||||
}
|
<IconButton aria-label={`${name} select`} onClick={handleDictionaryClick} edge="end">
|
||||||
{...(current.type ? { type: current.type } : {})}
|
<Icon>list</Icon>
|
||||||
onChange={handleChange}
|
</IconButton>
|
||||||
disabled={disabled}
|
</InputAdornment>
|
||||||
/>
|
) : null
|
||||||
|
}
|
||||||
|
{...(current.type ? { type: current.type } : {})}
|
||||||
|
onChange={handleChange}
|
||||||
|
disabled={disabled}
|
||||||
|
variant={P8P_INPUT_VARIANT.PRIMARY}
|
||||||
|
/>
|
||||||
|
</FormControl>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</FormControl>
|
</FormControl>
|
||||||
|
|||||||
@ -27,6 +27,16 @@ import {
|
|||||||
ListItemIcon,
|
ListItemIcon,
|
||||||
ListItemText
|
ListItemText
|
||||||
} from "@mui/material"; //Интерфейсные компоненты
|
} from "@mui/material"; //Интерфейсные компоненты
|
||||||
|
import { P8P_BOX_PANELS_MENU_CONTAINER } from "../theme/styles/box"; //Стили контейнеров
|
||||||
|
import { P8P_GRID_VARIANT } from "../theme/variants/p8p_grid_variants"; //Варианты сеток
|
||||||
|
import { P8P_CARD_VARIANT } from "../theme/variants/p8p_card_variants"; //Варианты карточек
|
||||||
|
import { P8P_COMPONENT_HEIGHT } from "../theme/styles/common"; //Стили - общие
|
||||||
|
import { P8P_ICON_VARIANT } from "../theme/variants/p8p_icon_variants"; //Варианты иконок
|
||||||
|
import { P8P_CARD_ACTIONS_VARIANT } from "../theme/variants/p8p_card_actions_variants"; //Варианты действий карточки
|
||||||
|
import { P8P_TYPOGRAPHY_VARIANT } from "../theme/p8p_typography"; //Варианты шрифтов
|
||||||
|
import { P8P_BUTTON_VARIANT } from "../theme/variants/p8p_button_variants"; //Варианты кнопок
|
||||||
|
import { P8P_LIST_ITEM_TEXT_VARIANT } from "../theme/variants/p8p_list_item_text_variants"; //Варианты значений списков
|
||||||
|
import { P8P_TYPOGRAPHY_PANEL_DESK } from "../theme/styles/typography"; //Стили текста
|
||||||
|
|
||||||
//---------
|
//---------
|
||||||
//Константы
|
//Константы
|
||||||
@ -52,37 +62,6 @@ const P8P_PANELS_MENU_PANEL_SHAPE = PropTypes.shape({
|
|||||||
url: PropTypes.string.isRequired
|
url: PropTypes.string.isRequired
|
||||||
});
|
});
|
||||||
|
|
||||||
//Стили
|
|
||||||
const STYLES = {
|
|
||||||
GRID_CONTAINER: { display: "flex", justifyContent: "center", alignItems: "flex-start", minHeight: "100vh" },
|
|
||||||
GRID: { maxWidth: 1200, direction: "row", justifyContent: "left", alignItems: "stretch" },
|
|
||||||
GRID_PANEL_CARD: { maxWidth: 400, height: "100%", flexDirection: "column", display: "flex" },
|
|
||||||
GRID_PANEL_CARD_MEDIA: { height: 140 },
|
|
||||||
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" },
|
|
||||||
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" },
|
|
||||||
width: "150px",
|
|
||||||
height: "90px",
|
|
||||||
flexDirection: "column",
|
|
||||||
justifyContent: "flex-start"
|
|
||||||
},
|
|
||||||
DESKTOP_ITEM_ICON: { width: "48px", height: "48px", fontSize: "48px" },
|
|
||||||
DESKTOP_ITEM_CATION: {
|
|
||||||
display: "-webkit-box",
|
|
||||||
overflow: "hidden",
|
|
||||||
WebkitBoxOrient: "vertical",
|
|
||||||
WebkitLineClamp: 2,
|
|
||||||
fontSize: "12px",
|
|
||||||
maxWidth: "140px",
|
|
||||||
lineHeight: "1.2"
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
//--------------------------------
|
//--------------------------------
|
||||||
//Вспомогательные классы и функции
|
//Вспомогательные классы и функции
|
||||||
//--------------------------------
|
//--------------------------------
|
||||||
@ -113,7 +92,7 @@ const getPanelsLinks = ({ variant, panels, selectedPanel, group, defaultGroupTyt
|
|||||||
panelsLinks.push(
|
panelsLinks.push(
|
||||||
variant === P8P_PANELS_MENU_VARIANT.GRID ? (
|
variant === P8P_PANELS_MENU_VARIANT.GRID ? (
|
||||||
<Grid item xs={12} sm={12} md={12} lg={12} xl={12} key={grp}>
|
<Grid item xs={12} sm={12} md={12} lg={12} xl={12} key={grp}>
|
||||||
<Typography variant="h5" color="secondary">
|
<Typography variant={P8P_TYPOGRAPHY_VARIANT.H5} color="P8PPurple">
|
||||||
{grp ? grp : defaultGroupTytle}
|
{grp ? grp : defaultGroupTytle}
|
||||||
</Typography>
|
</Typography>
|
||||||
</Grid>
|
</Grid>
|
||||||
@ -121,9 +100,7 @@ const getPanelsLinks = ({ variant, panels, selectedPanel, group, defaultGroupTyt
|
|||||||
<Divider key={grp} />
|
<Divider key={grp} />
|
||||||
) : (
|
) : (
|
||||||
<Box pb={1} key={grp}>
|
<Box pb={1} key={grp}>
|
||||||
<Typography variant="h7" sx={STYLES.DESKTOP_GROUP_HEADER}>
|
<Typography variant={P8P_TYPOGRAPHY_VARIANT.DESKTOP_GROUP}>{grp ? grp : defaultGroupTytle}</Typography>
|
||||||
{grp ? grp : defaultGroupTytle}
|
|
||||||
</Typography>
|
|
||||||
</Box>
|
</Box>
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
@ -132,28 +109,30 @@ const getPanelsLinks = ({ variant, panels, selectedPanel, group, defaultGroupTyt
|
|||||||
panelsLinks.push(
|
panelsLinks.push(
|
||||||
variant === P8P_PANELS_MENU_VARIANT.GRID ? (
|
variant === P8P_PANELS_MENU_VARIANT.GRID ? (
|
||||||
<Grid item xs={12} sm={6} md={4} lg={4} xl={4} key={panel.name}>
|
<Grid item xs={12} sm={6} md={4} lg={4} xl={4} key={panel.name}>
|
||||||
<Card sx={STYLES.GRID_PANEL_CARD}>
|
<Card variant={P8P_CARD_VARIANT.PANEL_INFO}>
|
||||||
{panel.preview ? (
|
{panel.preview ? (
|
||||||
<CardMedia component="img" alt={panel.name} image={panel.preview} sx={STYLES.GRID_PANEL_CARD_MEDIA} />
|
<CardMedia component="img" alt={panel.name} image={panel.preview} sx={P8P_COMPONENT_HEIGHT({ height: 140 })} />
|
||||||
) : (
|
) : (
|
||||||
<CardMedia
|
<CardMedia
|
||||||
component="img"
|
component="img"
|
||||||
alt={panel.name}
|
alt={panel.name}
|
||||||
image={"./img/default_preview.png"}
|
image={"./img/default_preview.png"}
|
||||||
sx={STYLES.GRID_PANEL_CARD_MEDIA}
|
sx={P8P_COMPONENT_HEIGHT({ height: 140 })}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
<CardContent>
|
<CardContent>
|
||||||
<Stack gap={1} direction="row" sx={STYLES.GRID_PANEL_CARD_CONTENT_TITLE}>
|
<Stack gap={1} direction="row" alignItems="flex-start">
|
||||||
{panel.icon ? <Icon sx={STYLES.GRID_PANEL_CARD_CONTENT_TITLE_ICON}>{panel.icon}</Icon> : null}
|
{panel.icon ? <Icon variant={P8P_ICON_VARIANT.PANEL_MENU_TITLE}>{panel.icon}</Icon> : null}
|
||||||
<Typography variant="h5">{panel.caption}</Typography>
|
<Typography variant={P8P_TYPOGRAPHY_VARIANT.H6_LIGHT}>{panel.caption}</Typography>
|
||||||
</Stack>
|
</Stack>
|
||||||
<Typography variant="body2" color="text.secondary">
|
<Typography variant={P8P_TYPOGRAPHY_VARIANT.BODY3_LIGHT}>{panel.desc}</Typography>
|
||||||
{panel.desc}
|
|
||||||
</Typography>
|
|
||||||
</CardContent>
|
</CardContent>
|
||||||
<CardActions sx={STYLES.GRID_PANEL_CARD_ACTIONS}>
|
<CardActions variant={P8P_CARD_ACTIONS_VARIANT.PANEL_CARD}>
|
||||||
<Button size="large" onClick={() => (onItemNavigate ? onItemNavigate(panel) : null)}>
|
<Button
|
||||||
|
size="large"
|
||||||
|
onClick={() => (onItemNavigate ? onItemNavigate(panel) : null)}
|
||||||
|
variant={P8P_BUTTON_VARIANT.TEXT}
|
||||||
|
>
|
||||||
{navigateCaption}
|
{navigateCaption}
|
||||||
</Button>
|
</Button>
|
||||||
</CardActions>
|
</CardActions>
|
||||||
@ -168,7 +147,7 @@ const getPanelsLinks = ({ variant, panels, selectedPanel, group, defaultGroupTyt
|
|||||||
<ListItemIcon>
|
<ListItemIcon>
|
||||||
<Icon>{panel.icon}</Icon>
|
<Icon>{panel.icon}</Icon>
|
||||||
</ListItemIcon>
|
</ListItemIcon>
|
||||||
<ListItemText primary={panel.caption} />
|
<ListItemText variant={P8P_LIST_ITEM_TEXT_VARIANT.PRIMARY} primary={panel.caption} />
|
||||||
</ListItemButton>
|
</ListItemButton>
|
||||||
</ListItem>
|
</ListItem>
|
||||||
) : (
|
) : (
|
||||||
@ -176,11 +155,11 @@ const getPanelsLinks = ({ variant, panels, selectedPanel, group, defaultGroupTyt
|
|||||||
p={3}
|
p={3}
|
||||||
key={panel.name}
|
key={panel.name}
|
||||||
onClick={() => (onItemNavigate ? onItemNavigate(panel) : null)}
|
onClick={() => (onItemNavigate ? onItemNavigate(panel) : null)}
|
||||||
sx={STYLES.DESKTOP_ITEM_BUTTON}
|
variant={P8P_BUTTON_VARIANT.DESKTOP_PANEL}
|
||||||
title={panel.caption}
|
title={panel.caption}
|
||||||
>
|
>
|
||||||
<Icon sx={STYLES.DESKTOP_ITEM_ICON}>{panel.icon}</Icon>
|
<Icon variant={P8P_ICON_VARIANT.DESKTOP_PANEL}>{panel.icon}</Icon>
|
||||||
<Typography sx={STYLES.DESKTOP_ITEM_CATION} variant="body1">
|
<Typography sx={P8P_TYPOGRAPHY_PANEL_DESK} variant={P8P_TYPOGRAPHY_VARIANT.DESKTOP_CAPTION}>
|
||||||
{panel.caption}
|
{panel.caption}
|
||||||
</Typography>
|
</Typography>
|
||||||
</Button>
|
</Button>
|
||||||
@ -216,12 +195,18 @@ P8PPanelsMenuDrawer.propTypes = {
|
|||||||
//Меню панелей - грид
|
//Меню панелей - грид
|
||||||
const P8PPanelsMenuGrid = ({ onItemNavigate, navigateCaption, panels = [], defaultGroupTytle } = {}) => {
|
const P8PPanelsMenuGrid = ({ onItemNavigate, navigateCaption, panels = [], defaultGroupTytle } = {}) => {
|
||||||
//Формируем ссылки на панели
|
//Формируем ссылки на панели
|
||||||
const panelsLinks = getPanelsLinks({ variant: P8P_PANELS_MENU_VARIANT.GRID, panels, defaultGroupTytle, navigateCaption, onItemNavigate });
|
const panelsLinks = getPanelsLinks({
|
||||||
|
variant: P8P_PANELS_MENU_VARIANT.GRID,
|
||||||
|
panels,
|
||||||
|
defaultGroupTytle,
|
||||||
|
navigateCaption,
|
||||||
|
onItemNavigate
|
||||||
|
});
|
||||||
|
|
||||||
//Генерация содержимого
|
//Генерация содержимого
|
||||||
return (
|
return (
|
||||||
<Box sx={STYLES.GRID_CONTAINER}>
|
<Box sx={P8P_BOX_PANELS_MENU_CONTAINER}>
|
||||||
<Grid container spacing={2} p={2} sx={STYLES.GRID}>
|
<Grid container spacing={2} p={2} variant={P8P_GRID_VARIANT.PANELS_MENU}>
|
||||||
{panelsLinks}
|
{panelsLinks}
|
||||||
</Grid>
|
</Grid>
|
||||||
</Box>
|
</Box>
|
||||||
|
|||||||
@ -11,21 +11,12 @@ import React, { useState, useContext, useMemo } from "react"; //Классы Rea
|
|||||||
import PropTypes from "prop-types"; //Контроль свойств компонента
|
import PropTypes from "prop-types"; //Контроль свойств компонента
|
||||||
import { Stack, List, ListItem, ListItemButton, ListItemText, Typography, Box, Divider } from "@mui/material"; //Интерфейсные элементы
|
import { Stack, List, ListItem, ListItemButton, ListItemText, Typography, Box, Divider } from "@mui/material"; //Интерфейсные элементы
|
||||||
import { P8PDialog, P8P_DIALOG_WIDTH } from "./p8p_dialog"; //Типовой диалог
|
import { P8PDialog, P8P_DIALOG_WIDTH } from "./p8p_dialog"; //Типовой диалог
|
||||||
import { APP_STYLES } from "../../app.styles"; //Типовые стили
|
|
||||||
import { P8PSettingsList } from "./p8p_settings_list"; //Список параметров
|
import { P8PSettingsList } from "./p8p_settings_list"; //Список параметров
|
||||||
import { ApplicationCtx } from "../context/application"; //Контекст приложения
|
import { ApplicationCtx } from "../context/application"; //Контекст приложения
|
||||||
import { deepCopyObject, hasValue } from "../core/utils"; //Вспомогательные функции
|
import { deepCopyObject, hasValue } from "../core/utils"; //Вспомогательные функции
|
||||||
|
import { P8P_BOX_SETTINGS_CONTAINER, P8P_BOX_SETTINGS_LIST, P8P_BOX_SETTINGS_PANELS } from "../theme/styles/box"; //Стили контейнеров
|
||||||
//---------
|
import { P8P_LIST_ITEM_TEXT_VARIANT } from "../theme/variants/p8p_list_item_text_variants"; //Варианты значений списков
|
||||||
//Константы
|
import { P8P_TYPOGRAPHY_VARIANT } from "../theme/p8p_typography"; //Варианты шрифтов
|
||||||
//---------
|
|
||||||
|
|
||||||
//Стили
|
|
||||||
const STYLES = {
|
|
||||||
CONTAINER: { display: "flex", flexDirection: "row", alignItems: "flex-start" },
|
|
||||||
BOX_PANELS: { width: "300px", height: "500px", overflow: "auto", ...APP_STYLES.SCROLL },
|
|
||||||
BOX_SETTINGS: { width: "520px", height: "500px", overflow: "auto", ...APP_STYLES.SCROLL }
|
|
||||||
};
|
|
||||||
|
|
||||||
//-----------
|
//-----------
|
||||||
//Тело модуля
|
//Тело модуля
|
||||||
@ -73,7 +64,7 @@ const P8PSettingsDialog = ({ settings, panel = null, onOk, onClose }) => {
|
|||||||
//Генерация содержимого
|
//Генерация содержимого
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Box sx={STYLES.BOX_PANELS}>
|
<Box sx={P8P_BOX_SETTINGS_PANELS}>
|
||||||
<List>
|
<List>
|
||||||
{Object.keys(panelSettings).map((panel, i) => {
|
{Object.keys(panelSettings).map((panel, i) => {
|
||||||
//Считываем информацию о панели
|
//Считываем информацию о панели
|
||||||
@ -83,12 +74,13 @@ const P8PSettingsDialog = ({ settings, panel = null, onOk, onClose }) => {
|
|||||||
<ListItem key={i}>
|
<ListItem key={i}>
|
||||||
<ListItemButton onClick={() => handlePanelSelect(panel)} selected={panel === selectedPanel}>
|
<ListItemButton onClick={() => handlePanelSelect(panel)} selected={panel === selectedPanel}>
|
||||||
<ListItemText
|
<ListItemText
|
||||||
|
variant={P8P_LIST_ITEM_TEXT_VARIANT.PRIMARY}
|
||||||
primary={panelInfo.name}
|
primary={panelInfo.name}
|
||||||
secondaryTypographyProps={{ component: "div" }}
|
secondaryTypographyProps={{ component: "div" }}
|
||||||
secondary={
|
secondary={
|
||||||
<Stack direction={"row"} justifyContent={"space-between"} gap={2}>
|
<Stack direction="row" justifyContent="space-between" gap={2}>
|
||||||
<Typography
|
<Typography
|
||||||
variant={"caption"}
|
variant={P8P_TYPOGRAPHY_VARIANT.CAPTION}
|
||||||
noWrap={true}
|
noWrap={true}
|
||||||
title={panelInfo.desc ? panelInfo.desc : "Описание отсутствует"}
|
title={panelInfo.desc ? panelInfo.desc : "Описание отсутствует"}
|
||||||
>{`${panelInfo.desc ? panelInfo.desc : "Описание отсутствует"}`}</Typography>
|
>{`${panelInfo.desc ? panelInfo.desc : "Описание отсутствует"}`}</Typography>
|
||||||
@ -117,20 +109,22 @@ const P8PSettingsDialog = ({ settings, panel = null, onOk, onClose }) => {
|
|||||||
okDisabled={Object.keys(panelSettings).length === 0}
|
okDisabled={Object.keys(panelSettings).length === 0}
|
||||||
>
|
>
|
||||||
{isSettingsExists ? (
|
{isSettingsExists ? (
|
||||||
<Box sx={STYLES.CONTAINER}>
|
<Box sx={P8P_BOX_SETTINGS_CONTAINER}>
|
||||||
{!hasValue(panel) ? panelsListRender() : null}
|
{!hasValue(panel) ? panelsListRender() : null}
|
||||||
<Box sx={STYLES.BOX_SETTINGS}>
|
<Box sx={P8P_BOX_SETTINGS_LIST}>
|
||||||
{hasValue(selectedPanel) ? (
|
{hasValue(selectedPanel) ? (
|
||||||
<P8PSettingsList settings={panelSettings[selectedPanel]} onSettingChange={handleSettingChange} />
|
<P8PSettingsList settings={panelSettings[selectedPanel]} onSettingChange={handleSettingChange} />
|
||||||
) : (
|
) : (
|
||||||
<Typography align="center" variant="subtitle1">
|
<>
|
||||||
Выберите панель для отображения параметров
|
<Typography align="center" component="h6" variant={P8P_TYPOGRAPHY_VARIANT.SUBTITLE1}>
|
||||||
</Typography>
|
Выберите панель для отображения параметров
|
||||||
|
</Typography>
|
||||||
|
</>
|
||||||
)}
|
)}
|
||||||
</Box>
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
) : (
|
) : (
|
||||||
<Typography align="center" variant="subtitle1">
|
<Typography align="center" component="h6" variant={P8P_TYPOGRAPHY_VARIANT.SUBTITLE1}>
|
||||||
Отсутствуют доступные параметры
|
Отсутствуют доступные параметры
|
||||||
</Typography>
|
</Typography>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@ -14,17 +14,10 @@ import { P8PDialog } from "./p8p_dialog"; //Типовой диалог
|
|||||||
import { deepCopyObject } from "../core/utils"; //Вспомогательные функции
|
import { deepCopyObject } from "../core/utils"; //Вспомогательные функции
|
||||||
import { ApplicationCtx } from "../context/application"; //Контекст приложения
|
import { ApplicationCtx } from "../context/application"; //Контекст приложения
|
||||||
import { P8P_DATA_TYPES } from "../core/data_types"; //Типы данных
|
import { P8P_DATA_TYPES } from "../core/data_types"; //Типы данных
|
||||||
|
import { P8P_LIST_VARIANT } from "../theme/variants/p8p_list_variants"; //Варианты списков
|
||||||
//---------
|
import { P8P_COMPONENT_WIDTH } from "../theme/styles/common"; //Стили - общие
|
||||||
//Константы
|
import { P8P_LIST_ITEM_TEXT_VARIANT } from "../theme/variants/p8p_list_item_text_variants"; //Варианты значений списков
|
||||||
//---------
|
import { P8P_TYPOGRAPHY_VARIANT } from "../theme/p8p_typography"; //Варианты шрифтов
|
||||||
|
|
||||||
//Стили
|
|
||||||
const STYLES = {
|
|
||||||
LIST: { width: "510px", bgcolor: "background.paper", overflowY: "auto" },
|
|
||||||
TYPOGRAPHY_VALUE: { maxWidth: "200px" },
|
|
||||||
TEXT_FIELD_STR_VALUE: { minWidth: "400px" }
|
|
||||||
};
|
|
||||||
|
|
||||||
//--------------------------------
|
//--------------------------------
|
||||||
//Вспомогательные классы и функции
|
//Вспомогательные классы и функции
|
||||||
@ -129,24 +122,25 @@ const P8PSettingsList = ({ settings, onSettingChange }) => {
|
|||||||
//Формирование представления
|
//Формирование представления
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<List sx={STYLES.LIST}>
|
<List variant={P8P_LIST_VARIANT.SETTINGS}>
|
||||||
{Object.keys(settings).map((setting, i) => {
|
{Object.keys(settings).map((setting, i) => {
|
||||||
return (
|
return (
|
||||||
<ListItem key={i}>
|
<ListItem key={i}>
|
||||||
<ListItemButton onClick={() => handleSettingClick(setting)}>
|
<ListItemButton onClick={() => handleSettingClick(setting)}>
|
||||||
<ListItemText
|
<ListItemText
|
||||||
|
variant={P8P_LIST_ITEM_TEXT_VARIANT.PRIMARY}
|
||||||
primary={settings[setting].name}
|
primary={settings[setting].name}
|
||||||
secondaryTypographyProps={{ component: "div" }}
|
secondaryTypographyProps={{ component: "div" }}
|
||||||
secondary={
|
secondary={
|
||||||
<Stack direction={"row"} justifyContent={"space-between"} gap={2}>
|
<Stack direction={"row"} justifyContent={"space-between"} gap={2}>
|
||||||
<Typography
|
<Typography
|
||||||
variant={"caption"}
|
variant={P8P_TYPOGRAPHY_VARIANT.CAPTION}
|
||||||
noWrap={true}
|
noWrap={true}
|
||||||
title={settings[setting].desc ? settings[setting].desc : "Описание отсутствует"}
|
title={settings[setting].desc ? settings[setting].desc : "Описание отсутствует"}
|
||||||
>{`${settings[setting].desc ? settings[setting].desc : "Описание отсутствует"}`}</Typography>
|
>{`${settings[setting].desc ? settings[setting].desc : "Описание отсутствует"}`}</Typography>
|
||||||
<Typography
|
<Typography
|
||||||
variant={"caption"}
|
variant={P8P_TYPOGRAPHY_VARIANT.CAPTION}
|
||||||
sx={STYLES.TYPOGRAPHY_VALUE}
|
sx={P8P_COMPONENT_WIDTH({ maxWidth: "200px" })}
|
||||||
noWrap={true}
|
noWrap={true}
|
||||||
title={settings[setting].value}
|
title={settings[setting].value}
|
||||||
>{`${settings[setting].value}`}</Typography>
|
>{`${settings[setting].value}`}</Typography>
|
||||||
|
|||||||
@ -10,17 +10,13 @@
|
|||||||
import React, { useEffect, useRef, useState } from "react"; //Классы React
|
import React, { useEffect, useRef, useState } from "react"; //Классы React
|
||||||
import { IconButton, Icon, Container, Grid } from "@mui/material"; //Интерфейсные элементы
|
import { IconButton, Icon, Container, Grid } from "@mui/material"; //Интерфейсные элементы
|
||||||
import PropTypes from "prop-types"; //Контроль свойств компонента
|
import PropTypes from "prop-types"; //Контроль свойств компонента
|
||||||
|
import { P8P_BOX_CENTER } from "../theme/styles/box"; //Стили контейнеров
|
||||||
|
import { P8P_GRID_VARIANT } from "../theme/variants/p8p_grid_variants"; //Стили сеток
|
||||||
|
|
||||||
//---------
|
//---------
|
||||||
//Константы
|
//Константы
|
||||||
//---------
|
//---------
|
||||||
|
|
||||||
//Стили
|
|
||||||
const STYLES = {
|
|
||||||
GRID_ITEM_CANVAS: { width: "100%", height: "100%" },
|
|
||||||
CONTROLS: { justifyContent: "center", alignItems: "center", display: "flex" }
|
|
||||||
};
|
|
||||||
|
|
||||||
//Структура элемента изображения
|
//Структура элемента изображения
|
||||||
const P8P_SVG_ITEM_SHAPE = PropTypes.shape({
|
const P8P_SVG_ITEM_SHAPE = PropTypes.shape({
|
||||||
id: PropTypes.oneOfType([PropTypes.string, PropTypes.number]).isRequired,
|
id: PropTypes.oneOfType([PropTypes.string, PropTypes.number]).isRequired,
|
||||||
@ -129,8 +125,8 @@ const P8PSVG = ({ data, items, onClick, onItemClick, canvasStyle, fillOpacity })
|
|||||||
? 0
|
? 0
|
||||||
: pv.currentImage + 1
|
: pv.currentImage + 1
|
||||||
: pv.currentImage - 1 < 0
|
: pv.currentImage - 1 < 0
|
||||||
? pv.imagesCount - 1
|
? pv.imagesCount - 1
|
||||||
: pv.currentImage - 1
|
: pv.currentImage - 1
|
||||||
}));
|
}));
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -156,12 +152,12 @@ const P8PSVG = ({ data, items, onClick, onItemClick, canvasStyle, fillOpacity })
|
|||||||
return (
|
return (
|
||||||
<Container>
|
<Container>
|
||||||
<Grid container direction="column" justifyContent="center" alignItems="center" spacing={0}>
|
<Grid container direction="column" justifyContent="center" alignItems="center" spacing={0}>
|
||||||
<Grid item xs={12} sx={STYLES.GRID_ITEM_CANVAS}>
|
<Grid item xs={12} variant={P8P_GRID_VARIANT.SVG_CONTAINER}>
|
||||||
<div ref={svgContainerRef} style={{ ...(canvasStyle ? canvasStyle : {}) }}></div>
|
<div ref={svgContainerRef} style={{ ...(canvasStyle ? canvasStyle : {}) }}></div>
|
||||||
</Grid>
|
</Grid>
|
||||||
{state.imagesCount > 1 ? (
|
{state.imagesCount > 1 ? (
|
||||||
<Grid item xs={12}>
|
<Grid item xs={12}>
|
||||||
<div style={STYLES.CONTROLS}>
|
<div style={P8P_BOX_CENTER}>
|
||||||
<IconButton onClick={handlePrevClick}>
|
<IconButton onClick={handlePrevClick}>
|
||||||
<Icon>arrow_left</Icon>
|
<Icon>arrow_left</Icon>
|
||||||
</IconButton>
|
</IconButton>
|
||||||
|
|||||||
@ -20,475 +20,38 @@ import {
|
|||||||
Paper,
|
Paper,
|
||||||
IconButton,
|
IconButton,
|
||||||
Icon,
|
Icon,
|
||||||
Menu,
|
|
||||||
MenuItem,
|
|
||||||
Divider,
|
|
||||||
Stack,
|
Stack,
|
||||||
Dialog,
|
|
||||||
DialogTitle,
|
|
||||||
DialogContent,
|
|
||||||
DialogActions,
|
|
||||||
Button,
|
Button,
|
||||||
TextField,
|
|
||||||
Chip,
|
|
||||||
Container,
|
Container,
|
||||||
Link
|
Link
|
||||||
} from "@mui/material"; //Интерфейсные компоненты
|
} from "@mui/material"; //Интерфейсные компоненты
|
||||||
import { useTheme } from "@mui/material/styles"; //Взаимодействие со стилями MUI
|
import { P8PAppInlineError, P8PHintDialog } from "../p8p_app_message"; //Встраиваемое сообщение об ошибке
|
||||||
import { P8PAppInlineError, P8PHintDialog } from "./p8p_app_message"; //Встраиваемое сообщение об ошибке
|
import { P8P_TABLE_AT, HEADER_INITIAL_STATE, p8pTableReducer } from "./p8p_table_reducer"; //Редьюсер состояния
|
||||||
import { P8P_TABLE_AT, HEADER_INITIAL_STATE, hasValue, p8pTableReducer } from "./p8p_table_reducer"; //Редьюсер состояния
|
import { P8PTableColumnToolBarLeft } from "./p8p_table_column_toolbar_left"; //Таблица - Панель инструментов столбца (левая)
|
||||||
import { P8P_DATA_TYPES } from "../core/data_types"; //Типы данных
|
import { P8PTableColumnToolBarRight } from "./p8p_table_column_toolbar_right"; //Таблица - Панель инструментов столбца (правая)
|
||||||
|
import { P8PTableColumnMenu } from "./p8p_table_column_menu"; //Таблица - Меню столбца
|
||||||
//---------
|
import { P8PTableColumnFilterDialog } from "./p8p_table_column_filter_dialog"; //Таблица - Диалог фильтра
|
||||||
//Константы
|
import { P8PTableFiltersChips } from "./p8p_table_filters_chips"; //Таблица - Сводный фильтр
|
||||||
//---------
|
import {
|
||||||
|
P8P_TABLE_SIZE,
|
||||||
//Размеры отступов
|
P8P_TABLE_DATA_TYPE,
|
||||||
const P8P_TABLE_SIZE = {
|
P8P_TABLE_COLUMN_ORDER_DIRECTIONS,
|
||||||
SMALL: "small",
|
P8P_TABLE_COLUMN_TOOL_BAR_ACTIONS,
|
||||||
MEDIUM: "medium"
|
P8P_TABLE_COLUMN_MENU_ACTIONS,
|
||||||
};
|
P8P_TABLE_FILTER_SHAPE,
|
||||||
|
P8P_TABLE_ORDER_SHAPE,
|
||||||
//Типы данных
|
P8P_TABLE_PAGINATOR_ALIGN,
|
||||||
const P8P_TABLE_DATA_TYPE = {
|
P8P_TABLE_PAGINATOR_POSITION,
|
||||||
STR: P8P_DATA_TYPES.STR,
|
P8P_TABLE_MORE_HEIGHT,
|
||||||
NUMB: P8P_DATA_TYPES.NUMB,
|
P8P_TABLE_FILTERS_HEIGHT
|
||||||
DATE: P8P_DATA_TYPES.DATE
|
} from "./p8p_table_constants"; //Константы таблицы
|
||||||
};
|
import { P8P_TABLE_VARIANT } from "../../theme/variants/p8p_table_variants"; //Варианты таблиц
|
||||||
|
import { P8P_TABLE_HEAD_VARIANT } from "../../theme/variants/p8p_table_head_variants"; //Варианты заголовков таблиц
|
||||||
//Направления сортировки
|
import { P8P_TABLE_CELL_VARIANT } from "../../theme/variants/p8p_table_cell_variants"; //Варианты ячеек таблиц
|
||||||
const P8P_TABLE_COLUMN_ORDER_DIRECTIONS = {
|
import { P8P_TABLE_ROW_VARIANT } from "../../theme/variants/p8p_table_row_variants"; //Варианты строк таблиц
|
||||||
ASC: "ASC",
|
import { P8P_CONTAINER_VARIANT } from "../../theme/variants/p8p_container_variants"; //Варианты контейнеров
|
||||||
DESC: "DESC"
|
import { P8P_PAGINATION_VARIANT } from "../../theme/variants/p8p_pagination_variants"; //Варианты пагинаторов
|
||||||
};
|
import { P8P_TYPOGRAPHY_VARIANT } from "../../theme/p8p_typography"; //Варианты шрифтов
|
||||||
|
|
||||||
//Действия панели инструментов столбца
|
|
||||||
const P8P_TABLE_COLUMN_TOOL_BAR_ACTIONS = {
|
|
||||||
ORDER_TOGGLE: "ORDER_TOGGLE",
|
|
||||||
FILTER_TOGGLE: "FILTER_TOGGLE",
|
|
||||||
EXPAND_TOGGLE: "EXPAND_TOGGLE"
|
|
||||||
};
|
|
||||||
|
|
||||||
//Действия меню столбца
|
|
||||||
const P8P_TABLE_COLUMN_MENU_ACTIONS = {
|
|
||||||
ORDER_ASC: "ORDER_ASC",
|
|
||||||
ORDER_DESC: "ORDER_DESC",
|
|
||||||
FILTER: "FILTER"
|
|
||||||
};
|
|
||||||
|
|
||||||
//Структура элемента описания фильтра
|
|
||||||
const P8P_TABLE_FILTER_SHAPE = PropTypes.shape({
|
|
||||||
name: PropTypes.string.isRequired,
|
|
||||||
from: PropTypes.any,
|
|
||||||
to: PropTypes.any
|
|
||||||
});
|
|
||||||
|
|
||||||
//Структура элемента описания сортировки
|
|
||||||
const P8P_TABLE_ORDER_SHAPE = PropTypes.shape({
|
|
||||||
direction: PropTypes.string.isRequired,
|
|
||||||
name: PropTypes.string.isRequired
|
|
||||||
});
|
|
||||||
|
|
||||||
//Размещение области страниц по вертикали
|
|
||||||
const P8P_TABLE_PAGINATOR_ALIGN = {
|
|
||||||
LEFT: "left",
|
|
||||||
RIGHT: "right",
|
|
||||||
CENTER: "center"
|
|
||||||
};
|
|
||||||
|
|
||||||
//Размещение области страниц по горизонтали
|
|
||||||
const P8P_TABLE_PAGINATOR_POSITION = {
|
|
||||||
TOP: "top",
|
|
||||||
BOTTOM: "bottom",
|
|
||||||
BOTH: "both"
|
|
||||||
};
|
|
||||||
|
|
||||||
//Высота кнопки догрузки данных
|
|
||||||
const P8P_TABLE_MORE_HEIGHT = "49px";
|
|
||||||
|
|
||||||
//Высота фильтров таблицы
|
|
||||||
const P8P_TABLE_FILTERS_HEIGHT = "48px";
|
|
||||||
|
|
||||||
//Стили
|
|
||||||
const STYLES = {
|
|
||||||
TABLE: {},
|
|
||||||
TABLE_HEAD_STICKY: {
|
|
||||||
position: "sticky",
|
|
||||||
top: 0,
|
|
||||||
zIndex: 1000
|
|
||||||
},
|
|
||||||
TABLE_HEAD_CELL_STICKY: (theme, left) => ({
|
|
||||||
position: "sticky",
|
|
||||||
left,
|
|
||||||
backgroundColor: theme.palette.background.default,
|
|
||||||
zIndex: 1000
|
|
||||||
}),
|
|
||||||
TABLE_ROW: {
|
|
||||||
"&:last-child td, &:last-child th": { border: 0 }
|
|
||||||
},
|
|
||||||
TABLE_CELL_STICKY: (theme, left) => ({
|
|
||||||
position: "sticky",
|
|
||||||
left,
|
|
||||||
backgroundColor: theme.palette.background.default,
|
|
||||||
zIndex: 500
|
|
||||||
}),
|
|
||||||
TABLE_CELL_EXPAND_CONTROL: {
|
|
||||||
minWidth: "60px",
|
|
||||||
maxWidth: "60px"
|
|
||||||
},
|
|
||||||
TABLE_CELL_EXPAND_CONTAINER: {
|
|
||||||
paddingBottom: 0,
|
|
||||||
paddingTop: 0,
|
|
||||||
paddingLeft: 0,
|
|
||||||
paddingRight: 0
|
|
||||||
},
|
|
||||||
TABLE_CELL_GROUP_HEADER: {
|
|
||||||
backgroundColor: "lightgray"
|
|
||||||
},
|
|
||||||
TABLE_CELL_GROUP_HEADER_STICKY: {
|
|
||||||
position: "sticky",
|
|
||||||
left: 0
|
|
||||||
},
|
|
||||||
TABLE_COLUMN_STACK: {
|
|
||||||
alignItems: "center"
|
|
||||||
},
|
|
||||||
TABLE_COLUMN_MENU_ITEM_ICON: {
|
|
||||||
paddingRight: "10px"
|
|
||||||
},
|
|
||||||
FILTER_CHIP: {
|
|
||||||
alignItems: "center"
|
|
||||||
},
|
|
||||||
PAGINATION: (pagesAlign, position) => ({
|
|
||||||
display: "flex",
|
|
||||||
justifyContent:
|
|
||||||
pagesAlign === P8P_TABLE_PAGINATOR_ALIGN.LEFT
|
|
||||||
? "flex-start"
|
|
||||||
: pagesAlign === P8P_TABLE_PAGINATOR_ALIGN.CENTER
|
|
||||||
? "space-around"
|
|
||||||
: "flex-end",
|
|
||||||
...(position === P8P_TABLE_PAGINATOR_POSITION.TOP ? { paddingBottom: "10px" } : { paddingTop: "10px" })
|
|
||||||
}),
|
|
||||||
MORE_BUTTON_CONTAINER: {
|
|
||||||
with: "100%",
|
|
||||||
textAlign: "center",
|
|
||||||
padding: "5px"
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
//--------------------------------
|
|
||||||
//Вспомогательные классы и функции
|
|
||||||
//--------------------------------
|
|
||||||
|
|
||||||
//Панель инструментов столбца (левая)
|
|
||||||
const P8PTableColumnToolBarLeft = ({ columnDef, onItemClick }) => {
|
|
||||||
//Кнопка развёртывания/свёртывания
|
|
||||||
let expButton = null;
|
|
||||||
if (columnDef.expandable)
|
|
||||||
expButton = (
|
|
||||||
<IconButton onClick={() => (onItemClick ? onItemClick(P8P_TABLE_COLUMN_TOOL_BAR_ACTIONS.EXPAND_TOGGLE, columnDef.name) : null)}>
|
|
||||||
<Icon>{columnDef.expanded ? "indeterminate_check_box" : "add_box"}</Icon>
|
|
||||||
</IconButton>
|
|
||||||
);
|
|
||||||
|
|
||||||
//Генерация содержимого
|
|
||||||
return <>{expButton}</>;
|
|
||||||
};
|
|
||||||
|
|
||||||
//Контроль свойств - Панель инструментов столбца (левая)
|
|
||||||
P8PTableColumnToolBarLeft.propTypes = {
|
|
||||||
columnDef: PropTypes.object.isRequired,
|
|
||||||
onItemClick: PropTypes.func
|
|
||||||
};
|
|
||||||
|
|
||||||
//Панель инструментов столбца (правая)
|
|
||||||
const P8PTableColumnToolBarRight = ({ columnDef, orders, filters, onItemClick }) => {
|
|
||||||
//Кнопка сортировки
|
|
||||||
const order = orders.find(o => o.name == columnDef.name);
|
|
||||||
let orderButton = null;
|
|
||||||
if (order)
|
|
||||||
orderButton = (
|
|
||||||
<IconButton onClick={() => (onItemClick ? onItemClick(P8P_TABLE_COLUMN_TOOL_BAR_ACTIONS.ORDER_TOGGLE, columnDef.name) : null)}>
|
|
||||||
<Icon>{order.direction === P8P_TABLE_COLUMN_ORDER_DIRECTIONS.ASC ? "arrow_upward" : "arrow_downward"}</Icon>
|
|
||||||
</IconButton>
|
|
||||||
);
|
|
||||||
|
|
||||||
//Кнопка фильтрации
|
|
||||||
const filter = filters.find(f => f.name == columnDef.name);
|
|
||||||
let filterButton = null;
|
|
||||||
if (hasValue(filter?.from) || hasValue(filter?.to))
|
|
||||||
filterButton = (
|
|
||||||
<IconButton onClick={() => (onItemClick ? onItemClick(P8P_TABLE_COLUMN_TOOL_BAR_ACTIONS.FILTER_TOGGLE, columnDef.name) : null)}>
|
|
||||||
<Icon>filter_alt</Icon>
|
|
||||||
</IconButton>
|
|
||||||
);
|
|
||||||
|
|
||||||
//Генерация содержимого
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
{orderButton}
|
|
||||||
{filterButton}
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
//Контроль свойств - Панель инструментов столбца (правая)
|
|
||||||
P8PTableColumnToolBarRight.propTypes = {
|
|
||||||
columnDef: PropTypes.object.isRequired,
|
|
||||||
orders: PropTypes.array.isRequired,
|
|
||||||
filters: PropTypes.array.isRequired,
|
|
||||||
onItemClick: PropTypes.func
|
|
||||||
};
|
|
||||||
|
|
||||||
//Меню столбца
|
|
||||||
const P8PTableColumnMenu = ({ columnDef, orderAscItemCaption, orderDescItemCaption, filterItemCaption, onItemClick }) => {
|
|
||||||
//Собственное состояние
|
|
||||||
const [anchorEl, setAnchorEl] = useState(null);
|
|
||||||
|
|
||||||
//Флаг отображения
|
|
||||||
const open = Boolean(anchorEl);
|
|
||||||
|
|
||||||
//По нажатию на открытие меню
|
|
||||||
const handleMenuButtonClick = event => {
|
|
||||||
setAnchorEl(event.currentTarget);
|
|
||||||
};
|
|
||||||
|
|
||||||
//По нажатию на пункт меню
|
|
||||||
const handleMenuItemClick = (event, index, action, columnName) => {
|
|
||||||
if (onItemClick) onItemClick(action, columnName);
|
|
||||||
setAnchorEl(null);
|
|
||||||
};
|
|
||||||
|
|
||||||
//При закрытии меню
|
|
||||||
const handleMenuClose = () => {
|
|
||||||
setAnchorEl(null);
|
|
||||||
};
|
|
||||||
|
|
||||||
//Формирование списка элементов меню в зависимости от описания колонки таблицы
|
|
||||||
const menuItems = [];
|
|
||||||
if (columnDef.order === true) {
|
|
||||||
menuItems.push(
|
|
||||||
<MenuItem
|
|
||||||
key={"orderAsc"}
|
|
||||||
onClick={(event, index) => handleMenuItemClick(event, index, P8P_TABLE_COLUMN_MENU_ACTIONS.ORDER_ASC, columnDef.name)}
|
|
||||||
>
|
|
||||||
<Icon sx={STYLES.TABLE_COLUMN_MENU_ITEM_ICON}>arrow_upward</Icon>
|
|
||||||
{orderAscItemCaption}
|
|
||||||
</MenuItem>
|
|
||||||
);
|
|
||||||
menuItems.push(
|
|
||||||
<MenuItem
|
|
||||||
key={"orderDesc"}
|
|
||||||
onClick={(event, index) => handleMenuItemClick(event, index, P8P_TABLE_COLUMN_MENU_ACTIONS.ORDER_DESC, columnDef.name)}
|
|
||||||
>
|
|
||||||
<Icon sx={STYLES.TABLE_COLUMN_MENU_ITEM_ICON}>arrow_downward</Icon>
|
|
||||||
{orderDescItemCaption}
|
|
||||||
</MenuItem>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
if (columnDef.filter === true) {
|
|
||||||
if (menuItems.length > 0) menuItems.push(<Divider key={"divider"} sx={{ my: 0.5 }} />);
|
|
||||||
menuItems.push(
|
|
||||||
<MenuItem
|
|
||||||
key={"filter"}
|
|
||||||
onClick={(event, index) => handleMenuItemClick(event, index, P8P_TABLE_COLUMN_MENU_ACTIONS.FILTER, columnDef.name)}
|
|
||||||
>
|
|
||||||
<Icon sx={STYLES.TABLE_COLUMN_MENU_ITEM_ICON}>filter_alt</Icon>
|
|
||||||
{filterItemCaption}
|
|
||||||
</MenuItem>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
//Генерация содержимого
|
|
||||||
return menuItems.length > 0 ? (
|
|
||||||
<>
|
|
||||||
<IconButton id={`${columnDef.name}_menu_button`} aria-haspopup="true" onClick={handleMenuButtonClick}>
|
|
||||||
<Icon>more_vert</Icon>
|
|
||||||
</IconButton>
|
|
||||||
<Menu id={`${columnDef.name}_menu`} anchorEl={anchorEl} open={open} onClose={handleMenuClose}>
|
|
||||||
{menuItems}
|
|
||||||
</Menu>
|
|
||||||
</>
|
|
||||||
) : null;
|
|
||||||
};
|
|
||||||
|
|
||||||
//Контроль свойств - Меню столбца
|
|
||||||
P8PTableColumnMenu.propTypes = {
|
|
||||||
columnDef: PropTypes.object.isRequired,
|
|
||||||
orderAscItemCaption: PropTypes.string.isRequired,
|
|
||||||
orderDescItemCaption: PropTypes.string.isRequired,
|
|
||||||
filterItemCaption: PropTypes.string.isRequired,
|
|
||||||
onItemClick: PropTypes.func
|
|
||||||
};
|
|
||||||
|
|
||||||
//Диалог фильтра
|
|
||||||
const P8PTableColumnFilterDialog = ({
|
|
||||||
columnDef,
|
|
||||||
from,
|
|
||||||
to,
|
|
||||||
valueCaption,
|
|
||||||
valueFromCaption,
|
|
||||||
valueToCaption,
|
|
||||||
okBtnCaption,
|
|
||||||
clearBtnCaption,
|
|
||||||
cancelBtnCaption,
|
|
||||||
valueFormatter,
|
|
||||||
onOk,
|
|
||||||
onClear,
|
|
||||||
onCancel
|
|
||||||
}) => {
|
|
||||||
//Собственное состояние - значения с-по
|
|
||||||
const [filterValues, setFilterValues] = useState({ from, to });
|
|
||||||
|
|
||||||
//Отработка воода значения в фильтр
|
|
||||||
const handleFilterTextFieldChanged = e => {
|
|
||||||
setFilterValues(prev => ({ ...prev, [e.target.name]: e.target.value }));
|
|
||||||
};
|
|
||||||
|
|
||||||
//Элементы ввода значений фильтра
|
|
||||||
let inputs = null;
|
|
||||||
if (Array.isArray(columnDef.values) && columnDef.values.length > 0) {
|
|
||||||
inputs = (
|
|
||||||
<TextField
|
|
||||||
name="from"
|
|
||||||
fullWidth
|
|
||||||
select
|
|
||||||
label={valueCaption}
|
|
||||||
variant="standard"
|
|
||||||
value={filterValues.from}
|
|
||||||
onChange={handleFilterTextFieldChanged}
|
|
||||||
>
|
|
||||||
{columnDef.values.map((v, i) => (
|
|
||||||
<MenuItem key={i} value={v}>
|
|
||||||
{valueFormatter ? valueFormatter({ value: v, columnDef }) : v}
|
|
||||||
</MenuItem>
|
|
||||||
))}
|
|
||||||
</TextField>
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
switch (columnDef.dataType) {
|
|
||||||
case P8P_TABLE_DATA_TYPE.STR: {
|
|
||||||
inputs = (
|
|
||||||
<TextField
|
|
||||||
name="from"
|
|
||||||
fullWidth
|
|
||||||
InputLabelProps={{ shrink: true }}
|
|
||||||
value={filterValues.from}
|
|
||||||
onChange={handleFilterTextFieldChanged}
|
|
||||||
label={valueCaption}
|
|
||||||
variant="standard"
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case P8P_TABLE_DATA_TYPE.NUMB:
|
|
||||||
case P8P_TABLE_DATA_TYPE.DATE: {
|
|
||||||
inputs = (
|
|
||||||
<>
|
|
||||||
<TextField
|
|
||||||
name="from"
|
|
||||||
InputLabelProps={{ shrink: true }}
|
|
||||||
type={columnDef.dataType == P8P_TABLE_DATA_TYPE.NUMB ? "number" : "date"}
|
|
||||||
value={filterValues.from}
|
|
||||||
onChange={handleFilterTextFieldChanged}
|
|
||||||
label={valueFromCaption}
|
|
||||||
variant="standard"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<TextField
|
|
||||||
name="to"
|
|
||||||
InputLabelProps={{ shrink: true }}
|
|
||||||
type={columnDef.dataType == P8P_TABLE_DATA_TYPE.NUMB ? "number" : "date"}
|
|
||||||
value={filterValues.to}
|
|
||||||
onChange={handleFilterTextFieldChanged}
|
|
||||||
label={valueToCaption}
|
|
||||||
variant="standard"
|
|
||||||
/>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Dialog
|
|
||||||
open={true}
|
|
||||||
aria-labelledby="filter-dialog-title"
|
|
||||||
aria-describedby="filter-dialog-description"
|
|
||||||
onClose={() => (onCancel ? onCancel(columnDef.name) : null)}
|
|
||||||
>
|
|
||||||
<DialogTitle id="filter-dialog-title">{columnDef.caption}</DialogTitle>
|
|
||||||
<DialogContent>{inputs}</DialogContent>
|
|
||||||
<DialogActions>
|
|
||||||
<Button onClick={() => (onOk ? onOk(columnDef.name, filterValues.from, filterValues.to) : null)}>{okBtnCaption}</Button>
|
|
||||||
<Button onClick={() => (onClear ? onClear(columnDef.name) : null)} variant="secondary">
|
|
||||||
{clearBtnCaption}
|
|
||||||
</Button>
|
|
||||||
<Button onClick={() => (onCancel ? onCancel(columnDef.name) : null)}>{cancelBtnCaption}</Button>
|
|
||||||
</DialogActions>
|
|
||||||
</Dialog>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
//Контроль свойств - Диалог фильтра
|
|
||||||
P8PTableColumnFilterDialog.propTypes = {
|
|
||||||
columnDef: PropTypes.object.isRequired,
|
|
||||||
from: PropTypes.any,
|
|
||||||
to: PropTypes.any,
|
|
||||||
valueCaption: PropTypes.string.isRequired,
|
|
||||||
valueFromCaption: PropTypes.string.isRequired,
|
|
||||||
valueToCaption: PropTypes.string.isRequired,
|
|
||||||
okBtnCaption: PropTypes.string.isRequired,
|
|
||||||
clearBtnCaption: PropTypes.string.isRequired,
|
|
||||||
cancelBtnCaption: PropTypes.string.isRequired,
|
|
||||||
valueFormatter: PropTypes.func,
|
|
||||||
onOk: PropTypes.func,
|
|
||||||
onClear: PropTypes.func,
|
|
||||||
onCancel: PropTypes.func
|
|
||||||
};
|
|
||||||
|
|
||||||
//Сводный фильтр
|
|
||||||
const P8PTableFiltersChips = ({ filters, columnsDef, valueFromCaption, valueToCaption, onFilterChipClick, onFilterChipDelete, valueFormatter }) => {
|
|
||||||
return (
|
|
||||||
<Stack direction="row" spacing={1} p={1}>
|
|
||||||
{filters.map((filter, i) => {
|
|
||||||
const columnDef = columnsDef.find(columnDef => columnDef.name == filter.name);
|
|
||||||
return (
|
|
||||||
<Chip
|
|
||||||
key={i}
|
|
||||||
label={
|
|
||||||
<Stack direction="row" sx={STYLES.FILTER_CHIP}>
|
|
||||||
<strong>{columnDef.caption}</strong>:
|
|
||||||
{hasValue(filter.from) && !columnDef.values && columnDef.dataType != P8P_TABLE_DATA_TYPE.STR
|
|
||||||
? `${valueFromCaption.toLowerCase()} `
|
|
||||||
: null}
|
|
||||||
{hasValue(filter.from) ? (valueFormatter ? valueFormatter({ value: filter.from, columnDef }) : filter.from) : null}
|
|
||||||
{hasValue(filter.to) && !columnDef.values && columnDef.dataType != P8P_TABLE_DATA_TYPE.STR
|
|
||||||
? ` ${valueToCaption.toLowerCase()} `
|
|
||||||
: null}
|
|
||||||
{hasValue(filter.to) ? (valueFormatter ? valueFormatter({ value: filter.to, columnDef }) : filter.to) : null}
|
|
||||||
</Stack>
|
|
||||||
}
|
|
||||||
variant="outlined"
|
|
||||||
onClick={() => (onFilterChipClick ? onFilterChipClick(columnDef.name) : null)}
|
|
||||||
onDelete={() => (onFilterChipDelete ? onFilterChipDelete(columnDef.name) : null)}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</Stack>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
//Контроль свойств - Сводный фильтр
|
|
||||||
P8PTableFiltersChips.propTypes = {
|
|
||||||
filters: PropTypes.array.isRequired,
|
|
||||||
columnsDef: PropTypes.array.isRequired,
|
|
||||||
valueFromCaption: PropTypes.string.isRequired,
|
|
||||||
valueToCaption: PropTypes.string.isRequired,
|
|
||||||
onFilterChipClick: PropTypes.func,
|
|
||||||
onFilterChipDelete: PropTypes.func,
|
|
||||||
valueFormatter: PropTypes.func
|
|
||||||
};
|
|
||||||
|
|
||||||
//-----------
|
//-----------
|
||||||
//Тело модуля
|
//Тело модуля
|
||||||
@ -530,6 +93,7 @@ const P8PTable = ({
|
|||||||
groupCellRender,
|
groupCellRender,
|
||||||
rowExpandRender,
|
rowExpandRender,
|
||||||
valueFormatter,
|
valueFormatter,
|
||||||
|
headExpandCellStyle,
|
||||||
onOrderChanged,
|
onOrderChanged,
|
||||||
onFilterChanged,
|
onFilterChanged,
|
||||||
onPagesCountChanged,
|
onPagesCountChanged,
|
||||||
@ -555,9 +119,6 @@ const P8PTable = ({
|
|||||||
//Собственное состояние - колонка с отображаемой подсказкой
|
//Собственное состояние - колонка с отображаемой подсказкой
|
||||||
const [displayHintColumn, setDisplayHintColumn] = useState(null);
|
const [displayHintColumn, setDisplayHintColumn] = useState(null);
|
||||||
|
|
||||||
//Стили
|
|
||||||
const theme = useTheme();
|
|
||||||
|
|
||||||
//Описание фильтруемой колонки
|
//Описание фильтруемой колонки
|
||||||
const filterColumnDef = filterColumn ? columnsDef.find(columnDef => columnDef.name == filterColumn) || null : null;
|
const filterColumnDef = filterColumn ? columnsDef.find(columnDef => columnDef.name == filterColumn) || null : null;
|
||||||
|
|
||||||
@ -597,8 +158,8 @@ const P8PTable = ({
|
|||||||
colOrder?.direction == P8P_TABLE_COLUMN_ORDER_DIRECTIONS.ASC
|
colOrder?.direction == P8P_TABLE_COLUMN_ORDER_DIRECTIONS.ASC
|
||||||
? P8P_TABLE_COLUMN_ORDER_DIRECTIONS.DESC
|
? P8P_TABLE_COLUMN_ORDER_DIRECTIONS.DESC
|
||||||
: colOrder?.direction == P8P_TABLE_COLUMN_ORDER_DIRECTIONS.DESC
|
: colOrder?.direction == P8P_TABLE_COLUMN_ORDER_DIRECTIONS.DESC
|
||||||
? null
|
? null
|
||||||
: P8P_TABLE_COLUMN_ORDER_DIRECTIONS.ASC;
|
: P8P_TABLE_COLUMN_ORDER_DIRECTIONS.ASC;
|
||||||
if (onOrderChanged) onOrderChanged({ columnName, direction: newDirection });
|
if (onOrderChanged) onOrderChanged({ columnName, direction: newDirection });
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -688,34 +249,33 @@ const P8PTable = ({
|
|||||||
const renderGroupCell = group => {
|
const renderGroupCell = group => {
|
||||||
let customRender = {};
|
let customRender = {};
|
||||||
if (groupCellRender) customRender = groupCellRender({ columnsDef: header.columnsDef, group }) || {};
|
if (groupCellRender) customRender = groupCellRender({ columnsDef: header.columnsDef, group }) || {};
|
||||||
return header.displayDataColumns.map((columnDef, i) => (
|
return header.displayDataColumns.map((columnDef, i) => {
|
||||||
<TableCell
|
return (
|
||||||
key={`group-header-cell-${i}`}
|
<TableCell
|
||||||
{...customRender.cellProps}
|
variant={P8P_TABLE_CELL_VARIANT.GROUP_HEADER}
|
||||||
sx={{
|
data-variant-props={{ width: columnDef.width, fixed: i == 0 && fixedColumns }}
|
||||||
...STYLES.TABLE_CELL_GROUP_HEADER,
|
key={`group-header-cell-${i}`}
|
||||||
...customRender.cellStyle,
|
{...customRender.cellProps}
|
||||||
...(columnDef.width ? { minWidth: columnDef.width, maxWidth: columnDef.width } : {}),
|
sx={{ ...customRender.cellStyle }}
|
||||||
...(i == 0 && fixedColumns ? STYLES.TABLE_CELL_GROUP_HEADER_STICKY : {})
|
colSpan={expandable && rowExpandRender ? 2 : 1}
|
||||||
}}
|
>
|
||||||
colSpan={expandable && rowExpandRender ? 2 : 1}
|
{i == 0 ? (
|
||||||
>
|
<Stack direction="row" alignItems="center">
|
||||||
{i == 0 ? (
|
{group.expandable ? (
|
||||||
<Stack direction="row" sx={STYLES.TABLE_COLUMN_STACK}>
|
<IconButton
|
||||||
{group.expandable ? (
|
onClick={() => {
|
||||||
<IconButton
|
setExpandedGroups(pv => ({ ...pv, ...{ [group.name]: !pv[group.name] } }));
|
||||||
onClick={() => {
|
}}
|
||||||
setExpandedGroups(pv => ({ ...pv, ...{ [group.name]: !pv[group.name] } }));
|
>
|
||||||
}}
|
<Icon>{expandedGroups[group.name] ? "indeterminate_check_box" : "add_box"}</Icon>
|
||||||
>
|
</IconButton>
|
||||||
<Icon>{expandedGroups[group.name] ? "indeterminate_check_box" : "add_box"}</Icon>
|
) : null}
|
||||||
</IconButton>
|
{customRender.data ? customRender.data : group.caption}
|
||||||
) : null}
|
</Stack>
|
||||||
{customRender.data ? customRender.data : group.caption}
|
) : null}
|
||||||
</Stack>
|
</TableCell>
|
||||||
) : null}
|
);
|
||||||
</TableCell>
|
});
|
||||||
));
|
|
||||||
};
|
};
|
||||||
|
|
||||||
//Генерация области страниц
|
//Генерация области страниц
|
||||||
@ -731,7 +291,8 @@ const P8PTable = ({
|
|||||||
<>
|
<>
|
||||||
{pagesCount && pagesCount > 0 && isVisible ? (
|
{pagesCount && pagesCount > 0 && isVisible ? (
|
||||||
<Pagination
|
<Pagination
|
||||||
sx={STYLES.PAGINATION(pagesAlign, position)}
|
variant={P8P_PAGINATION_VARIANT.TABLE_PAGINATION}
|
||||||
|
data-variant-props={{ pagesAlign, position }}
|
||||||
count={pagesCount}
|
count={pagesCount}
|
||||||
defaultPage={1}
|
defaultPage={1}
|
||||||
page={pageNumber}
|
page={pageNumber}
|
||||||
@ -777,18 +338,22 @@ const P8PTable = ({
|
|||||||
) : null}
|
) : null}
|
||||||
{renderPagination(P8P_TABLE_PAGINATOR_POSITION.TOP)}
|
{renderPagination(P8P_TABLE_PAGINATOR_POSITION.TOP)}
|
||||||
<TableContainer component={containerComponent ? containerComponent : Paper} {...(containerComponentProps ? containerComponentProps : {})}>
|
<TableContainer component={containerComponent ? containerComponent : Paper} {...(containerComponentProps ? containerComponentProps : {})}>
|
||||||
<Table stickyHeader={fixedHeader} sx={{ ...STYLES.TABLE, ...(tableStyle || {}) }} size={size || P8P_TABLE_SIZE.MEDIUM}>
|
<Table
|
||||||
<TableHead sx={fixedHeader ? STYLES.TABLE_HEAD_STICKY : {}}>
|
variant={P8P_TABLE_VARIANT.PRIMARY}
|
||||||
|
stickyHeader={fixedHeader}
|
||||||
|
sx={{ ...(tableStyle || {}) }}
|
||||||
|
size={size || P8P_TABLE_SIZE.MEDIUM}
|
||||||
|
>
|
||||||
|
<TableHead variant={fixedHeader ? P8P_TABLE_HEAD_VARIANT.STICKY : "primary"}>
|
||||||
{header.displayLevels.map((level, i) => (
|
{header.displayLevels.map((level, i) => (
|
||||||
<TableRow key={level}>
|
<TableRow key={level}>
|
||||||
{expandable && rowExpandRender && i == 0 ? (
|
{expandable && rowExpandRender && i == 0 ? (
|
||||||
<TableCell
|
<TableCell
|
||||||
|
variant={P8P_TABLE_CELL_VARIANT.HEADER_EXPAND}
|
||||||
|
data-variant-props={{ fixed: fixedColumns }}
|
||||||
key="head-cell-expand-control"
|
key="head-cell-expand-control"
|
||||||
align="center"
|
align="center"
|
||||||
sx={{
|
sx={{ ...headExpandCellStyle }}
|
||||||
...STYLES.TABLE_CELL_EXPAND_CONTROL,
|
|
||||||
...(fixedColumns ? STYLES.TABLE_HEAD_CELL_STICKY(theme, 0) : {})
|
|
||||||
}}
|
|
||||||
rowSpan={header.displayLevelsColumns[level][0].rowSpan}
|
rowSpan={header.displayLevelsColumns[level][0].rowSpan}
|
||||||
></TableCell>
|
></TableCell>
|
||||||
) : null}
|
) : null}
|
||||||
@ -797,11 +362,11 @@ const P8PTable = ({
|
|||||||
if (headCellRender) customRender = headCellRender({ columnDef }) || {};
|
if (headCellRender) customRender = headCellRender({ columnDef }) || {};
|
||||||
return (
|
return (
|
||||||
<TableCell
|
<TableCell
|
||||||
|
variant={P8P_TABLE_CELL_VARIANT.HEADER_CELL}
|
||||||
|
data-variant-props={{ width: columnDef.width, fixed: columnDef.fixed, left: columnDef.fixedLeft }}
|
||||||
key={`head-cell-${j}`}
|
key={`head-cell-${j}`}
|
||||||
align={getAlignByDataType(columnDef)}
|
align={getAlignByDataType(columnDef)}
|
||||||
sx={{
|
sx={{
|
||||||
...(columnDef.width ? { minWidth: columnDef.width, maxWidth: columnDef.width } : {}),
|
|
||||||
...(columnDef.fixed ? STYLES.TABLE_HEAD_CELL_STICKY(theme, columnDef.fixedLeft) : {}),
|
|
||||||
...customRender.cellStyle
|
...customRender.cellStyle
|
||||||
}}
|
}}
|
||||||
rowSpan={columnDef.rowSpan}
|
rowSpan={columnDef.rowSpan}
|
||||||
@ -811,7 +376,8 @@ const P8PTable = ({
|
|||||||
<Stack
|
<Stack
|
||||||
direction="row"
|
direction="row"
|
||||||
justifyContent={getJustifyContentByDataType(columnDef)}
|
justifyContent={getJustifyContentByDataType(columnDef)}
|
||||||
sx={{ ...STYLES.TABLE_COLUMN_STACK, ...customRender.stackStyle }}
|
alignItems="center"
|
||||||
|
sx={{ ...customRender.stackStyle }}
|
||||||
{...customRender.stackProps}
|
{...customRender.stackProps}
|
||||||
>
|
>
|
||||||
<P8PTableColumnToolBarLeft columnDef={columnDef} onItemClick={handleToolBarItemClick} />
|
<P8PTableColumnToolBarLeft columnDef={columnDef} onItemClick={handleToolBarItemClick} />
|
||||||
@ -820,7 +386,7 @@ const P8PTable = ({
|
|||||||
) : columnDef.hint ? (
|
) : columnDef.hint ? (
|
||||||
<Link
|
<Link
|
||||||
component="button"
|
component="button"
|
||||||
variant="body2"
|
variant={P8P_TYPOGRAPHY_VARIANT.COLUMN}
|
||||||
align="left"
|
align="left"
|
||||||
underline="always"
|
underline="always"
|
||||||
onClick={() => handleColumnShowHintClick(columnDef.name)}
|
onClick={() => handleColumnShowHintClick(columnDef.name)}
|
||||||
@ -856,15 +422,13 @@ const P8PTable = ({
|
|||||||
const rowsView = rows.map((row, i) =>
|
const rowsView = rows.map((row, i) =>
|
||||||
!group?.name || group?.name == row.groupName ? (
|
!group?.name || group?.name == row.groupName ? (
|
||||||
<React.Fragment key={`data-${i}`}>
|
<React.Fragment key={`data-${i}`}>
|
||||||
<TableRow key={`data-row-${i}`} sx={STYLES.TABLE_ROW}>
|
<TableRow key={`data-row-${i}`} variant={P8P_TABLE_ROW_VARIANT.PRIMARY}>
|
||||||
{expandable && rowExpandRender ? (
|
{expandable && rowExpandRender ? (
|
||||||
<TableCell
|
<TableCell
|
||||||
|
variant={P8P_TABLE_CELL_VARIANT.EXPAND}
|
||||||
|
data-variant-props={{ fixed: fixedColumns }}
|
||||||
key={`data-cell-expand-control-${i}`}
|
key={`data-cell-expand-control-${i}`}
|
||||||
align="center"
|
align="center"
|
||||||
sx={{
|
|
||||||
...STYLES.TABLE_CELL_EXPAND_CONTROL,
|
|
||||||
...(fixedColumns ? STYLES.TABLE_CELL_STICKY(theme, 0) : {})
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
<IconButton onClick={() => handleExpandClick(i)}>
|
<IconButton onClick={() => handleExpandClick(i)}>
|
||||||
<Icon>{expanded[i] === true ? "keyboard_arrow_down" : "keyboard_arrow_right"}</Icon>
|
<Icon>{expanded[i] === true ? "keyboard_arrow_down" : "keyboard_arrow_right"}</Icon>
|
||||||
@ -876,11 +440,15 @@ const P8PTable = ({
|
|||||||
if (dataCellRender) customRender = dataCellRender({ row, columnDef }) || {};
|
if (dataCellRender) customRender = dataCellRender({ row, columnDef }) || {};
|
||||||
return (
|
return (
|
||||||
<TableCell
|
<TableCell
|
||||||
|
variant={P8P_TABLE_CELL_VARIANT.CELL}
|
||||||
|
data-variant-props={{
|
||||||
|
width: columnDef.width,
|
||||||
|
fixed: columnDef.fixed,
|
||||||
|
left: columnDef.fixedLeft
|
||||||
|
}}
|
||||||
key={`data-cell-${j}`}
|
key={`data-cell-${j}`}
|
||||||
align={getAlignByDataType(columnDef)}
|
align={getAlignByDataType(columnDef)}
|
||||||
sx={{
|
sx={{
|
||||||
...(columnDef.width ? { minWidth: columnDef.width, maxWidth: columnDef.width } : {}),
|
|
||||||
...(columnDef.fixed ? STYLES.TABLE_CELL_STICKY(theme, columnDef.fixedLeft) : {}),
|
|
||||||
...customRender.cellStyle
|
...customRender.cellStyle
|
||||||
}}
|
}}
|
||||||
{...customRender.cellProps}
|
{...customRender.cellProps}
|
||||||
@ -888,8 +456,8 @@ const P8PTable = ({
|
|||||||
{customRender.data
|
{customRender.data
|
||||||
? customRender.data
|
? customRender.data
|
||||||
: valueFormatter
|
: valueFormatter
|
||||||
? valueFormatter({ value: row[columnDef.name], columnDef })
|
? valueFormatter({ value: row[columnDef.name], columnDef })
|
||||||
: row[columnDef.name]}
|
: row[columnDef.name]}
|
||||||
</TableCell>
|
</TableCell>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
@ -897,10 +465,8 @@ const P8PTable = ({
|
|||||||
{expandable && rowExpandRender && expanded[i] === true ? (
|
{expandable && rowExpandRender && expanded[i] === true ? (
|
||||||
<TableRow key={`data-row-expand-${i}`}>
|
<TableRow key={`data-row-expand-${i}`}>
|
||||||
<TableCell
|
<TableCell
|
||||||
sx={{
|
variant={P8P_TABLE_CELL_VARIANT.EXPAND_CONTAINER}
|
||||||
...STYLES.TABLE_CELL_EXPAND_CONTAINER,
|
data-variant-props={{ fixed: fixedColumns }}
|
||||||
...(fixedColumns ? STYLES.TABLE_CELL_STICKY(theme, 0) : {})
|
|
||||||
}}
|
|
||||||
colSpan={fixedColumns ? header.displayFixedColumnsCount + 1 : header.displayDataColumnsCount}
|
colSpan={fixedColumns ? header.displayFixedColumnsCount + 1 : header.displayDataColumnsCount}
|
||||||
>
|
>
|
||||||
{rowExpandRender({ columnsDef, row })}
|
{rowExpandRender({ columnsDef, row })}
|
||||||
@ -931,7 +497,7 @@ const P8PTable = ({
|
|||||||
</TableContainer>
|
</TableContainer>
|
||||||
{renderPagination(P8P_TABLE_PAGINATOR_POSITION.BOTTOM)}
|
{renderPagination(P8P_TABLE_PAGINATOR_POSITION.BOTTOM)}
|
||||||
{morePages && (!pagesCount || pagesCount <= 0) ? (
|
{morePages && (!pagesCount || pagesCount <= 0) ? (
|
||||||
<Container style={STYLES.MORE_BUTTON_CONTAINER}>
|
<Container variant={P8P_CONTAINER_VARIANT.TABLE_MORE_BUTTON}>
|
||||||
<Button fullWidth onClick={handleMorePagesBtnClick} {...(morePagesBtnProps ? morePagesBtnProps : {})}>
|
<Button fullWidth onClick={handleMorePagesBtnClick} {...(morePagesBtnProps ? morePagesBtnProps : {})}>
|
||||||
{morePagesBtnCaption}
|
{morePagesBtnCaption}
|
||||||
</Button>
|
</Button>
|
||||||
@ -998,6 +564,7 @@ P8PTable.propTypes = {
|
|||||||
groupCellRender: PropTypes.func,
|
groupCellRender: PropTypes.func,
|
||||||
rowExpandRender: PropTypes.func,
|
rowExpandRender: PropTypes.func,
|
||||||
valueFormatter: PropTypes.func,
|
valueFormatter: PropTypes.func,
|
||||||
|
headExpandCellStyle: PropTypes.object,
|
||||||
onOrderChanged: PropTypes.func,
|
onOrderChanged: PropTypes.func,
|
||||||
onFilterChanged: PropTypes.func,
|
onFilterChanged: PropTypes.func,
|
||||||
onPagesCountChanged: PropTypes.func,
|
onPagesCountChanged: PropTypes.func,
|
||||||
@ -1015,7 +582,7 @@ export {
|
|||||||
P8P_TABLE_DATA_TYPE,
|
P8P_TABLE_DATA_TYPE,
|
||||||
P8P_TABLE_SIZE,
|
P8P_TABLE_SIZE,
|
||||||
P8P_TABLE_FILTER_SHAPE,
|
P8P_TABLE_FILTER_SHAPE,
|
||||||
P8P_TABLE_ORDER_SHAPE,
|
P8P_TABLE_ORDER_SHAPE,
|
||||||
P8P_TABLE_MORE_HEIGHT,
|
P8P_TABLE_MORE_HEIGHT,
|
||||||
P8P_TABLE_FILTERS_HEIGHT,
|
P8P_TABLE_FILTERS_HEIGHT,
|
||||||
P8P_TABLE_PAGINATOR_ALIGN,
|
P8P_TABLE_PAGINATOR_ALIGN,
|
||||||
164
app/components/p8p_table/p8p_table_column_filter_dialog.js
Normal file
164
app/components/p8p_table/p8p_table_column_filter_dialog.js
Normal file
@ -0,0 +1,164 @@
|
|||||||
|
/*
|
||||||
|
Парус 8 - Панели мониторинга - Таблица
|
||||||
|
Компонент: Диалог фильтра
|
||||||
|
*/
|
||||||
|
|
||||||
|
//---------------------
|
||||||
|
//Подключение библиотек
|
||||||
|
//---------------------
|
||||||
|
|
||||||
|
import React, { useState } from "react"; //Классы React
|
||||||
|
import PropTypes from "prop-types"; //Контроль свойств компонента
|
||||||
|
import { MenuItem, Dialog, DialogTitle, DialogContent, DialogActions, Button, TextField, Typography } from "@mui/material"; //Интерфейсные компоненты
|
||||||
|
import { P8P_TABLE_DATA_TYPE } from "./p8p_table_constants"; //Типы данных
|
||||||
|
import { P8P_TEXT_FIELD_VARIANT } from "../../theme/variants/p8p_text_field_variants"; //Варианты полей ввода
|
||||||
|
import { P8P_TYPOGRAPHY_VARIANT } from "../../theme/p8p_typography"; //Варианты шрифтов
|
||||||
|
import { P8P_BUTTON_VARIANT } from "../../theme/variants/p8p_button_variants"; //Варианты кнопок
|
||||||
|
import { P8P_MENU_ITEM_VARIANT } from "../../theme/variants/p8p_menu_item_variants"; //Варианты элементов меню
|
||||||
|
|
||||||
|
//-----------
|
||||||
|
//Тело модуля
|
||||||
|
//-----------
|
||||||
|
|
||||||
|
//Диалог фильтра
|
||||||
|
const P8PTableColumnFilterDialog = ({
|
||||||
|
columnDef,
|
||||||
|
from,
|
||||||
|
to,
|
||||||
|
valueCaption,
|
||||||
|
valueFromCaption,
|
||||||
|
valueToCaption,
|
||||||
|
okBtnCaption,
|
||||||
|
clearBtnCaption,
|
||||||
|
cancelBtnCaption,
|
||||||
|
valueFormatter,
|
||||||
|
onOk,
|
||||||
|
onClear,
|
||||||
|
onCancel
|
||||||
|
}) => {
|
||||||
|
//Собственное состояние - значения с-по
|
||||||
|
const [filterValues, setFilterValues] = useState({ from, to });
|
||||||
|
|
||||||
|
//Отработка воода значения в фильтр
|
||||||
|
const handleFilterTextFieldChanged = e => {
|
||||||
|
setFilterValues(prev => ({ ...prev, [e.target.name]: e.target.value }));
|
||||||
|
};
|
||||||
|
|
||||||
|
//Элементы ввода значений фильтра
|
||||||
|
let inputs = null;
|
||||||
|
if (Array.isArray(columnDef.values) && columnDef.values.length > 0) {
|
||||||
|
inputs = (
|
||||||
|
<TextField
|
||||||
|
name="from"
|
||||||
|
fullWidth
|
||||||
|
select
|
||||||
|
label={valueCaption}
|
||||||
|
variant="standard"
|
||||||
|
data-variant={P8P_TEXT_FIELD_VARIANT.PRIMARY}
|
||||||
|
value={filterValues.from}
|
||||||
|
onChange={handleFilterTextFieldChanged}
|
||||||
|
>
|
||||||
|
{columnDef.values.map((v, i) => (
|
||||||
|
<MenuItem key={i} value={v} variant={P8P_MENU_ITEM_VARIANT.PRIMARY}>
|
||||||
|
{valueFormatter ? valueFormatter({ value: v, columnDef }) : v}
|
||||||
|
</MenuItem>
|
||||||
|
))}
|
||||||
|
</TextField>
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
switch (columnDef.dataType) {
|
||||||
|
case P8P_TABLE_DATA_TYPE.STR: {
|
||||||
|
inputs = (
|
||||||
|
<TextField
|
||||||
|
name="from"
|
||||||
|
fullWidth
|
||||||
|
InputLabelProps={{ shrink: true }}
|
||||||
|
value={filterValues.from}
|
||||||
|
onChange={handleFilterTextFieldChanged}
|
||||||
|
label={valueCaption}
|
||||||
|
variant="standard"
|
||||||
|
data-variant={P8P_TEXT_FIELD_VARIANT.PRIMARY}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case P8P_TABLE_DATA_TYPE.NUMB:
|
||||||
|
case P8P_TABLE_DATA_TYPE.DATE: {
|
||||||
|
inputs = (
|
||||||
|
<>
|
||||||
|
<TextField
|
||||||
|
name="from"
|
||||||
|
InputLabelProps={{ shrink: true }}
|
||||||
|
type={columnDef.dataType == P8P_TABLE_DATA_TYPE.NUMB ? "number" : "date"}
|
||||||
|
value={filterValues.from}
|
||||||
|
onChange={handleFilterTextFieldChanged}
|
||||||
|
label={valueFromCaption}
|
||||||
|
variant="standard"
|
||||||
|
data-variant={P8P_TEXT_FIELD_VARIANT.PRIMARY}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<TextField
|
||||||
|
name="to"
|
||||||
|
InputLabelProps={{ shrink: true }}
|
||||||
|
type={columnDef.dataType == P8P_TABLE_DATA_TYPE.NUMB ? "number" : "date"}
|
||||||
|
value={filterValues.to}
|
||||||
|
onChange={handleFilterTextFieldChanged}
|
||||||
|
label={valueToCaption}
|
||||||
|
variant="standard"
|
||||||
|
data-variant={P8P_TEXT_FIELD_VARIANT.PRIMARY}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Dialog
|
||||||
|
open={true}
|
||||||
|
aria-labelledby="filter-dialog-title"
|
||||||
|
aria-describedby="filter-dialog-description"
|
||||||
|
onClose={() => (onCancel ? onCancel(columnDef.name) : null)}
|
||||||
|
>
|
||||||
|
<DialogTitle id="filter-dialog-title">
|
||||||
|
<Typography variant={P8P_TYPOGRAPHY_VARIANT.H6}>{columnDef.caption}</Typography>
|
||||||
|
</DialogTitle>
|
||||||
|
<DialogContent>{inputs}</DialogContent>
|
||||||
|
<DialogActions>
|
||||||
|
<Button variant={P8P_BUTTON_VARIANT.OUTLINED} onClick={() => (onClear ? onClear(columnDef.name) : null)}>
|
||||||
|
{clearBtnCaption}
|
||||||
|
</Button>
|
||||||
|
<Button variant={P8P_BUTTON_VARIANT.SECONDARY} onClick={() => (onCancel ? onCancel(columnDef.name) : null)}>
|
||||||
|
{cancelBtnCaption}
|
||||||
|
</Button>
|
||||||
|
<Button variant={P8P_BUTTON_VARIANT.PRIMARY} onClick={() => (onOk ? onOk(columnDef.name, filterValues.from, filterValues.to) : null)}>
|
||||||
|
{okBtnCaption}
|
||||||
|
</Button>
|
||||||
|
</DialogActions>
|
||||||
|
</Dialog>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
//Контроль свойств - Диалог фильтра
|
||||||
|
P8PTableColumnFilterDialog.propTypes = {
|
||||||
|
columnDef: PropTypes.object.isRequired,
|
||||||
|
from: PropTypes.any,
|
||||||
|
to: PropTypes.any,
|
||||||
|
valueCaption: PropTypes.string.isRequired,
|
||||||
|
valueFromCaption: PropTypes.string.isRequired,
|
||||||
|
valueToCaption: PropTypes.string.isRequired,
|
||||||
|
okBtnCaption: PropTypes.string.isRequired,
|
||||||
|
clearBtnCaption: PropTypes.string.isRequired,
|
||||||
|
cancelBtnCaption: PropTypes.string.isRequired,
|
||||||
|
valueFormatter: PropTypes.func,
|
||||||
|
onOk: PropTypes.func,
|
||||||
|
onClear: PropTypes.func,
|
||||||
|
onCancel: PropTypes.func
|
||||||
|
};
|
||||||
|
|
||||||
|
//----------------
|
||||||
|
//Интерфейс модуля
|
||||||
|
//----------------
|
||||||
|
|
||||||
|
export { P8PTableColumnFilterDialog };
|
||||||
106
app/components/p8p_table/p8p_table_column_menu.js
Normal file
106
app/components/p8p_table/p8p_table_column_menu.js
Normal file
@ -0,0 +1,106 @@
|
|||||||
|
/*
|
||||||
|
Парус 8 - Панели мониторинга - Таблица
|
||||||
|
Компонент: Меню столбца
|
||||||
|
*/
|
||||||
|
|
||||||
|
//---------------------
|
||||||
|
//Подключение библиотек
|
||||||
|
//---------------------
|
||||||
|
|
||||||
|
import React, { useState } from "react"; //Классы React
|
||||||
|
import PropTypes from "prop-types"; //Контроль свойств компонента
|
||||||
|
import { IconButton, Icon, Menu, MenuItem, Divider, Typography } from "@mui/material"; //Интерфейсные компоненты
|
||||||
|
import { P8P_TABLE_COLUMN_MENU_ACTIONS } from "./p8p_table_constants"; //Действия меню столбца
|
||||||
|
import { P8P_TYPOGRAPHY_VARIANT } from "../../theme/p8p_typography"; //Варианты шрифтов
|
||||||
|
import { P8P_ICON_VARIANT } from "../../theme/variants/p8p_icon_variants"; //Варианты иконок
|
||||||
|
|
||||||
|
//-----------
|
||||||
|
//Тело модуля
|
||||||
|
//-----------
|
||||||
|
|
||||||
|
//Меню столбца
|
||||||
|
const P8PTableColumnMenu = ({ columnDef, orderAscItemCaption, orderDescItemCaption, filterItemCaption, onItemClick }) => {
|
||||||
|
//Собственное состояние
|
||||||
|
const [anchorEl, setAnchorEl] = useState(null);
|
||||||
|
|
||||||
|
//Флаг отображения
|
||||||
|
const open = Boolean(anchorEl);
|
||||||
|
|
||||||
|
//По нажатию на открытие меню
|
||||||
|
const handleMenuButtonClick = event => {
|
||||||
|
setAnchorEl(event.currentTarget);
|
||||||
|
};
|
||||||
|
|
||||||
|
//По нажатию на пункт меню
|
||||||
|
const handleMenuItemClick = (event, index, action, columnName) => {
|
||||||
|
if (onItemClick) onItemClick(action, columnName);
|
||||||
|
setAnchorEl(null);
|
||||||
|
};
|
||||||
|
|
||||||
|
//При закрытии меню
|
||||||
|
const handleMenuClose = () => {
|
||||||
|
setAnchorEl(null);
|
||||||
|
};
|
||||||
|
|
||||||
|
//Формирование списка элементов меню в зависимости от описания колонки таблицы
|
||||||
|
const menuItems = [];
|
||||||
|
if (columnDef.order === true) {
|
||||||
|
menuItems.push(
|
||||||
|
<MenuItem
|
||||||
|
key={"orderAsc"}
|
||||||
|
onClick={(event, index) => handleMenuItemClick(event, index, P8P_TABLE_COLUMN_MENU_ACTIONS.ORDER_ASC, columnDef.name)}
|
||||||
|
>
|
||||||
|
<Icon variant={P8P_ICON_VARIANT.TABLE_COLUMN_MENU}>arrow_upward</Icon>
|
||||||
|
<Typography variant={P8P_TYPOGRAPHY_VARIANT.BODY1}>{orderAscItemCaption}</Typography>
|
||||||
|
</MenuItem>
|
||||||
|
);
|
||||||
|
menuItems.push(
|
||||||
|
<MenuItem
|
||||||
|
key={"orderDesc"}
|
||||||
|
onClick={(event, index) => handleMenuItemClick(event, index, P8P_TABLE_COLUMN_MENU_ACTIONS.ORDER_DESC, columnDef.name)}
|
||||||
|
>
|
||||||
|
<Icon variant={P8P_ICON_VARIANT.TABLE_COLUMN_MENU}>arrow_downward</Icon>
|
||||||
|
<Typography variant={P8P_TYPOGRAPHY_VARIANT.BODY1}>{orderDescItemCaption}</Typography>
|
||||||
|
</MenuItem>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (columnDef.filter === true) {
|
||||||
|
if (menuItems.length > 0) menuItems.push(<Divider key={"divider"} sx={{ my: 0.5 }} />);
|
||||||
|
menuItems.push(
|
||||||
|
<MenuItem
|
||||||
|
key={"filter"}
|
||||||
|
onClick={(event, index) => handleMenuItemClick(event, index, P8P_TABLE_COLUMN_MENU_ACTIONS.FILTER, columnDef.name)}
|
||||||
|
>
|
||||||
|
<Icon variant={P8P_ICON_VARIANT.TABLE_COLUMN_MENU}>filter_alt</Icon>
|
||||||
|
<Typography variant={P8P_TYPOGRAPHY_VARIANT.BODY1}>{filterItemCaption}</Typography>
|
||||||
|
</MenuItem>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Генерация содержимого
|
||||||
|
return menuItems.length > 0 ? (
|
||||||
|
<>
|
||||||
|
<IconButton id={`${columnDef.name}_menu_button`} aria-haspopup="true" onClick={handleMenuButtonClick}>
|
||||||
|
<Icon>more_vert</Icon>
|
||||||
|
</IconButton>
|
||||||
|
<Menu id={`${columnDef.name}_menu`} anchorEl={anchorEl} open={open} onClose={handleMenuClose}>
|
||||||
|
{menuItems}
|
||||||
|
</Menu>
|
||||||
|
</>
|
||||||
|
) : null;
|
||||||
|
};
|
||||||
|
|
||||||
|
//Контроль свойств - Меню столбца
|
||||||
|
P8PTableColumnMenu.propTypes = {
|
||||||
|
columnDef: PropTypes.object.isRequired,
|
||||||
|
orderAscItemCaption: PropTypes.string.isRequired,
|
||||||
|
orderDescItemCaption: PropTypes.string.isRequired,
|
||||||
|
filterItemCaption: PropTypes.string.isRequired,
|
||||||
|
onItemClick: PropTypes.func
|
||||||
|
};
|
||||||
|
|
||||||
|
//----------------
|
||||||
|
//Интерфейс модуля
|
||||||
|
//----------------
|
||||||
|
|
||||||
|
export { P8PTableColumnMenu };
|
||||||
44
app/components/p8p_table/p8p_table_column_toolbar_left.js
Normal file
44
app/components/p8p_table/p8p_table_column_toolbar_left.js
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
/*
|
||||||
|
Парус 8 - Панели мониторинга - Таблица
|
||||||
|
Компонент: Панель инструментов столбца (левая)
|
||||||
|
*/
|
||||||
|
|
||||||
|
//---------------------
|
||||||
|
//Подключение библиотек
|
||||||
|
//---------------------
|
||||||
|
|
||||||
|
import React from "react"; //Классы React
|
||||||
|
import PropTypes from "prop-types"; //Контроль свойств компонента
|
||||||
|
import { IconButton, Icon } from "@mui/material"; //Интерфейсные компоненты
|
||||||
|
import { P8P_TABLE_COLUMN_TOOL_BAR_ACTIONS } from "./p8p_table_constants"; //Действия панели инструментов столбца
|
||||||
|
|
||||||
|
//-----------
|
||||||
|
//Тело модуля
|
||||||
|
//-----------
|
||||||
|
|
||||||
|
//Панель инструментов столбца (левая)
|
||||||
|
const P8PTableColumnToolBarLeft = ({ columnDef, onItemClick }) => {
|
||||||
|
//Кнопка развёртывания/свёртывания
|
||||||
|
let expButton = null;
|
||||||
|
if (columnDef.expandable)
|
||||||
|
expButton = (
|
||||||
|
<IconButton onClick={() => (onItemClick ? onItemClick(P8P_TABLE_COLUMN_TOOL_BAR_ACTIONS.EXPAND_TOGGLE, columnDef.name) : null)}>
|
||||||
|
<Icon>{columnDef.expanded ? "indeterminate_check_box" : "add_box"}</Icon>
|
||||||
|
</IconButton>
|
||||||
|
);
|
||||||
|
|
||||||
|
//Генерация содержимого
|
||||||
|
return <>{expButton}</>;
|
||||||
|
};
|
||||||
|
|
||||||
|
//Контроль свойств - Панель инструментов столбца (левая)
|
||||||
|
P8PTableColumnToolBarLeft.propTypes = {
|
||||||
|
columnDef: PropTypes.object.isRequired,
|
||||||
|
onItemClick: PropTypes.func
|
||||||
|
};
|
||||||
|
|
||||||
|
//----------------
|
||||||
|
//Интерфейс модуля
|
||||||
|
//----------------
|
||||||
|
|
||||||
|
export { P8PTableColumnToolBarLeft };
|
||||||
63
app/components/p8p_table/p8p_table_column_toolbar_right.js
Normal file
63
app/components/p8p_table/p8p_table_column_toolbar_right.js
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
/*
|
||||||
|
Парус 8 - Панели мониторинга - Таблица
|
||||||
|
Компонент: Панель инструментов столбца (правая)
|
||||||
|
*/
|
||||||
|
|
||||||
|
//---------------------
|
||||||
|
//Подключение библиотек
|
||||||
|
//---------------------
|
||||||
|
|
||||||
|
import React from "react"; //Классы React
|
||||||
|
import PropTypes from "prop-types"; //Контроль свойств компонента
|
||||||
|
import { IconButton, Icon } from "@mui/material"; //Интерфейсные компоненты
|
||||||
|
import { hasValue } from "./p8p_table_reducer"; //Редьюсер состояния
|
||||||
|
import { P8P_TABLE_COLUMN_ORDER_DIRECTIONS, P8P_TABLE_COLUMN_TOOL_BAR_ACTIONS } from "./p8p_table_constants"; //Константы таблицы
|
||||||
|
|
||||||
|
//-----------
|
||||||
|
//Тело модуля
|
||||||
|
//-----------
|
||||||
|
|
||||||
|
//Панель инструментов столбца (правая)
|
||||||
|
const P8PTableColumnToolBarRight = ({ columnDef, orders, filters, onItemClick }) => {
|
||||||
|
//Кнопка сортировки
|
||||||
|
const order = orders.find(o => o.name == columnDef.name);
|
||||||
|
let orderButton = null;
|
||||||
|
if (order)
|
||||||
|
orderButton = (
|
||||||
|
<IconButton onClick={() => (onItemClick ? onItemClick(P8P_TABLE_COLUMN_TOOL_BAR_ACTIONS.ORDER_TOGGLE, columnDef.name) : null)}>
|
||||||
|
<Icon>{order.direction === P8P_TABLE_COLUMN_ORDER_DIRECTIONS.ASC ? "arrow_upward" : "arrow_downward"}</Icon>
|
||||||
|
</IconButton>
|
||||||
|
);
|
||||||
|
|
||||||
|
//Кнопка фильтрации
|
||||||
|
const filter = filters.find(f => f.name == columnDef.name);
|
||||||
|
let filterButton = null;
|
||||||
|
if (hasValue(filter?.from) || hasValue(filter?.to))
|
||||||
|
filterButton = (
|
||||||
|
<IconButton onClick={() => (onItemClick ? onItemClick(P8P_TABLE_COLUMN_TOOL_BAR_ACTIONS.FILTER_TOGGLE, columnDef.name) : null)}>
|
||||||
|
<Icon>filter_alt</Icon>
|
||||||
|
</IconButton>
|
||||||
|
);
|
||||||
|
|
||||||
|
//Генерация содержимого
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{orderButton}
|
||||||
|
{filterButton}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
//Контроль свойств - Панель инструментов столбца (правая)
|
||||||
|
P8PTableColumnToolBarRight.propTypes = {
|
||||||
|
columnDef: PropTypes.object.isRequired,
|
||||||
|
orders: PropTypes.array.isRequired,
|
||||||
|
filters: PropTypes.array.isRequired,
|
||||||
|
onItemClick: PropTypes.func
|
||||||
|
};
|
||||||
|
|
||||||
|
//----------------
|
||||||
|
//Интерфейс модуля
|
||||||
|
//----------------
|
||||||
|
|
||||||
|
export { P8PTableColumnToolBarRight };
|
||||||
99
app/components/p8p_table/p8p_table_constants.js
Normal file
99
app/components/p8p_table/p8p_table_constants.js
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
/*
|
||||||
|
Парус 8 - Панели мониторинга - Таблица
|
||||||
|
Компонент: Константы
|
||||||
|
*/
|
||||||
|
|
||||||
|
//---------------------
|
||||||
|
//Подключение библиотек
|
||||||
|
//---------------------
|
||||||
|
|
||||||
|
import PropTypes from "prop-types"; //Контроль свойств компонента
|
||||||
|
import { P8P_DATA_TYPES } from "../../core/data_types"; //Типы данных
|
||||||
|
|
||||||
|
//-----------
|
||||||
|
//Тело модуля
|
||||||
|
//-----------
|
||||||
|
|
||||||
|
//Размеры отступов
|
||||||
|
const P8P_TABLE_SIZE = {
|
||||||
|
SMALL: "small",
|
||||||
|
MEDIUM: "medium"
|
||||||
|
};
|
||||||
|
|
||||||
|
//Типы данных
|
||||||
|
const P8P_TABLE_DATA_TYPE = {
|
||||||
|
STR: P8P_DATA_TYPES.STR,
|
||||||
|
NUMB: P8P_DATA_TYPES.NUMB,
|
||||||
|
DATE: P8P_DATA_TYPES.DATE
|
||||||
|
};
|
||||||
|
|
||||||
|
//Направления сортировки
|
||||||
|
const P8P_TABLE_COLUMN_ORDER_DIRECTIONS = {
|
||||||
|
ASC: "ASC",
|
||||||
|
DESC: "DESC"
|
||||||
|
};
|
||||||
|
|
||||||
|
//Действия панели инструментов столбца
|
||||||
|
const P8P_TABLE_COLUMN_TOOL_BAR_ACTIONS = {
|
||||||
|
ORDER_TOGGLE: "ORDER_TOGGLE",
|
||||||
|
FILTER_TOGGLE: "FILTER_TOGGLE",
|
||||||
|
EXPAND_TOGGLE: "EXPAND_TOGGLE"
|
||||||
|
};
|
||||||
|
|
||||||
|
//Действия меню столбца
|
||||||
|
const P8P_TABLE_COLUMN_MENU_ACTIONS = {
|
||||||
|
ORDER_ASC: "ORDER_ASC",
|
||||||
|
ORDER_DESC: "ORDER_DESC",
|
||||||
|
FILTER: "FILTER"
|
||||||
|
};
|
||||||
|
|
||||||
|
//Структура элемента описания фильтра
|
||||||
|
const P8P_TABLE_FILTER_SHAPE = PropTypes.shape({
|
||||||
|
name: PropTypes.string.isRequired,
|
||||||
|
from: PropTypes.any,
|
||||||
|
to: PropTypes.any
|
||||||
|
});
|
||||||
|
|
||||||
|
//Структура элемента описания сортировки
|
||||||
|
const P8P_TABLE_ORDER_SHAPE = PropTypes.shape({
|
||||||
|
direction: PropTypes.string.isRequired,
|
||||||
|
name: PropTypes.string.isRequired
|
||||||
|
});
|
||||||
|
|
||||||
|
//Размещение области страниц по вертикали
|
||||||
|
const P8P_TABLE_PAGINATOR_ALIGN = {
|
||||||
|
LEFT: "left",
|
||||||
|
RIGHT: "right",
|
||||||
|
CENTER: "center"
|
||||||
|
};
|
||||||
|
|
||||||
|
//Размещение области страниц по горизонтали
|
||||||
|
const P8P_TABLE_PAGINATOR_POSITION = {
|
||||||
|
TOP: "top",
|
||||||
|
BOTTOM: "bottom",
|
||||||
|
BOTH: "both"
|
||||||
|
};
|
||||||
|
|
||||||
|
//Высота кнопки догрузки данных
|
||||||
|
const P8P_TABLE_MORE_HEIGHT = "49px";
|
||||||
|
|
||||||
|
//Высота фильтров таблицы
|
||||||
|
const P8P_TABLE_FILTERS_HEIGHT = "48px";
|
||||||
|
|
||||||
|
//----------------
|
||||||
|
//Интерфейс модуля
|
||||||
|
//----------------
|
||||||
|
|
||||||
|
export {
|
||||||
|
P8P_TABLE_SIZE,
|
||||||
|
P8P_TABLE_DATA_TYPE,
|
||||||
|
P8P_TABLE_COLUMN_ORDER_DIRECTIONS,
|
||||||
|
P8P_TABLE_COLUMN_TOOL_BAR_ACTIONS,
|
||||||
|
P8P_TABLE_COLUMN_MENU_ACTIONS,
|
||||||
|
P8P_TABLE_FILTER_SHAPE,
|
||||||
|
P8P_TABLE_ORDER_SHAPE,
|
||||||
|
P8P_TABLE_PAGINATOR_ALIGN,
|
||||||
|
P8P_TABLE_PAGINATOR_POSITION,
|
||||||
|
P8P_TABLE_MORE_HEIGHT,
|
||||||
|
P8P_TABLE_FILTERS_HEIGHT
|
||||||
|
};
|
||||||
74
app/components/p8p_table/p8p_table_filters_chips.js
Normal file
74
app/components/p8p_table/p8p_table_filters_chips.js
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
/*
|
||||||
|
Парус 8 - Панели мониторинга - Таблица
|
||||||
|
Компонент: Сводный фильтр
|
||||||
|
*/
|
||||||
|
|
||||||
|
//---------------------
|
||||||
|
//Подключение библиотек
|
||||||
|
//---------------------
|
||||||
|
|
||||||
|
import React from "react"; //Классы React
|
||||||
|
import PropTypes from "prop-types"; //Контроль свойств компонента
|
||||||
|
import { Stack, Chip, Typography } from "@mui/material"; //Интерфейсные компоненты
|
||||||
|
import { hasValue } from "./p8p_table_reducer"; //Редьюсер состояния
|
||||||
|
import { P8P_TABLE_DATA_TYPE } from "./p8p_table_constants"; //Типы данных
|
||||||
|
import { P8P_TYPOGRAPHY_VARIANT } from "../../theme/p8p_typography"; //Варианты шрифтов
|
||||||
|
|
||||||
|
//-----------
|
||||||
|
//Тело модуля
|
||||||
|
//-----------
|
||||||
|
|
||||||
|
//Сводный фильтр
|
||||||
|
const P8PTableFiltersChips = ({ filters, columnsDef, valueFromCaption, valueToCaption, onFilterChipClick, onFilterChipDelete, valueFormatter }) => {
|
||||||
|
return (
|
||||||
|
<Stack direction="row" spacing={1} p={1}>
|
||||||
|
{filters.map((filter, i) => {
|
||||||
|
const columnDef = columnsDef.find(columnDef => columnDef.name == filter.name);
|
||||||
|
return (
|
||||||
|
<Chip
|
||||||
|
key={i}
|
||||||
|
label={
|
||||||
|
<Stack direction="row" alignItems="center">
|
||||||
|
<Typography variant={P8P_TYPOGRAPHY_VARIANT.BODY2_BOLD}>{columnDef.caption}: </Typography>
|
||||||
|
<Typography variant={P8P_TYPOGRAPHY_VARIANT.BODY2}>
|
||||||
|
{hasValue(filter.from) && !columnDef.values && columnDef.dataType != P8P_TABLE_DATA_TYPE.STR
|
||||||
|
? `${valueFromCaption.toLowerCase()} `
|
||||||
|
: null}
|
||||||
|
{hasValue(filter.from)
|
||||||
|
? valueFormatter
|
||||||
|
? valueFormatter({ value: filter.from, columnDef })
|
||||||
|
: filter.from
|
||||||
|
: null}
|
||||||
|
{hasValue(filter.to) && !columnDef.values && columnDef.dataType != P8P_TABLE_DATA_TYPE.STR
|
||||||
|
? ` ${valueToCaption.toLowerCase()} `
|
||||||
|
: null}
|
||||||
|
{hasValue(filter.to) ? (valueFormatter ? valueFormatter({ value: filter.to, columnDef }) : filter.to) : null}
|
||||||
|
</Typography>
|
||||||
|
</Stack>
|
||||||
|
}
|
||||||
|
variant="outlined"
|
||||||
|
onClick={() => (onFilterChipClick ? onFilterChipClick(columnDef.name) : null)}
|
||||||
|
onDelete={() => (onFilterChipDelete ? onFilterChipDelete(columnDef.name) : null)}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</Stack>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
//Контроль свойств - Сводный фильтр
|
||||||
|
P8PTableFiltersChips.propTypes = {
|
||||||
|
filters: PropTypes.array.isRequired,
|
||||||
|
columnsDef: PropTypes.array.isRequired,
|
||||||
|
valueFromCaption: PropTypes.string.isRequired,
|
||||||
|
valueToCaption: PropTypes.string.isRequired,
|
||||||
|
onFilterChipClick: PropTypes.func,
|
||||||
|
onFilterChipDelete: PropTypes.func,
|
||||||
|
valueFormatter: PropTypes.func
|
||||||
|
};
|
||||||
|
|
||||||
|
//----------------
|
||||||
|
//Интерфейс модуля
|
||||||
|
//----------------
|
||||||
|
|
||||||
|
export { P8PTableFiltersChips };
|
||||||
@ -12,7 +12,7 @@ import { deepCopyObject } from "./core/utils"; //Вспомогательные
|
|||||||
import { TITLES, BUTTONS, TEXTS, CAPTIONS } from "../app.text"; //Текстовые ресурсы и константы
|
import { TITLES, BUTTONS, TEXTS, CAPTIONS } from "../app.text"; //Текстовые ресурсы и константы
|
||||||
import { P8PPanelsMenuGrid, P8P_PANELS_MENU_PANEL_SHAPE } from "./components/p8p_panels_menu"; //Меню панелей
|
import { P8PPanelsMenuGrid, P8P_PANELS_MENU_PANEL_SHAPE } from "./components/p8p_panels_menu"; //Меню панелей
|
||||||
import { P8PAppWorkspace } from "./components/p8p_app_workspace"; //Рабочее пространство
|
import { P8PAppWorkspace } from "./components/p8p_app_workspace"; //Рабочее пространство
|
||||||
import { P8PTable, P8P_TABLE_DATA_TYPE, P8P_TABLE_SIZE, P8P_TABLE_FILTER_SHAPE } from "./components/p8p_table"; //Таблица данных
|
import { P8PTable, P8P_TABLE_DATA_TYPE, P8P_TABLE_SIZE, P8P_TABLE_FILTER_SHAPE } from "./components/p8p_table/p8p_table"; //Таблица данных
|
||||||
import { P8PDataGrid, P8P_DATA_GRID_DATA_TYPE, P8P_DATA_GRID_SIZE, P8P_DATA_GRID_FILTER_SHAPE } from "./components/p8p_data_grid"; //Таблица данных
|
import { P8PDataGrid, P8P_DATA_GRID_DATA_TYPE, P8P_DATA_GRID_SIZE, P8P_DATA_GRID_FILTER_SHAPE } from "./components/p8p_data_grid"; //Таблица данных
|
||||||
import { P8PGantt, P8P_GANTT_TASK_SHAPE, P8P_GANTT_TASK_ATTRIBUTE_SHAPE, P8P_GANTT_TASK_COLOR_SHAPE } from "./components/p8p_gantt"; //Диаграмма Ганта
|
import { P8PGantt, P8P_GANTT_TASK_SHAPE, P8P_GANTT_TASK_ATTRIBUTE_SHAPE, P8P_GANTT_TASK_COLOR_SHAPE } from "./components/p8p_gantt"; //Диаграмма Ганта
|
||||||
import { P8PCyclogram } from "./components/p8p_cyclogram"; //Циклограмма
|
import { P8PCyclogram } from "./components/p8p_cyclogram"; //Циклограмма
|
||||||
|
|||||||
22
app/root.js
22
app/root.js
@ -10,6 +10,7 @@
|
|||||||
import React from "react"; //Классы React
|
import React from "react"; //Классы React
|
||||||
import { MessagingContext } from "./context/messaging"; //Контекст сообщений
|
import { MessagingContext } from "./context/messaging"; //Контекст сообщений
|
||||||
import { BackEndContext } from "./context/backend"; //Контекст взаимодействия с сервером
|
import { BackEndContext } from "./context/backend"; //Контекст взаимодействия с сервером
|
||||||
|
import { SettingsContext } from "./context/settings"; //Контекст взаимодействия с параметрами
|
||||||
import { ApplicationContext } from "./context/application"; //Контекст приложения
|
import { ApplicationContext } from "./context/application"; //Контекст приложения
|
||||||
import { App } from "./app"; //Приложение
|
import { App } from "./app"; //Приложение
|
||||||
import { ERRORS, TITLES, TEXTS, BUTTONS } from "../app.text"; //Текстовые ресурсы и константы
|
import { ERRORS, TITLES, TEXTS, BUTTONS } from "../app.text"; //Текстовые ресурсы и константы
|
||||||
@ -17,6 +18,9 @@ import { getDisplaySize, genGUID } from "./core/utils"; //Вспомогател
|
|||||||
import config from "../app.config"; //Настройки приложения
|
import config from "../app.config"; //Настройки приложения
|
||||||
import client from "./core/client"; //Клиент для взаимодействия с сервером
|
import client from "./core/client"; //Клиент для взаимодействия с сервером
|
||||||
|
|
||||||
|
import { ThemeProvider } from "@mui/material/styles"; //Подключение темы
|
||||||
|
import { theme } from ".//theme/theme"; //Тема компонентов
|
||||||
|
|
||||||
//-----------
|
//-----------
|
||||||
//Тело модуля
|
//Тело модуля
|
||||||
//-----------
|
//-----------
|
||||||
@ -24,13 +28,17 @@ import client from "./core/client"; //Клиент для взаимодейст
|
|||||||
//Обёртка для контекста
|
//Обёртка для контекста
|
||||||
const Root = () => {
|
const Root = () => {
|
||||||
return (
|
return (
|
||||||
<MessagingContext titles={TITLES} texts={TEXTS} buttons={BUTTONS}>
|
<ThemeProvider theme={theme}>
|
||||||
<BackEndContext client={client}>
|
<MessagingContext titles={TITLES} texts={TEXTS} buttons={BUTTONS}>
|
||||||
<ApplicationContext errors={ERRORS} displaySizeGetter={getDisplaySize} guidGenerator={genGUID} config={config}>
|
<BackEndContext client={client}>
|
||||||
<App />
|
<ApplicationContext errors={ERRORS} displaySizeGetter={getDisplaySize} guidGenerator={genGUID} config={config}>
|
||||||
</ApplicationContext>
|
<SettingsContext>
|
||||||
</BackEndContext>
|
<App />
|
||||||
</MessagingContext>
|
</SettingsContext>
|
||||||
|
</ApplicationContext>
|
||||||
|
</BackEndContext>
|
||||||
|
</MessagingContext>
|
||||||
|
</ThemeProvider>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
42
app/theme/colors/common.js
Normal file
42
app/theme/colors/common.js
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
/*
|
||||||
|
Парус 8 - Панели мониторинга
|
||||||
|
Дополнительные цвета: общие
|
||||||
|
*/
|
||||||
|
|
||||||
|
//---------------------
|
||||||
|
//Подключение библиотек
|
||||||
|
//---------------------
|
||||||
|
|
||||||
|
import { STATE } from "../../../app.text"; //Типовые текстовые ресурсы и константы
|
||||||
|
import { P8P_COLOR_GREEN } from "../colors/green"; //Дополнительные цвета: зеленый
|
||||||
|
import { P8P_COLOR_RED } from "../colors/red"; //Дополнительные цвета: красный
|
||||||
|
import { P8P_COLOR_ORANGE } from "../colors/orange"; //Дополнительные цвета: оранжевый
|
||||||
|
import { P8P_COLOR_GREY } from "./grey"; //Дополнительные цвета: серый
|
||||||
|
|
||||||
|
//----------------
|
||||||
|
//Интерфейс модуля
|
||||||
|
//----------------
|
||||||
|
|
||||||
|
//Цвет - белый
|
||||||
|
export const P8P_COLOR_WHITE = "#FFF";
|
||||||
|
|
||||||
|
//Цвет - черный
|
||||||
|
export const P8P_COLOR_BLACK = "#000000";
|
||||||
|
|
||||||
|
//Цвет состояния
|
||||||
|
export const P8P_COLOR_STATE = {
|
||||||
|
[STATE.UNDEFINED]: P8P_COLOR_GREY[900],
|
||||||
|
[STATE.INFO]: P8P_COLOR_BLACK,
|
||||||
|
[STATE.OK]: P8P_COLOR_GREEN[900],
|
||||||
|
[STATE.ERR]: P8P_COLOR_RED[900],
|
||||||
|
[STATE.WARN]: P8P_COLOR_ORANGE[900]
|
||||||
|
};
|
||||||
|
|
||||||
|
//Цвет заливки состояния
|
||||||
|
export const P8P_COLOR_STATE_BG = {
|
||||||
|
[STATE.UNDEFINED]: P8P_COLOR_GREY[200],
|
||||||
|
[STATE.INFO]: P8P_COLOR_WHITE,
|
||||||
|
[STATE.OK]: P8P_COLOR_GREEN[200],
|
||||||
|
[STATE.ERR]: P8P_COLOR_RED[200],
|
||||||
|
[STATE.WARN]: P8P_COLOR_ORANGE[200]
|
||||||
|
};
|
||||||
21
app/theme/colors/green.js
Normal file
21
app/theme/colors/green.js
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
/*
|
||||||
|
Парус 8 - Панели мониторинга
|
||||||
|
Дополнительные цвета: зеленый
|
||||||
|
*/
|
||||||
|
|
||||||
|
//----------------
|
||||||
|
//Интерфейс модуля
|
||||||
|
//----------------
|
||||||
|
|
||||||
|
export const P8P_COLOR_GREEN = {
|
||||||
|
50: "#e8f5e9",
|
||||||
|
100: "#c8e6c9",
|
||||||
|
200: "#a5d6a7",
|
||||||
|
300: "#81c784",
|
||||||
|
400: "#66bb6a",
|
||||||
|
500: "#4caf50",
|
||||||
|
600: "#43a047",
|
||||||
|
700: "#388e3c",
|
||||||
|
800: "#2e7d32",
|
||||||
|
900: "#1b5e20"
|
||||||
|
};
|
||||||
21
app/theme/colors/grey.js
Normal file
21
app/theme/colors/grey.js
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
/*
|
||||||
|
Парус 8 - Панели мониторинга
|
||||||
|
Дополнительные цвета: серый
|
||||||
|
*/
|
||||||
|
|
||||||
|
//----------------
|
||||||
|
//Интерфейс модуля
|
||||||
|
//----------------
|
||||||
|
|
||||||
|
export const P8P_COLOR_GREY = {
|
||||||
|
50: "#fafafa",
|
||||||
|
100: "#f5f5f5",
|
||||||
|
200: "#eeeeee",
|
||||||
|
300: "#e0e0e0",
|
||||||
|
400: "#bdbdbd",
|
||||||
|
500: "#9e9e9e",
|
||||||
|
600: "#757575",
|
||||||
|
700: "#616161",
|
||||||
|
800: "#424242",
|
||||||
|
900: "#212121"
|
||||||
|
};
|
||||||
21
app/theme/colors/orange.js
Normal file
21
app/theme/colors/orange.js
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
/*
|
||||||
|
Парус 8 - Панели мониторинга
|
||||||
|
Дополнительные цвета: оранжевый
|
||||||
|
*/
|
||||||
|
|
||||||
|
//----------------
|
||||||
|
//Интерфейс модуля
|
||||||
|
//----------------
|
||||||
|
|
||||||
|
export const P8P_COLOR_ORANGE = {
|
||||||
|
50: "#fff3e0",
|
||||||
|
100: "#ffe0b2",
|
||||||
|
200: "#ffcc80",
|
||||||
|
300: "#ffb74d",
|
||||||
|
400: "#ffa726",
|
||||||
|
500: "#ff9800",
|
||||||
|
600: "#fb8c00",
|
||||||
|
700: "#f57c00",
|
||||||
|
800: "#ef6c00",
|
||||||
|
900: "#e65100"
|
||||||
|
};
|
||||||
21
app/theme/colors/red.js
Normal file
21
app/theme/colors/red.js
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
/*
|
||||||
|
Парус 8 - Панели мониторинга
|
||||||
|
Дополнительные цвета: красный
|
||||||
|
*/
|
||||||
|
|
||||||
|
//----------------
|
||||||
|
//Интерфейс модуля
|
||||||
|
//----------------
|
||||||
|
|
||||||
|
export const P8P_COLOR_RED = {
|
||||||
|
50: "#ffebee",
|
||||||
|
100: "#fecdd2",
|
||||||
|
200: "#ef9a9a",
|
||||||
|
300: "#e57373",
|
||||||
|
400: "#ef5350",
|
||||||
|
500: "#f44336",
|
||||||
|
600: "#e53935",
|
||||||
|
700: "#d32f2f",
|
||||||
|
800: "#c62828",
|
||||||
|
900: "#b71c1c"
|
||||||
|
};
|
||||||
67
app/theme/p8p_components.js
Normal file
67
app/theme/p8p_components.js
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
/*
|
||||||
|
Парус 8 - Панели мониторинга
|
||||||
|
Кастомные компоненты
|
||||||
|
*/
|
||||||
|
|
||||||
|
//---------------------
|
||||||
|
//Подключение библиотек
|
||||||
|
//---------------------
|
||||||
|
|
||||||
|
import { P8P_BUTTON_OVERRIDES } from "./variants/p8p_button_variants"; //Расширение Button
|
||||||
|
import { P8P_TABLE_OVERRIDES } from "./variants/p8p_table_variants"; //Расширение Table
|
||||||
|
import { P8P_TABLE_HEAD_OVERRIDES } from "./variants/p8p_table_head_variants"; //Расширение TableHead
|
||||||
|
import { P8P_TABLE_CELL_OVERRIDES } from "./variants/p8p_table_cell_variants"; //Расширение TableCell
|
||||||
|
import { P8P_TABLE_ROW_OVERRIDES } from "./variants/p8p_table_row_variants"; //Расширение TableRow
|
||||||
|
import { P8P_PAGINATION_OVERRIDES } from "./variants/p8p_pagination_variants"; //Расширение Pagination
|
||||||
|
import { P8P_CONTAINER_OVERRIDES } from "./variants/p8p_container_variants"; //Расширение Container
|
||||||
|
import { P8P_ICON_OVERRIDES } from "./variants/p8p_icon_variants"; //Расширение Icon
|
||||||
|
import { P8P_ICON_BUTTON_OVERRIDES } from "./variants/p8p_icon_button_variants"; //Расширение IconButton
|
||||||
|
import { P8P_TEXT_FIELD_OVERRIDES } from "./variants/p8p_text_field_variants"; //Расширение TextField
|
||||||
|
import { P8P_LIST_OVERRIDES } from "./variants/p8p_list_variants"; //Расширение List
|
||||||
|
import { P8P_LIST_ITEM_TEXT_OVERRIDES } from "./variants/p8p_list_item_text_variants"; //Расширение ListItemText
|
||||||
|
import { P8P_DIALOG_TITLE_OVERRIDES } from "./variants/p8p_dialog_title_variants"; //Расширение DialogTitle
|
||||||
|
import { P8P_DIALOG_CONTENT_OVERRIDES } from "./variants/p8p_dialog_content_variants"; //Расширение DialogContent
|
||||||
|
import { P8P_DIALOG_CONTENT_TEXT_OVERRIDES } from "./variants/p8p_dialog_content_text_variants"; //Расширение DialogContentText
|
||||||
|
import { P8P_DRAWER_OVERRIDES } from "./variants/p8p_drawer_variants"; //Расширение Drawer
|
||||||
|
import { P8P_APP_BAR_OVERRIDES } from "./variants/p8p_app_bar_variants"; //Расширение AppBar
|
||||||
|
import { P8P_GRID_OVERRIDES } from "./variants/p8p_grid_variants"; //Расширение Grid
|
||||||
|
import { P8P_CARD_OVERRIDES } from "./variants/p8p_card_variants"; //Расширение Card
|
||||||
|
import { P8P_CARD_ACTIONS_OVERRIDES } from "./variants/p8p_card_actions_variants"; //Расширение CardActions
|
||||||
|
import { P8P_SELECT_OVERRIDES } from "./variants/p8p_select_variants"; //Расширение Select
|
||||||
|
import { P8P_INPUT_OVERRIDES } from "./variants/p8p_input_variants"; //Расширение Input
|
||||||
|
import { P8P_INPUT_LABEL_OVERRIDES } from "./variants/p8p_input_label_variants"; //Расширение InputLable
|
||||||
|
import { P8P_MENU_ITEM_OVERRIDES } from "./variants/p8p_menu_item_variants"; //Расширение MenuItem
|
||||||
|
import { P8P_AUTOCOMPLETE_OVERRIDES } from "./variants/p8p_autocomplete_variants"; //Расширение Autocomplete
|
||||||
|
|
||||||
|
//----------------
|
||||||
|
//Интерфейс модуля
|
||||||
|
//----------------
|
||||||
|
|
||||||
|
//Кастомные компоненты
|
||||||
|
export const P8P_COMPONENTS = {
|
||||||
|
MuiButton: P8P_BUTTON_OVERRIDES,
|
||||||
|
MuiTable: P8P_TABLE_OVERRIDES,
|
||||||
|
MuiTableHead: P8P_TABLE_HEAD_OVERRIDES,
|
||||||
|
MuiTableRow: P8P_TABLE_ROW_OVERRIDES,
|
||||||
|
MuiTableCell: P8P_TABLE_CELL_OVERRIDES,
|
||||||
|
MuiPagination: P8P_PAGINATION_OVERRIDES,
|
||||||
|
MuiContainer: P8P_CONTAINER_OVERRIDES,
|
||||||
|
MuiIcon: P8P_ICON_OVERRIDES,
|
||||||
|
MuiIconButton: P8P_ICON_BUTTON_OVERRIDES,
|
||||||
|
MuiTextField: P8P_TEXT_FIELD_OVERRIDES,
|
||||||
|
MuiDialogTitle: P8P_DIALOG_TITLE_OVERRIDES,
|
||||||
|
MuiDialogContent: P8P_DIALOG_CONTENT_OVERRIDES,
|
||||||
|
MuiDialogContentText: P8P_DIALOG_CONTENT_TEXT_OVERRIDES,
|
||||||
|
MuiList: P8P_LIST_OVERRIDES,
|
||||||
|
MuiListItemText: P8P_LIST_ITEM_TEXT_OVERRIDES,
|
||||||
|
MuiDrawer: P8P_DRAWER_OVERRIDES,
|
||||||
|
MuiAppBar: P8P_APP_BAR_OVERRIDES,
|
||||||
|
MuiGrid: P8P_GRID_OVERRIDES,
|
||||||
|
MuiCard: P8P_CARD_OVERRIDES,
|
||||||
|
MuiCardActions: P8P_CARD_ACTIONS_OVERRIDES,
|
||||||
|
MuiSelect: P8P_SELECT_OVERRIDES,
|
||||||
|
MuiInputLabel: P8P_INPUT_LABEL_OVERRIDES,
|
||||||
|
MuiInput: P8P_INPUT_OVERRIDES,
|
||||||
|
MuiMenuItem: P8P_MENU_ITEM_OVERRIDES,
|
||||||
|
MuiAutocomplete: P8P_AUTOCOMPLETE_OVERRIDES
|
||||||
|
};
|
||||||
72
app/theme/p8p_palette.js
Normal file
72
app/theme/p8p_palette.js
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
/*
|
||||||
|
Парус 8 - Панели мониторинга
|
||||||
|
Кастомная палитра
|
||||||
|
*/
|
||||||
|
|
||||||
|
//----------------
|
||||||
|
//Интерфейс модуля
|
||||||
|
//----------------
|
||||||
|
|
||||||
|
//Кастомная палитра
|
||||||
|
export const P8P_PALETTE = {
|
||||||
|
P8PText: {
|
||||||
|
primary: "#2a3039de",
|
||||||
|
secondary: "#2a303999",
|
||||||
|
disabled: "#2a303961"
|
||||||
|
},
|
||||||
|
P8PPrimary: {
|
||||||
|
main: "#0F71BD",
|
||||||
|
dark: "#005EA6",
|
||||||
|
light: "#8DC2E2",
|
||||||
|
contrastText: "#FFF",
|
||||||
|
hover: "#0f71bd0a",
|
||||||
|
selected: "#0f71bd14",
|
||||||
|
focus: "#0f71bd1f",
|
||||||
|
focusVisible: "#0f71bd4d",
|
||||||
|
outlinedBorder: "#2a30391f"
|
||||||
|
},
|
||||||
|
P8PSecondary: {
|
||||||
|
main: "#37474F",
|
||||||
|
dark: "#2A3039",
|
||||||
|
light: "#607D8B",
|
||||||
|
contrastText: "#FFF",
|
||||||
|
outlinedBorder: "#2a303980"
|
||||||
|
},
|
||||||
|
P8PError: {
|
||||||
|
main: "#D32F2F",
|
||||||
|
dark: "#C62828",
|
||||||
|
light: "#EF5350"
|
||||||
|
},
|
||||||
|
P8PWarning: {
|
||||||
|
main: "#EF6C00",
|
||||||
|
dark: "#E65100",
|
||||||
|
light: "#FF9800"
|
||||||
|
},
|
||||||
|
P8PInfo: {
|
||||||
|
main: "#0F71BD",
|
||||||
|
dark: "#005EA6",
|
||||||
|
light: "#03A9F4"
|
||||||
|
},
|
||||||
|
P8PSuccess: {
|
||||||
|
main: "#2E7D32",
|
||||||
|
dark: "#1B5E20",
|
||||||
|
light: "#4CAF50"
|
||||||
|
},
|
||||||
|
P8PBackground: {
|
||||||
|
primary: "#FFF",
|
||||||
|
secondary: "#F8FAFD",
|
||||||
|
tableHeader: "#E6EAF3"
|
||||||
|
},
|
||||||
|
P8PAction: {
|
||||||
|
active: "#0000008a"
|
||||||
|
},
|
||||||
|
P8PCyclogram: {
|
||||||
|
group: "#e6eaf3",
|
||||||
|
task: "#cfd8dc"
|
||||||
|
},
|
||||||
|
P8PDesktop: {
|
||||||
|
main: "#1976d2",
|
||||||
|
hover: "#c3e1ff"
|
||||||
|
},
|
||||||
|
P8PPurple: "#5e35b1"
|
||||||
|
};
|
||||||
217
app/theme/p8p_typography.js
Normal file
217
app/theme/p8p_typography.js
Normal file
@ -0,0 +1,217 @@
|
|||||||
|
/*
|
||||||
|
Парус 8 - Панели мониторинга
|
||||||
|
Кастомные шрифты
|
||||||
|
*/
|
||||||
|
|
||||||
|
//---------
|
||||||
|
//Константы
|
||||||
|
//---------
|
||||||
|
|
||||||
|
//Шрифт "Montserrat"
|
||||||
|
const P8PFontMontserrat = {
|
||||||
|
fontFamily: "Montserrat",
|
||||||
|
fontStyle: "normal"
|
||||||
|
};
|
||||||
|
|
||||||
|
//----------------
|
||||||
|
//Интерфейс модуля
|
||||||
|
//----------------
|
||||||
|
|
||||||
|
//Кастомные шрифты
|
||||||
|
export const P8P_TYPOGRAPHY = {
|
||||||
|
P8PFontMontserrat: "Montserrat",
|
||||||
|
P8PH1: {
|
||||||
|
...P8PFontMontserrat,
|
||||||
|
fontSize: "96px",
|
||||||
|
fontWeight: "500",
|
||||||
|
lineHeight: "117%",
|
||||||
|
letterSpacing: "-1.5px"
|
||||||
|
},
|
||||||
|
P8PH2: {
|
||||||
|
...P8PFontMontserrat,
|
||||||
|
fontSize: "60px",
|
||||||
|
fontWeight: "500",
|
||||||
|
lineHeight: "120%",
|
||||||
|
letterSpacing: "-0.5px"
|
||||||
|
},
|
||||||
|
P8PH3: {
|
||||||
|
...P8PFontMontserrat,
|
||||||
|
fontSize: "48px",
|
||||||
|
fontWeight: "500",
|
||||||
|
lineHeight: "118%"
|
||||||
|
},
|
||||||
|
P8PH4: {
|
||||||
|
...P8PFontMontserrat,
|
||||||
|
fontSize: "32px",
|
||||||
|
fontWeight: "600",
|
||||||
|
lineHeight: "120%",
|
||||||
|
letterSpacing: "0.25px"
|
||||||
|
},
|
||||||
|
P8PH5: {
|
||||||
|
...P8PFontMontserrat,
|
||||||
|
fontSize: "24px",
|
||||||
|
fontWeight: "600",
|
||||||
|
lineHeight: "130%"
|
||||||
|
},
|
||||||
|
P8PH6: {
|
||||||
|
...P8PFontMontserrat,
|
||||||
|
fontSize: "20px",
|
||||||
|
fontWeight: "600",
|
||||||
|
lineHeight: "140%",
|
||||||
|
letterSpacing: "0.15px"
|
||||||
|
},
|
||||||
|
P8PH6Light: {
|
||||||
|
...P8PFontMontserrat,
|
||||||
|
fontSize: "20px",
|
||||||
|
fontWeight: "500",
|
||||||
|
lineHeight: "140%",
|
||||||
|
letterSpacing: "0.15px"
|
||||||
|
},
|
||||||
|
P8PH7: {
|
||||||
|
...P8PFontMontserrat,
|
||||||
|
fontSize: "18px",
|
||||||
|
fontWeight: "600",
|
||||||
|
lineHeight: "130%",
|
||||||
|
letterSpacing: "0.15px"
|
||||||
|
},
|
||||||
|
P8PSubtitle1: {
|
||||||
|
...P8PFontMontserrat,
|
||||||
|
fontSize: "16px",
|
||||||
|
fontWeight: "600",
|
||||||
|
lineHeight: "130%",
|
||||||
|
letterSpacing: "0.15px"
|
||||||
|
},
|
||||||
|
P8PSubtitle2: {
|
||||||
|
...P8PFontMontserrat,
|
||||||
|
fontSize: "14px",
|
||||||
|
fontWeight: "600",
|
||||||
|
lineHeight: "140%",
|
||||||
|
letterSpacing: "0.1px"
|
||||||
|
},
|
||||||
|
P8PBody1: {
|
||||||
|
...P8PFontMontserrat,
|
||||||
|
fontSize: "16px",
|
||||||
|
fontWeight: "500",
|
||||||
|
lineHeight: "150%",
|
||||||
|
letterSpacing: "0.15px"
|
||||||
|
},
|
||||||
|
P8PBody2: {
|
||||||
|
...P8PFontMontserrat,
|
||||||
|
fontSize: "12px",
|
||||||
|
fontWeight: "500",
|
||||||
|
lineHeight: "143%",
|
||||||
|
letterSpacing: "0.17px"
|
||||||
|
},
|
||||||
|
P8PBody2Light: {
|
||||||
|
...P8PFontMontserrat,
|
||||||
|
fontSize: "12px",
|
||||||
|
fontWeight: "400",
|
||||||
|
lineHeight: "143%",
|
||||||
|
letterSpacing: "0.17px"
|
||||||
|
},
|
||||||
|
P8PBody3: {
|
||||||
|
...P8PFontMontserrat,
|
||||||
|
fontSize: "14px",
|
||||||
|
fontWeight: "500",
|
||||||
|
lineHeight: "143%",
|
||||||
|
letterSpacing: "0.17px"
|
||||||
|
},
|
||||||
|
P8PBody3Light: {
|
||||||
|
...P8PFontMontserrat,
|
||||||
|
fontSize: "14px",
|
||||||
|
fontWeight: "400",
|
||||||
|
lineHeight: "143%",
|
||||||
|
letterSpacing: "0.17px"
|
||||||
|
},
|
||||||
|
P8PBody4: {
|
||||||
|
...P8PFontMontserrat,
|
||||||
|
fontSize: "15px",
|
||||||
|
fontWeight: "500",
|
||||||
|
lineHeight: "143%",
|
||||||
|
letterSpacing: "0.17px"
|
||||||
|
},
|
||||||
|
P8PCaption: {
|
||||||
|
...P8PFontMontserrat,
|
||||||
|
fontSize: "12px",
|
||||||
|
fontWeight: "500",
|
||||||
|
lineHeight: "166%",
|
||||||
|
letterSpacing: "0.4px"
|
||||||
|
},
|
||||||
|
P8POverline: {
|
||||||
|
...P8PFontMontserrat,
|
||||||
|
fontSize: "12px",
|
||||||
|
fontWeight: "400",
|
||||||
|
lineHeight: "266%",
|
||||||
|
letterSpacing: "1px"
|
||||||
|
},
|
||||||
|
P8PButton: {
|
||||||
|
...P8PFontMontserrat,
|
||||||
|
fontSize: "15px",
|
||||||
|
fontWeight: "600",
|
||||||
|
lineHeight: "26px",
|
||||||
|
letterSpacing: "0.46px"
|
||||||
|
},
|
||||||
|
P8PColumn: {
|
||||||
|
...P8PFontMontserrat,
|
||||||
|
fontSize: "12px",
|
||||||
|
fontWeight: "600",
|
||||||
|
lineHeight: "24px",
|
||||||
|
letterSpacing: "0.17px"
|
||||||
|
},
|
||||||
|
P8PInputLabel: {
|
||||||
|
...P8PFontMontserrat,
|
||||||
|
fontSize: "16px"
|
||||||
|
},
|
||||||
|
P8PBody2Bold: {
|
||||||
|
...P8PFontMontserrat,
|
||||||
|
fontSize: "12px",
|
||||||
|
fontWeight: "700",
|
||||||
|
lineHeight: "143%",
|
||||||
|
letterSpacing: "0.17px"
|
||||||
|
},
|
||||||
|
P8PTitle: {
|
||||||
|
...P8PFontMontserrat,
|
||||||
|
fontSize: "15px",
|
||||||
|
fontWeight: "500",
|
||||||
|
lineHeight: "140%",
|
||||||
|
letterSpacing: "0.1px"
|
||||||
|
},
|
||||||
|
P8PDesktopGroup: {
|
||||||
|
fontFamily: "tahoma, arial, verdana, sans-serif!important",
|
||||||
|
fontSize: "13px !important",
|
||||||
|
fontWeight: "bold"
|
||||||
|
},
|
||||||
|
P8PDesktopCaption: {
|
||||||
|
fontFamily: "tahoma, arial, verdana, sans-serif!important",
|
||||||
|
fontSize: "12px",
|
||||||
|
lineHeight: "1.2"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
//Наименование кастомных шрифтов
|
||||||
|
export const P8P_TYPOGRAPHY_VARIANT = {
|
||||||
|
H1: "P8PH1",
|
||||||
|
H2: "P8PH2",
|
||||||
|
H3: "P8PH3",
|
||||||
|
H4: "P8PH4",
|
||||||
|
H5: "P8PH5",
|
||||||
|
H6: "P8PH6",
|
||||||
|
H6_LIGHT: "P8PH6Light",
|
||||||
|
H7: "P8PH7",
|
||||||
|
SUBTITLE1: "P8PSubtitle1",
|
||||||
|
SUBTITLE2: "P8PSubtitle2",
|
||||||
|
BODY1: "P8PBody1",
|
||||||
|
BODY2: "P8PBody2",
|
||||||
|
BODY2_LIGHT: "P8PBody2Light",
|
||||||
|
BODY3: "P8PBody3",
|
||||||
|
BODY3_LIGHT: "P8PBody3Light",
|
||||||
|
CAPTION: "P8PCaption",
|
||||||
|
OVERLINE: "P8POverline",
|
||||||
|
BUTTON: "P8PButton",
|
||||||
|
COLUMN: "P8PColumn",
|
||||||
|
INPUT_LABEL: "P8PInputLabel",
|
||||||
|
BODY2_BOLD: "P8PBody2Bold",
|
||||||
|
TITLE: "P8PTitle",
|
||||||
|
DESKTOP_GROUP: "P8PDesktopGroup",
|
||||||
|
DESKTOP_CAPTION: "P8PDesktopCaption"
|
||||||
|
};
|
||||||
152
app/theme/styles/box.js
Normal file
152
app/theme/styles/box.js
Normal file
@ -0,0 +1,152 @@
|
|||||||
|
/*
|
||||||
|
Парус 8 - Панели мониторинга
|
||||||
|
Вспомогательные стили Box
|
||||||
|
*/
|
||||||
|
|
||||||
|
//---------------------
|
||||||
|
//Подключение библиотек
|
||||||
|
//---------------------
|
||||||
|
|
||||||
|
import { P8P_COMPONENT_WIDTH, P8P_COMPONENT_HEIGHT, P8P_SCROLL_AUTO } from "./common"; //Стили - общие
|
||||||
|
import { useTheme } from "@mui/material/styles"; //Хук темы приложения
|
||||||
|
|
||||||
|
//---------
|
||||||
|
//Общие стили контейнеров
|
||||||
|
//---------
|
||||||
|
|
||||||
|
//Контейнер плавающий
|
||||||
|
export const P8P_BOX_FLEX = { display: "flex" };
|
||||||
|
|
||||||
|
//Контейнер плавающий, элементы по центру, к началу
|
||||||
|
export const P8P_BOX_CENTER_START = {
|
||||||
|
display: "flex",
|
||||||
|
alignItems: "center",
|
||||||
|
justifyContent: "flex-start"
|
||||||
|
};
|
||||||
|
|
||||||
|
//Контейнер плавающий, элементы по центру, к концу
|
||||||
|
export const P8P_BOX_CENTER_END = {
|
||||||
|
display: "flex",
|
||||||
|
alignItems: "center",
|
||||||
|
justifyContent: "flex-end"
|
||||||
|
};
|
||||||
|
|
||||||
|
//Контейнер плавающий, элементы по центру, равномерно
|
||||||
|
export const P8P_BOX_CENTER_BETWEEN = {
|
||||||
|
display: "flex",
|
||||||
|
alignItems: "center",
|
||||||
|
justifyContent: "space-between"
|
||||||
|
};
|
||||||
|
|
||||||
|
//Контейнер плавающий, элементы по центру
|
||||||
|
export const P8P_BOX_CENTER = { display: "flex", alignItems: "center", justifyContent: "center" };
|
||||||
|
|
||||||
|
//---------
|
||||||
|
//Стили приложения
|
||||||
|
//---------
|
||||||
|
|
||||||
|
//Контейнер рабочего пространства
|
||||||
|
export const P8P_BOX_APP_WORKSPACE = {
|
||||||
|
...P8P_COMPONENT_WIDTH({ width: "100vw" }),
|
||||||
|
//width: "100vw",
|
||||||
|
...P8P_BOX_CENTER_BETWEEN
|
||||||
|
};
|
||||||
|
|
||||||
|
//Меню панелей - контейнер грида
|
||||||
|
export const P8P_BOX_PANELS_MENU_CONTAINER = {
|
||||||
|
...P8P_BOX_CENTER_START,
|
||||||
|
...P8P_COMPONENT_HEIGHT({ minHeight: "100vh" })
|
||||||
|
};
|
||||||
|
|
||||||
|
//---------
|
||||||
|
//Стили настроек панелей
|
||||||
|
//---------
|
||||||
|
|
||||||
|
//Список настроек панели
|
||||||
|
export const P8P_BOX_SETTINGS_LIST = {
|
||||||
|
...P8P_COMPONENT_WIDTH({ width: "520px" }),
|
||||||
|
...P8P_COMPONENT_HEIGHT({ height: "500px" }),
|
||||||
|
...P8P_SCROLL_AUTO
|
||||||
|
};
|
||||||
|
|
||||||
|
//Список панелей настроек панелей
|
||||||
|
export const P8P_BOX_SETTINGS_PANELS = {
|
||||||
|
...P8P_COMPONENT_WIDTH({ width: "300px" }),
|
||||||
|
...P8P_COMPONENT_HEIGHT({ height: "500px" }),
|
||||||
|
...P8P_SCROLL_AUTO
|
||||||
|
};
|
||||||
|
|
||||||
|
//Контейнер настроек панелей
|
||||||
|
export const P8P_BOX_SETTINGS_CONTAINER = {
|
||||||
|
display: "flex",
|
||||||
|
flexDirection: "row",
|
||||||
|
alignItems: "flex-start"
|
||||||
|
};
|
||||||
|
|
||||||
|
//---------
|
||||||
|
//Стили Ганта
|
||||||
|
//---------
|
||||||
|
|
||||||
|
//Контейнер диаграмы Ганта
|
||||||
|
export const P8P_BOX_GANTT = ({ noData, zoomBarHeight, titleHeight }) => ({
|
||||||
|
...P8P_COMPONENT_HEIGHT({ height: `calc(100% - ${zoomBarHeight ? zoomBarHeight : "0px"} - ${titleHeight ? titleHeight : "0px"})` }),
|
||||||
|
//height: `calc(100% - ${zoomBarHeight ? zoomBarHeight : "0px"} - ${titleHeight ? titleHeight : "0px"})`,
|
||||||
|
display: noData ? "none" : ""
|
||||||
|
});
|
||||||
|
|
||||||
|
//---------
|
||||||
|
//Стили циклограммы
|
||||||
|
//---------
|
||||||
|
|
||||||
|
//Контейнер циклограммы
|
||||||
|
export const P8P_BOX_CYCLOGRAM = ({ noData, zoomBarHeight, titleHeight }) => ({
|
||||||
|
position: "relative",
|
||||||
|
overflow: "auto",
|
||||||
|
padding: "0px 8px",
|
||||||
|
...P8P_COMPONENT_HEIGHT({ height: `calc(100% - ${zoomBarHeight ? zoomBarHeight : "0px"} - ${titleHeight ? titleHeight : "0px"})` }),
|
||||||
|
//height: `calc(100% - ${zoomBarHeight ? zoomBarHeight : "0px"} - ${titleHeight ? titleHeight : "0px"})`,
|
||||||
|
display: noData ? "none" : ""
|
||||||
|
});
|
||||||
|
|
||||||
|
//Контейнер строки циклограммы
|
||||||
|
export const P8P_BOX_CYCLOGRAM_ROW = ({ index }) => {
|
||||||
|
//Определение темы приложения
|
||||||
|
const theme = useTheme();
|
||||||
|
//Возвращаем стиль
|
||||||
|
return {
|
||||||
|
...(index % 2 === 0 ? { backgroundColor: theme.palette.P8PBackground.primary } : { backgroundColor: theme.palette.P8PBackground.secondary })
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
//Контейнер заголовка группы циклограммы
|
||||||
|
export const P8P_BOX_CYCLOGRAM_GROUP = ({ height }) => {
|
||||||
|
//Определение темы приложения
|
||||||
|
const theme = useTheme();
|
||||||
|
//Возвращаем стиль
|
||||||
|
return {
|
||||||
|
border: "1px solid",
|
||||||
|
backgroundColor: theme.palette.P8PCyclogram.group,
|
||||||
|
...P8P_BOX_CENTER,
|
||||||
|
height
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
//Контейнер задачи циклограммы
|
||||||
|
export const P8P_BOX_CYCLOGRAM_TASK = ({ lineHeight, bgColor, textColor, highlightColor }) => {
|
||||||
|
//Определение темы приложения
|
||||||
|
const theme = useTheme();
|
||||||
|
//Возвращаем стиль
|
||||||
|
return {
|
||||||
|
display: "flex",
|
||||||
|
alignItems: "center",
|
||||||
|
backgroundColor: bgColor ? bgColor : theme.palette.P8PCyclogram.task,
|
||||||
|
...(textColor ? { color: textColor } : {}),
|
||||||
|
height: lineHeight,
|
||||||
|
"&:hover": {
|
||||||
|
...(highlightColor
|
||||||
|
? { backgroundColor: `${highlightColor} !important`, filter: "brightness(1) !important" }
|
||||||
|
: { filter: `brightness(${bgColor ? "1.25" : "1.1"}) !important` }),
|
||||||
|
cursor: "pointer !important"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
58
app/theme/styles/common.js
Normal file
58
app/theme/styles/common.js
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
/*
|
||||||
|
Парус 8 - Панели мониторинга
|
||||||
|
Вспомогательные стили - общие
|
||||||
|
*/
|
||||||
|
|
||||||
|
//---------------------
|
||||||
|
//Подключение библиотек
|
||||||
|
//---------------------
|
||||||
|
|
||||||
|
import { APP_STYLES } from "../../../app.styles"; //Типовые стили
|
||||||
|
|
||||||
|
//----------------
|
||||||
|
//Интерфейс модуля
|
||||||
|
//----------------
|
||||||
|
|
||||||
|
//Ширина компонента
|
||||||
|
export const P8P_COMPONENT_WIDTH = ({ width, minWidth, maxWidth }) => ({
|
||||||
|
...(width ? { width } : {}),
|
||||||
|
...(minWidth ? { minWidth } : {}),
|
||||||
|
...(maxWidth ? { maxWidth } : {})
|
||||||
|
});
|
||||||
|
|
||||||
|
//Высота компонента
|
||||||
|
export const P8P_COMPONENT_HEIGHT = ({ height, minHeight, maxHeight }) => ({
|
||||||
|
...(height ? { height } : {}),
|
||||||
|
...(minHeight ? { minHeight } : {}),
|
||||||
|
...(maxHeight ? { maxHeight } : {})
|
||||||
|
});
|
||||||
|
|
||||||
|
//Отображаемый скролл
|
||||||
|
export const P8P_SCROLL_AUTO = {
|
||||||
|
overflow: "auto",
|
||||||
|
...APP_STYLES.SCROLL
|
||||||
|
};
|
||||||
|
|
||||||
|
//Отсутствие отступов
|
||||||
|
export const P8P_COMPONENT_ZERO_PADDING = {
|
||||||
|
padding: "0px"
|
||||||
|
};
|
||||||
|
|
||||||
|
//Стили
|
||||||
|
export const P8P_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"
|
||||||
|
}
|
||||||
|
};
|
||||||
32
app/theme/styles/icon.js
Normal file
32
app/theme/styles/icon.js
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
/*
|
||||||
|
Парус 8 - Панели мониторинга
|
||||||
|
Вспомогательные стили Icon
|
||||||
|
*/
|
||||||
|
|
||||||
|
//---------------------
|
||||||
|
//Подключение библиотек
|
||||||
|
//---------------------
|
||||||
|
|
||||||
|
import { STATE } from "../../../app.text"; //Типовые текстовые ресурсы и константы
|
||||||
|
import { P8P_COLOR_STATE } from "../colors/common"; //Дополнительные цвета - общие
|
||||||
|
|
||||||
|
//---------
|
||||||
|
//Константы
|
||||||
|
//---------
|
||||||
|
|
||||||
|
//Цвета текста и иконок индикатора
|
||||||
|
const P8P_INDICATOR_COLOR = {
|
||||||
|
[STATE.OK]: P8P_COLOR_STATE[STATE.OK],
|
||||||
|
[STATE.ERR]: P8P_COLOR_STATE[STATE.ERR],
|
||||||
|
[STATE.WARN]: P8P_COLOR_STATE[STATE.WARN]
|
||||||
|
};
|
||||||
|
|
||||||
|
//----------------
|
||||||
|
//Интерфейс модуля
|
||||||
|
//----------------
|
||||||
|
|
||||||
|
//Иконка индикатора
|
||||||
|
export const P8P_ICON_INDICATOR = ({ state, fontSize, color }) => ({
|
||||||
|
fontSize,
|
||||||
|
color: color || P8P_INDICATOR_COLOR[state]
|
||||||
|
});
|
||||||
13
app/theme/styles/main.js
Normal file
13
app/theme/styles/main.js
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
/*
|
||||||
|
Парус 8 - Панели мониторинга
|
||||||
|
Вспомогательные стили main
|
||||||
|
*/
|
||||||
|
|
||||||
|
//----------------
|
||||||
|
//Интерфейс модуля
|
||||||
|
//----------------
|
||||||
|
|
||||||
|
//Содержимое рабочего пространства
|
||||||
|
export const P8P_MAIN_APP_WORKSPACE = {
|
||||||
|
flexGrow: 1
|
||||||
|
};
|
||||||
66
app/theme/styles/paper.js
Normal file
66
app/theme/styles/paper.js
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
/*
|
||||||
|
Парус 8 - Панели мониторинга
|
||||||
|
Вспомогательные стили Paper
|
||||||
|
*/
|
||||||
|
|
||||||
|
//---------------------
|
||||||
|
//Подключение библиотек
|
||||||
|
//---------------------
|
||||||
|
|
||||||
|
import { useTheme } from "@mui/material/styles"; //Хук темы приложения
|
||||||
|
import { STATE } from "../../../app.text"; //Типовые текстовые ресурсы и константы
|
||||||
|
import { P8P_COLOR_STATE, P8P_COLOR_STATE_BG } from "../colors/common"; //Дополнительные цвета - общие
|
||||||
|
import { P8P_COMPONENT_WIDTH, P8P_COMPONENT_HEIGHT } from "./common"; //Стили - общие
|
||||||
|
|
||||||
|
//---------
|
||||||
|
//Константы
|
||||||
|
//---------
|
||||||
|
|
||||||
|
//Цвета заливки индикатора
|
||||||
|
const P8P_INDICATOR_BG_COLOR = {
|
||||||
|
[STATE.OK]: P8P_COLOR_STATE_BG[STATE.OK],
|
||||||
|
[STATE.ERR]: P8P_COLOR_STATE_BG[STATE.ERR],
|
||||||
|
[STATE.WARN]: P8P_COLOR_STATE_BG[STATE.WARN]
|
||||||
|
};
|
||||||
|
|
||||||
|
//Цвета текста и иконок индикатора
|
||||||
|
const P8P_INDICATOR_COLOR = {
|
||||||
|
[STATE.OK]: P8P_COLOR_STATE[STATE.OK],
|
||||||
|
[STATE.ERR]: P8P_COLOR_STATE[STATE.ERR],
|
||||||
|
[STATE.WARN]: P8P_COLOR_STATE[STATE.WARN]
|
||||||
|
};
|
||||||
|
|
||||||
|
//-----------------------
|
||||||
|
//Вспомогательные функции
|
||||||
|
//-----------------------
|
||||||
|
|
||||||
|
//----------------
|
||||||
|
//Интерфейс модуля
|
||||||
|
//----------------
|
||||||
|
|
||||||
|
//Стиль для контейнера индикатора
|
||||||
|
export const P8P_PAPER_INDICATOR = ({ state, color, backgroundColor, clickable }) => {
|
||||||
|
//Определение темы приложения
|
||||||
|
const theme = useTheme();
|
||||||
|
//Возвращаем стиль
|
||||||
|
return {
|
||||||
|
padding: "10px",
|
||||||
|
...P8P_COMPONENT_WIDTH({ width: "100%" }),
|
||||||
|
...P8P_COMPONENT_HEIGHT({ height: "100%" }),
|
||||||
|
//width: "100%",
|
||||||
|
//height: "100%",
|
||||||
|
overflow: "hidden",
|
||||||
|
backgroundColor: backgroundColor || P8P_INDICATOR_BG_COLOR[state],
|
||||||
|
color: color || P8P_INDICATOR_COLOR[state],
|
||||||
|
display: "flex",
|
||||||
|
flexDirection: "column",
|
||||||
|
justifyContent: "center",
|
||||||
|
...(clickable
|
||||||
|
? {
|
||||||
|
cursor: "pointer",
|
||||||
|
"&:hover": { filter: "brightness(0.92) !important" },
|
||||||
|
"&:active": { backgroundColor: theme.palette.P8PAction.active }
|
||||||
|
}
|
||||||
|
: {})
|
||||||
|
};
|
||||||
|
};
|
||||||
22
app/theme/styles/stack.js
Normal file
22
app/theme/styles/stack.js
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
/*
|
||||||
|
Парус 8 - Панели мониторинга
|
||||||
|
Вспомогательные стили Stack
|
||||||
|
*/
|
||||||
|
|
||||||
|
//---------------------
|
||||||
|
//Подключение библиотек
|
||||||
|
//---------------------
|
||||||
|
|
||||||
|
import { P8P_COMPONENT_WIDTH } from "./common"; //Стили - общие
|
||||||
|
|
||||||
|
//----------------
|
||||||
|
//Интерфейс модуля
|
||||||
|
//----------------
|
||||||
|
|
||||||
|
//Адаптивный с сокрытием
|
||||||
|
export const P8P_STACK_INLINE_HIDDEN = {
|
||||||
|
...P8P_COMPONENT_WIDTH({ width: "100%" }),
|
||||||
|
containerType: "inline-size",
|
||||||
|
//width: "100%",
|
||||||
|
overflow: "hidden"
|
||||||
|
};
|
||||||
86
app/theme/styles/typography.js
Normal file
86
app/theme/styles/typography.js
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
/*
|
||||||
|
Парус 8 - Панели мониторинга
|
||||||
|
Вспомогательные стили Typography
|
||||||
|
*/
|
||||||
|
|
||||||
|
//---------------------
|
||||||
|
//Подключение библиотек
|
||||||
|
//---------------------
|
||||||
|
|
||||||
|
import { P8P_COMPONENT_WIDTH, P8P_COMPONENT_HEIGHT } from "./common"; //Стили - общие
|
||||||
|
|
||||||
|
//----------------
|
||||||
|
//Интерфейс модуля
|
||||||
|
//----------------
|
||||||
|
|
||||||
|
//---------
|
||||||
|
//Общие стили текста
|
||||||
|
//---------
|
||||||
|
|
||||||
|
//Текст с возможностью нажатия
|
||||||
|
export const P8P_TYPOGRAPHY_CLICKABLE = {
|
||||||
|
cursor: "pointer"
|
||||||
|
};
|
||||||
|
|
||||||
|
//Заголовок полноэкранного диалога
|
||||||
|
export const P8P_TYPOGRAPHY_DIALOG_TITLE = {
|
||||||
|
marginLeft: "16px",
|
||||||
|
flex: 1
|
||||||
|
};
|
||||||
|
|
||||||
|
//Заголовок
|
||||||
|
export const P8P_TYPOGRAPHY_TITLE = {
|
||||||
|
...P8P_COMPONENT_HEIGHT({ height: "44px" })
|
||||||
|
//height: "44px"
|
||||||
|
};
|
||||||
|
|
||||||
|
//---------
|
||||||
|
//Стили приложения
|
||||||
|
//---------
|
||||||
|
|
||||||
|
//Описание панели на рабочем столе
|
||||||
|
export const P8P_TYPOGRAPHY_PANEL_DESK = {
|
||||||
|
display: "-webkit-box",
|
||||||
|
overflow: "hidden",
|
||||||
|
WebkitBoxOrient: "vertical",
|
||||||
|
WebkitLineClamp: 2,
|
||||||
|
...P8P_COMPONENT_WIDTH({ maxWidth: "140px" })
|
||||||
|
//maxWidth: "140px"
|
||||||
|
};
|
||||||
|
|
||||||
|
//---------
|
||||||
|
//Стили циклограммы
|
||||||
|
//---------
|
||||||
|
|
||||||
|
//Колонка циклограммы
|
||||||
|
export const P8P_TYPOGRAPHY_CG_HEADER = {
|
||||||
|
textOverflow: "ellipsis",
|
||||||
|
overflow: "hidden",
|
||||||
|
whiteSpace: "pre",
|
||||||
|
textAlign: "center",
|
||||||
|
lineHeight: "35px",
|
||||||
|
padding: "0px 5px"
|
||||||
|
};
|
||||||
|
|
||||||
|
//Группа циклограммы
|
||||||
|
export const P8P_TYPOGRAPHY_CG_GROUP = ({ maxWidth, maxHeight }) => ({
|
||||||
|
maxWidth,
|
||||||
|
maxHeight,
|
||||||
|
textAlign: "center",
|
||||||
|
wordWrap: "break-word"
|
||||||
|
});
|
||||||
|
|
||||||
|
//Задача циклограммы
|
||||||
|
export const P8P_TYPOGRAPHY_CG_TASK = ({ maxHeight, availableLines }) => ({
|
||||||
|
maxHeight,
|
||||||
|
...P8P_COMPONENT_WIDTH({ width: "100%" }),
|
||||||
|
//width: "100%",
|
||||||
|
padding: "0px 5px",
|
||||||
|
overflowWrap: "break-word",
|
||||||
|
wordBreak: "break-all",
|
||||||
|
overflow: "hidden",
|
||||||
|
textOverflow: "ellipsis",
|
||||||
|
display: "-webkit-box",
|
||||||
|
WebkitBoxOrient: "vertical",
|
||||||
|
WebkitLineClamp: availableLines < 1 ? 1 : availableLines
|
||||||
|
});
|
||||||
24
app/theme/theme.js
Normal file
24
app/theme/theme.js
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
/*
|
||||||
|
Парус 8 - Панели мониторинга
|
||||||
|
Стилистика компонентов
|
||||||
|
*/
|
||||||
|
|
||||||
|
//---------------------
|
||||||
|
//Подключение библиотек
|
||||||
|
//---------------------
|
||||||
|
|
||||||
|
import { createTheme } from "@mui/material/styles"; //Функция создания темы MUI
|
||||||
|
import { P8P_TYPOGRAPHY } from "./p8p_typography"; //Кастомные шрифты
|
||||||
|
import { P8P_PALETTE } from "./p8p_palette"; //Кастомная палитра
|
||||||
|
import { P8P_COMPONENTS } from "./p8p_components"; //Кастомные компоненты
|
||||||
|
|
||||||
|
//----------------
|
||||||
|
//Интерфейс модуля
|
||||||
|
//----------------
|
||||||
|
|
||||||
|
//Кастомная тема MUI
|
||||||
|
export const theme = createTheme({
|
||||||
|
palette: P8P_PALETTE,
|
||||||
|
typography: P8P_TYPOGRAPHY,
|
||||||
|
components: P8P_COMPONENTS
|
||||||
|
});
|
||||||
43
app/theme/utils.js
Normal file
43
app/theme/utils.js
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
//---------------------
|
||||||
|
//Подключение библиотек
|
||||||
|
//---------------------
|
||||||
|
|
||||||
|
import { alpha } from "@mui/material/styles"; //Интерфейсные стили компонентов
|
||||||
|
|
||||||
|
//----------------
|
||||||
|
//Интерфейс модуля
|
||||||
|
//----------------
|
||||||
|
|
||||||
|
//Универсальное определение цвета кнопки
|
||||||
|
export const getButtonColorStyles = (color, theme, isOutlined = false) => {
|
||||||
|
//Определяем цвет
|
||||||
|
const colorObj = !color ? theme.palette.primary : theme.palette[color];
|
||||||
|
//Если цвет неопределен или нет разбивки на оттенки
|
||||||
|
if (!colorObj || typeof colorObj !== "object" || !colorObj.main) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
//Возвращаем результат
|
||||||
|
return {
|
||||||
|
backgroundColor: !isOutlined ? colorObj.main : null,
|
||||||
|
color: !isOutlined ? colorObj.contrastText || "#FFF" : colorObj.main,
|
||||||
|
...(isOutlined ? { border: `1px solid ${colorObj.main}` } : {}),
|
||||||
|
"&:hover": {
|
||||||
|
textDecoration: "none",
|
||||||
|
backgroundColor: !isOutlined ? colorObj.dark || colorObj.main : alpha(colorObj.dark, 0.04),
|
||||||
|
...(!isOutlined
|
||||||
|
? { boxShadow: "0px 2px 4px -1px rgba(0,0,0,0.2),0px 4px 5px 0px rgba(0,0,0,0.14),0px 1px 10px 0px rgba(0,0,0,0.12)" }
|
||||||
|
: {})
|
||||||
|
},
|
||||||
|
"&:active": {
|
||||||
|
backgroundColor: !isOutlined ? colorObj.light || colorObj.main : null,
|
||||||
|
...(!isOutlined
|
||||||
|
? { boxShadow: "0px 5px 5px -3px rgba(0, 0, 0, 0.2) 0px 8px 10px 1px rgba(0, 0, 0, 0.14) 0px 3px 14px 2px rgba(0, 0, 0, 0.12)" }
|
||||||
|
: {})
|
||||||
|
},
|
||||||
|
"&.Mui-disabled": {
|
||||||
|
boxShadow: "none",
|
||||||
|
backgroundColor: "rgba(0, 0, 0, 0.12)",
|
||||||
|
color: "rgba(0, 0, 0, 0.26)"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
33
app/theme/variants/p8p_app_bar_variants.js
Normal file
33
app/theme/variants/p8p_app_bar_variants.js
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
/*
|
||||||
|
Парус 8 - Панели мониторинга
|
||||||
|
Расширение стилистики AppBar
|
||||||
|
*/
|
||||||
|
|
||||||
|
//----------------
|
||||||
|
//Интерфейс модуля
|
||||||
|
//----------------
|
||||||
|
|
||||||
|
//Кастомные области заголовка
|
||||||
|
export const P8P_APP_BARS = {
|
||||||
|
primary: {},
|
||||||
|
P8PFixed: { position: "fixed" },
|
||||||
|
P8PRelative: { position: "relative" }
|
||||||
|
};
|
||||||
|
|
||||||
|
//Наименование кастомных областей заголовка
|
||||||
|
export const P8P_APP_BAR_VARIANT = {
|
||||||
|
FIXED: "P8PFixed",
|
||||||
|
RELATIVE: "P8PRelative"
|
||||||
|
};
|
||||||
|
|
||||||
|
//Кастомная стилистика компонента
|
||||||
|
export const P8P_APP_BAR_OVERRIDES = {
|
||||||
|
styleOverrides: {
|
||||||
|
root: ({ ownerState }) => {
|
||||||
|
//Определяем вариант
|
||||||
|
const variant = ownerState["variant"] || "primary";
|
||||||
|
//Возвращаем стили варианта
|
||||||
|
return P8P_APP_BARS[variant];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
31
app/theme/variants/p8p_autocomplete_variants.js
Normal file
31
app/theme/variants/p8p_autocomplete_variants.js
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
/*
|
||||||
|
Парус 8 - Панели мониторинга
|
||||||
|
Расширение стилистики Autocomplete
|
||||||
|
*/
|
||||||
|
|
||||||
|
//----------------
|
||||||
|
//Интерфейс модуля
|
||||||
|
//----------------
|
||||||
|
|
||||||
|
//Кастомные поля выбора
|
||||||
|
export const P8P_AUTOCOMPLETES = theme => ({
|
||||||
|
primary: {},
|
||||||
|
P8PPrimary: { ...theme.typography.P8PBody1 }
|
||||||
|
});
|
||||||
|
|
||||||
|
//Наименование кастомных полей выбора
|
||||||
|
export const P8P_AUTOCOMPLETE_VARIANT = {
|
||||||
|
PRIMARY: "P8PPrimary"
|
||||||
|
};
|
||||||
|
|
||||||
|
//Кастомная стилистика компонента
|
||||||
|
export const P8P_AUTOCOMPLETE_OVERRIDES = {
|
||||||
|
styleOverrides: {
|
||||||
|
option: ({ ownerState, theme }) => {
|
||||||
|
//Определяем вариант
|
||||||
|
const variant = ownerState["variant"] || "primary";
|
||||||
|
//Возвращаем стили варианта
|
||||||
|
return P8P_AUTOCOMPLETES(theme)[variant];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
106
app/theme/variants/p8p_button_variants.js
Normal file
106
app/theme/variants/p8p_button_variants.js
Normal file
@ -0,0 +1,106 @@
|
|||||||
|
/*
|
||||||
|
Парус 8 - Панели мониторинга
|
||||||
|
Расширение стилистики Button
|
||||||
|
*/
|
||||||
|
|
||||||
|
//---------------------
|
||||||
|
//Подключение библиотек
|
||||||
|
//---------------------
|
||||||
|
|
||||||
|
import { getButtonColorStyles } from "../utils"; //Дополнительные функции стилизации
|
||||||
|
import { P8P_COMPONENT_HEIGHT, P8P_COMPONENT_WIDTH } from "../styles/common"; //Стили - общие
|
||||||
|
|
||||||
|
//---------
|
||||||
|
//Константы
|
||||||
|
//---------
|
||||||
|
|
||||||
|
//Размеры кнопок
|
||||||
|
const P8P_BUTTON_SIZE = {
|
||||||
|
small: {
|
||||||
|
fontSize: "13px",
|
||||||
|
padding: "4px 22px"
|
||||||
|
},
|
||||||
|
medium: {
|
||||||
|
fontSize: "14px",
|
||||||
|
padding: "6px 22px"
|
||||||
|
},
|
||||||
|
large: {
|
||||||
|
fontSize: "15px",
|
||||||
|
padding: "8px 22px"
|
||||||
|
},
|
||||||
|
default: {
|
||||||
|
fontSize: "15px",
|
||||||
|
padding: "6px 22px"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
//Общие стили
|
||||||
|
const defaultStyles = (theme, size) => ({
|
||||||
|
borderRadius: "4px",
|
||||||
|
...theme.typography.P8PButton,
|
||||||
|
...(size ? P8P_BUTTON_SIZE[size] : P8P_BUTTON_SIZE.default)
|
||||||
|
});
|
||||||
|
|
||||||
|
//----------------
|
||||||
|
//Интерфейс модуля
|
||||||
|
//----------------
|
||||||
|
|
||||||
|
//Кастомные кнопки
|
||||||
|
export const P8P_BUTTONS = ({ theme, color, size }) => ({
|
||||||
|
P8PPrimary: {
|
||||||
|
...defaultStyles(theme, size),
|
||||||
|
...getButtonColorStyles(color === "primary" ? "P8PInfo" : color, theme)
|
||||||
|
},
|
||||||
|
P8PSecondary: {
|
||||||
|
...defaultStyles(theme, size),
|
||||||
|
...getButtonColorStyles(color === "primary" ? "P8PSecondary" : color, theme)
|
||||||
|
},
|
||||||
|
P8POutlined: {
|
||||||
|
...defaultStyles(theme, size),
|
||||||
|
...getButtonColorStyles(color === "primary" ? "P8PSecondary" : color, theme, true)
|
||||||
|
},
|
||||||
|
P8PText: {
|
||||||
|
...theme.typography.P8PSubtitle2,
|
||||||
|
...getButtonColorStyles(color === "primary" ? "P8PInfo" : color, theme, true),
|
||||||
|
...(size ? P8P_BUTTON_SIZE[size] : P8P_BUTTON_SIZE.default),
|
||||||
|
border: "none"
|
||||||
|
},
|
||||||
|
P8PDesktopPanel: {
|
||||||
|
fontSize: "12px",
|
||||||
|
textTransform: "none",
|
||||||
|
...P8P_COMPONENT_WIDTH({ width: "150px" }),
|
||||||
|
...P8P_COMPONENT_HEIGHT({ width: "90px" }),
|
||||||
|
// width: "150px",
|
||||||
|
// height: "90px",
|
||||||
|
flexDirection: "column",
|
||||||
|
justifyContent: "flex-start",
|
||||||
|
color: theme.palette.P8PDesktop.main,
|
||||||
|
"&:hover": { backgroundColor: theme.palette.P8PDesktop.hover }
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
//Наименование кастомных кнопок
|
||||||
|
export const P8P_BUTTON_VARIANT = {
|
||||||
|
PRIMARY: "P8PPrimary",
|
||||||
|
SECONDARY: "P8PSecondary",
|
||||||
|
OUTLINED: "P8POutlined",
|
||||||
|
TEXT: "P8PText",
|
||||||
|
DESKTOP_PANEL: "P8PDesktopPanel"
|
||||||
|
};
|
||||||
|
|
||||||
|
//Кастомная стилистика компонента
|
||||||
|
export const P8P_BUTTON_OVERRIDES = {
|
||||||
|
styleOverrides: {
|
||||||
|
root: ({ ownerState, theme }) => {
|
||||||
|
//Определяем цвет
|
||||||
|
const { color, size } = ownerState;
|
||||||
|
//Возвращаем варианты
|
||||||
|
return {
|
||||||
|
variants: Object.entries(P8P_BUTTONS({ theme, color, size })).map(([name, styles]) => ({
|
||||||
|
props: { variant: name },
|
||||||
|
style: styles
|
||||||
|
}))
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
31
app/theme/variants/p8p_card_actions_variants.js
Normal file
31
app/theme/variants/p8p_card_actions_variants.js
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
/*
|
||||||
|
Парус 8 - Панели мониторинга
|
||||||
|
Расширение стилистики CardActions
|
||||||
|
*/
|
||||||
|
|
||||||
|
//----------------
|
||||||
|
//Интерфейс модуля
|
||||||
|
//----------------
|
||||||
|
|
||||||
|
//Кастомные действия карточки
|
||||||
|
export const P8P_CARD_ACTIONS = {
|
||||||
|
primary: {},
|
||||||
|
P8PPanelCard: { marginTop: "auto", display: "flex", justifyContent: "flex-end", alignItems: "flex-start" }
|
||||||
|
};
|
||||||
|
|
||||||
|
//Наименование кастомных действий карточек
|
||||||
|
export const P8P_CARD_ACTIONS_VARIANT = {
|
||||||
|
PANEL_CARD: "P8PPanelCard"
|
||||||
|
};
|
||||||
|
|
||||||
|
//Кастомная стилистика компонента
|
||||||
|
export const P8P_CARD_ACTIONS_OVERRIDES = {
|
||||||
|
styleOverrides: {
|
||||||
|
root: ({ ownerState }) => {
|
||||||
|
//Определяем вариант
|
||||||
|
const variant = ownerState["variant"] || "primary";
|
||||||
|
//Возвращаем стили варианта
|
||||||
|
return P8P_CARD_ACTIONS[variant];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
44
app/theme/variants/p8p_card_variants.js
Normal file
44
app/theme/variants/p8p_card_variants.js
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
/*
|
||||||
|
Парус 8 - Панели мониторинга
|
||||||
|
Расширение стилистики Card
|
||||||
|
*/
|
||||||
|
|
||||||
|
//---------------------
|
||||||
|
//Подключение библиотек
|
||||||
|
//---------------------
|
||||||
|
|
||||||
|
import { P8P_COMPONENT_HEIGHT, P8P_COMPONENT_WIDTH } from "../styles/common"; //Стили - общие
|
||||||
|
|
||||||
|
//----------------
|
||||||
|
//Интерфейс модуля
|
||||||
|
//----------------
|
||||||
|
|
||||||
|
//Кастомные карточки
|
||||||
|
export const P8P_CARDS = {
|
||||||
|
primary: {},
|
||||||
|
P8PPanelInfo: {
|
||||||
|
...P8P_COMPONENT_WIDTH({ maxWidth: 400 }),
|
||||||
|
...P8P_COMPONENT_HEIGHT({ height: "100%" }),
|
||||||
|
//maxWidth: 400,
|
||||||
|
//height: "100%",
|
||||||
|
flexDirection: "column",
|
||||||
|
display: "flex"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
//Наименование кастомных карточек
|
||||||
|
export const P8P_CARD_VARIANT = {
|
||||||
|
PANEL_INFO: "P8PPanelInfo"
|
||||||
|
};
|
||||||
|
|
||||||
|
//Кастомная стилистика компонента
|
||||||
|
export const P8P_CARD_OVERRIDES = {
|
||||||
|
styleOverrides: {
|
||||||
|
root: ({ ownerState }) => {
|
||||||
|
//Определяем вариант
|
||||||
|
const variant = ownerState["variant"] || "primary";
|
||||||
|
//Возвращаем стили варианта
|
||||||
|
return P8P_CARDS[variant];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
48
app/theme/variants/p8p_container_variants.js
Normal file
48
app/theme/variants/p8p_container_variants.js
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
/*
|
||||||
|
Парус 8 - Панели мониторинга
|
||||||
|
Расширение стилистики Container
|
||||||
|
*/
|
||||||
|
|
||||||
|
//---------------------
|
||||||
|
//Подключение библиотек
|
||||||
|
//---------------------
|
||||||
|
|
||||||
|
import { P8P_COMPONENT_WIDTH } from "../styles/common"; //Стили - общие
|
||||||
|
|
||||||
|
//----------------
|
||||||
|
//Интерфейс модуля
|
||||||
|
//----------------
|
||||||
|
|
||||||
|
//Кастомные контейнеры
|
||||||
|
export const P8P_CONTAINERS = {
|
||||||
|
primary: {},
|
||||||
|
P8PTableMoreButton: {
|
||||||
|
...P8P_COMPONENT_WIDTH({ width: "100%" }),
|
||||||
|
//width: "100%",
|
||||||
|
textAlign: "center",
|
||||||
|
padding: "5px"
|
||||||
|
},
|
||||||
|
P8PInlineMessage: {
|
||||||
|
...P8P_COMPONENT_WIDTH({ width: "100%" }),
|
||||||
|
//width: "100%",
|
||||||
|
textAlign: "center"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
//Наименование кастомных контейнеров
|
||||||
|
export const P8P_CONTAINER_VARIANT = {
|
||||||
|
TABLE_MORE_BUTTON: "P8PTableMoreButton",
|
||||||
|
INLINE_MSG: "P8PInlineMessage"
|
||||||
|
};
|
||||||
|
|
||||||
|
//Кастомная стилистика компонента
|
||||||
|
export const P8P_CONTAINER_OVERRIDES = {
|
||||||
|
styleOverrides: {
|
||||||
|
root: ({ ownerState }) => {
|
||||||
|
//Определяем вариант
|
||||||
|
const variant = ownerState?.variant || "primary";
|
||||||
|
//Возвращаем стили варианта
|
||||||
|
return P8P_CONTAINERS[variant];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
37
app/theme/variants/p8p_dialog_content_text_variants.js
Normal file
37
app/theme/variants/p8p_dialog_content_text_variants.js
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
/*
|
||||||
|
Парус 8 - Панели мониторинга
|
||||||
|
Расширение стилистики DialogContentText
|
||||||
|
*/
|
||||||
|
|
||||||
|
//----------------
|
||||||
|
//Интерфейс модуля
|
||||||
|
//----------------
|
||||||
|
|
||||||
|
//Кастомные диалоги (текстовое содержимое)
|
||||||
|
export const P8P_DIALOG_CONTENT_TEXTS = theme => ({
|
||||||
|
primary: {},
|
||||||
|
P8PPrimary: { ...theme.typography.P8PBody1 },
|
||||||
|
P8PInfo: { color: theme.palette.P8PText.primary, ...theme.typography.P8PBody1 },
|
||||||
|
P8PWarn: { color: theme.palette.P8PWarning.main, ...theme.typography.P8PBody1 },
|
||||||
|
P8PError: { color: theme.palette.P8PError.main, ...theme.typography.P8PBody1 }
|
||||||
|
});
|
||||||
|
|
||||||
|
//Наименование кастомных диалогов (текстовое содержимое)
|
||||||
|
export const P8P_DIALOG_CONTENT_TEXT_VARIANT = {
|
||||||
|
PRIMARY: "P8PPrimary",
|
||||||
|
INFO: "P8PInfo",
|
||||||
|
WARN: "P8PWarn",
|
||||||
|
ERROR: "P8PError"
|
||||||
|
};
|
||||||
|
|
||||||
|
//Кастомная стилистика компонента
|
||||||
|
export const P8P_DIALOG_CONTENT_TEXT_OVERRIDES = {
|
||||||
|
styleOverrides: {
|
||||||
|
root: ({ ownerState, theme }) => {
|
||||||
|
//Определяем вариант
|
||||||
|
const variant = ownerState["variant"] || "primary";
|
||||||
|
//Возвращаем стили варианта
|
||||||
|
return P8P_DIALOG_CONTENT_TEXTS(theme)[variant];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
48
app/theme/variants/p8p_dialog_content_variants.js
Normal file
48
app/theme/variants/p8p_dialog_content_variants.js
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
/*
|
||||||
|
Парус 8 - Панели мониторинга
|
||||||
|
Расширение стилистики DialogContent
|
||||||
|
*/
|
||||||
|
|
||||||
|
//---------------------
|
||||||
|
//Подключение библиотек
|
||||||
|
//---------------------
|
||||||
|
|
||||||
|
import { APP_STYLES } from "../../../app.styles"; //Типовые стили
|
||||||
|
import { P8P_COMPONENT_WIDTH } from "../styles/common"; //Стили - общие
|
||||||
|
|
||||||
|
//----------------
|
||||||
|
//Интерфейс модуля
|
||||||
|
//----------------
|
||||||
|
|
||||||
|
//Кастомные диалоги (содержимое)
|
||||||
|
export const P8P_DIALOG_CONTENTS = theme => ({
|
||||||
|
primary: {},
|
||||||
|
P8PPrimary: { overflow: "auto", ...APP_STYLES.SCROLL },
|
||||||
|
P8PTask: {
|
||||||
|
...P8P_COMPONENT_WIDTH({ minWidth: 400 }),
|
||||||
|
//minWidth: 400,
|
||||||
|
overflowX: "auto"
|
||||||
|
},
|
||||||
|
P8PHint: { ...theme.typography.P8PBody4, color: theme.palette.P8PText.primary },
|
||||||
|
P8PHidden: { display: "flex", flexDirection: "column", overflow: "hidden" }
|
||||||
|
});
|
||||||
|
|
||||||
|
//Наименование кастомных диалогов (содержимое)
|
||||||
|
export const P8P_DIALOG_CONTENT_VARIANT = {
|
||||||
|
PRIMARY: "P8PPrimary",
|
||||||
|
TASK: "P8PTask",
|
||||||
|
HINT: "P8PHint",
|
||||||
|
HIDDEN: "P8PHidden"
|
||||||
|
};
|
||||||
|
|
||||||
|
//Кастомная стилистика компонента
|
||||||
|
export const P8P_DIALOG_CONTENT_OVERRIDES = {
|
||||||
|
styleOverrides: {
|
||||||
|
root: ({ ownerState, theme }) => {
|
||||||
|
//Определяем вариант
|
||||||
|
const variant = ownerState["variant"] || "primary";
|
||||||
|
//Возвращаем стили варианта
|
||||||
|
return P8P_DIALOG_CONTENTS(theme)[variant];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
37
app/theme/variants/p8p_dialog_title_variants.js
Normal file
37
app/theme/variants/p8p_dialog_title_variants.js
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
/*
|
||||||
|
Парус 8 - Панели мониторинга
|
||||||
|
Расширение стилистики DialogTitle
|
||||||
|
*/
|
||||||
|
|
||||||
|
//----------------
|
||||||
|
//Интерфейс модуля
|
||||||
|
//----------------
|
||||||
|
|
||||||
|
//Кастомные диалоги (заголовок)
|
||||||
|
export const P8P_DIALOG_TITLES = theme => ({
|
||||||
|
primary: {},
|
||||||
|
P8PPrimary: { ...theme.typography.P8PH6, color: theme.palette.P8PText.primary },
|
||||||
|
P8PInfo: { ...theme.typography.P8PH6, color: theme.palette.P8PText.primary },
|
||||||
|
P8PWarn: { ...theme.typography.P8PH6, color: theme.palette.P8PWarning.main },
|
||||||
|
P8PError: { ...theme.typography.P8PH6, color: theme.palette.P8PError.main }
|
||||||
|
});
|
||||||
|
|
||||||
|
//Наименование кастомных диалогов (заголовок)
|
||||||
|
export const P8P_DIALOG_TITLE_VARIANT = {
|
||||||
|
PRIMARY: "P8PPrimary",
|
||||||
|
INFO: "P8PInfo",
|
||||||
|
WARN: "P8PWarn",
|
||||||
|
ERROR: "P8PError"
|
||||||
|
};
|
||||||
|
|
||||||
|
//Кастомная стилистика компонента
|
||||||
|
export const P8P_DIALOG_TITLE_OVERRIDES = {
|
||||||
|
styleOverrides: {
|
||||||
|
root: ({ ownerState, theme }) => {
|
||||||
|
//Определяем вариант
|
||||||
|
const variant = ownerState["variant"] || "primary";
|
||||||
|
//Возвращаем стили варианта
|
||||||
|
return P8P_DIALOG_TITLES(theme)[variant];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
37
app/theme/variants/p8p_drawer_variants.js
Normal file
37
app/theme/variants/p8p_drawer_variants.js
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
/*
|
||||||
|
Парус 8 - Панели мониторинга
|
||||||
|
Расширение стилистики Drawer
|
||||||
|
*/
|
||||||
|
|
||||||
|
//---------------------
|
||||||
|
//Подключение библиотек
|
||||||
|
//---------------------
|
||||||
|
|
||||||
|
import { APP_STYLES } from "../../../app.styles"; //Типовые стили
|
||||||
|
|
||||||
|
//----------------
|
||||||
|
//Интерфейс модуля
|
||||||
|
//----------------
|
||||||
|
|
||||||
|
//Кастомные выезжающие области
|
||||||
|
export const P8P_DRAWERS = {
|
||||||
|
primary: {},
|
||||||
|
P8PPrimary: { [`& .MuiDrawer-paper`]: { ...APP_STYLES.SCROLL } }
|
||||||
|
};
|
||||||
|
|
||||||
|
//Наименование кастомных выезжающих областей
|
||||||
|
export const P8P_DRAWER_VARIANT = {
|
||||||
|
PRIMARY: "P8PPrimary"
|
||||||
|
};
|
||||||
|
|
||||||
|
//Кастомная стилистика компонента
|
||||||
|
export const P8P_DRAWER_OVERRIDES = {
|
||||||
|
styleOverrides: {
|
||||||
|
root: ({ ownerState }) => {
|
||||||
|
//Определяем вариант
|
||||||
|
const variant = ownerState["data-variant"] || "primary";
|
||||||
|
//Возвращаем стили варианта
|
||||||
|
return P8P_DRAWERS[variant];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
52
app/theme/variants/p8p_grid_variants.js
Normal file
52
app/theme/variants/p8p_grid_variants.js
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
/*
|
||||||
|
Парус 8 - Панели мониторинга
|
||||||
|
Расширение стилистики Grid
|
||||||
|
*/
|
||||||
|
|
||||||
|
//---------------------
|
||||||
|
//Подключение библиотек
|
||||||
|
//---------------------
|
||||||
|
|
||||||
|
import { P8P_COMPONENT_HEIGHT, P8P_COMPONENT_WIDTH } from "../styles/common"; //Стили - общие
|
||||||
|
|
||||||
|
//----------------
|
||||||
|
//Интерфейс модуля
|
||||||
|
//----------------
|
||||||
|
|
||||||
|
//Кастомные сетки
|
||||||
|
export const P8P_GRIDS = {
|
||||||
|
primary: {},
|
||||||
|
P8PPrimary: {},
|
||||||
|
P8PSvgContainer: {
|
||||||
|
...P8P_COMPONENT_WIDTH({ width: "100%" }),
|
||||||
|
...P8P_COMPONENT_HEIGHT({ height: "100%" })
|
||||||
|
//width: "100%",
|
||||||
|
//height: "100%"
|
||||||
|
},
|
||||||
|
P8PPanelsMenu: {
|
||||||
|
...P8P_COMPONENT_WIDTH({ maxWidth: 1200 }),
|
||||||
|
//maxWidth: 1200,
|
||||||
|
direction: "row",
|
||||||
|
justifyContent: "left",
|
||||||
|
alignItems: "stretch"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
//Наименование кастомных сеток
|
||||||
|
export const P8P_GRID_VARIANT = {
|
||||||
|
PRIMARY: "P8PPrimary",
|
||||||
|
SVG_CONTAINER: "P8PSvgContainer",
|
||||||
|
PANELS_MENU: "P8PPanelsMenu"
|
||||||
|
};
|
||||||
|
|
||||||
|
//Кастомная стилистика компонента
|
||||||
|
export const P8P_GRID_OVERRIDES = {
|
||||||
|
styleOverrides: {
|
||||||
|
root: ({ ownerState }) => {
|
||||||
|
//Определяем вариант
|
||||||
|
const variant = ownerState["variant"] || "primary";
|
||||||
|
//Возвращаем стили варианта
|
||||||
|
return P8P_GRIDS[variant];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
33
app/theme/variants/p8p_icon_button_variants.js
Normal file
33
app/theme/variants/p8p_icon_button_variants.js
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
/*
|
||||||
|
Парус 8 - Панели мониторинга
|
||||||
|
Расширение стилистики IconButton
|
||||||
|
*/
|
||||||
|
|
||||||
|
//----------------
|
||||||
|
//Интерфейс модуля
|
||||||
|
//----------------
|
||||||
|
|
||||||
|
//Кастомные кнопки-иконки
|
||||||
|
export const P8P_ICON_BUTTONS = {
|
||||||
|
primary: {},
|
||||||
|
P8PAppBarButton: {
|
||||||
|
marginRight: "16px"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
//Наименования кастомных кнопок-иконкок
|
||||||
|
export const P8P_ICON_BUTTON_VARIANT = {
|
||||||
|
APP_BAR_BUTTON: "P8PAppBarButton"
|
||||||
|
};
|
||||||
|
|
||||||
|
//Кастомная стилистика компонента
|
||||||
|
export const P8P_ICON_BUTTON_OVERRIDES = {
|
||||||
|
styleOverrides: {
|
||||||
|
root: ({ ownerState }) => {
|
||||||
|
//Определяем вариант
|
||||||
|
const variant = ownerState?.variant || "primary";
|
||||||
|
//Возвращаем стили варианта
|
||||||
|
return P8P_ICON_BUTTONS[variant];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
51
app/theme/variants/p8p_icon_variants.js
Normal file
51
app/theme/variants/p8p_icon_variants.js
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
/*
|
||||||
|
Парус 8 - Панели мониторинга
|
||||||
|
Расширение стилистики Icon
|
||||||
|
*/
|
||||||
|
|
||||||
|
//---------------------
|
||||||
|
//Подключение библиотек
|
||||||
|
//---------------------
|
||||||
|
|
||||||
|
import { P8P_COMPONENT_HEIGHT, P8P_COMPONENT_WIDTH } from "../styles/common"; //Стили - общие
|
||||||
|
|
||||||
|
//----------------
|
||||||
|
//Интерфейс модуля
|
||||||
|
//----------------
|
||||||
|
|
||||||
|
//Кастомные иконки
|
||||||
|
export const P8P_ICONS = {
|
||||||
|
primary: {},
|
||||||
|
P8PTableColumnMenu: {
|
||||||
|
marginRight: "10px"
|
||||||
|
},
|
||||||
|
P8PPanelMenuTitle: {
|
||||||
|
paddingTop: "4px"
|
||||||
|
},
|
||||||
|
P8PDesktopPanel: {
|
||||||
|
...P8P_COMPONENT_WIDTH({ width: "48px" }),
|
||||||
|
...P8P_COMPONENT_HEIGHT({ height: "48px" }),
|
||||||
|
// width: "48px",
|
||||||
|
// height: "48px",
|
||||||
|
fontSize: "48px"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
//Наименование кастомных иконок
|
||||||
|
export const P8P_ICON_VARIANT = {
|
||||||
|
TABLE_COLUMN_MENU: "P8PTableColumnMenu",
|
||||||
|
PANEL_MENU_TITLE: "P8PPanelMenuTitle",
|
||||||
|
DESKTOP_PANEL: "P8PDesktopPanel"
|
||||||
|
};
|
||||||
|
|
||||||
|
//Кастомная стилистика компонента
|
||||||
|
export const P8P_ICON_OVERRIDES = {
|
||||||
|
styleOverrides: {
|
||||||
|
root: ({ ownerState }) => {
|
||||||
|
//Определяем вариант
|
||||||
|
const variant = ownerState?.variant || "primary";
|
||||||
|
//Возвращаем стили варианта
|
||||||
|
return P8P_ICONS[variant];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
31
app/theme/variants/p8p_input_label_variants.js
Normal file
31
app/theme/variants/p8p_input_label_variants.js
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
/*
|
||||||
|
Парус 8 - Панели мониторинга
|
||||||
|
Расширение стилистики InputLabel
|
||||||
|
*/
|
||||||
|
|
||||||
|
//----------------
|
||||||
|
//Интерфейс модуля
|
||||||
|
//----------------
|
||||||
|
|
||||||
|
//Кастомные метки ввода
|
||||||
|
export const P8P_INPUT_LABELS = theme => ({
|
||||||
|
primary: {},
|
||||||
|
P8PPrimary: { ...theme.typography.P8PInputLabel }
|
||||||
|
});
|
||||||
|
|
||||||
|
//Наименование кастомных меток ввода
|
||||||
|
export const P8P_INPUT_LABEL_VARIANT = {
|
||||||
|
PRIMARY: "P8PPrimary"
|
||||||
|
};
|
||||||
|
|
||||||
|
//Кастомная стилистика компонента
|
||||||
|
export const P8P_INPUT_LABEL_OVERRIDES = {
|
||||||
|
styleOverrides: {
|
||||||
|
root: ({ ownerState, theme }) => {
|
||||||
|
//Определяем вариант
|
||||||
|
const variant = ownerState["data-variant"] || "primary";
|
||||||
|
//Возвращаем стили варианта
|
||||||
|
return P8P_INPUT_LABELS(theme)[variant];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
40
app/theme/variants/p8p_input_variants.js
Normal file
40
app/theme/variants/p8p_input_variants.js
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
/*
|
||||||
|
Парус 8 - Панели мониторинга
|
||||||
|
Расширение стилистики Input
|
||||||
|
*/
|
||||||
|
|
||||||
|
//----------------
|
||||||
|
//Интерфейс модуля
|
||||||
|
//----------------
|
||||||
|
|
||||||
|
//Кастомные поля ввода
|
||||||
|
export const P8P_INPUTS = theme => ({
|
||||||
|
primary: {},
|
||||||
|
P8PPrimary: {
|
||||||
|
"& .MuiOutlinedInput-notchedOutline": {
|
||||||
|
"& legend": {
|
||||||
|
fontFamily: theme.typography.P8PFontMontserrat
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"& .MuiInputBase-input": {
|
||||||
|
...theme.typography.P8PBody1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
//Наименование кастомных полей ввода
|
||||||
|
export const P8P_INPUT_VARIANT = {
|
||||||
|
PRIMARY: "P8PPrimary"
|
||||||
|
};
|
||||||
|
|
||||||
|
//Кастомная стилистика компонента
|
||||||
|
export const P8P_INPUT_OVERRIDES = {
|
||||||
|
styleOverrides: {
|
||||||
|
root: ({ ownerState, theme }) => {
|
||||||
|
//Определяем вариант
|
||||||
|
const variant = ownerState["variant"] || "primary";
|
||||||
|
//Возвращаем стили варианта
|
||||||
|
return P8P_INPUTS(theme)[variant];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
38
app/theme/variants/p8p_list_item_text_variants.js
Normal file
38
app/theme/variants/p8p_list_item_text_variants.js
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
/*
|
||||||
|
Парус 8 - Панели мониторинга
|
||||||
|
Расширение стилистики ListItemText
|
||||||
|
*/
|
||||||
|
|
||||||
|
//----------------
|
||||||
|
//Интерфейс модуля
|
||||||
|
//----------------
|
||||||
|
|
||||||
|
//Кастомные значения списков
|
||||||
|
export const P8P_LIST_ITEM_TEXTS = theme => ({
|
||||||
|
primary: {},
|
||||||
|
P8PPrimary: {
|
||||||
|
"& .MuiListItemText-primary": {
|
||||||
|
...theme.typography.P8PBody1
|
||||||
|
},
|
||||||
|
"& .MuiListItemText-secondary": {
|
||||||
|
...theme.typography.P8PBody3
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
//Наименование кастомных значений списков
|
||||||
|
export const P8P_LIST_ITEM_TEXT_VARIANT = {
|
||||||
|
PRIMARY: "P8PPrimary"
|
||||||
|
};
|
||||||
|
|
||||||
|
//Кастомная стилистика компонента
|
||||||
|
export const P8P_LIST_ITEM_TEXT_OVERRIDES = {
|
||||||
|
styleOverrides: {
|
||||||
|
root: ({ ownerState, theme }) => {
|
||||||
|
//Определяем вариант
|
||||||
|
const variant = ownerState["variant"] || "primary";
|
||||||
|
//Возвращаем стили варианта
|
||||||
|
return P8P_LIST_ITEM_TEXTS(theme)[variant];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
46
app/theme/variants/p8p_list_variants.js
Normal file
46
app/theme/variants/p8p_list_variants.js
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
/*
|
||||||
|
Парус 8 - Панели мониторинга
|
||||||
|
Расширение стилистики List
|
||||||
|
*/
|
||||||
|
|
||||||
|
//---------------------
|
||||||
|
//Подключение библиотек
|
||||||
|
//---------------------
|
||||||
|
|
||||||
|
import { P8P_COMPONENT_WIDTH } from "../styles/common"; //Стили - общие
|
||||||
|
|
||||||
|
//----------------
|
||||||
|
//Интерфейс модуля
|
||||||
|
//----------------
|
||||||
|
|
||||||
|
//Кастомные списки
|
||||||
|
export const P8P_LISTS = {
|
||||||
|
primary: {},
|
||||||
|
P8PGanttTask: {
|
||||||
|
...P8P_COMPONENT_WIDTH({ width: "100%", minWidth: 300, maxWidth: 700 })
|
||||||
|
//width: "100%", minWidth: 300, maxWidth: 700
|
||||||
|
},
|
||||||
|
P8PSettings: {
|
||||||
|
...P8P_COMPONENT_WIDTH({ width: "510px" }),
|
||||||
|
//width: "510px",
|
||||||
|
overflowY: "auto"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
//Наименование кастомных списков
|
||||||
|
export const P8P_LIST_VARIANT = {
|
||||||
|
GANTT_TASK: "P8PGanttTask",
|
||||||
|
SETTINGS: "P8PSettings"
|
||||||
|
};
|
||||||
|
|
||||||
|
//Кастомная стилистика компонента
|
||||||
|
export const P8P_LIST_OVERRIDES = {
|
||||||
|
styleOverrides: {
|
||||||
|
root: ({ ownerState }) => {
|
||||||
|
//Определяем вариант
|
||||||
|
const variant = ownerState["variant"] || "primary";
|
||||||
|
//Возвращаем стили варианта
|
||||||
|
return P8P_LISTS[variant];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
31
app/theme/variants/p8p_menu_item_variants.js
Normal file
31
app/theme/variants/p8p_menu_item_variants.js
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
/*
|
||||||
|
Парус 8 - Панели мониторинга
|
||||||
|
Расширение стилистики MenuItem
|
||||||
|
*/
|
||||||
|
|
||||||
|
//----------------
|
||||||
|
//Интерфейс модуля
|
||||||
|
//----------------
|
||||||
|
|
||||||
|
//Кастомные элементы меню
|
||||||
|
export const P8P_MENU_ITEMS = theme => ({
|
||||||
|
primary: {},
|
||||||
|
P8PPrimary: { ...theme.typography.P8PBody1 }
|
||||||
|
});
|
||||||
|
|
||||||
|
//Наименование кастомных элементов меню
|
||||||
|
export const P8P_MENU_ITEM_VARIANT = {
|
||||||
|
PRIMARY: "P8PPrimary"
|
||||||
|
};
|
||||||
|
|
||||||
|
//Кастомная стилистика компонента
|
||||||
|
export const P8P_MENU_ITEM_OVERRIDES = {
|
||||||
|
styleOverrides: {
|
||||||
|
root: ({ ownerState, theme }) => {
|
||||||
|
//Определяем вариант
|
||||||
|
const variant = ownerState["variant"] || "primary";
|
||||||
|
//Возвращаем стили варианта
|
||||||
|
return P8P_MENU_ITEMS(theme)[variant];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
51
app/theme/variants/p8p_pagination_variants.js
Normal file
51
app/theme/variants/p8p_pagination_variants.js
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
/*
|
||||||
|
Парус 8 - Панели мониторинга
|
||||||
|
Расширение стилистики Pagination
|
||||||
|
*/
|
||||||
|
|
||||||
|
//---------------------
|
||||||
|
//Подключение библиотек
|
||||||
|
//---------------------
|
||||||
|
|
||||||
|
import { P8P_TABLE_PAGINATOR_ALIGN, P8P_TABLE_PAGINATOR_POSITION } from "../../components/p8p_table/p8p_table_constants"; //Константы таблиц
|
||||||
|
|
||||||
|
//----------------
|
||||||
|
//Интерфейс модуля
|
||||||
|
//----------------
|
||||||
|
|
||||||
|
//Кастомные пагинаторы
|
||||||
|
export const P8P_PAGINATIONS = ({ theme, pagesAlign, position }) => ({
|
||||||
|
primary: {},
|
||||||
|
P8PTablePagination: {
|
||||||
|
display: "flex",
|
||||||
|
justifyContent:
|
||||||
|
pagesAlign === P8P_TABLE_PAGINATOR_ALIGN.LEFT
|
||||||
|
? "flex-start"
|
||||||
|
: pagesAlign === P8P_TABLE_PAGINATOR_ALIGN.CENTER
|
||||||
|
? "space-around"
|
||||||
|
: "flex-end",
|
||||||
|
...(position === P8P_TABLE_PAGINATOR_POSITION.TOP ? { paddingBottom: "10px" } : { paddingTop: "10px" }),
|
||||||
|
"& .MuiPaginationItem-root": {
|
||||||
|
...theme.typography.P8PBody2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
//Наименование кастомных пагинаторов
|
||||||
|
export const P8P_PAGINATION_VARIANT = {
|
||||||
|
TABLE_PAGINATION: "P8PTablePagination"
|
||||||
|
};
|
||||||
|
|
||||||
|
//Кастомная стилистика компонента
|
||||||
|
export const P8P_PAGINATION_OVERRIDES = {
|
||||||
|
styleOverrides: {
|
||||||
|
root: ({ ownerState, theme }) => {
|
||||||
|
//Определяем вариант
|
||||||
|
const variant = ownerState?.variant || "primary";
|
||||||
|
//Определяем доп. параметры
|
||||||
|
const { pagesAlign, position } = ownerState["data-variant-props"] || {};
|
||||||
|
//Возвращаем стили варианта
|
||||||
|
return P8P_PAGINATIONS({ theme, pagesAlign, position })[variant];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
38
app/theme/variants/p8p_select_variants.js
Normal file
38
app/theme/variants/p8p_select_variants.js
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
/*
|
||||||
|
Парус 8 - Панели мониторинга
|
||||||
|
Расширение стилистики Select
|
||||||
|
*/
|
||||||
|
|
||||||
|
//----------------
|
||||||
|
//Интерфейс модуля
|
||||||
|
//----------------
|
||||||
|
|
||||||
|
//Кастомные поля выбора
|
||||||
|
export const P8P_SELECTS = theme => ({
|
||||||
|
primary: {},
|
||||||
|
P8PPrimary: {
|
||||||
|
"& .MuiOutlinedInput-notchedOutline": {
|
||||||
|
"& legend": {
|
||||||
|
fontFamily: theme.typography.P8PFontMontserrat
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"& .MuiSelect-select": { ...theme.typography.P8PBody1 }
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
//Наименование кастомных полей выбора
|
||||||
|
export const P8P_SELECT_VARIANT = {
|
||||||
|
PRIMARY: "P8PPrimary"
|
||||||
|
};
|
||||||
|
|
||||||
|
//Кастомная стилистика компонента
|
||||||
|
export const P8P_SELECT_OVERRIDES = {
|
||||||
|
styleOverrides: {
|
||||||
|
root: ({ ownerState, theme }) => {
|
||||||
|
//Определяем вариант
|
||||||
|
const variant = ownerState["data-variant"] || "primary";
|
||||||
|
//Возвращаем стили варианта
|
||||||
|
return P8P_SELECTS(theme)[variant];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
93
app/theme/variants/p8p_table_cell_variants.js
Normal file
93
app/theme/variants/p8p_table_cell_variants.js
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
/*
|
||||||
|
Парус 8 - Панели мониторинга
|
||||||
|
Расширение стилистики TableCell
|
||||||
|
*/
|
||||||
|
|
||||||
|
//---------
|
||||||
|
//Константы
|
||||||
|
//---------
|
||||||
|
|
||||||
|
//Общие стили
|
||||||
|
const STYLES = {
|
||||||
|
CELL_WIDTH: width => ({
|
||||||
|
...(width ? { minWidth: width, maxWidth: width } : {})
|
||||||
|
}),
|
||||||
|
CELL_DEF: (fixed, theme, left, isHeader = false) => ({
|
||||||
|
...(fixed
|
||||||
|
? {
|
||||||
|
position: "sticky",
|
||||||
|
left,
|
||||||
|
zIndex: isHeader ? 1000 : 500
|
||||||
|
}
|
||||||
|
: {})
|
||||||
|
})
|
||||||
|
};
|
||||||
|
|
||||||
|
//----------------
|
||||||
|
//Интерфейс модуля
|
||||||
|
//----------------
|
||||||
|
|
||||||
|
//Кастомные ячейки таблицы
|
||||||
|
export const P8P_TABLE_CELLS = ({ theme, width, fixed, left }) => ({
|
||||||
|
primary: {},
|
||||||
|
P8PGroupHeader: {
|
||||||
|
...theme.typography.P8PBody2,
|
||||||
|
...STYLES.CELL_WIDTH(width),
|
||||||
|
...(fixed ? { position: "sticky", left: 0 } : {})
|
||||||
|
},
|
||||||
|
P8PHeaderExpand: {
|
||||||
|
...theme.typography.P8PColumn,
|
||||||
|
...STYLES.CELL_WIDTH("60px"),
|
||||||
|
...STYLES.CELL_DEF(fixed, theme, 0, true),
|
||||||
|
backgroundColor: theme.palette.P8PBackground.tableHeader
|
||||||
|
},
|
||||||
|
P8PHeaderCell: {
|
||||||
|
...theme.typography.P8PColumn,
|
||||||
|
...STYLES.CELL_WIDTH(width),
|
||||||
|
...STYLES.CELL_DEF(fixed, theme, left, true),
|
||||||
|
backgroundColor: theme.palette.P8PBackground.tableHeader
|
||||||
|
},
|
||||||
|
P8PExpand: {
|
||||||
|
...theme.typography.P8PBody2,
|
||||||
|
...STYLES.CELL_WIDTH("60px"),
|
||||||
|
...STYLES.CELL_DEF(fixed, theme, 0),
|
||||||
|
backgroundColor: "inherit"
|
||||||
|
},
|
||||||
|
P8PCell: {
|
||||||
|
...theme.typography.P8PBody2,
|
||||||
|
...STYLES.CELL_WIDTH(width),
|
||||||
|
...STYLES.CELL_DEF(fixed, theme, left),
|
||||||
|
backgroundColor: "inherit"
|
||||||
|
},
|
||||||
|
P8PExpandContainer: {
|
||||||
|
paddingBottom: 0,
|
||||||
|
paddingTop: 0,
|
||||||
|
paddingLeft: 0,
|
||||||
|
paddingRight: 0,
|
||||||
|
...STYLES.CELL_DEF(fixed, theme, left)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
//Наименование кастомных ячеек таблиц
|
||||||
|
export const P8P_TABLE_CELL_VARIANT = {
|
||||||
|
GROUP_HEADER: "P8PGroupHeader",
|
||||||
|
HEADER_EXPAND: "P8PHeaderExpand",
|
||||||
|
HEADER_CELL: "P8PHeaderCell",
|
||||||
|
EXPAND: "P8PExpand",
|
||||||
|
CELL: "P8PCell",
|
||||||
|
EXPAND_CONTAINER: "P8PExpandContainer"
|
||||||
|
};
|
||||||
|
|
||||||
|
//Кастомная стилистика компонента
|
||||||
|
export const P8P_TABLE_CELL_OVERRIDES = {
|
||||||
|
styleOverrides: {
|
||||||
|
root: ({ ownerState, theme }) => {
|
||||||
|
//Определяем вариант
|
||||||
|
const variant = ownerState?.variant || "primary";
|
||||||
|
//Определяем доп. параметры
|
||||||
|
const { width, fixed, left } = ownerState["data-variant-props"] || {};
|
||||||
|
//Возвращаем стили варианта
|
||||||
|
return P8P_TABLE_CELLS({ theme, width, fixed, left })[variant];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
35
app/theme/variants/p8p_table_head_variants.js
Normal file
35
app/theme/variants/p8p_table_head_variants.js
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
/*
|
||||||
|
Парус 8 - Панели мониторинга
|
||||||
|
Расширение стилистики TableHead
|
||||||
|
*/
|
||||||
|
|
||||||
|
//----------------
|
||||||
|
//Интерфейс модуля
|
||||||
|
//----------------
|
||||||
|
|
||||||
|
//Кастомные заголовки таблицы
|
||||||
|
export const P8P_TABLE_HEADS = {
|
||||||
|
primary: {},
|
||||||
|
P8PSticky: {
|
||||||
|
position: "sticky",
|
||||||
|
top: 0,
|
||||||
|
zIndex: 1000
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
//Наименование кастомных заголовков таблиц
|
||||||
|
export const P8P_TABLE_HEAD_VARIANT = {
|
||||||
|
STICKY: "P8PSticky"
|
||||||
|
};
|
||||||
|
|
||||||
|
//Кастомная стилистика компонента
|
||||||
|
export const P8P_TABLE_HEAD_OVERRIDES = {
|
||||||
|
styleOverrides: {
|
||||||
|
root: ({ ownerState }) => {
|
||||||
|
//Определяем вариант
|
||||||
|
const variant = ownerState?.variant || "primary";
|
||||||
|
//Возвращаем стили варианта
|
||||||
|
return P8P_TABLE_HEADS[variant];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
33
app/theme/variants/p8p_table_row_variants.js
Normal file
33
app/theme/variants/p8p_table_row_variants.js
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
/*
|
||||||
|
Парус 8 - Панели мониторинга
|
||||||
|
Расширение стилистики TableRow
|
||||||
|
*/
|
||||||
|
|
||||||
|
//----------------
|
||||||
|
//Интерфейс модуля
|
||||||
|
//----------------
|
||||||
|
|
||||||
|
//Кастомные строки таблицы
|
||||||
|
export const P8P_TABLE_ROWS = {
|
||||||
|
primary: {},
|
||||||
|
P8PPrimary: {
|
||||||
|
"&:last-child td, &:last-child th": { border: 0 }
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
//Наименование кастомных строк таблиц
|
||||||
|
export const P8P_TABLE_ROW_VARIANT = {
|
||||||
|
PRIMARY: "P8PPrimary"
|
||||||
|
};
|
||||||
|
|
||||||
|
//Кастомная стилистика компонента
|
||||||
|
export const P8P_TABLE_ROW_OVERRIDES = {
|
||||||
|
styleOverrides: {
|
||||||
|
root: ({ ownerState }) => {
|
||||||
|
//Определяем вариант
|
||||||
|
const variant = ownerState?.variant || "primary";
|
||||||
|
//Возвращаем стили варианта
|
||||||
|
return P8P_TABLE_ROWS[variant];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
38
app/theme/variants/p8p_table_variants.js
Normal file
38
app/theme/variants/p8p_table_variants.js
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
/*
|
||||||
|
Парус 8 - Панели мониторинга
|
||||||
|
Расширение стилистики Table
|
||||||
|
*/
|
||||||
|
|
||||||
|
//----------------
|
||||||
|
//Интерфейс модуля
|
||||||
|
//----------------
|
||||||
|
|
||||||
|
//Кастомные таблицы
|
||||||
|
export const P8P_TABLES = theme => ({
|
||||||
|
primary: {},
|
||||||
|
P8PPrimary: {
|
||||||
|
".MuiTableRow-root:nth-of-type(even)": {
|
||||||
|
backgroundColor: theme.palette.P8PBackground.primary
|
||||||
|
},
|
||||||
|
".MuiTableRow-root:nth-of-type(odd)": {
|
||||||
|
backgroundColor: theme.palette.P8PBackground.secondary
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
//Наименование кастомных таблиц
|
||||||
|
export const P8P_TABLE_VARIANT = {
|
||||||
|
PRIMARY: "P8PPrimary"
|
||||||
|
};
|
||||||
|
|
||||||
|
//Кастомная стилистика компонента
|
||||||
|
export const P8P_TABLE_OVERRIDES = {
|
||||||
|
styleOverrides: {
|
||||||
|
root: ({ ownerState, theme }) => {
|
||||||
|
//Определяем вариант
|
||||||
|
const variant = ownerState?.variant || "primary";
|
||||||
|
//Возвращаем стили варианта
|
||||||
|
return P8P_TABLES(theme)[variant];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
56
app/theme/variants/p8p_text_field_variants.js
Normal file
56
app/theme/variants/p8p_text_field_variants.js
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
/*
|
||||||
|
Парус 8 - Панели мониторинга
|
||||||
|
Расширение стилистики TextField
|
||||||
|
*/
|
||||||
|
|
||||||
|
//----------------
|
||||||
|
//Интерфейс модуля
|
||||||
|
//----------------
|
||||||
|
|
||||||
|
//Кастомные поля ввода
|
||||||
|
export const P8P_TEXT_FIELDS = theme => ({
|
||||||
|
primary: {},
|
||||||
|
P8PPrimary: {
|
||||||
|
"& .MuiInputLabel-root": {
|
||||||
|
...theme.typography.P8PInputLabel
|
||||||
|
},
|
||||||
|
"& .MuiOutlinedInput-notchedOutline": {
|
||||||
|
"& legend": {
|
||||||
|
fontFamily: theme.typography.P8PFontMontserrat
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"& .MuiInputBase-input": {
|
||||||
|
...theme.typography.P8PBody1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
//Кастомные списки выбора
|
||||||
|
export const P8P_TEXT_FIELD_OPTIONS = theme => ({
|
||||||
|
primary: {},
|
||||||
|
P8PPrimary: { ...theme.typography.P8PBody1 }
|
||||||
|
});
|
||||||
|
|
||||||
|
//Наименование кастомных полей ввода
|
||||||
|
export const P8P_TEXT_FIELD_VARIANT = {
|
||||||
|
PRIMARY: "P8PPrimary"
|
||||||
|
};
|
||||||
|
|
||||||
|
//Кастомная стилистика компонента
|
||||||
|
export const P8P_TEXT_FIELD_OVERRIDES = {
|
||||||
|
styleOverrides: {
|
||||||
|
root: ({ ownerState, theme }) => {
|
||||||
|
//Определяем вариант
|
||||||
|
const variant = ownerState["data-variant"] || "primary";
|
||||||
|
//Возвращаем стили варианта
|
||||||
|
return P8P_TEXT_FIELDS(theme)[variant];
|
||||||
|
},
|
||||||
|
option: ({ ownerState, theme }) => {
|
||||||
|
//Определяем вариант
|
||||||
|
const variant = ownerState["data-variant"] || "primary";
|
||||||
|
console.log({ option: P8P_TEXT_FIELD_OPTIONS(theme)[variant] });
|
||||||
|
//Возвращаем стили варианта
|
||||||
|
return P8P_TEXT_FIELD_OPTIONS(theme)[variant];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
Loading…
x
Reference in New Issue
Block a user