WEB APP: Реализована интеграция главного меню в рабочий стол "Парус Онлайн"
This commit is contained in:
parent
1c02fc9684
commit
86a8b43c8c
24
app/app.js
24
app/app.js
@ -14,7 +14,7 @@ import { ApplicationСtx } from "./context/application"; //Контекст пр
|
|||||||
import { NavigationContext, NavigationCtx, getRootLocation } from "./context/navigation"; //Контекст навигации
|
import { NavigationContext, NavigationCtx, getRootLocation } from "./context/navigation"; //Контекст навигации
|
||||||
import { P8PAppErrorPage } from "./components/p8p_app_error_page"; //Страница с ошибкой
|
import { P8PAppErrorPage } from "./components/p8p_app_error_page"; //Страница с ошибкой
|
||||||
import { P8PAppWorkspace } from "./components/p8p_app_workspace"; //Рабочее пространство панели
|
import { P8PAppWorkspace } from "./components/p8p_app_workspace"; //Рабочее пространство панели
|
||||||
import { P8PPanelsMenuGrid, P8P_PANELS_MENU_PANEL_SHAPE } from "./components/p8p_panels_menu"; //Меню панелей
|
import { P8PPanelsMenuDesktop, P8PPanelsMenuGrid, P8P_PANELS_MENU_PANEL_SHAPE } from "./components/p8p_panels_menu"; //Меню панелей
|
||||||
import { BUTTONS, ERRORS, ERRORS_HTTP } from "../app.text"; //Текстовые ресурсы и константы
|
import { BUTTONS, ERRORS, ERRORS_HTTP } from "../app.text"; //Текстовые ресурсы и константы
|
||||||
import { P8P_PANELS_MENU_GRID_CONFIG_PROPS, P8P_APP_WORKSPACE_CONFIG_PROPS } from "./config_wrapper"; //Подключение компонентов к настройкам приложения
|
import { P8P_PANELS_MENU_GRID_CONFIG_PROPS, P8P_APP_WORKSPACE_CONFIG_PROPS } from "./config_wrapper"; //Подключение компонентов к настройкам приложения
|
||||||
|
|
||||||
@ -51,13 +51,29 @@ RouterError.propTypes = {
|
|||||||
//Главное меню приложения
|
//Главное меню приложения
|
||||||
const MainMenu = ({ panels = [] } = {}) => {
|
const MainMenu = ({ panels = [] } = {}) => {
|
||||||
//Подключение к контексту навигации
|
//Подключение к контексту навигации
|
||||||
const { navigatePanel } = useContext(NavigationCtx);
|
const { navigatePanel, isNavigationSearch, getNavigationSearch } = useContext(NavigationCtx);
|
||||||
|
|
||||||
|
//Подключение к контексту приложения
|
||||||
|
const { configUrlBase, pOnlineShowTab } = useContext(ApplicationСtx);
|
||||||
|
|
||||||
|
//Получим параметры запроса из адресной строки
|
||||||
|
const qS = isNavigationSearch() ? getNavigationSearch() : null;
|
||||||
|
|
||||||
//Отработка действия навигации элемента меню
|
//Отработка действия навигации элемента меню
|
||||||
const handleItemNavigate = panel => navigatePanel(panel);
|
const handleItemNavigate = (panel, newTab) =>
|
||||||
|
newTab ? pOnlineShowTab({ id: panel.name, url: `${configUrlBase}${panel.url}`, caption: panel.caption }) : navigatePanel(panel);
|
||||||
|
|
||||||
//Генерация содержимого
|
//Генерация содержимого
|
||||||
return <P8PPanelsMenuGrid {...P8P_PANELS_MENU_GRID_CONFIG_PROPS} panels={panels} onItemNavigate={handleItemNavigate} />;
|
return qS?.mode === "DESKTOP" ? (
|
||||||
|
<P8PPanelsMenuDesktop
|
||||||
|
{...P8P_PANELS_MENU_GRID_CONFIG_PROPS}
|
||||||
|
group={qS?.group}
|
||||||
|
panels={panels}
|
||||||
|
onItemNavigate={panel => handleItemNavigate(panel, true)}
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<P8PPanelsMenuGrid {...P8P_PANELS_MENU_GRID_CONFIG_PROPS} panels={panels} onItemNavigate={panel => handleItemNavigate(panel, false)} />
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
//Контроль свойств - главное меню приложения
|
//Контроль свойств - главное меню приложения
|
||||||
|
@ -35,7 +35,8 @@ import {
|
|||||||
//Типы меню
|
//Типы меню
|
||||||
const P8P_PANELS_MENU_VARIANT = {
|
const P8P_PANELS_MENU_VARIANT = {
|
||||||
DRAWER: "DRAWER",
|
DRAWER: "DRAWER",
|
||||||
GRID: "GRID"
|
GRID: "GRID",
|
||||||
|
DESKTOP: "DESKTOP"
|
||||||
};
|
};
|
||||||
|
|
||||||
//Структура элемента описания панели
|
//Структура элемента описания панели
|
||||||
@ -53,36 +54,16 @@ const P8P_PANELS_MENU_PANEL_SHAPE = PropTypes.shape({
|
|||||||
|
|
||||||
//Стили
|
//Стили
|
||||||
const STYLES = {
|
const STYLES = {
|
||||||
CONTAINER: {
|
GRID_CONTAINER: { display: "flex", justifyContent: "center", alignItems: "flex-start", minHeight: "100vh" },
|
||||||
display: "flex",
|
GRID: { maxWidth: 1200, direction: "row", justifyContent: "left", alignItems: "stretch" },
|
||||||
justifyContent: "center",
|
GRID_PANEL_CARD: { maxWidth: 400, height: "100%", flexDirection: "column", display: "flex" },
|
||||||
alignItems: "flex-start",
|
GRID_PANEL_CARD_MEDIA: { height: 140 },
|
||||||
minHeight: "100vh"
|
GRID_PANEL_CARD_CONTENT_TITLE: { alignItems: "center" },
|
||||||
},
|
GRID_PANEL_CARD_ACTIONS: { marginTop: "auto", display: "flex", justifyContent: "flex-end", alignItems: "flex-start" },
|
||||||
GRID: {
|
DESKTOP_GROUP_HEADER: { fontWeight: "bold", fontFamily: "tahoma, arial, verdana, sans-serif!important", fontSize: "13px!important" },
|
||||||
maxWidth: 1200,
|
DESKTOP_ITEM_BUTTON: { fontSize: "12px", textTransform: "none", "&:hover": { backgroundColor: "#c3e1ff" } },
|
||||||
direction: "row",
|
DESKTOP_ITEM_STACK: { justifyContent: "center", alignItems: "center" },
|
||||||
justifyContent: "left",
|
DESKTOP_ITEM_ICON: { width: "64px", height: "64px", fontSize: "64px" }
|
||||||
alignItems: "stretch"
|
|
||||||
},
|
|
||||||
PANEL_CARD: {
|
|
||||||
maxWidth: 400,
|
|
||||||
height: "100%",
|
|
||||||
flexDirection: "column",
|
|
||||||
display: "flex"
|
|
||||||
},
|
|
||||||
PANEL_CARD_MEDIA: {
|
|
||||||
height: 140
|
|
||||||
},
|
|
||||||
PANEL_CARD_CONTENT_TITLE: {
|
|
||||||
alignItems: "center"
|
|
||||||
},
|
|
||||||
PANEL_CARD_ACTIONS: {
|
|
||||||
marginTop: "auto",
|
|
||||||
display: "flex",
|
|
||||||
justifyContent: "flex-end",
|
|
||||||
alignItems: "flex-start"
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
//--------------------------------
|
//--------------------------------
|
||||||
@ -90,7 +71,7 @@ const STYLES = {
|
|||||||
//--------------------------------
|
//--------------------------------
|
||||||
|
|
||||||
//Формирование групп
|
//Формирование групп
|
||||||
const getGroups = panels => {
|
const getGroups = (panels, group) => {
|
||||||
let res = [];
|
let res = [];
|
||||||
let addDefaultGroup = false;
|
let addDefaultGroup = false;
|
||||||
for (const panel of panels)
|
for (const panel of panels)
|
||||||
@ -99,13 +80,14 @@ const getGroups = panels => {
|
|||||||
if (!panel.group) addDefaultGroup = true;
|
if (!panel.group) addDefaultGroup = true;
|
||||||
}
|
}
|
||||||
if (addDefaultGroup || res.length == 0) res.push(null);
|
if (addDefaultGroup || res.length == 0) res.push(null);
|
||||||
|
if (group) res = res.filter(g => g == group);
|
||||||
return res;
|
return res;
|
||||||
};
|
};
|
||||||
|
|
||||||
//Формирование ссылок на панели
|
//Формирование ссылок на панели
|
||||||
const getPanelsLinks = ({ variant, panels, selectedPanel, defaultGroupTytle, navigateCaption, onItemNavigate }) => {
|
const getPanelsLinks = ({ variant, panels, selectedPanel, group, defaultGroupTytle, navigateCaption, onItemNavigate }) => {
|
||||||
//Получим группы
|
//Получим группы
|
||||||
let grps = getGroups(panels);
|
let grps = getGroups(panels, group);
|
||||||
|
|
||||||
//Построим ссылки
|
//Построим ссылки
|
||||||
const panelsLinks = [];
|
const panelsLinks = [];
|
||||||
@ -118,8 +100,14 @@ const getPanelsLinks = ({ variant, panels, selectedPanel, defaultGroupTytle, nav
|
|||||||
{grp ? grp : defaultGroupTytle}
|
{grp ? grp : defaultGroupTytle}
|
||||||
</Typography>
|
</Typography>
|
||||||
</Grid>
|
</Grid>
|
||||||
) : (
|
) : variant === P8P_PANELS_MENU_VARIANT.DRAWER ? (
|
||||||
<Divider key={grp} />
|
<Divider key={grp} />
|
||||||
|
) : (
|
||||||
|
<Box pb={1} key={grp}>
|
||||||
|
<Typography variant="h7" sx={STYLES.DESKTOP_GROUP_HEADER}>
|
||||||
|
{grp ? grp : defaultGroupTytle}
|
||||||
|
</Typography>
|
||||||
|
</Box>
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
for (const panel of panels) {
|
for (const panel of panels) {
|
||||||
@ -127,12 +115,12 @@ const getPanelsLinks = ({ variant, panels, selectedPanel, defaultGroupTytle, nav
|
|||||||
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.PANEL_CARD}>
|
<Card sx={STYLES.GRID_PANEL_CARD}>
|
||||||
{panel.preview ? (
|
{panel.preview ? (
|
||||||
<CardMedia component="img" alt={panel.name} image={panel.preview} sx={STYLES.PANEL_CARD_MEDIA} />
|
<CardMedia component="img" alt={panel.name} image={panel.preview} sx={STYLES.GRID_PANEL_CARD_MEDIA} />
|
||||||
) : null}
|
) : null}
|
||||||
<CardContent>
|
<CardContent>
|
||||||
<Stack gap={1} direction="row" sx={STYLES.PANEL_CARD_CONTENT_TITLE}>
|
<Stack gap={1} direction="row" sx={STYLES.GRID_PANEL_CARD_CONTENT_TITLE}>
|
||||||
{panel.icon ? <Icon>{panel.icon}</Icon> : null}
|
{panel.icon ? <Icon>{panel.icon}</Icon> : null}
|
||||||
<Typography variant="h5">{panel.caption}</Typography>
|
<Typography variant="h5">{panel.caption}</Typography>
|
||||||
</Stack>
|
</Stack>
|
||||||
@ -140,14 +128,14 @@ const getPanelsLinks = ({ variant, panels, selectedPanel, defaultGroupTytle, nav
|
|||||||
{panel.desc}
|
{panel.desc}
|
||||||
</Typography>
|
</Typography>
|
||||||
</CardContent>
|
</CardContent>
|
||||||
<CardActions sx={STYLES.PANEL_CARD_ACTIONS}>
|
<CardActions sx={STYLES.GRID_PANEL_CARD_ACTIONS}>
|
||||||
<Button size="large" onClick={() => (onItemNavigate ? onItemNavigate(panel) : null)}>
|
<Button size="large" onClick={() => (onItemNavigate ? onItemNavigate(panel) : null)}>
|
||||||
{navigateCaption}
|
{navigateCaption}
|
||||||
</Button>
|
</Button>
|
||||||
</CardActions>
|
</CardActions>
|
||||||
</Card>
|
</Card>
|
||||||
</Grid>
|
</Grid>
|
||||||
) : (
|
) : variant === P8P_PANELS_MENU_VARIANT.DRAWER ? (
|
||||||
<ListItem key={panel.name} disablePadding>
|
<ListItem key={panel.name} disablePadding>
|
||||||
<ListItemButton
|
<ListItemButton
|
||||||
selected={selectedPanel?.name === panel.name}
|
selected={selectedPanel?.name === panel.name}
|
||||||
@ -159,6 +147,18 @@ const getPanelsLinks = ({ variant, panels, selectedPanel, defaultGroupTytle, nav
|
|||||||
<ListItemText primary={panel.caption} />
|
<ListItemText primary={panel.caption} />
|
||||||
</ListItemButton>
|
</ListItemButton>
|
||||||
</ListItem>
|
</ListItem>
|
||||||
|
) : (
|
||||||
|
<Button
|
||||||
|
p={3}
|
||||||
|
key={panel.name}
|
||||||
|
onClick={() => (onItemNavigate ? onItemNavigate(panel) : null)}
|
||||||
|
sx={STYLES.DESKTOP_ITEM_BUTTON}
|
||||||
|
>
|
||||||
|
<Stack sx={STYLES.DESKTOP_ITEM_STACK}>
|
||||||
|
<Icon sx={STYLES.DESKTOP_ITEM_ICON}>{panel.icon}</Icon>
|
||||||
|
{panel.caption}
|
||||||
|
</Stack>
|
||||||
|
</Button>
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -195,7 +195,7 @@ const P8PPanelsMenuGrid = ({ onItemNavigate, navigateCaption, panels = [], defau
|
|||||||
|
|
||||||
//Генерация содержимого
|
//Генерация содержимого
|
||||||
return (
|
return (
|
||||||
<Box sx={STYLES.CONTAINER}>
|
<Box sx={STYLES.GRID_CONTAINER}>
|
||||||
<Grid container spacing={2} p={2} sx={STYLES.GRID}>
|
<Grid container spacing={2} p={2} sx={STYLES.GRID}>
|
||||||
{panelsLinks}
|
{panelsLinks}
|
||||||
</Grid>
|
</Grid>
|
||||||
@ -211,8 +211,25 @@ P8PPanelsMenuGrid.propTypes = {
|
|||||||
defaultGroupTytle: PropTypes.string.isRequired
|
defaultGroupTytle: PropTypes.string.isRequired
|
||||||
};
|
};
|
||||||
|
|
||||||
|
//Меню панелей - рабочий стол
|
||||||
|
const P8PPanelsMenuDesktop = ({ group, onItemNavigate, panels = [], defaultGroupTytle } = {}) => {
|
||||||
|
//Формируем ссылки на панели
|
||||||
|
const panelsLinks = getPanelsLinks({ variant: P8P_PANELS_MENU_VARIANT.DESKTOP, panels, group, defaultGroupTytle, onItemNavigate });
|
||||||
|
|
||||||
|
//Генерация содержимого
|
||||||
|
return <Box p={2}>{panelsLinks}</Box>;
|
||||||
|
};
|
||||||
|
|
||||||
|
//Контроль свойств - Меню панелей - рабочий стол
|
||||||
|
P8PPanelsMenuDesktop.propTypes = {
|
||||||
|
group: PropTypes.string,
|
||||||
|
onItemNavigate: PropTypes.func,
|
||||||
|
panels: PropTypes.arrayOf(P8P_PANELS_MENU_PANEL_SHAPE).isRequired,
|
||||||
|
defaultGroupTytle: PropTypes.string.isRequired
|
||||||
|
};
|
||||||
|
|
||||||
//----------------
|
//----------------
|
||||||
//Интерфейс модуля
|
//Интерфейс модуля
|
||||||
//----------------
|
//----------------
|
||||||
|
|
||||||
export { P8P_PANELS_MENU_PANEL_SHAPE, P8PPanelsMenuDrawer, P8PPanelsMenuGrid };
|
export { P8P_PANELS_MENU_PANEL_SHAPE, P8PPanelsMenuDrawer, P8PPanelsMenuGrid, P8PPanelsMenuDesktop };
|
||||||
|
@ -18,7 +18,7 @@ import { BackEndСtx } from "./backend"; //Контекст взаимодейс
|
|||||||
//---------
|
//---------
|
||||||
|
|
||||||
//Клиентский API "ПАРУС 8 Онлайн"
|
//Клиентский API "ПАРУС 8 Онлайн"
|
||||||
const P8O_API = window.parent?.parus?.clientApi;
|
const P8O_API = window.top?.parus?.clientApi;
|
||||||
|
|
||||||
//Структура объекта с описанием ошибок
|
//Структура объекта с описанием ошибок
|
||||||
const APPLICATION_CONTEXT_ERRORS_SHAPE = PropTypes.shape({
|
const APPLICATION_CONTEXT_ERRORS_SHAPE = PropTypes.shape({
|
||||||
@ -49,6 +49,9 @@ export const ApplicationContext = ({ errors, displaySizeGetter, guidGenerator, c
|
|||||||
//Установка текущего размера экрана
|
//Установка текущего размера экрана
|
||||||
const setDisplaySize = displaySize => dispatch({ type: APP_AT.SET_DISPLAY_SIZE, payload: displaySize });
|
const setDisplaySize = displaySize => dispatch({ type: APP_AT.SET_DISPLAY_SIZE, payload: displaySize });
|
||||||
|
|
||||||
|
//Установка базового URL приложения
|
||||||
|
const setUrlBase = urlBase => dispatch({ type: APP_AT.SET_URL_BASE, payload: urlBase });
|
||||||
|
|
||||||
//Установка списка панелей
|
//Установка списка панелей
|
||||||
const setPanels = panels => dispatch({ type: APP_AT.LOAD_PANELS, payload: panels });
|
const setPanels = panels => dispatch({ type: APP_AT.LOAD_PANELS, payload: panels });
|
||||||
|
|
||||||
@ -117,10 +120,15 @@ export const ApplicationContext = ({ errors, displaySizeGetter, guidGenerator, c
|
|||||||
//Получение количества записей на странице
|
//Получение количества записей на странице
|
||||||
const configSystemPageSize = useMemo(() => config.SYSTEM.PAGE_SIZE, [config.SYSTEM.PAGE_SIZE]);
|
const configSystemPageSize = useMemo(() => config.SYSTEM.PAGE_SIZE, [config.SYSTEM.PAGE_SIZE]);
|
||||||
|
|
||||||
|
//Получение базового URL приложения
|
||||||
|
const configUrlBase = useMemo(() => state.urlBase, [state.urlBase]);
|
||||||
|
|
||||||
//Инициализация приложения
|
//Инициализация приложения
|
||||||
const initApp = useCallback(async () => {
|
const initApp = useCallback(async () => {
|
||||||
//Читаем конфигурацию с сервера
|
//Читаем конфигурацию с сервера
|
||||||
let res = await getConfig();
|
let res = await getConfig();
|
||||||
|
//Сохраняем базовый URL приложения
|
||||||
|
setUrlBase(getRespPayload(res)?.Panels?.urlBase);
|
||||||
//Сохраняем список панелей
|
//Сохраняем список панелей
|
||||||
setPanels(getRespPayload(res)?.Panels?.Panel);
|
setPanels(getRespPayload(res)?.Panels?.Panel);
|
||||||
//Установим флаг завершения инициализации
|
//Установим флаг завершения инициализации
|
||||||
@ -151,6 +159,7 @@ export const ApplicationContext = ({ errors, displaySizeGetter, guidGenerator, c
|
|||||||
pOnlineUserProcedure,
|
pOnlineUserProcedure,
|
||||||
pOnlineUserReport,
|
pOnlineUserReport,
|
||||||
configSystemPageSize,
|
configSystemPageSize,
|
||||||
|
configUrlBase,
|
||||||
appState: state
|
appState: state
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
|
|
||||||
//Типы действий
|
//Типы действий
|
||||||
const APP_AT = {
|
const APP_AT = {
|
||||||
|
SET_URL_BASE: "SET_URL_BASE", //Установка базового URL приложения
|
||||||
LOAD_PANELS: "LOAD_PANELS", //Загрузка списка панелей
|
LOAD_PANELS: "LOAD_PANELS", //Загрузка списка панелей
|
||||||
SET_INITIALIZED: "SET_INITIALIZED", //Установка флага инициализированности приложения
|
SET_INITIALIZED: "SET_INITIALIZED", //Установка флага инициализированности приложения
|
||||||
SET_DISPLAY_SIZE: "SET_DISPLAY_SIZE" //Установка текущего типового размера экрана
|
SET_DISPLAY_SIZE: "SET_DISPLAY_SIZE" //Установка текущего типового размера экрана
|
||||||
@ -17,6 +18,7 @@ const APP_AT = {
|
|||||||
//Состояние приложения по умолчанию
|
//Состояние приложения по умолчанию
|
||||||
const INITIAL_STATE = displaySizeGetter => ({
|
const INITIAL_STATE = displaySizeGetter => ({
|
||||||
displaySize: displaySizeGetter(),
|
displaySize: displaySizeGetter(),
|
||||||
|
urlBase: "",
|
||||||
panels: [],
|
panels: [],
|
||||||
panelsLoaded: false,
|
panelsLoaded: false,
|
||||||
initialized: false
|
initialized: false
|
||||||
@ -28,6 +30,8 @@ const INITIAL_STATE = displaySizeGetter => ({
|
|||||||
|
|
||||||
//Обработчики действий
|
//Обработчики действий
|
||||||
const handlers = {
|
const handlers = {
|
||||||
|
//Установка базового URL приложения
|
||||||
|
[APP_AT.SET_URL_BASE]: (state, { payload }) => ({ ...state, urlBase: payload }),
|
||||||
//Загрузка списка панелей
|
//Загрузка списка панелей
|
||||||
[APP_AT.LOAD_PANELS]: (state, { payload }) => {
|
[APP_AT.LOAD_PANELS]: (state, { payload }) => {
|
||||||
let panels = [];
|
let panels = [];
|
||||||
|
@ -19,10 +19,10 @@ import { BUTTONS, ERRORS } from "../../../app.text"; //Текстовые рес
|
|||||||
//Заглушка
|
//Заглушка
|
||||||
const Dummy = () => {
|
const Dummy = () => {
|
||||||
//Подключение к контексту навигации
|
//Подключение к контексту навигации
|
||||||
const { navigateBack } = useContext(NavigationCtx);
|
const { navigateRoot } = useContext(NavigationCtx);
|
||||||
|
|
||||||
//Генерация содержимого
|
//Генерация содержимого
|
||||||
return <P8PAppErrorPage errorMessage={ERRORS.UNDER_CONSTRUCTION} onNavigate={() => navigateBack()} navigateCaption={BUTTONS.NAVIGATE_BACK} />;
|
return <P8PAppErrorPage errorMessage={ERRORS.UNDER_CONSTRUCTION} onNavigate={() => navigateRoot()} navigateCaption={BUTTONS.NAVIGATE_HOME} />;
|
||||||
};
|
};
|
||||||
|
|
||||||
//----------------
|
//----------------
|
||||||
|
Loading…
x
Reference in New Issue
Block a user