diff --git a/public/manifest.json b/public/manifest.json index 1f2f141..0af2648 100755 --- a/public/manifest.json +++ b/public/manifest.json @@ -1,6 +1,6 @@ { - "short_name": "React App", - "name": "Create React App Sample", + "short_name": "ЕЦП", + "name": "Единая Цифровая Платформа", "icons": [ { "src": "favicon.ico", diff --git a/src/App.tsx b/src/App.tsx index d883e77..7498b86 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,49 +1,62 @@ import { BrowserRouter as Router, Navigate, Route, Routes } from 'react-router-dom' -import { memo } from 'react' -import { ConfigProvider } from 'antd' +import { lazy, memo, Suspense } from 'react' import locale from 'antd/lib/locale/ru_RU' +import { ConfigProvider } from 'antd' import { RootPathContext } from '@asb/context' -import { getUserToken, NoAccessComponent } from '@utils' +import { UserOutlet } from '@components/outlets' +import LayoutPortal from '@components/LayoutPortal' +import SuspenseFallback from '@components/SuspenseFallback' +import { getUser, NoAccessComponent } from '@utils' import { OpenAPI } from '@api' -import AdminPanel from '@pages/AdminPanel' -import Well from '@pages/Well' -import Login from '@pages/Login' -import Cluster from '@pages/Cluster' -import Deposit from '@pages/Deposit' -import Register from '@pages/Register' -import FileDownload from '@pages/FileDownload' - -import '@styles/App.less' import '@styles/include/antd_theme.less' +import '@styles/App.less' -//OpenAPI.BASE = 'http://localhost:3000' -OpenAPI.TOKEN = async () => getUserToken() ?? '' -OpenAPI.HEADERS = {'Content-Type': 'application/json'} +const Login = lazy(() => import('@pages/public/Login')) +const Register = lazy(() => import('@pages/public/Register')) +const FileDownload = lazy(() => import('@pages/FileDownload')) + +const AdminPanel = lazy(() => import('@pages/AdminPanel')) +const Deposit = lazy(() => import('@pages/Deposit')) +const Cluster = lazy(() => import('@pages/Cluster')) +const Well = lazy(() => import('@pages/Well')) + +// OpenAPI.BASE = 'http://localhost:3000' +// TODO: Удалить взятие из 'token' в следующем релизе, вставлено для совместимости +OpenAPI.TOKEN = async () => getUser().token || localStorage.getItem('token') || '' +OpenAPI.HEADERS = { 'Content-Type': 'application/json' } export const App = memo(() => ( - - - } /> - } /> + }> + + + } /> + } /> - {/* Public pages */} - } /> - } /> + {/* Public pages */} + } /> + } /> - {/* Admin pages */} - } /> + {/* User pages */} + }> + } /> - {/* User pages */} - } /> - } /> - } /> - } /> - - + }> + {/* Admin pages */} + } /> + + {/* Client pages */} + } /> + } /> + } /> + + + + + )) diff --git a/src/components/ChangePassword.tsx b/src/components/ChangePassword.tsx index e1ec41f..0ab8890 100755 --- a/src/components/ChangePassword.tsx +++ b/src/components/ChangePassword.tsx @@ -2,8 +2,8 @@ import { memo, useCallback, useMemo, useState } from 'react' import { Rule } from 'antd/lib/form' import { Form, Input, Modal, FormProps } from 'antd' +import { useUser } from '@asb/context' import { AuthService, UserDto } from '@api' -import { getUserId, getUserLogin } from '@utils' import { passwordRules, createPasswordRules } from '@utils/validationRules' import LoaderPortal from './LoaderPortal' @@ -31,7 +31,8 @@ export const ChangePassword = memo(({ user, visible, onCanc const [showLoader, setShowLoader] = useState(false) const [isDisabled, setIsDisabled] = useState(true) - const userData = useMemo(() => user ?? { id: getUserId(), login: getUserLogin() } as UserDto, [user]) + const userContext = useUser() + const userData = useMemo(() => user ?? userContext, [user]) const [form] = Form.useForm() @@ -63,7 +64,7 @@ export const ChangePassword = memo(({ user, visible, onCanc {user && <> ()} )} - visible={visible} + open={visible} onCancel={onModalCancel} onOk={() => form.submit()} okText={'Сохранить'} diff --git a/src/components/ColorPicker.tsx b/src/components/ColorPicker.tsx index 8e4cbef..bd8fe1a 100644 --- a/src/components/ColorPicker.tsx +++ b/src/components/ColorPicker.tsx @@ -106,7 +106,7 @@ export const ColorPicker = memo(({ value = '#AA33BB', onChange return (
diff --git a/src/components/Layout/AdminLayoutPortal.tsx b/src/components/Layout/AdminLayoutPortal.tsx deleted file mode 100755 index 1d087ba..0000000 --- a/src/components/Layout/AdminLayoutPortal.tsx +++ /dev/null @@ -1,28 +0,0 @@ -import { memo, ReactNode } from 'react' -import { Link, useLocation } from 'react-router-dom' -import { Button, Layout, LayoutProps } from 'antd' - -import PageHeader from '@components/PageHeader' - -export type AdminLayoutPortalProps = LayoutProps & { - title?: ReactNode -} - -export const AdminLayoutPortal = memo(({ title, ...props }) => { - const location = useLocation() - - return ( - - - - - - - - - ) -}) - -export default AdminLayoutPortal diff --git a/src/components/Layout/LayoutPortal.tsx b/src/components/Layout/LayoutPortal.tsx deleted file mode 100755 index e754811..0000000 --- a/src/components/Layout/LayoutPortal.tsx +++ /dev/null @@ -1,31 +0,0 @@ -import { Key, memo, ReactNode } from 'react' -import { Layout, LayoutProps } from 'antd' - -import PageHeader from '@components/PageHeader' -import { WellTreeSelector, WellTreeSelectorProps } from '@components/selectors/WellTreeSelector' -import { wrapPrivateComponent } from '@utils' - -export type LayoutPortalProps = LayoutProps & { - title?: ReactNode - noSheet?: boolean - selector?: WellTreeSelectorProps -} - -const _LayoutPortal = memo(({ title, noSheet, selector, ...props }) => ( - - - - - - {noSheet ? props.children : ( - - )} - - -)) - -export const LayoutPortal = wrapPrivateComponent(_LayoutPortal, { - requirements: ['Deposit.get'], -}) - -export default LayoutPortal diff --git a/src/components/Layout/index.ts b/src/components/Layout/index.ts deleted file mode 100755 index 044f1bc..0000000 --- a/src/components/Layout/index.ts +++ /dev/null @@ -1,5 +0,0 @@ -export * from './AdminLayoutPortal' -export * from './LayoutPortal' - -export type { AdminLayoutPortalProps } from './AdminLayoutPortal' -export type { LayoutPortalProps } from './LayoutPortal' diff --git a/src/components/LayoutPortal.tsx b/src/components/LayoutPortal.tsx new file mode 100644 index 0000000..909172e --- /dev/null +++ b/src/components/LayoutPortal.tsx @@ -0,0 +1,136 @@ +import { Breadcrumb, Layout, LayoutProps, Menu, SiderProps } from 'antd' +import { Key, memo, ReactNode, Suspense, useCallback, useEffect, useMemo, useState } from 'react' +import { ItemType } from 'antd/lib/menu/hooks/useItems' +import { Link, Outlet } from 'react-router-dom' +import { + ApartmentOutlined, + CodeOutlined, + HomeOutlined, + UserOutlined, +} from '@ant-design/icons' + +import { LayoutPropsContext } from '@asb/context' +import { UserMenu, UserMenuProps } from '@components/UserMenu' +import { WellTreeSelector, WellTreeSelectorProps } from '@components/selectors/WellTreeSelector' +import { isURLAvailable, wrapPrivateComponent } from '@utils' + +import SuspenseFallback from './SuspenseFallback' + +import Logo from '@images/Logo' + +import '@styles/layout.less' + +const { Content, Sider } = Layout + +export type LayoutPortalProps = Omit & { + title?: ReactNode + sheet?: boolean + showSelector?: boolean + selectorProps?: WellTreeSelectorProps + sider?: boolean | JSX.Element + siderProps?: SiderProps & { userMenuProps?: UserMenuProps } + isAdmin?: boolean + fallback?: JSX.Element + breadcrumb?: boolean | JSX.Element + topRightBlock?: 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(() => { + 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, breadcrumb, topRightBlock, ...other } = useMemo(() => props, [props]) + + const setLayoutProps = useCallback((props: LayoutPortalProps) => setProps({ ...defaultProps, ...props}), []) + + useEffect(() => { + if (typeof showSelector === 'boolean') + setWellsTreeOpen(showSelector) + }, [showSelector]) + + const menuItems = useMemo(() => [ + !isAdmin && makeItem(currentWell, 'well', , null, () => setWellsTreeOpen((prev) => !prev)), + isAdmin && makeItem('Вернуться на сайт', 'go_back', , Домой), + !isAdmin && isURLAvailable('/admin') && makeItem('Панель администратора', 'admin_panel', , Панель администратора), + makeItem('Профиль', 'profile', , null, () => setUserMenuOpen((prev) => !prev)), + ].filter(Boolean) as ItemType[], [isAdmin, currentWell]) + + return ( + + {(sider || siderProps) && ( + +
+ +
+ {sider} +
+ + setUserMenuOpen(false)} + isAdmin={isAdmin} + {...siderProps?.userMenuProps} + /> +
+
+ )} + {!isAdmin && ( + setWellsTreeOpen(false)} + {...selectorProps} + onChange={(well) => setCurrentWell(well ?? 'Выберите месторождение')} + /> + )} + + + {(breadcrumb || topRightBlock) && ( +
+ {breadcrumb && ( + + + + + {!isAdmin && ( + + setWellsTreeOpen((prev) => !prev)}>{currentWell} + + )} + {breadcrumb} + + )} + {topRightBlock} +
+ )} + + }> + + + +
+
+
+ ) +}) + +export const LayoutPortal = wrapPrivateComponent(_LayoutPortal, { requirements: ['Deposit.get'] }) + +export default LayoutPortal diff --git a/src/components/MenuBreadcrumb.tsx b/src/components/MenuBreadcrumb.tsx new file mode 100644 index 0000000..05cbc74 --- /dev/null +++ b/src/components/MenuBreadcrumb.tsx @@ -0,0 +1,56 @@ +import { Breadcrumb, BreadcrumbItemProps } from 'antd' +import { Link, useLocation } from 'react-router-dom' +import { memo, useMemo } from 'react' +import { join } from 'path' + +import { PrivateWellMenuItem } from '@components/PrivateWellMenu' +import { FunctionalValue, useFunctionalValue } from '@utils' + +export const makeBreadcrumbItems = (items: PrivateWellMenuItem[], pathParts: string[], root: string = '/') => { + const out = [] + const parts = [...pathParts] + let route = root + let arr: PrivateWellMenuItem[] | undefined = items + while (arr && parts.length > 0) { + const child: PrivateWellMenuItem | undefined = arr.find(elm => elm.route.toLowerCase() === parts[0].toLowerCase()) + if (!child) break + route = join(route, child.route) + out.push({ ...child, route }) + parts.splice(0, 1) + arr = child.children + } + return out +} + +export type MenuBreadcrumbItemsProps = { + menuItems: PrivateWellMenuItem[] + pathRoot?: RegExp + itemsProps?: FunctionalValue<(item: PrivateWellMenuItem) => BreadcrumbItemProps> + itemRender?: (item: PrivateWellMenuItem) => JSX.Element +} + +export const MenuBreadcrumbItems = memo(({ menuItems, pathRoot = /^\//, itemsProps, itemRender }) => { + const location = useLocation() + const getItemProps = useFunctionalValue(itemsProps) + + const items = useMemo(() => { + const path = location.pathname + const rootPart = pathRoot.exec(path) + if (!rootPart || rootPart.length <= 0) return [] + const root = rootPart[0] + const parts = path.trim().slice(root.length).split('/') + return makeBreadcrumbItems(menuItems, parts, root) + }, [location, menuItems, pathRoot]) + + return ( + <> + {items.map((item) => ( + + {itemRender ? itemRender(item) : ( + {item.title} + )} + + ))} + + ) +}) diff --git a/src/components/PageHeader.tsx b/src/components/PageHeader.tsx deleted file mode 100755 index 3dc6c02..0000000 --- a/src/components/PageHeader.tsx +++ /dev/null @@ -1,30 +0,0 @@ -import { memo } from 'react' -import { Layout } from 'antd' -import { Link } from 'react-router-dom' -import { BasicProps } from 'antd/lib/layout/layout' - -import { headerHeight } from '@utils' -import { UserMenu } from './UserMenu' - -import Logo from '@images/Logo' - -export type PageHeaderProps = BasicProps & { - title?: string - isAdmin?: boolean - children?: React.ReactNode -} - -export const PageHeader: React.FC = memo(({ title = 'Мониторинг', isAdmin, children, ...other }) => ( - - - - - -

{title}

- {children} - -
-
-)) - -export default PageHeader diff --git a/src/components/Private/PrivateContent.tsx b/src/components/Private/PrivateContent.tsx deleted file mode 100755 index 9b9e02b..0000000 --- a/src/components/Private/PrivateContent.tsx +++ /dev/null @@ -1,14 +0,0 @@ -import { memo, ReactElement } from 'react' - -import { isURLAvailable } from '@utils' - -export type PrivateContentProps = { - absolutePath: string - children?: ReactElement -} - -export const PrivateContent = memo(({ absolutePath, children = null }) => - isURLAvailable(absolutePath) ? children : null -) - -export default PrivateContent diff --git a/src/components/Private/PrivateDefaultRoute.tsx b/src/components/Private/PrivateDefaultRoute.tsx deleted file mode 100755 index e1cc07e..0000000 --- a/src/components/Private/PrivateDefaultRoute.tsx +++ /dev/null @@ -1,19 +0,0 @@ -import { memo } from 'react' -import { Navigate, Route, RouteProps } from 'react-router-dom' - -import { isURLAvailable } from '@utils' - -import { getDefaultRedirectPath } from './PrivateRoutes' - -export type PrivateDefaultRouteProps = RouteProps & { - urls: string[] - elseRedirect?: string -} - -export const PrivateDefaultRoute = memo(({ elseRedirect, urls, ...other }) => ( - isURLAvailable(url)) ?? elseRedirect ?? getDefaultRedirectPath()} /> - )} /> -)) - -export default PrivateDefaultRoute diff --git a/src/components/Private/PrivateMenu.tsx b/src/components/Private/PrivateMenu.tsx deleted file mode 100644 index 8913560..0000000 --- a/src/components/Private/PrivateMenu.tsx +++ /dev/null @@ -1,75 +0,0 @@ -import { join } from 'path' -import { Menu, MenuProps } from 'antd' -import { ItemType } from 'antd/lib/menu/hooks/useItems' -import { Link, LinkProps } from 'react-router-dom' -import { Children, isValidElement, memo, ReactNode, RefAttributes, useMemo } from 'react' - -import { useRootPath } from '@asb/context' -import { getTabname, hasPermission, PrivateComponent, PrivateProps } from '@utils' - -export type PrivateMenuProps = MenuProps & { root?: string } - -export type PrivateMenuLinkProps = Partial & Omit & RefAttributes & { - icon?: ReactNode - danger?: boolean - title?: ReactNode - content?: PrivateComponent - path?: string - visible?: boolean - permissions?: string[] -} - -export const PrivateMenuLink = memo(({ content, path = '', title, ...other }) => ( - {title ?? content?.title} -)) - -const PrivateMenuMain = memo(({ selectable, mode, selectedKeys, root, children, ...other }) => { - const rootContext = useRootPath() - const rootPath = useMemo(() => root ?? rootContext ?? '', [root, rootContext]) - - const tab = getTabname() - const keys = useMemo(() => selectedKeys ?? (tab ? [tab] : []), [selectedKeys, tab]) - - const items = useMemo(() => Children.map(children, (child) => { - if (!child || !isValidElement(child)) - return null - const content: PrivateProps | undefined = child.props.content - const visible: boolean | undefined = child.props.visible - - if (visible === false) return null - let key - if (content?.key) - key = content.key - else if (content?.route) - key = content.route - else if (child.key) { - key = child.key?.toString() - key = key.slice(key.lastIndexOf('$') + 1) - } else return null - - const permissions = child.props.permissions ?? content?.requirements - const path = child.props.path ?? join(rootPath, key) - - if (visible || hasPermission(permissions)) - return { - ...child.props, - key, - label: , - } - return null - })?.filter((v) => v) ?? [], [children, rootPath]) - - return ( - - ) -}) - -export const PrivateMenu = Object.assign(PrivateMenuMain, { Link: PrivateMenuLink }) - -export default PrivateMenu diff --git a/src/components/Private/PrivateMenuItem.tsx b/src/components/Private/PrivateMenuItem.tsx deleted file mode 100755 index e549625..0000000 --- a/src/components/Private/PrivateMenuItem.tsx +++ /dev/null @@ -1,37 +0,0 @@ -import { join } from 'path' -import { Menu, MenuItemProps } from 'antd' -import { memo, NamedExoticComponent } from 'react' -import { Link, useLocation } from 'react-router-dom' - -import { isURLAvailable } from '@utils' - -export type PrivateMenuItemProps = MenuItemProps & { - root: string - path: string -} - -export type PrivateMenuItemLinkProps = MenuItemProps & { - root?: string - path: string - title: string -} - -export const PrivateMenuItemLink = memo(({ root = '', path, title, ...other }) => { - const location = useLocation() - return ( - - {title} - - ) -}) - -export const PrivateMenuItem: NamedExoticComponent & { - Link: NamedExoticComponent -} = Object.assign(memo(({ root, path, ...other }) => -
- - + +
+ + {depositsData.map(deposit => ( + + + {deposit.clusters.map(cluster => ( + +
{cluster.caption}
+ + ))} +
+ } trigger={['click']} title={deposit.caption}> +
+ + + +
+
+ + ))} + + + ) }) diff --git a/src/pages/FileDownload.jsx b/src/pages/FileDownload.jsx index 810894e..88877d5 100644 --- a/src/pages/FileDownload.jsx +++ b/src/pages/FileDownload.jsx @@ -7,8 +7,6 @@ import { downloadFile, invokeWebApiWrapperAsync } from '@components/factory' import { wrapPrivateComponent } from '@utils' import { FileService } from '@api' -import AccessDenied from './AccessDenied' - const { Paragraph, Text } = Typography export const getLinkToFile = (fileInfo) => `/file_download/${fileInfo.id}` @@ -97,4 +95,4 @@ FileDownload.displayName = 'FileDownloadMemo' export default wrapPrivateComponent(FileDownload, { requirements: ['File.get'], route: 'file_download/:idFile/*', -}, ) +}) diff --git a/src/pages/Reports/index.jsx b/src/pages/Reports/index.jsx deleted file mode 100644 index d28275c..0000000 --- a/src/pages/Reports/index.jsx +++ /dev/null @@ -1,48 +0,0 @@ -import { Navigate, Route, Routes } from 'react-router-dom' -import { memo, useMemo } from 'react' -import { FilePdfOutlined } from '@ant-design/icons' -import { Layout } from 'antd' - -import { RootPathContext, useRootPath } from '@asb/context' -import { PrivateMenu } from '@components/Private' -import { NoAccessComponent, wrapPrivateComponent } from '@utils' - -import DailyReport from './DailyReport' -import DiagramReport from './DiagramReport' - -const { Content } = Layout - -const Reports = memo(() => { - const root = useRootPath() - const rootPath = useMemo(() => `${root}/reports`, [root]) - - return ( - - - - } /> - - - - - - - } /> - } /> - - } /> - } /> - - - - - - ) -}) - -export default wrapPrivateComponent(Reports, { - requirements: [], - title: 'Рапорта', - route: 'reports/*', - key: 'reports', -}) diff --git a/src/pages/Telemetry/index.jsx b/src/pages/Telemetry/index.jsx deleted file mode 100755 index d85f7e8..0000000 --- a/src/pages/Telemetry/index.jsx +++ /dev/null @@ -1,63 +0,0 @@ -import { Navigate, Route, Routes } from 'react-router-dom' -import { memo, useMemo } from 'react' -import { Layout } from 'antd' -import { AlertOutlined, FundViewOutlined, DatabaseOutlined } from '@ant-design/icons' - -import { RootPathContext, useRootPath } from '@asb/context' -import { PrivateMenu } from '@components/Private' -import { NoAccessComponent, wrapPrivateComponent } from '@utils' - -import Archive from './Archive' -import Messages from './Messages' -import Operations from './Operations' -import DashboardNNB from './DashboardNNB' -import TelemetryView from './TelemetryView' -import OperationTime from './OperationTime' - -import '@styles/index.css' - -const { Content } = Layout - -const Telemetry = memo(() => { - const root = useRootPath() - const rootPath = useMemo(() => `${root}/telemetry`, [root]) - - return ( - - - - } /> - } /> - } /> - - - - - - - - - } /> - } /> - - } /> - } /> - } /> - } /> - } /> - } /> - - - - - - ) -}) - -export default wrapPrivateComponent(Telemetry, { - requirements: [], - icon: , - title: 'Телеметрия', - route: 'telemetry/*', - key: 'telemetry', -}) diff --git a/src/pages/Well.jsx b/src/pages/Well.jsx deleted file mode 100755 index 1310bd6..0000000 --- a/src/pages/Well.jsx +++ /dev/null @@ -1,104 +0,0 @@ -import { - FolderOutlined, - FilePdfOutlined, - ExperimentOutlined, - DeploymentUnitOutlined, -} from '@ant-design/icons' -import { Layout } from 'antd' -import { 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/Layout' -import { PrivateMenu } from '@components/Private' -import { invokeWebApiWrapperAsync } from '@components/factory' -import { NoAccessComponent, wrapPrivateComponent } from '@utils' -import { WellService } from '@api' - -import Measure from './Measure' -import Reports from './Reports' -import WellCase from './WellCase' -import Analytics from './Analytics' -import Documents from './Documents' -import Telemetry from './Telemetry' -import WellOperations from './WellOperations' -import DrillingProgram from './DrillingProgram' - -import '@styles/index.css' - -const { Content } = Layout - -const Well = memo(() => { - const { idWell } = useParams() - - const [well, setWell] = useState({ id: idWell }) - - 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 updateWell = useCallback((data) => invokeWebApiWrapperAsync( - async () => { - const newWell = { ...well, ...data } - await WellService.updateWell(newWell) - setWell(newWell) - }, - undefined, - `Не удалось изменить данные скважины`, - { actionName: 'Изменение данных скважины', well } - ), [well]) - - return ( - - - - - } /> - } /> - } /> - } /> - } /> - } /> - } /> - - - - - - - } /> - } /> - - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - - - - - - - ) -}) - -export default wrapPrivateComponent(Well, { - requirements: [], - title: 'Скважина', - route: 'well/:idWell/*', - key: 'well', -}) diff --git a/src/pages/Analytics/Statistics.jsx b/src/pages/Well/Analytics/Statistics.jsx old mode 100755 new mode 100644 similarity index 100% rename from src/pages/Analytics/Statistics.jsx rename to src/pages/Well/Analytics/Statistics.jsx diff --git a/src/pages/Analytics/WellCompositeEditor/NewParamsTable.jsx b/src/pages/Well/Analytics/WellCompositeEditor/NewParamsTable.jsx old mode 100755 new mode 100644 similarity index 54% rename from src/pages/Analytics/WellCompositeEditor/NewParamsTable.jsx rename to src/pages/Well/Analytics/WellCompositeEditor/NewParamsTable.jsx index bf504df..9c3d812 --- a/src/pages/Analytics/WellCompositeEditor/NewParamsTable.jsx +++ b/src/pages/Well/Analytics/WellCompositeEditor/NewParamsTable.jsx @@ -2,12 +2,75 @@ import { memo, useCallback, useEffect, useState } from 'react' import { Button, Modal, Popconfirm } from 'antd' import { useWell } from '@asb/context' -import { Table } from '@components/Table' +import { makeColumn, makeGroupColumn, makeNumericRender, makeSelectColumn, Table } from '@components/Table' import LoaderPortal from '@components/LoaderPortal' import { invokeWebApiWrapperAsync } from '@components/factory' -import { DrillParamsService } from '@api' +import { DrillParamsService, WellOperationService } from '@api' -import { getColumns } from '@pages/WellOperations/WellDrillParams' +const getDeepValue = (data, key) => { + if (!key || key.trim() === '') return null + const keys = key.split('.') + let out = data + while (keys.length > 0) { + if (!(keys[0] in out)) return null + out = out[keys[0]] + keys.splice(0, 1) + } + return out +} + +const makeNumericSorter = (keys) => (a, b) => getDeepValue(a, keys) - getDeepValue(b, keys) + +const numericRender = makeNumericRender(1) +const makeNumericColumn = (title, dataIndex, render, other) => makeColumn(title, dataIndex, { + sorter: makeNumericSorter(dataIndex), + render: (_, record, index) => { + const func = render ?? ((value) => <>{value}) + const item = getDeepValue(record, dataIndex) + return func(item, record, index) + }, + align: 'right', + ...other, +}) + +const makeAvgRender = (dataIndex) => (avg, record) => { + const max = record[dataIndex]?.max + const fillW = (max - avg) / max * 100 + return ( +
+
+
+ {numericRender(avg)} +
+
+ ) +} + +const makeNumericAvgRange = (title, dataIndex, defaultRender = false) => makeGroupColumn(title, [ + makeNumericColumn('мин', `${dataIndex}.min`), + makeNumericColumn('сред', `${dataIndex}.avg`, defaultRender ? undefined : makeAvgRender(dataIndex)), + makeNumericColumn('макс', `${dataIndex}.max`), +]) + +export const getColumns = async (idWell) => { + let sectionTypes = await WellOperationService.getSectionTypes(idWell) + sectionTypes = Object.entries(sectionTypes).map(([id, value]) => ({ + label: value, + value: id, + })) + + return [ + makeSelectColumn('Конструкция секции','idWellSectionType', sectionTypes, null, { + width: 160, + sorter: makeNumericSorter('idWellSectionType'), + }), + makeNumericAvgRange('Нагрузка, т', 'axialLoad'), + makeNumericAvgRange('Давление, атм', 'pressure'), + makeNumericAvgRange('Момент на ВСП, кН·м', 'rotorTorque', true), + makeNumericAvgRange('Обороты на ВСП, об/мин', 'rotorSpeed'), + makeNumericAvgRange('Расход, л/с', 'flow'), + ] +} export const NewParamsTable = memo(({ selectedWellsKeys }) => { const [params, setParams] = useState([]) @@ -54,7 +117,7 @@ export const NewParamsTable = memo(({ selectedWellsKeys }) => { setIsParamsModalVisible(false)} width={1700} footer={( diff --git a/src/pages/Analytics/WellCompositeEditor/WellCompositeSections.jsx b/src/pages/Well/Analytics/WellCompositeEditor/WellCompositeSections.jsx similarity index 88% rename from src/pages/Analytics/WellCompositeEditor/WellCompositeSections.jsx rename to src/pages/Well/Analytics/WellCompositeEditor/WellCompositeSections.jsx index 2a608a5..db9229a 100644 --- a/src/pages/Analytics/WellCompositeEditor/WellCompositeSections.jsx +++ b/src/pages/Well/Analytics/WellCompositeEditor/WellCompositeSections.jsx @@ -1,7 +1,7 @@ import { Link, useLocation } from 'react-router-dom' -import { useState, useEffect, memo, useMemo } from 'react' +import { useState, useEffect, memo, useMemo, lazy, Suspense } from 'react' import { LineChartOutlined, ProfileOutlined, TeamOutlined } from '@ant-design/icons' -import { Table, Tag, Button, Badge, Divider, Modal, Row, Col } from 'antd' +import { Table, Button, Badge, Divider, Modal, Row, Col } from 'antd' import { useWell } from '@asb/context' import LoaderPortal from '@components/LoaderPortal' @@ -16,10 +16,12 @@ import { getOperations } from '@utils' -import Tvd from '@pages/WellOperations/Tvd' -import WellOperationsTable from '@pages/Cluster/WellOperationsTable' import NewParamsTable from './NewParamsTable' -import CompaniesTable from '@pages/Cluster/CompaniesTable' +import SuspenseFallback from '@asb/components/SuspenseFallback' + +const Tvd = lazy(() => import('@pages/Well/WellOperations/Tvd')) +const CompaniesTable = lazy(() => import('@pages/Cluster/CompaniesTable')) +const WellOperationsTable = lazy(() => import('@pages/Cluster/WellOperationsTable')) const filtersMinMax = [ { text: 'min', value: 'min' }, @@ -222,38 +224,44 @@ const WellCompositeSections = memo(({ statsWells, selectedSections }) => { setIsTVDModalVisible(false)} width={1500} footer={null} > - + }> + + setIsOpsModalVisible(false)} width={1500} footer={null} > - - - + }> + + + + setIsCompaniesModalVisible(false)} width={1500} footer={null} > - - - + }> + + + + ) diff --git a/src/pages/Analytics/WellCompositeEditor/index.jsx b/src/pages/Well/Analytics/WellCompositeEditor/index.jsx old mode 100755 new mode 100644 similarity index 52% rename from src/pages/Analytics/WellCompositeEditor/index.jsx rename to src/pages/Well/Analytics/WellCompositeEditor/index.jsx index c0cc5b9..b2ab94b --- a/src/pages/Analytics/WellCompositeEditor/index.jsx +++ b/src/pages/Well/Analytics/WellCompositeEditor/index.jsx @@ -1,35 +1,26 @@ -import { useState, useEffect, memo, useMemo } from 'react' import { Navigate, Route, Routes } from 'react-router-dom' -import { Col, Layout, Row } from 'antd' +import { useState, useEffect, memo, Suspense, lazy } from 'react' +import { Row } from 'antd' -import { useWell, useRootPath } from '@asb/context' -import { PrivateMenu } from '@components/Private' +import { useWell } from '@asb/context' import LoaderPortal from '@components/LoaderPortal' +import SuspenseFallback from '@components/SuspenseFallback' import WellSelector from '@components/selectors/WellSelector' import { invokeWebApiWrapperAsync } from '@components/factory' import { arrayOrDefault, NoAccessComponent, wrapPrivateComponent } from '@utils' import { OperationStatService, WellCompositeService } from '@api' -import ClusterWells from '@pages/Cluster/ClusterWells' import WellCompositeSections from './WellCompositeSections' -const { Content } = Layout +import '@styles/well_composite.less' -const properties = { - requirements: ['OperationStat.get', 'WellComposite.get'], - title: 'Композитная скважина', - route: 'composite/*', - key: 'composite', -} +const ClusterWells = lazy(() => import('@pages/Cluster/ClusterWells')) const WellCompositeEditor = memo(() => { const [well] = useWell() - const root = useRootPath() - const rootPath = useMemo(() => `${root}/${properties.key}`, [root]) const [statsWells, setStatsWells] = useState([]) const [showLoader, setShowLoader] = useState(false) - const [showTabLoader, setShowTabLoader] = useState(false) const [selectedIdWells, setSelectedIdWells] = useState([]) const [selectedSections, setSelectedSections] = useState([]) @@ -61,7 +52,7 @@ const WellCompositeEditor = memo(() => { const stats = arrayOrDefault(await OperationStatService.getWellsStat(selectedIdWells)) setStatsWells(stats) }, - setShowTabLoader, + setShowLoader, 'Не удалось загрузить статистику по скважинам/секциям', { actionName: 'Получение статистики по скважинам/секциям' } ) @@ -69,32 +60,20 @@ const WellCompositeEditor = memo(() => { return ( - - - - - - - - - - + + - - - - - } /> - } /> + }> + + } /> + } /> - } /> - } /> - - - - + } /> + } /> + + ) }) -export default wrapPrivateComponent(WellCompositeEditor, properties) +export default wrapPrivateComponent(WellCompositeEditor, { requirements: ['OperationStat.get', 'WellComposite.get'] }) diff --git a/src/pages/Well/Analytics/index.jsx b/src/pages/Well/Analytics/index.jsx new file mode 100644 index 0000000..f610484 --- /dev/null +++ b/src/pages/Well/Analytics/index.jsx @@ -0,0 +1,23 @@ +import { memo, useMemo } from 'react' +import { Outlet } from 'react-router-dom' + +import { RootPathContext, useRootPath } from '@asb/context' +import { wrapPrivateComponent } from '@utils' + +const Analytics = memo(() => { + const root = useRootPath() + const rootPath = useMemo(() => `${root}/analytics`, [root]) + + return ( + + + + ) +}) + +export default wrapPrivateComponent(Analytics, { + requirements: [], + title: 'Аналитика', + route: 'analytics/*', + key: 'analytics', +}) diff --git a/src/pages/Documents/DocumentsTemplate.jsx b/src/pages/Well/Documents/DocumentsTemplate.jsx old mode 100755 new mode 100644 similarity index 98% rename from src/pages/Documents/DocumentsTemplate.jsx rename to src/pages/Well/Documents/DocumentsTemplate.jsx index 4452c05..673a8a2 --- a/src/pages/Documents/DocumentsTemplate.jsx +++ b/src/pages/Well/Documents/DocumentsTemplate.jsx @@ -94,7 +94,7 @@ export const DocumentsTemplate = ({ idCategory, well: givenWell, mimeTypes, head return ( -
+
Фильтр по дате
@@ -158,6 +158,7 @@ export const DocumentsTemplate = ({ idCategory, well: givenWell, mimeTypes, head onRowDelete={handleFileDelete} rowKey={(record) => record.id} tableName={tableName ?? `file_${idCategory}`} + scroll={{ x: true }} /> ) diff --git a/src/pages/Documents/index.jsx b/src/pages/Well/Documents/index.jsx old mode 100755 new mode 100644 similarity index 59% rename from src/pages/Documents/index.jsx rename to src/pages/Well/Documents/index.jsx index d3882fb..1b4c293 --- a/src/pages/Documents/index.jsx +++ b/src/pages/Well/Documents/index.jsx @@ -1,16 +1,11 @@ import { Navigate, Route, Routes } from 'react-router-dom' import { memo, useMemo } from 'react' -import { FolderOutlined } from '@ant-design/icons' -import { Layout } from 'antd' import { RootPathContext, useRootPath } from '@asb/context' -import { PrivateMenu } from '@components/Private' -import { getTabname, wrapPrivateComponent, NoAccessComponent, hasPermission } from '@utils' +import { wrapPrivateComponent, NoAccessComponent, hasPermission } from '@utils' import DocumentsTemplate from './DocumentsTemplate' -const { Content } = Layout - const makeDocCat = (id, key, title, permissions = ['File.get']) => ({ id, key, title, permissions }) export const documentCategories = [ @@ -27,7 +22,6 @@ export const documentCategories = [ ] const MenuDocuments = memo(() => { - const category = getTabname() const root = useRootPath() const rootPath = useMemo(() => `${root}/document`, [root]) @@ -35,34 +29,21 @@ const MenuDocuments = memo(() => { return ( - - {categories.map(category => ( - } - title={category.title} - /> - ))} - - - - - {categories.length > 0 && ( - } /> - )} - } /> + + {categories.length > 0 && ( + } /> + )} + } /> - {categories.map(category => ( - - )} /> - ))} - - - + {categories.map(category => ( + + )} /> + ))} + ) }) diff --git a/src/pages/DrillingProgram/CategoryAdder.jsx b/src/pages/Well/DrillingProgram/CategoryAdder.jsx old mode 100755 new mode 100644 similarity index 100% rename from src/pages/DrillingProgram/CategoryAdder.jsx rename to src/pages/Well/DrillingProgram/CategoryAdder.jsx diff --git a/src/pages/DrillingProgram/CategoryEditor.jsx b/src/pages/Well/DrillingProgram/CategoryEditor.jsx old mode 100755 new mode 100644 similarity index 99% rename from src/pages/DrillingProgram/CategoryEditor.jsx rename to src/pages/Well/DrillingProgram/CategoryEditor.jsx index b1066e1..cab4df1 --- a/src/pages/DrillingProgram/CategoryEditor.jsx +++ b/src/pages/Well/DrillingProgram/CategoryEditor.jsx @@ -159,7 +159,7 @@ export const CategoryEditor = memo(({ visible, category, onClosed }) => { { title={'История категории'} width={1200} centered - visible={!!visible} + open={!!visible} onCancel={onClose} footer={( diff --git a/src/pages/DrillingProgram/CategoryRender.jsx b/src/pages/Well/DrillingProgram/CategoryRender.jsx old mode 100755 new mode 100644 similarity index 100% rename from src/pages/DrillingProgram/CategoryRender.jsx rename to src/pages/Well/DrillingProgram/CategoryRender.jsx diff --git a/src/pages/DrillingProgram/MarksCard.jsx b/src/pages/Well/DrillingProgram/MarksCard.jsx old mode 100755 new mode 100644 similarity index 100% rename from src/pages/DrillingProgram/MarksCard.jsx rename to src/pages/Well/DrillingProgram/MarksCard.jsx diff --git a/src/pages/DrillingProgram/index.jsx b/src/pages/Well/DrillingProgram/index.jsx old mode 100755 new mode 100644 similarity index 100% rename from src/pages/DrillingProgram/index.jsx rename to src/pages/Well/DrillingProgram/index.jsx diff --git a/src/pages/Measure/InclinometryTable.jsx b/src/pages/Well/Measure/InclinometryTable.jsx old mode 100755 new mode 100644 similarity index 97% rename from src/pages/Measure/InclinometryTable.jsx rename to src/pages/Well/Measure/InclinometryTable.jsx index 18d1660..2725743 --- a/src/pages/Measure/InclinometryTable.jsx +++ b/src/pages/Well/Measure/InclinometryTable.jsx @@ -35,7 +35,7 @@ export const InclinometryTable = memo(({ group, visible, onClose }) => { , [ + makeItem('Мониторинг', 'telemetry', [], ), + makeItem('Сообщения', 'messages', [], ), + makeItem('Архив', 'archive', [], ), + makeItem('ННБ', 'dashboard_nnb', [], ), + makeItem('Операции', 'operations', [], ), + makeItem('Наработка', 'operation_time', [], ), + ]), + makeItem('Рапорта', 'reports', [], , [ + makeItem('Диаграмма', 'diagram_report', [], ), + makeItem('Суточный рапорт', 'daily_report', [], ), + ]), + makeItem('Аналитика', 'analytics', [], , [ + makeItem('Композитная скважина', 'composite', [], , [ + makeItem('Статистика по скважинам', 'wells', [], ), + makeItem('Статистика по секциям', 'sections', [], ), + ]), + makeItem('Оценка по ЦБ', 'statistics', [], ), + ]), + makeItem('Операции по скважине', 'operations', [], , [ + makeItem('TVD', 'tvd', [], ), + makeItem('Секции', 'sections', [], ), + makeItem('План', 'plan', [], ), + makeItem('Факт', 'fact', [], ), + makeItem('РТК', 'drillProcessFlow', [], ), + makeItem('Режимы', 'params', [], ), + ]), + makeItem('Документы', 'document', [], , [ + makeItem('Растворный сервис', 'fluidService', [], ), + makeItem('Цементирование', 'cementing', [], ), + makeItem('ННБ', 'nnb', [], ), + makeItem('ГТИ', 'gti', [], ), + makeItem('Документы по скважине', 'documentsForWell', [], ), + makeItem('Супервайзер', 'supervisor', [], ), + makeItem('Мастер', 'master', [], ), + makeItem('Долотный сервис', 'toolService', [], ), + makeItem('Буровой подрядчик', 'drillService', [], ), + makeItem('Сервис по заканчиванию скважины', 'closingService', [], ), + ]), + makeItem('Измерения', 'measure', [], ), + makeItem('Программа бурения', 'drillingProgram', [], ), + makeItem('Дело скважины', 'well_case', [], ), +] + +export const NavigationMenu = memo((props) => ( + +)) + +export default NavigationMenu diff --git a/src/pages/Reports/DailyReport/ReportEditor.jsx b/src/pages/Well/Reports/DailyReport/ReportEditor.jsx similarity index 99% rename from src/pages/Reports/DailyReport/ReportEditor.jsx rename to src/pages/Well/Reports/DailyReport/ReportEditor.jsx index c39ef39..e77fc61 100644 --- a/src/pages/Reports/DailyReport/ReportEditor.jsx +++ b/src/pages/Well/Reports/DailyReport/ReportEditor.jsx @@ -374,7 +374,7 @@ export const ReportEditor = memo(({ visible, data, onDone, onCancel, checkIsDate (
)) diff --git a/src/pages/Telemetry/Operations/TargetEditor.jsx b/src/pages/Well/Telemetry/Operations/TargetEditor.jsx similarity index 99% rename from src/pages/Telemetry/Operations/TargetEditor.jsx rename to src/pages/Well/Telemetry/Operations/TargetEditor.jsx index 1df0c9a..69f49cf 100644 --- a/src/pages/Telemetry/Operations/TargetEditor.jsx +++ b/src/pages/Well/Telemetry/Operations/TargetEditor.jsx @@ -96,7 +96,7 @@ export const TargetEditor = memo(({ loading, onChange }) => { centered width={1000} footer={null} - visible={showModal} + open={showModal} onCancel={onModalCancel} title={'Цели бурения'} > diff --git a/src/pages/Telemetry/Operations/index.jsx b/src/pages/Well/Telemetry/Operations/index.jsx similarity index 95% rename from src/pages/Telemetry/Operations/index.jsx rename to src/pages/Well/Telemetry/Operations/index.jsx index af06d26..fd34730 100644 --- a/src/pages/Telemetry/Operations/index.jsx +++ b/src/pages/Well/Telemetry/Operations/index.jsx @@ -1,11 +1,12 @@ import { memo, useCallback, useEffect, useMemo, useState } from 'react' -import { Empty, InputNumber, Select } from 'antd' +import { InputNumber, Select } from 'antd' import moment from 'moment' import { useWell } from '@asb/context' import LoaderPortal from '@components/LoaderPortal' import { DateRangeWrapper } from '@components/Table' import { invokeWebApiWrapperAsync } from '@components/factory' +import { unique } from '@utils/filters' import { getPermissions, arrayOrDefault, range, wrapPrivateComponent, pretify } from '@utils' import { DetectedOperationService, DrillerService, TelemetryDataSaubService } from '@api' @@ -16,7 +17,6 @@ import OperationsChart from './OperationsChart' import OperationsTable from './OperationsTable' import '@styles/detected_operations.less' -import { unique } from '@asb/utils/filters' const Operations = memo(() => { const [isLoading, setIsLoading] = useState(false) @@ -161,11 +161,4 @@ const Operations = memo(() => { ) }) -export default wrapPrivateComponent(Operations, { - requirements: [ - 'DetectedOperation.get', - 'TelemetryDataSaub.get', - ], - title: 'Операции', - route: 'operations', -}) +export default wrapPrivateComponent(Operations, { requirements: ['DetectedOperation.get', 'TelemetryDataSaub.get'] }) diff --git a/src/pages/Telemetry/TelemetryView/ActiveMessagesOnline.jsx b/src/pages/Well/Telemetry/TelemetryView/ActiveMessagesOnline.jsx old mode 100755 new mode 100644 similarity index 100% rename from src/pages/Telemetry/TelemetryView/ActiveMessagesOnline.jsx rename to src/pages/Well/Telemetry/TelemetryView/ActiveMessagesOnline.jsx diff --git a/src/pages/Telemetry/TelemetryView/CustomColumn.jsx b/src/pages/Well/Telemetry/TelemetryView/CustomColumn.jsx old mode 100755 new mode 100644 similarity index 100% rename from src/pages/Telemetry/TelemetryView/CustomColumn.jsx rename to src/pages/Well/Telemetry/TelemetryView/CustomColumn.jsx diff --git a/src/pages/Telemetry/TelemetryView/ModeDisplay.jsx b/src/pages/Well/Telemetry/TelemetryView/ModeDisplay.jsx old mode 100755 new mode 100644 similarity index 100% rename from src/pages/Telemetry/TelemetryView/ModeDisplay.jsx rename to src/pages/Well/Telemetry/TelemetryView/ModeDisplay.jsx diff --git a/src/pages/Telemetry/TelemetryView/RigMnemo.jsx b/src/pages/Well/Telemetry/TelemetryView/RigMnemo.jsx old mode 100755 new mode 100644 similarity index 100% rename from src/pages/Telemetry/TelemetryView/RigMnemo.jsx rename to src/pages/Well/Telemetry/TelemetryView/RigMnemo.jsx diff --git a/src/pages/Telemetry/TelemetryView/Setpoints/SetpointSender.jsx b/src/pages/Well/Telemetry/TelemetryView/Setpoints/SetpointSender.jsx old mode 100755 new mode 100644 similarity index 99% rename from src/pages/Telemetry/TelemetryView/Setpoints/SetpointSender.jsx rename to src/pages/Well/Telemetry/TelemetryView/Setpoints/SetpointSender.jsx index 0d7bcf4..537ed29 --- a/src/pages/Telemetry/TelemetryView/Setpoints/SetpointSender.jsx +++ b/src/pages/Well/Telemetry/TelemetryView/Setpoints/SetpointSender.jsx @@ -80,7 +80,7 @@ export const SetpointSender = memo(({ onClose, visible, setpointNames }) => { diff --git a/src/pages/Telemetry/TelemetryView/Setpoints/index.jsx b/src/pages/Well/Telemetry/TelemetryView/Setpoints/index.jsx old mode 100755 new mode 100644 similarity index 99% rename from src/pages/Telemetry/TelemetryView/Setpoints/index.jsx rename to src/pages/Well/Telemetry/TelemetryView/Setpoints/index.jsx index 828f61c..a5822de --- a/src/pages/Telemetry/TelemetryView/Setpoints/index.jsx +++ b/src/pages/Well/Telemetry/TelemetryView/Setpoints/index.jsx @@ -89,7 +89,7 @@ export const Setpoints = memo(({ ...other }) => { )} - visible={isModalVisible} + open={isModalVisible} onCancel={() => setIsModalVisible(false)} footer={null} > diff --git a/src/pages/Telemetry/TelemetryView/UserOfWells.jsx b/src/pages/Well/Telemetry/TelemetryView/UserOfWells.jsx old mode 100755 new mode 100644 similarity index 100% rename from src/pages/Telemetry/TelemetryView/UserOfWells.jsx rename to src/pages/Well/Telemetry/TelemetryView/UserOfWells.jsx diff --git a/src/pages/Telemetry/TelemetryView/WirelineRunOut.jsx b/src/pages/Well/Telemetry/TelemetryView/WirelineRunOut.jsx similarity index 95% rename from src/pages/Telemetry/TelemetryView/WirelineRunOut.jsx rename to src/pages/Well/Telemetry/TelemetryView/WirelineRunOut.jsx index d3ef138..fd98f71 100644 --- a/src/pages/Telemetry/TelemetryView/WirelineRunOut.jsx +++ b/src/pages/Well/Telemetry/TelemetryView/WirelineRunOut.jsx @@ -33,7 +33,7 @@ export const WirelineRunOut = memo(() => { return ( ) diff --git a/src/pages/Telemetry/TelemetryView/cursorRender.jsx b/src/pages/Well/Telemetry/TelemetryView/cursorRender.jsx similarity index 100% rename from src/pages/Telemetry/TelemetryView/cursorRender.jsx rename to src/pages/Well/Telemetry/TelemetryView/cursorRender.jsx diff --git a/src/pages/Telemetry/TelemetryView/index.jsx b/src/pages/Well/Telemetry/TelemetryView/index.jsx old mode 100755 new mode 100644 similarity index 100% rename from src/pages/Telemetry/TelemetryView/index.jsx rename to src/pages/Well/Telemetry/TelemetryView/index.jsx diff --git a/src/pages/Well/Telemetry/index.jsx b/src/pages/Well/Telemetry/index.jsx new file mode 100644 index 0000000..e893433 --- /dev/null +++ b/src/pages/Well/Telemetry/index.jsx @@ -0,0 +1,27 @@ +import { FundViewOutlined } from '@ant-design/icons' +import { Outlet } from 'react-router-dom' +import { memo, useMemo } from 'react' + +import { RootPathContext, useRootPath } from '@asb/context' +import { wrapPrivateComponent } from '@utils' + +import '@styles/index.css' + +const Telemetry = memo(() => { + const root = useRootPath() + const rootPath = useMemo(() => `${root}/telemetry`, [root]) + + return ( + + + + ) +}) + +export default wrapPrivateComponent(Telemetry, { + requirements: [], + icon: , + title: 'Телеметрия', + route: 'telemetry/*', + key: 'telemetry', +}) diff --git a/src/pages/WellCase/HistoryTable.jsx b/src/pages/Well/WellCase/HistoryTable.jsx similarity index 100% rename from src/pages/WellCase/HistoryTable.jsx rename to src/pages/Well/WellCase/HistoryTable.jsx diff --git a/src/pages/WellCase/WellCaseEditor.jsx b/src/pages/Well/WellCase/WellCaseEditor.jsx similarity index 99% rename from src/pages/WellCase/WellCaseEditor.jsx rename to src/pages/Well/WellCase/WellCaseEditor.jsx index e8ef061..dcc287c 100644 --- a/src/pages/WellCase/WellCaseEditor.jsx +++ b/src/pages/Well/WellCase/WellCaseEditor.jsx @@ -117,7 +117,7 @@ export const WellCaseEditor = memo(({ categories: currentCategories, show, onClo { }, [well]) const columns = useMemo(() => [ - makeTextColumn('Категория', 'nameCategory'), + makeTextColumn('Категория', 'nameCategory', undefined, undefined, undefined, { width: 300 }), makeColumn('Файл', 'file', { render: (file, category) => (
@@ -59,10 +59,12 @@ const WellCase = memo(() => { )}
), + width: 300, }), - makeDateColumn('Дата загрузки', 'uploadDate'), + makeDateColumn('Дата загрузки', 'uploadDate', undefined, undefined, { width: 150 }), makeColumn('Ответственные', 'publishers', { - render: (publishers) => publishers?.map((user) => ), + render: (publishers) => publishers?.map((user, i) => ), + width: 200, }), ], [well, updateTable]) @@ -92,6 +94,7 @@ const WellCase = memo(() => { pagination={false} dataSource={categories} expandable={expandable} + scroll={{ x: true }} /> diff --git a/src/pages/WellOperations/DrillProcessFlow.jsx b/src/pages/Well/WellOperations/DrillProcessFlow.jsx old mode 100755 new mode 100644 similarity index 100% rename from src/pages/WellOperations/DrillProcessFlow.jsx rename to src/pages/Well/WellOperations/DrillProcessFlow.jsx diff --git a/src/pages/Well/WellOperations/OperationEditor/Fact.jsx b/src/pages/Well/WellOperations/OperationEditor/Fact.jsx new file mode 100644 index 0000000..3671de2 --- /dev/null +++ b/src/pages/Well/WellOperations/OperationEditor/Fact.jsx @@ -0,0 +1,14 @@ +import { wrapPrivateComponent } from '@utils' + +import WellOperationsEditor from './WellOperationsEditor' + +export const WellOperationsEditorFact = wrapPrivateComponent( + () => , + { + requirements: [ 'WellOperation.get' ], + title: 'Факт', + route: 'fact', + } +) + +export default WellOperationsEditorFact diff --git a/src/pages/WellOperations/ImportExportBar.jsx b/src/pages/Well/WellOperations/OperationEditor/ImportExportBar.jsx old mode 100755 new mode 100644 similarity index 98% rename from src/pages/WellOperations/ImportExportBar.jsx rename to src/pages/Well/WellOperations/OperationEditor/ImportExportBar.jsx index 3776ffd..3cc574a --- a/src/pages/WellOperations/ImportExportBar.jsx +++ b/src/pages/Well/WellOperations/OperationEditor/ImportExportBar.jsx @@ -48,7 +48,7 @@ export const ImportExportBar = memo(({ well: givenWell, onImported, disabled }) setIsImportModalVisible(false)} footer={null} > diff --git a/src/pages/WellOperations/ImportOperations.jsx b/src/pages/Well/WellOperations/OperationEditor/ImportOperations.jsx old mode 100755 new mode 100644 similarity index 100% rename from src/pages/WellOperations/ImportOperations.jsx rename to src/pages/Well/WellOperations/OperationEditor/ImportOperations.jsx diff --git a/src/pages/Well/WellOperations/OperationEditor/Plan.jsx b/src/pages/Well/WellOperations/OperationEditor/Plan.jsx new file mode 100644 index 0000000..240a189 --- /dev/null +++ b/src/pages/Well/WellOperations/OperationEditor/Plan.jsx @@ -0,0 +1,14 @@ +import { wrapPrivateComponent } from '@utils' + +import WellOperationsEditor from './WellOperationsEditor' + +export const WellOperationsEditorPlan = wrapPrivateComponent( + () => , + { + requirements: [ 'WellOperation.get' ], + title: 'План', + route: 'plan', + } +) + +export default WellOperationsEditorPlan diff --git a/src/pages/WellOperations/WellOperationsEditor.jsx b/src/pages/Well/WellOperations/OperationEditor/WellOperationsEditor.jsx old mode 100755 new mode 100644 similarity index 90% rename from src/pages/WellOperations/WellOperationsEditor.jsx rename to src/pages/Well/WellOperations/OperationEditor/WellOperationsEditor.jsx index 5ac3cfc..653ec16 --- a/src/pages/WellOperations/WellOperationsEditor.jsx +++ b/src/pages/Well/WellOperations/OperationEditor/WellOperationsEditor.jsx @@ -3,7 +3,7 @@ import { Input } from 'antd' import { useLocation } from 'react-router-dom' import { useState, useEffect, memo, useMemo, useCallback } from 'react' -import { useWell } from '@asb/context' +import { useTopRightBlock, useWell } from '@asb/context' import { EditableTable, makeColumn, @@ -17,9 +17,11 @@ import { } from '@components/Table' import LoaderPortal from '@components/LoaderPortal' import { invokeWebApiWrapperAsync } from '@components/factory' -import { arrayOrDefault, wrapPrivateComponent } from '@utils' +import { arrayOrDefault } from '@utils' import { WellOperationService } from '@api' +import ImportExportBar from './ImportExportBar' + const { TextArea } = Input const basePageSize = 160 @@ -51,13 +53,14 @@ const generateColumns = (showNpt = false, categories = [], sectionTypes = []) => makeTextColumn('Комментарий', 'comment', null, null, null, { editable: true, input: