From 718d32f2b9f5f92e98ab5ddc4aa8da3850fea458 Mon Sep 17 00:00:00 2001 From: goodmice Date: Thu, 13 Oct 2022 18:16:43 +0500 Subject: [PATCH] =?UTF-8?q?*=20=D0=9D=D0=B0=D0=B2=D0=B8=D0=B3=D0=B0=D1=86?= =?UTF-8?q?=D0=B8=D0=BE=D0=BD=D0=BD=D0=BE=D0=B5=20=D0=BC=D0=B5=D0=BD=D1=8E?= =?UTF-8?q?=20=D1=81=D0=BA=D0=B2=D0=B0=D0=B6=D0=B8=D0=BD=D1=8B=20=D0=BF?= =?UTF-8?q?=D0=B5=D1=80=D0=B5=D0=BD=D0=B5=D1=81=D0=B5=D0=BD=D0=BE=20=D0=B2?= =?UTF-8?q?=20=D1=81=D0=BE=D0=BE=D1=82=D0=B2=D0=B5=D1=82=D1=81=D1=82=D0=B2?= =?UTF-8?q?=D1=83=D1=8E=D1=89=D1=83=D1=8E=20=D0=B4=D0=B8=D1=80=D0=B5=D0=BA?= =?UTF-8?q?=D1=82=D0=BE=D1=80=D0=B8=D1=8E=20*=20LayoutPortal=20=D0=BF?= =?UTF-8?q?=D0=B5=D1=80=D0=B5=D0=B4=D0=B5=D0=BB=D0=B0=D0=BD=20=D0=B2=20?= =?UTF-8?q?=D0=BE=D0=B1=D1=91=D1=80=D1=82=D0=BA=D1=83=20=D0=B4=D0=BB=D1=8F?= =?UTF-8?q?=20=D1=81=D0=BE=D0=BA=D1=80=D0=B0=D1=89=D0=B5=D0=BD=D0=B8=D1=8F?= =?UTF-8?q?=20=D0=BF=D0=BE=D0=B2=D1=82=D0=BE=D1=80=D0=B5=D0=BD=D0=B8=D0=B9?= =?UTF-8?q?=20*=20=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB=D0=B5=D0=BD=20?= =?UTF-8?q?=D0=BA=D0=BE=D0=BD=D1=82=D0=B5=D0=BA=D1=81=D1=82=20=D0=B8=20?= =?UTF-8?q?=D1=85=D1=83=D0=BA=20=D0=B4=D0=BB=D1=8F=20=D0=BE=D0=B1=D0=BD?= =?UTF-8?q?=D0=BE=D0=B2=D0=BB=D0=B5=D0=BD=D0=B8=D1=8F=20=D0=BF=D0=B0=D1=80?= =?UTF-8?q?=D0=B0=D0=BC=D0=B5=D1=82=D1=80=D0=BE=D0=B2=20LayoutPortal?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/App.tsx | 18 ++-- src/components/LayoutPortal.tsx | 34 +++++-- src/components/PageHeader.tsx | 2 +- src/components/PrivateWellMenu.tsx | 8 +- src/context.ts | 20 +++- src/pages/AdminPanel/index.jsx | 56 +++++------ src/pages/Cluster/ClusterWells.jsx | 12 ++- src/pages/Cluster/index.jsx | 16 ++-- src/pages/Deposit.jsx | 71 +++++++------- src/pages/{ => Well}/NavigationMenu.jsx | 0 src/pages/Well/index.jsx | 118 ++++++++++++------------ 11 files changed, 205 insertions(+), 150 deletions(-) rename src/pages/{ => Well}/NavigationMenu.jsx (100%) diff --git a/src/App.tsx b/src/App.tsx index 05295c2..83743d4 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -5,6 +5,7 @@ import { ConfigProvider } from 'antd' import { RootPathContext } from '@asb/context' import { UserOutlet } from '@components/outlets' +import LayoutPortal from '@components/LayoutPortal' import SuspenseFallback from '@components/SuspenseFallback' import { getUserToken, NoAccessComponent } from '@utils' import { OpenAPI } from '@api' @@ -40,14 +41,17 @@ export const App = memo(() => ( {/* User pages */} }> - {/* Admin pages */} - } /> - - {/* Client pages */} } /> - } /> - } /> - } /> + + }> + {/* Admin pages */} + } /> + + {/* Client pages */} + } /> + } /> + } /> + diff --git a/src/components/LayoutPortal.tsx b/src/components/LayoutPortal.tsx index 1bcb344..e713c8a 100644 --- a/src/components/LayoutPortal.tsx +++ b/src/components/LayoutPortal.tsx @@ -1,7 +1,7 @@ import { Button, Layout, LayoutProps, Menu, SiderProps } from 'antd' -import { HTMLProps, Key, memo, ReactNode, useEffect, useMemo, useState } from 'react' +import { Key, memo, ReactNode, Suspense, useCallback, useEffect, useMemo, useState } from 'react' import { ItemType } from 'antd/lib/menu/hooks/useItems' -import { Link } from 'react-router-dom' +import { Link, Outlet } from 'react-router-dom' import { ApartmentOutlined, CodeOutlined, @@ -11,32 +11,47 @@ import { UserOutlined, } from '@ant-design/icons' +import { LayoutPropsContext } from '@asb/context' import PageHeader from '@components/PageHeader' import { UserMenu, UserMenuProps } from '@components/UserMenu' import { WellTreeSelector, WellTreeSelectorProps } from '@components/selectors/WellTreeSelector' import { isURLAvailable, wrapPrivateComponent } from '@utils' +import SuspenseFallback from './SuspenseFallback' + import '@styles/layout.less' const { Content, Sider } = Layout -export type LayoutPortalProps = HTMLProps & { +export type LayoutPortalProps = LayoutProps & { title?: ReactNode - noSheet?: boolean + sheet?: boolean showSelector?: boolean selectorProps?: WellTreeSelectorProps sider?: boolean | JSX.Element siderProps?: SiderProps & { userMenuProps?: UserMenuProps } isAdmin?: boolean + fallback?: JSX.Element +} + +const defaultProps: LayoutPortalProps = { + title: 'Единая цифровая платформа', + sider: true, + sheet: true, } const makeItem = (title: string, key: Key, icon: JSX.Element, label?: ReactNode, onClick?: () => void) => ({ icon, key, title, label: label ?? title, onClick }) -const _LayoutPortal = memo(({ isAdmin, title, noSheet, showSelector, selectorProps, sider, siderProps, ...props }) => { +const _LayoutPortal = memo(() => { const [menuCollapsed, setMenuCollapsed] = useState(true) const [wellsTreeOpen, setWellsTreeOpen] = useState(false) const [userMenuOpen, setUserMenuOpen] = useState(false) const [currentWell, setCurrentWell] = useState('') + const [props, setProps] = useState(defaultProps) + + const { isAdmin, title, sheet, showSelector, selectorProps, sider, siderProps, fallback, ...other } = useMemo(() => props, [props]) + + const setLayoutProps = useCallback((props: LayoutPortalProps) => setProps({ ...defaultProps, ...props}), []) useEffect(() => { if (typeof showSelector === 'boolean') @@ -64,7 +79,6 @@ const _LayoutPortal = memo(({ isAdmin, title, noSheet, showSe @@ -95,8 +109,12 @@ const _LayoutPortal = memo(({ isAdmin, title, noSheet, showSe )} - -
+ + + }> + + + diff --git a/src/components/PageHeader.tsx b/src/components/PageHeader.tsx index 9c8ab99..2b3fd4c 100755 --- a/src/components/PageHeader.tsx +++ b/src/components/PageHeader.tsx @@ -14,7 +14,7 @@ export type PageHeaderProps = BasicProps & { children?: React.ReactNode } -export const PageHeader: React.FC = memo(({ title = 'Мониторинг', children, ...other }) => ( +export const PageHeader: React.FC = memo(({ title, children, ...other }) => ( diff --git a/src/components/PrivateWellMenu.tsx b/src/components/PrivateWellMenu.tsx index 5f8994d..bcd2c0f 100644 --- a/src/components/PrivateWellMenu.tsx +++ b/src/components/PrivateWellMenu.tsx @@ -4,7 +4,6 @@ import { Link, useLocation } from 'react-router-dom' import { join } from 'path' import { Menu, MenuProps } from 'antd' -import { useWell } from '@asb/context' import { hasPermission, Permission } from '@utils' type PrivateWellMenuItem = { @@ -71,16 +70,15 @@ export const makeItem = ( }) export type PrivateWellMenuProps = MenuProps & { + idWell?: number items: PrivateWellMenuItem[] rootPath?: string } -export const PrivateWellMenu = memo(({ items, rootPath = '/', ...other }) => { - const [well] = useWell() - +export const PrivateWellMenu = memo(({ idWell, items, rootPath = '/', ...other }) => { const location = useLocation() - const menuItems = useMemo(() => makeItemList(items, rootPath, well.id), [items, rootPath, well.id]) + const menuItems = useMemo(() => makeItemList(items, rootPath, idWell), [items, rootPath, idWell]) const tabKeys = useMemo(() => { const out = [] diff --git a/src/context.ts b/src/context.ts index 4fddc4f..83e5f55 100644 --- a/src/context.ts +++ b/src/context.ts @@ -1,6 +1,7 @@ -import { createContext, useContext } from 'react' +import { createContext, useContext, useEffect } from 'react' import { UserTokenDto, WellDto } from '@api' +import { LayoutPortalProps } from './components/LayoutPortal' /** Контекст текущей скважины */ export const WellContext = createContext<[WellDto, (well: WellDto) => void]>([{}, () => {}]) @@ -8,6 +9,8 @@ export const WellContext = createContext<[WellDto, (well: WellDto) => void]>([{} export const RootPathContext = createContext('/') /** Контекст текущего пользователя */ export const UserContext = createContext({}) +/** Контекст метода редактирования параметров заголовка и меню */ +export const LayoutPropsContext = createContext<(props: LayoutPortalProps) => void>(() => {}) /** * Получить текущую скважину @@ -29,3 +32,18 @@ export const useRootPath = () => useContext(RootPathContext) * @returns Текущий пользователь, либо `null` */ export const useUser = () => useContext(UserContext) + +/** + * Получить метод задания параметров заголовка и меню + * + * @returns Получить метод задания параметров заголовка и меню + */ +export const useLayoutProps = (props?: LayoutPortalProps) => { + const setLayoutProps = useContext(LayoutPropsContext) + + useEffect(() => { + if (props) setLayoutProps(props) + }, [setLayoutProps, props]) + + return setLayoutProps +} diff --git a/src/pages/AdminPanel/index.jsx b/src/pages/AdminPanel/index.jsx index 33296e6..d515175 100755 --- a/src/pages/AdminPanel/index.jsx +++ b/src/pages/AdminPanel/index.jsx @@ -1,9 +1,7 @@ import { Navigate, Route, Routes } from 'react-router-dom' -import { lazy, memo, Suspense, useMemo } from 'react' +import { lazy, memo, useMemo } from 'react' -import { RootPathContext, useRootPath } from '@asb/context' -import { LayoutPortal } from '@components/LayoutPortal' -import SuspenseFallback from '@components/SuspenseFallback' +import { RootPathContext, useLayoutProps, useRootPath } from '@asb/context' import { NoAccessComponent, wrapPrivateComponent } from '@utils' import AdminNavigationMenu from './AdminNavigationMenu' @@ -21,35 +19,39 @@ const TelemetryViewer = lazy(() => import('./Telemetry/TelemetryViewer')) const TelemetryMerger = lazy(() => import('./Telemetry/TelemetryMerger')) const VisitLog = lazy(() => import('./VisitLog')) +const layoutProps = { + sider: , + title: 'Администраторская панель', + isAdmin: true, +} + const AdminPanel = memo(() => { const root = useRootPath() const rootPath = useMemo(() => `${root}/admin`, [root]) + useLayoutProps(layoutProps) + return ( - }> - }> - - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - }> - } /> - } /> - } /> - } /> - - } /> - - - + + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + }> + } /> + } /> + } /> + } /> + + } /> + ) }) diff --git a/src/pages/Cluster/ClusterWells.jsx b/src/pages/Cluster/ClusterWells.jsx index 8397928..b76034b 100755 --- a/src/pages/Cluster/ClusterWells.jsx +++ b/src/pages/Cluster/ClusterWells.jsx @@ -1,5 +1,5 @@ import { Link, useLocation } from 'react-router-dom' -import { useState, useEffect, memo, useMemo } from 'react' +import { useState, useEffect, memo, useMemo, lazy, Suspense } from 'react' import { Button, Modal } from 'antd' import { LineChartOutlined, ProfileOutlined, TeamOutlined } from '@ant-design/icons' @@ -15,6 +15,7 @@ import { } from '@components/Table' import LoaderPortal from '@components/LoaderPortal' import PointerIcon from '@components/icons/PointerIcon' +import SuspenseFallback from '@components/SuspenseFallback' import { invokeWebApiWrapperAsync } from '@components/factory' import { getOperations, @@ -24,8 +25,9 @@ import { wrapPrivateComponent } from '@utils' -import Tvd from '@pages/Well/WellOperations/Tvd' -import CompaniesTable from '@pages/Cluster/CompaniesTable' +const Tvd = lazy(() => import('@pages/Well/WellOperations/Tvd')) + +import CompaniesTable from './CompaniesTable' import WellOperationsTable from './WellOperationsTable' const filtersMinMax = [ @@ -182,7 +184,9 @@ const ClusterWells = memo(({ statsWells }) => { width={1500} footer={null} > - + }> + + { const { idCluster } = useParams() const [data, setData] = useState([]) const [showLoader, setShowLoader] = useState(false) + useLayoutProps(layoutProps) + useEffect(() => { invokeWebApiWrapperAsync( async () => { @@ -27,11 +33,9 @@ const Cluster = memo(() => { }, [idCluster]) return ( - - - - - + + + ) }) diff --git a/src/pages/Deposit.jsx b/src/pages/Deposit.jsx index ba3c8b6..893a03d 100755 --- a/src/pages/Deposit.jsx +++ b/src/pages/Deposit.jsx @@ -3,8 +3,8 @@ import { useState, useEffect, memo, useMemo } from 'react' import { Link, useLocation } from 'react-router-dom' import { Popover, Badge } from 'antd' +import { useLayoutProps } from '@asb/context' import { PointerIcon } from '@components/icons' -import { LayoutPortal } from '@components/LayoutPortal' import LoaderPortal from '@components/LoaderPortal' import { invokeWebApiWrapperAsync } from '@components/factory' import { arrayOrDefault, limitValue, wrapPrivateComponent } from '@utils' @@ -47,6 +47,8 @@ const Deposit = memo(() => { const [showLoader, setShowLoader] = useState(false) const [viewParams, setViewParams] = useState(defaultViewParams) + const setLayoutProps = useLayoutProps() + const location = useLocation() const selectorProps = useMemo(() => { @@ -58,6 +60,13 @@ const Deposit = memo(() => { } }, [location.pathname]) + useEffect(() => setLayoutProps({ + sheet: false, + showSelector: true, + selectorProps, + title: 'Месторождение', + }), [setLayoutProps, selectorProps]) + useEffect(() => { invokeWebApiWrapperAsync( async () => { @@ -72,37 +81,35 @@ const Deposit = memo(() => { }, []) return ( - - -
- - {depositsData.map(deposit => ( - - - {deposit.clusters.map(cluster => ( - -
{cluster.caption}
- - ))} -
- } trigger={['click']} title={deposit.caption}> -
- - - -
- - - ))} - -
- - + +
+ + {depositsData.map(deposit => ( + + + {deposit.clusters.map(cluster => ( + +
{cluster.caption}
+ + ))} +
+ } trigger={['click']} title={deposit.caption}> +
+ + + +
+ + + ))} + + +
) }) diff --git a/src/pages/NavigationMenu.jsx b/src/pages/Well/NavigationMenu.jsx similarity index 100% rename from src/pages/NavigationMenu.jsx rename to src/pages/Well/NavigationMenu.jsx diff --git a/src/pages/Well/index.jsx b/src/pages/Well/index.jsx index d9c3dec..4519f2b 100644 --- a/src/pages/Well/index.jsx +++ b/src/pages/Well/index.jsx @@ -1,14 +1,12 @@ -import { lazy, memo, Suspense, useCallback, useEffect, useMemo, useState } from 'react' +import { lazy, memo, useCallback, useEffect, useMemo, useState } from 'react' import { Navigate, Route, Routes, useParams } from 'react-router-dom' -import { WellContext, RootPathContext, useRootPath } from '@asb/context' -import { LayoutPortal } from '@components/LayoutPortal' -import SuspenseFallback from '@components/SuspenseFallback' +import { WellContext, RootPathContext, useRootPath, useLayoutProps } from '@asb/context' import { invokeWebApiWrapperAsync } from '@components/factory' import { NoAccessComponent, wrapPrivateComponent } from '@utils' import { WellService } from '@api' -import NavigationMenu from '../NavigationMenu' +import NavigationMenu from './NavigationMenu' import '@styles/index.css' @@ -49,16 +47,9 @@ const Well = memo(() => { const root = useRootPath() const rootPath = useMemo(() => `${root}/well/${idWell}`, [root, idWell]) - useEffect(() => { - invokeWebApiWrapperAsync( - async () => { - const well = await WellService.get(idWell) - setWell(well ?? { id: idWell }) - }, - undefined, - 'Не удалось получить данные по скважине' - ) - }, [idWell]) + const setLayoutProps = useLayoutProps() + + useEffect(() => console.log(well), [well]) const updateWell = useCallback((data) => invokeWebApiWrapperAsync( async () => { @@ -71,58 +62,67 @@ const Well = memo(() => { { actionName: 'Изменение данных скважины', well } ), [well]) + useEffect(() => { + invokeWebApiWrapperAsync( + async () => { + const well = await WellService.get(idWell) + setWell(well ?? { id: idWell }) + }, + undefined, + 'Не удалось получить данные по скважине' + ) + }, [idWell]) + + useEffect(() => setLayoutProps({ sider: }), [well, setLayoutProps]) + return ( - }> - }> - - } /> - } /> + + } /> + } /> - }> - } /> - } /> + }> + } /> + } /> - } /> - } /> - } /> - } /> - } /> - } /> - - }> - } /> - } /> + } /> + } /> + } /> + } /> + } /> + } /> + + }> + } /> + } /> - } /> - } /> - - }> - } /> - } /> + } /> + } /> + + }> + } /> + } /> - } /> - } /> - - }> - } /> - } /> + } /> + } /> + + }> + } /> + } /> - } /> - } /> - } /> - } /> - } /> - } /> - - } /> - } /> - } /> - } /> - - - + } /> + } /> + } /> + } /> + } /> + } /> + + } /> + } /> + } /> + } /> + )