forked from CITKParus/P8-Panels
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 { P8PAppErrorPage } from "./components/p8p_app_error_page"; //Страница с ошибкой
|
||||
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 { P8P_PANELS_MENU_GRID_CONFIG_PROPS, P8P_APP_WORKSPACE_CONFIG_PROPS } from "./config_wrapper"; //Подключение компонентов к настройкам приложения
|
||||
|
||||
@ -51,13 +51,29 @@ RouterError.propTypes = {
|
||||
//Главное меню приложения
|
||||
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 = {
|
||||
DRAWER: "DRAWER",
|
||||
GRID: "GRID"
|
||||
GRID: "GRID",
|
||||
DESKTOP: "DESKTOP"
|
||||
};
|
||||
|
||||
//Структура элемента описания панели
|
||||
@ -53,36 +54,16 @@ const P8P_PANELS_MENU_PANEL_SHAPE = PropTypes.shape({
|
||||
|
||||
//Стили
|
||||
const STYLES = {
|
||||
CONTAINER: {
|
||||
display: "flex",
|
||||
justifyContent: "center",
|
||||
alignItems: "flex-start",
|
||||
minHeight: "100vh"
|
||||
},
|
||||
GRID: {
|
||||
maxWidth: 1200,
|
||||
direction: "row",
|
||||
justifyContent: "left",
|
||||
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"
|
||||
}
|
||||
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: "center" },
|
||||
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" } },
|
||||
DESKTOP_ITEM_STACK: { justifyContent: "center", alignItems: "center" },
|
||||
DESKTOP_ITEM_ICON: { width: "64px", height: "64px", fontSize: "64px" }
|
||||
};
|
||||
|
||||
//--------------------------------
|
||||
@ -90,7 +71,7 @@ const STYLES = {
|
||||
//--------------------------------
|
||||
|
||||
//Формирование групп
|
||||
const getGroups = panels => {
|
||||
const getGroups = (panels, group) => {
|
||||
let res = [];
|
||||
let addDefaultGroup = false;
|
||||
for (const panel of panels)
|
||||
@ -99,13 +80,14 @@ const getGroups = panels => {
|
||||
if (!panel.group) addDefaultGroup = true;
|
||||
}
|
||||
if (addDefaultGroup || res.length == 0) res.push(null);
|
||||
if (group) res = res.filter(g => g == group);
|
||||
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 = [];
|
||||
@ -118,8 +100,14 @@ const getPanelsLinks = ({ variant, panels, selectedPanel, defaultGroupTytle, nav
|
||||
{grp ? grp : defaultGroupTytle}
|
||||
</Typography>
|
||||
</Grid>
|
||||
) : (
|
||||
) : variant === P8P_PANELS_MENU_VARIANT.DRAWER ? (
|
||||
<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) {
|
||||
@ -127,12 +115,12 @@ const getPanelsLinks = ({ variant, panels, selectedPanel, defaultGroupTytle, nav
|
||||
panelsLinks.push(
|
||||
variant === P8P_PANELS_MENU_VARIANT.GRID ? (
|
||||
<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 ? (
|
||||
<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}
|
||||
<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}
|
||||
<Typography variant="h5">{panel.caption}</Typography>
|
||||
</Stack>
|
||||
@ -140,14 +128,14 @@ const getPanelsLinks = ({ variant, panels, selectedPanel, defaultGroupTytle, nav
|
||||
{panel.desc}
|
||||
</Typography>
|
||||
</CardContent>
|
||||
<CardActions sx={STYLES.PANEL_CARD_ACTIONS}>
|
||||
<CardActions sx={STYLES.GRID_PANEL_CARD_ACTIONS}>
|
||||
<Button size="large" onClick={() => (onItemNavigate ? onItemNavigate(panel) : null)}>
|
||||
{navigateCaption}
|
||||
</Button>
|
||||
</CardActions>
|
||||
</Card>
|
||||
</Grid>
|
||||
) : (
|
||||
) : variant === P8P_PANELS_MENU_VARIANT.DRAWER ? (
|
||||
<ListItem key={panel.name} disablePadding>
|
||||
<ListItemButton
|
||||
selected={selectedPanel?.name === panel.name}
|
||||
@ -159,6 +147,18 @@ const getPanelsLinks = ({ variant, panels, selectedPanel, defaultGroupTytle, nav
|
||||
<ListItemText primary={panel.caption} />
|
||||
</ListItemButton>
|
||||
</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 (
|
||||
<Box sx={STYLES.CONTAINER}>
|
||||
<Box sx={STYLES.GRID_CONTAINER}>
|
||||
<Grid container spacing={2} p={2} sx={STYLES.GRID}>
|
||||
{panelsLinks}
|
||||
</Grid>
|
||||
@ -211,8 +211,25 @@ P8PPanelsMenuGrid.propTypes = {
|
||||
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 Онлайн"
|
||||
const P8O_API = window.parent?.parus?.clientApi;
|
||||
const P8O_API = window.top?.parus?.clientApi;
|
||||
|
||||
//Структура объекта с описанием ошибок
|
||||
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 });
|
||||
|
||||
//Установка базового URL приложения
|
||||
const setUrlBase = urlBase => dispatch({ type: APP_AT.SET_URL_BASE, payload: urlBase });
|
||||
|
||||
//Установка списка панелей
|
||||
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]);
|
||||
|
||||
//Получение базового URL приложения
|
||||
const configUrlBase = useMemo(() => state.urlBase, [state.urlBase]);
|
||||
|
||||
//Инициализация приложения
|
||||
const initApp = useCallback(async () => {
|
||||
//Читаем конфигурацию с сервера
|
||||
let res = await getConfig();
|
||||
//Сохраняем базовый URL приложения
|
||||
setUrlBase(getRespPayload(res)?.Panels?.urlBase);
|
||||
//Сохраняем список панелей
|
||||
setPanels(getRespPayload(res)?.Panels?.Panel);
|
||||
//Установим флаг завершения инициализации
|
||||
@ -151,6 +159,7 @@ export const ApplicationContext = ({ errors, displaySizeGetter, guidGenerator, c
|
||||
pOnlineUserProcedure,
|
||||
pOnlineUserReport,
|
||||
configSystemPageSize,
|
||||
configUrlBase,
|
||||
appState: state
|
||||
}}
|
||||
>
|
||||
|
@ -9,6 +9,7 @@
|
||||
|
||||
//Типы действий
|
||||
const APP_AT = {
|
||||
SET_URL_BASE: "SET_URL_BASE", //Установка базового URL приложения
|
||||
LOAD_PANELS: "LOAD_PANELS", //Загрузка списка панелей
|
||||
SET_INITIALIZED: "SET_INITIALIZED", //Установка флага инициализированности приложения
|
||||
SET_DISPLAY_SIZE: "SET_DISPLAY_SIZE" //Установка текущего типового размера экрана
|
||||
@ -17,6 +18,7 @@ const APP_AT = {
|
||||
//Состояние приложения по умолчанию
|
||||
const INITIAL_STATE = displaySizeGetter => ({
|
||||
displaySize: displaySizeGetter(),
|
||||
urlBase: "",
|
||||
panels: [],
|
||||
panelsLoaded: false,
|
||||
initialized: false
|
||||
@ -28,6 +30,8 @@ const INITIAL_STATE = displaySizeGetter => ({
|
||||
|
||||
//Обработчики действий
|
||||
const handlers = {
|
||||
//Установка базового URL приложения
|
||||
[APP_AT.SET_URL_BASE]: (state, { payload }) => ({ ...state, urlBase: payload }),
|
||||
//Загрузка списка панелей
|
||||
[APP_AT.LOAD_PANELS]: (state, { payload }) => {
|
||||
let panels = [];
|
||||
|
@ -19,10 +19,10 @@ import { BUTTONS, ERRORS } from "../../../app.text"; //Текстовые рес
|
||||
//Заглушка
|
||||
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