forked from ddrilling/asb_cloud_front
* Добавлен компонент для получения Route по умолчанию
* Доблена страница "Доступ запрещён" * Актуализирована работа с правами * Добавлен переключатель оси X TVD
This commit is contained in:
parent
439df9401a
commit
85f98044c6
@ -1,11 +1,13 @@
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
import { Role, Permission, hasPermission, isInRole } from '../../utils/permissions'
|
|
||||||
|
|
||||||
type PrivateContentProps = {
|
import { isURLAvailable } from '@utils/permissions'
|
||||||
roles?: Role[] | Role
|
|
||||||
permission?: Permission
|
export type PrivateContentProps = {
|
||||||
|
absolutePath: string
|
||||||
children?: React.ReactElement<any, any>
|
children?: React.ReactElement<any, any>
|
||||||
}
|
}
|
||||||
|
|
||||||
export const PrivateContent: React.FC<PrivateContentProps> = ({ permission, roles, children = null }) =>
|
export const PrivateContent: React.FC<PrivateContentProps> = ({ absolutePath, children = null }) =>
|
||||||
hasPermission(permission) && isInRole(roles) ? children : null
|
isURLAvailable(absolutePath) ? children : null
|
||||||
|
|
||||||
|
export default PrivateContent
|
||||||
|
17
src/components/Private/PrivateDefaultRoute.tsx
Normal file
17
src/components/Private/PrivateDefaultRoute.tsx
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
import { memo } from 'react'
|
||||||
|
import { Redirect, Route, RouteProps } from 'react-router-dom'
|
||||||
|
|
||||||
|
import { isURLAvailable } from '@utils/permissions'
|
||||||
|
|
||||||
|
export type PrivateDefaultRouteProps = RouteProps & {
|
||||||
|
urls: string[]
|
||||||
|
elseRedirect?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export const PrivateDefaultRoute = memo<PrivateDefaultRouteProps>(({ elseRedirect, urls, ...other }) => (
|
||||||
|
<Route {...other} path={'/'}>
|
||||||
|
<Redirect to={{ pathname: urls.find((url) => isURLAvailable(url)) ?? elseRedirect ?? '/access_denied' }} />
|
||||||
|
</Route>
|
||||||
|
))
|
||||||
|
|
||||||
|
export default PrivateDefaultRoute
|
@ -1,14 +1,34 @@
|
|||||||
import React from 'react'
|
import { join } from 'path'
|
||||||
import { Menu, MenuItemProps } from 'antd'
|
import { Menu, MenuItemProps } from 'antd'
|
||||||
import { Role, Permission, hasPermission, isInRole } from '../../utils/permissions'
|
import { memo, NamedExoticComponent } from 'react'
|
||||||
|
|
||||||
|
import { isURLAvailable } from '@utils/permissions'
|
||||||
|
import { Link } from 'react-router-dom'
|
||||||
|
|
||||||
type PrivateMenuItemProps = MenuItemProps & {
|
export type PrivateMenuItemProps = MenuItemProps & {
|
||||||
roles?: Role[] | Role
|
root: string
|
||||||
permission?: Permission
|
path: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export const PrivateMenuItem: React.FC<PrivateMenuItemProps> = ({ roles, permission, ...props }) =>
|
export type PrivateMenuLinkProps = MenuItemProps & {
|
||||||
hasPermission(permission) && isInRole(roles) ? <Menu.Item {...props}/> : null
|
root?: string
|
||||||
|
path: string
|
||||||
|
title: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export const PrivateMenuItemLink = memo<PrivateMenuLinkProps>(({ root = '', path, title, ...other }) => (
|
||||||
|
<PrivateMenuItem key={path} root={root} path={path} {...other}>
|
||||||
|
<Link to={join(root, path)}>{title}</Link>
|
||||||
|
</PrivateMenuItem>
|
||||||
|
))
|
||||||
|
|
||||||
|
export const PrivateMenuItem: NamedExoticComponent<PrivateMenuItemProps> & {
|
||||||
|
Link: NamedExoticComponent<PrivateMenuLinkProps>
|
||||||
|
} = Object.assign(memo<PrivateMenuItemProps>(({ root, path, ...other }) =>
|
||||||
|
isURLAvailable(join(root, path)) ? <Menu.Item key={path} {...other}/> : null
|
||||||
|
), {
|
||||||
|
Link: PrivateMenuItemLink
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
export default PrivateMenuItem
|
export default PrivateMenuItem
|
||||||
|
@ -1,30 +1,32 @@
|
|||||||
import { FC, ReactNode } from 'react'
|
|
||||||
import { Location } from 'history'
|
import { Location } from 'history'
|
||||||
|
import { memo, ReactNode } from 'react'
|
||||||
import { Redirect, Route, RouteProps } from 'react-router-dom'
|
import { Redirect, Route, RouteProps } from 'react-router-dom'
|
||||||
|
import { join } from 'path'
|
||||||
|
|
||||||
import { Role, Permission, hasPermission, isInRole } from '../../utils/permissions'
|
import { isURLAvailable } from '@utils/permissions'
|
||||||
import { getUserToken } from '../../utils/storage'
|
|
||||||
|
|
||||||
export type PrivateRouteProps = RouteProps & {
|
export type PrivateRouteProps = RouteProps & {
|
||||||
roles: Role[] | Role
|
root: string
|
||||||
permission?: Permission
|
path: string
|
||||||
children?: ReactNode
|
children?: ReactNode
|
||||||
redirect?: (location?: Location<unknown>) => ReactNode
|
redirect?: (location?: Location<unknown>) => ReactNode
|
||||||
}
|
}
|
||||||
|
|
||||||
export const defaultRedirect = (location?: Location<unknown>) => (
|
export const defaultRedirect = (location?: Location<unknown>) => (
|
||||||
<Redirect to={{ pathname: '/login', state: { from: location } }} />
|
<Redirect to={{ pathname: '/access_denied', state: { from: location } }} />
|
||||||
)
|
)
|
||||||
|
|
||||||
export const PrivateRoute: FC<PrivateRouteProps> = ({ permission, roles, component, children, redirect = defaultRedirect, ...other }) => {
|
export const PrivateRoute = memo<PrivateRouteProps>(({ root = '', path, component, children, redirect = defaultRedirect, ...other }) => {
|
||||||
const available = getUserToken() && (hasPermission(permission) && isInRole(roles))
|
const available = isURLAvailable(join(root, path))
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Route {...other}
|
<Route
|
||||||
|
{...other}
|
||||||
|
path={path}
|
||||||
component={available ? component : undefined}
|
component={available ? component : undefined}
|
||||||
render={({ location }) => available ? children : redirect(location)}
|
render={({ location }) => available ? children : redirect(location)}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
}
|
})
|
||||||
|
|
||||||
export default PrivateRoute
|
export default PrivateRoute
|
||||||
|
@ -1,3 +1,9 @@
|
|||||||
export { PrivateRoute } from './PrivateRoute'
|
export { PrivateRoute, defaultRedirect } from './PrivateRoute'
|
||||||
export { PrivateContent } from './PrivateContent'
|
export { PrivateContent } from './PrivateContent'
|
||||||
export { PrivateMenuItem } from './PrivateMenuItem'
|
export { PrivateMenuItem, PrivateMenuItemLink } from './PrivateMenuItem'
|
||||||
|
export { PrivateDefaultRoute } from './PrivateDefaultRoute'
|
||||||
|
|
||||||
|
export type { PrivateRouteProps } from './PrivateRoute'
|
||||||
|
export type { PrivateContentProps } from './PrivateContent'
|
||||||
|
export type { PrivateMenuItemProps, PrivateMenuLinkProps } from './PrivateMenuItem'
|
||||||
|
export type { PrivateDefaultRouteProps } from './PrivateDefaultRoute'
|
||||||
|
@ -1,18 +1,16 @@
|
|||||||
import { MouseEventHandler, useState } from 'react'
|
import { memo, MouseEventHandler, useState } from 'react'
|
||||||
import { Link, useHistory } from 'react-router-dom'
|
import { Link, useHistory } from 'react-router-dom'
|
||||||
import { Button, Dropdown, Menu } from 'antd'
|
import { Button, Dropdown, DropDownProps, Menu } from 'antd'
|
||||||
import { UserOutlined } from '@ant-design/icons'
|
import { UserOutlined } from '@ant-design/icons'
|
||||||
|
|
||||||
import { getUserLogin, removeUser } from '../utils/storage'
|
import { getUserLogin, removeUser } from '@utils/storage'
|
||||||
|
|
||||||
import { PrivateMenuItem } from './Private'
|
|
||||||
import { ChangePassword } from './ChangePassword'
|
import { ChangePassword } from './ChangePassword'
|
||||||
|
import { PrivateMenuItemLink } from './Private/PrivateMenuItem'
|
||||||
|
|
||||||
type UserMenuProps = {
|
type UserMenuProps = Omit<DropDownProps, 'overlay'> & { isAdmin?: boolean }
|
||||||
isAdmin?: boolean
|
|
||||||
}
|
|
||||||
|
|
||||||
export const UserMenu: React.FC<UserMenuProps> = ({ isAdmin }) => {
|
export const UserMenu = memo<UserMenuProps>(({ isAdmin, ...other }) => {
|
||||||
const [isModalVisible, setIsModalVisible] = useState<boolean>(false)
|
const [isModalVisible, setIsModalVisible] = useState<boolean>(false)
|
||||||
|
|
||||||
const history = useHistory()
|
const history = useHistory()
|
||||||
@ -30,16 +28,15 @@ export const UserMenu: React.FC<UserMenuProps> = ({ isAdmin }) => {
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Dropdown
|
<Dropdown
|
||||||
|
{...other}
|
||||||
placement={'bottomRight'}
|
placement={'bottomRight'}
|
||||||
overlay={(
|
overlay={(
|
||||||
<Menu style={{ textAlign: 'right' }}>
|
<Menu style={{ textAlign: 'right' }}>
|
||||||
<PrivateMenuItem permission={'admin_panel'}>
|
|
||||||
{isAdmin ? (
|
{isAdmin ? (
|
||||||
<Link to={'/'}>Вернуться на сайт</Link>
|
<PrivateMenuItemLink path={'/'} title={'Вернуться на сайт'}/>
|
||||||
) : (
|
) : (
|
||||||
<Link to={'/admin'}>Панель администратора</Link>
|
<PrivateMenuItemLink path={'/admin'} title={'Панель администратора'}/>
|
||||||
)}
|
)}
|
||||||
</PrivateMenuItem>
|
|
||||||
<Menu.Item>
|
<Menu.Item>
|
||||||
<Link to={'/'} onClick={onChangePasswordClick}>Сменить пароль</Link>
|
<Link to={'/'} onClick={onChangePasswordClick}>Сменить пароль</Link>
|
||||||
</Menu.Item>
|
</Menu.Item>
|
||||||
@ -58,4 +55,4 @@ export const UserMenu: React.FC<UserMenuProps> = ({ isAdmin }) => {
|
|||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
}
|
})
|
||||||
|
15
src/pages/AccessDenied.jsx
Normal file
15
src/pages/AccessDenied.jsx
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
import { memo } from 'react'
|
||||||
|
|
||||||
|
export const AccessDenied = memo(() => (
|
||||||
|
<div style={{
|
||||||
|
width: '100vw',
|
||||||
|
height: '100vh',
|
||||||
|
display: 'flex',
|
||||||
|
justifyContent: 'center',
|
||||||
|
alignItems: 'center'
|
||||||
|
}}>
|
||||||
|
Доступ запрещён
|
||||||
|
</div>
|
||||||
|
))
|
||||||
|
|
||||||
|
export default AccessDenied
|
@ -1,7 +1,5 @@
|
|||||||
import { useEffect, useState } from 'react'
|
import { useEffect, useState } from 'react'
|
||||||
|
|
||||||
import { invokeWebApiWrapperAsync } from '../../components/factory'
|
|
||||||
import LoaderPortal from '../../components/LoaderPortal'
|
|
||||||
import {
|
import {
|
||||||
EditableTable,
|
EditableTable,
|
||||||
makeColumn,
|
makeColumn,
|
||||||
@ -9,10 +7,13 @@ import {
|
|||||||
makeActionHandler,
|
makeActionHandler,
|
||||||
makeStringSorter,
|
makeStringSorter,
|
||||||
defaultPagination
|
defaultPagination
|
||||||
} from '../../components/Table'
|
} from '@components/Table'
|
||||||
import { AdminClusterService, AdminDepositService } from '../../services/api'
|
import LoaderPortal from '@components/LoaderPortal'
|
||||||
import { arrayOrDefault } from '../../utils'
|
import { invokeWebApiWrapperAsync } from '@components/factory'
|
||||||
import { min1 } from '../../utils/validationRules'
|
import { AdminClusterService, AdminDepositService } from '@api'
|
||||||
|
import { arrayOrDefault } from '@utils'
|
||||||
|
import { min1 } from '@utils/validationRules'
|
||||||
|
import { hasPermission } from '@utils/permissions'
|
||||||
|
|
||||||
import { coordsFixed } from './DepositController'
|
import { coordsFixed } from './DepositController'
|
||||||
|
|
||||||
@ -73,9 +74,9 @@ export const ClusterController = () => {
|
|||||||
dataSource={clusters}
|
dataSource={clusters}
|
||||||
columns={clusterColumns}
|
columns={clusterColumns}
|
||||||
pagination={defaultPagination}
|
pagination={defaultPagination}
|
||||||
onRowAdd={makeActionHandler('insert', handlerProps)}
|
onRowAdd={hasPermission('AdminCluster.edit') && makeActionHandler('insert', handlerProps)}
|
||||||
onRowEdit={makeActionHandler('put', handlerProps)}
|
onRowEdit={hasPermission('AdminCluster.edit') && makeActionHandler('put', handlerProps)}
|
||||||
onRowDelete={makeActionHandler('delete', handlerProps)}
|
onRowDelete={hasPermission('AdminCluster.delete') && makeActionHandler('delete', handlerProps)}
|
||||||
/>
|
/>
|
||||||
</LoaderPortal>
|
</LoaderPortal>
|
||||||
)
|
)
|
||||||
|
@ -1,7 +1,5 @@
|
|||||||
import { useEffect, useState } from 'react'
|
import { useEffect, useState } from 'react'
|
||||||
|
|
||||||
import { invokeWebApiWrapperAsync } from '../../components/factory'
|
|
||||||
import LoaderPortal from '../../components/LoaderPortal'
|
|
||||||
import {
|
import {
|
||||||
EditableTable,
|
EditableTable,
|
||||||
makeColumn,
|
makeColumn,
|
||||||
@ -9,10 +7,13 @@ import {
|
|||||||
makeStringSorter,
|
makeStringSorter,
|
||||||
makeSelectColumn,
|
makeSelectColumn,
|
||||||
defaultPagination
|
defaultPagination
|
||||||
} from '../../components/Table'
|
} from '@components/Table'
|
||||||
import { AdminCompanyService, AdminCompanyTypeService } from '../../services/api'
|
import LoaderPortal from '@components/LoaderPortal'
|
||||||
import { arrayOrDefault } from '../../utils'
|
import { invokeWebApiWrapperAsync } from '@components/factory'
|
||||||
import { min1 } from '../../utils/validationRules'
|
import { AdminCompanyService, AdminCompanyTypeService } from '@api'
|
||||||
|
import { arrayOrDefault } from '@utils'
|
||||||
|
import { min1 } from '@utils/validationRules'
|
||||||
|
import { hasPermission } from '@utils/permissions'
|
||||||
|
|
||||||
|
|
||||||
export const CompanyController = () => {
|
export const CompanyController = () => {
|
||||||
@ -70,9 +71,9 @@ export const CompanyController = () => {
|
|||||||
columns={columns}
|
columns={columns}
|
||||||
dataSource={companies}
|
dataSource={companies}
|
||||||
pagination={defaultPagination}
|
pagination={defaultPagination}
|
||||||
onRowAdd={makeActionHandler('insert', handlerProps)}
|
onRowAdd={hasPermission('AdminCompany.edit') && makeActionHandler('insert', handlerProps)}
|
||||||
onRowEdit={makeActionHandler('put', handlerProps)}
|
onRowEdit={hasPermission('AdminCompany.edit') && makeActionHandler('put', handlerProps)}
|
||||||
onRowDelete={makeActionHandler('delete', handlerProps)}
|
onRowDelete={hasPermission('AdminCompany.delete') && makeActionHandler('delete', handlerProps)}
|
||||||
/>
|
/>
|
||||||
</LoaderPortal>
|
</LoaderPortal>
|
||||||
)
|
)
|
||||||
|
@ -1,17 +1,18 @@
|
|||||||
import { useEffect, useState } from 'react'
|
import { useEffect, useState } from 'react'
|
||||||
|
|
||||||
import { invokeWebApiWrapperAsync } from '../../components/factory'
|
|
||||||
import LoaderPortal from '../../components/LoaderPortal'
|
|
||||||
import {
|
import {
|
||||||
EditableTable,
|
EditableTable,
|
||||||
makeColumn,
|
makeColumn,
|
||||||
makeActionHandler,
|
makeActionHandler,
|
||||||
makeStringSorter,
|
makeStringSorter,
|
||||||
defaultPagination
|
defaultPagination
|
||||||
} from '../../components/Table'
|
} from '@components/Table'
|
||||||
import { AdminCompanyTypeService } from '../../services/api'
|
import LoaderPortal from '@components/LoaderPortal'
|
||||||
import { arrayOrDefault } from '../../utils'
|
import { invokeWebApiWrapperAsync } from '@components/factory'
|
||||||
import { min1 } from '../../utils/validationRules'
|
import { AdminCompanyTypeService } from '@api'
|
||||||
|
import { arrayOrDefault } from '@utils'
|
||||||
|
import { min1 } from '@utils/validationRules'
|
||||||
|
import { hasPermission } from '@asb/utils/permissions'
|
||||||
|
|
||||||
const columns = [
|
const columns = [
|
||||||
makeColumn('Название', 'caption', {
|
makeColumn('Название', 'caption', {
|
||||||
@ -52,9 +53,9 @@ export const CompanyTypeController = () => {
|
|||||||
columns={columns}
|
columns={columns}
|
||||||
dataSource={companyTypes}
|
dataSource={companyTypes}
|
||||||
pagination={defaultPagination}
|
pagination={defaultPagination}
|
||||||
onRowAdd={makeActionHandler('insert', handlerProps)}
|
onRowAdd={hasPermission('AdminCompanyType.edit') && makeActionHandler('insert', handlerProps)}
|
||||||
onRowEdit={makeActionHandler('put', handlerProps)}
|
onRowEdit={hasPermission('AdminCompanyType.edit') && makeActionHandler('put', handlerProps)}
|
||||||
onRowDelete={makeActionHandler('delete', handlerProps)}
|
onRowDelete={hasPermission('AdminCompanyType.delete') && makeActionHandler('delete', handlerProps)}
|
||||||
/>
|
/>
|
||||||
</LoaderPortal>
|
</LoaderPortal>
|
||||||
)
|
)
|
||||||
|
@ -1,11 +1,12 @@
|
|||||||
import { useEffect, useState } from 'react'
|
import { useEffect, useState } from 'react'
|
||||||
|
|
||||||
import LoaderPortal from '../../components/LoaderPortal'
|
import LoaderPortal from '@components/LoaderPortal'
|
||||||
import { invokeWebApiWrapperAsync } from '../../components/factory'
|
import { invokeWebApiWrapperAsync } from '@components/factory'
|
||||||
import { EditableTable, makeColumn, makeActionHandler, defaultPagination } from '../../components/Table'
|
import { EditableTable, makeColumn, makeActionHandler, defaultPagination } from '@components/Table'
|
||||||
import { AdminDepositService } from '../../services/api'
|
import { AdminDepositService } from '@api'
|
||||||
import { arrayOrDefault } from '../../utils'
|
import { arrayOrDefault } from '@utils'
|
||||||
import { min1 } from '../../utils/validationRules'
|
import { min1 } from '@utils/validationRules'
|
||||||
|
import { hasPermission } from '@utils/permissions'
|
||||||
|
|
||||||
export const coordsFixed = (coords) => coords && isFinite(coords) ? (+coords).toPrecision(10) : '-'
|
export const coordsFixed = (coords) => coords && isFinite(coords) ? (+coords).toPrecision(10) : '-'
|
||||||
|
|
||||||
@ -45,9 +46,9 @@ export const DepositController = () => {
|
|||||||
dataSource={deposits}
|
dataSource={deposits}
|
||||||
columns={depositColumns}
|
columns={depositColumns}
|
||||||
pagination={defaultPagination}
|
pagination={defaultPagination}
|
||||||
onRowAdd={makeActionHandler('insert', handlerProps)}
|
onRowAdd={hasPermission('AdminDeposit.edit') && makeActionHandler('insert', handlerProps)}
|
||||||
onRowEdit={makeActionHandler('put', handlerProps)}
|
onRowEdit={hasPermission('AdminDeposit.edit') && makeActionHandler('put', handlerProps)}
|
||||||
onRowDelete={makeActionHandler('delete', handlerProps)}
|
onRowDelete={hasPermission('AdminDeposit.delete') && makeActionHandler('delete', handlerProps)}
|
||||||
/>
|
/>
|
||||||
</LoaderPortal>
|
</LoaderPortal>
|
||||||
)
|
)
|
||||||
|
@ -1,16 +1,17 @@
|
|||||||
import { useEffect, useState } from 'react'
|
import { useEffect, useState } from 'react'
|
||||||
|
|
||||||
import { invokeWebApiWrapperAsync } from '../../components/factory'
|
|
||||||
import LoaderPortal from '../../components/LoaderPortal'
|
|
||||||
import {
|
import {
|
||||||
EditableTable,
|
EditableTable,
|
||||||
makeActionHandler,
|
makeActionHandler,
|
||||||
makeColumn,
|
makeColumn,
|
||||||
makeStringSorter
|
makeStringSorter
|
||||||
} from '../../components/Table'
|
} from '@components/Table'
|
||||||
import { AdminPermissionService } from '../../services/api'
|
import LoaderPortal from '@components/LoaderPortal'
|
||||||
import { arrayOrDefault } from '../../utils'
|
import { invokeWebApiWrapperAsync } from '@components/factory'
|
||||||
import { min1 } from '../../utils/validationRules'
|
import { AdminPermissionService } from '@api'
|
||||||
|
import { arrayOrDefault } from '@utils'
|
||||||
|
import { min1 } from '@utils/validationRules'
|
||||||
|
import { hasPermission } from '@utils/permissions'
|
||||||
|
|
||||||
const columns = [
|
const columns = [
|
||||||
makeColumn('Название', 'name', {
|
makeColumn('Название', 'name', {
|
||||||
@ -55,9 +56,9 @@ export const PermissionController = () => {
|
|||||||
columns={columns}
|
columns={columns}
|
||||||
dataSource={permissions}
|
dataSource={permissions}
|
||||||
pagination={{ showSizeChanger: true }}
|
pagination={{ showSizeChanger: true }}
|
||||||
onRowAdd={makeActionHandler('insert', handlerProps)}
|
onRowAdd={hasPermission('AdminPermission.edit') && makeActionHandler('insert', handlerProps)}
|
||||||
onRowEdit={makeActionHandler('put', handlerProps)}
|
onRowEdit={hasPermission('AdminPermission.edit') && makeActionHandler('put', handlerProps)}
|
||||||
onRowDelete={makeActionHandler('delete', handlerProps)}
|
onRowDelete={hasPermission('AdminPermission.delete') && makeActionHandler('delete', handlerProps)}
|
||||||
/>
|
/>
|
||||||
</LoaderPortal>
|
</LoaderPortal>
|
||||||
)
|
)
|
||||||
|
@ -1,12 +1,13 @@
|
|||||||
import { memo, useEffect, useState } from 'react'
|
import { memo, useEffect, useState } from 'react'
|
||||||
|
|
||||||
import LoaderPortal from '../../components/LoaderPortal'
|
import LoaderPortal from '@components/LoaderPortal'
|
||||||
import { PermissionView, RoleView } from '../../components/views'
|
import { PermissionView, RoleView } from '@components/views'
|
||||||
import { invokeWebApiWrapperAsync } from '../../components/factory'
|
import { invokeWebApiWrapperAsync } from '@components/factory'
|
||||||
import { EditableTable, makeActionHandler, makeColumn, makeTagColumn } from '../../components/Table'
|
import { EditableTable, makeActionHandler, makeColumn, makeTagColumn } from '@components/Table'
|
||||||
import { AdminPermissionService, AdminUserRoleService } from '../../services/api'
|
import { AdminPermissionService, AdminUserRoleService } from '@api'
|
||||||
import { arrayOrDefault } from '../../utils'
|
import { arrayOrDefault } from '@utils'
|
||||||
import { min1 } from '../../utils/validationRules'
|
import { min1 } from '@utils/validationRules'
|
||||||
|
import { hasPermission } from '@utils/permissions'
|
||||||
|
|
||||||
export const RoleController = memo(() => {
|
export const RoleController = memo(() => {
|
||||||
const [permissions, setPermissions] = useState([])
|
const [permissions, setPermissions] = useState([])
|
||||||
@ -62,9 +63,9 @@ export const RoleController = memo(() => {
|
|||||||
size={'small'}
|
size={'small'}
|
||||||
columns={columns}
|
columns={columns}
|
||||||
dataSource={roles}
|
dataSource={roles}
|
||||||
onRowAdd={makeActionHandler('insert', handlerProps)}
|
onRowAdd={hasPermission('AdminUserRole.edit') && makeActionHandler('insert', handlerProps)}
|
||||||
onRowEdit={makeActionHandler('put', handlerProps)}
|
onRowEdit={hasPermission('AdminUserRole.edit') && makeActionHandler('put', handlerProps)}
|
||||||
onRowDelete={makeActionHandler('delete', handlerProps)}
|
onRowDelete={hasPermission('AdminUserRole.delete') && makeActionHandler('delete', handlerProps)}
|
||||||
/>
|
/>
|
||||||
</LoaderPortal>
|
</LoaderPortal>
|
||||||
)
|
)
|
||||||
|
@ -2,10 +2,6 @@ import { Button, Tag } from 'antd'
|
|||||||
import { UserSwitchOutlined } from '@ant-design/icons'
|
import { UserSwitchOutlined } from '@ant-design/icons'
|
||||||
import { useEffect, useState } from 'react'
|
import { useEffect, useState } from 'react'
|
||||||
|
|
||||||
import { RoleView } from '../../../components/views'
|
|
||||||
import LoaderPortal from '../../../components/LoaderPortal'
|
|
||||||
import { ChangePassword } from '../../../components/ChangePassword'
|
|
||||||
import { invokeWebApiWrapperAsync } from '../../../components/factory'
|
|
||||||
import {
|
import {
|
||||||
EditableTable,
|
EditableTable,
|
||||||
makeColumn,
|
makeColumn,
|
||||||
@ -14,14 +10,19 @@ import {
|
|||||||
makeStringSorter,
|
makeStringSorter,
|
||||||
makeNumericSorter,
|
makeNumericSorter,
|
||||||
defaultPagination
|
defaultPagination
|
||||||
} from '../../../components/Table'
|
} from '@components/Table'
|
||||||
import { AdminCompanyService, AdminUserRoleService, AdminUserService } from '../../../services/api'
|
import { RoleView } from '@components/views'
|
||||||
import { createLoginRules, nameRules, phoneRules, emailRules } from '../../../utils/validationRules'
|
import LoaderPortal from '@components/LoaderPortal'
|
||||||
import { arrayOrDefault } from '../../../utils'
|
import { ChangePassword } from '@components/ChangePassword'
|
||||||
|
import { invokeWebApiWrapperAsync } from '@components/factory'
|
||||||
|
import { AdminCompanyService, AdminUserRoleService, AdminUserService } from '@api'
|
||||||
|
import { createLoginRules, nameRules, phoneRules, emailRules } from '@utils/validationRules'
|
||||||
|
import { makeTextOnFilter, makeTextFilters } from '@utils/table'
|
||||||
|
import { hasPermission } from '@utils/permissions'
|
||||||
|
import { arrayOrDefault } from '@utils'
|
||||||
|
|
||||||
import RoleTag from './RoleTag'
|
import RoleTag from './RoleTag'
|
||||||
|
|
||||||
import { makeTextOnFilter, makeTextFilters } from '../../../utils/table'
|
|
||||||
|
|
||||||
export const UserController = () => {
|
export const UserController = () => {
|
||||||
const [users, setUsers] = useState([])
|
const [users, setUsers] = useState([])
|
||||||
@ -153,9 +154,9 @@ export const UserController = () => {
|
|||||||
bordered
|
bordered
|
||||||
columns={columns}
|
columns={columns}
|
||||||
dataSource={users}
|
dataSource={users}
|
||||||
onRowAdd={makeActionHandler('insert', handlerProps)}
|
onRowAdd={hasPermission('AdminUser.edit') && makeActionHandler('insert', handlerProps)}
|
||||||
onRowEdit={makeActionHandler('put', handlerProps)}
|
onRowEdit={hasPermission('AdminUser.edit') && makeActionHandler('put', handlerProps)}
|
||||||
onRowDelete={makeActionHandler('delete', handlerProps)}
|
onRowDelete={hasPermission('AdminUser.delete') && makeActionHandler('delete', handlerProps)}
|
||||||
additionalButtons={additionalButtons}
|
additionalButtons={additionalButtons}
|
||||||
buttonsWidth={120}
|
buttonsWidth={120}
|
||||||
pagination={defaultPagination}
|
pagination={defaultPagination}
|
||||||
|
@ -3,15 +3,10 @@ import { Select } from 'antd'
|
|||||||
|
|
||||||
import { getTelemetryLabel } from '@components/views'
|
import { getTelemetryLabel } from '@components/views'
|
||||||
|
|
||||||
export const TelemetrySelect = memo(({ telemetry, value, onChange }) => {
|
export const TelemetrySelect = memo(({ telemetry, value, onChange }) => (
|
||||||
const onSelectChange = (id) => {
|
|
||||||
onChange?.(telemetry.find((row) => row.id === id))
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Select
|
<Select
|
||||||
value={value?.id}
|
value={value?.id}
|
||||||
onChange={onSelectChange}
|
onChange={(id) => onChange?.(telemetry.find((row) => row.id === id))}
|
||||||
dropdownClassName={'telemetry_select'}
|
dropdownClassName={'telemetry_select'}
|
||||||
>
|
>
|
||||||
{telemetry.map((row, i) => (
|
{telemetry.map((row, i) => (
|
||||||
@ -22,7 +17,6 @@ export const TelemetrySelect = memo(({ telemetry, value, onChange }) => {
|
|||||||
</Select.Option>
|
</Select.Option>
|
||||||
))}
|
))}
|
||||||
</Select>
|
</Select>
|
||||||
)
|
))
|
||||||
})
|
|
||||||
|
|
||||||
export default TelemetrySelect
|
export default TelemetrySelect
|
||||||
|
@ -2,9 +2,12 @@ import { useEffect, useState } from 'react'
|
|||||||
import { Button } from 'antd'
|
import { Button } from 'antd'
|
||||||
import { CopyOutlined } from '@ant-design/icons'
|
import { CopyOutlined } from '@ant-design/icons'
|
||||||
|
|
||||||
import LoaderPortal from '../../../components/LoaderPortal'
|
import {
|
||||||
import { invokeWebApiWrapperAsync } from '../../../components/factory'
|
AdminClusterService,
|
||||||
import { TelemetryView, CompanyView } from '../../../components/views'
|
AdminCompanyService,
|
||||||
|
AdminTelemetryService,
|
||||||
|
AdminWellService,
|
||||||
|
} from '@api'
|
||||||
import {
|
import {
|
||||||
EditableTable,
|
EditableTable,
|
||||||
makeColumn,
|
makeColumn,
|
||||||
@ -14,19 +17,17 @@ import {
|
|||||||
makeNumericSorter,
|
makeNumericSorter,
|
||||||
makeTagColumn,
|
makeTagColumn,
|
||||||
defaultPagination,
|
defaultPagination,
|
||||||
} from '../../../components/Table'
|
} from '@components/Table'
|
||||||
import {
|
import LoaderPortal from '@components/LoaderPortal'
|
||||||
AdminClusterService,
|
import { invokeWebApiWrapperAsync } from '@components/factory'
|
||||||
AdminCompanyService,
|
import { TelemetryView, CompanyView } from '@components/views'
|
||||||
AdminTelemetryService,
|
import { arrayOrDefault } from '@utils'
|
||||||
AdminWellService,
|
|
||||||
} from '../../../services/api'
|
|
||||||
import { arrayOrDefault } from '../../../utils'
|
|
||||||
|
|
||||||
import { coordsFixed } from '../DepositController'
|
import { coordsFixed } from '../DepositController'
|
||||||
import TelemetrySelect from './TelemetrySelect'
|
import TelemetrySelect from './TelemetrySelect'
|
||||||
|
|
||||||
import '../../../styles/admin.css'
|
import '@styles/admin.css'
|
||||||
|
import { hasPermission } from '@asb/utils/permissions'
|
||||||
|
|
||||||
const wellTypes = [
|
const wellTypes = [
|
||||||
{ value: 1, label: 'Наклонно-направленная' },
|
{ value: 1, label: 'Наклонно-направленная' },
|
||||||
@ -124,9 +125,9 @@ export const WellController = () => {
|
|||||||
columns={columns}
|
columns={columns}
|
||||||
dataSource={wells}
|
dataSource={wells}
|
||||||
pagination={defaultPagination}
|
pagination={defaultPagination}
|
||||||
onRowAdd={makeActionHandler('insert', handlerProps, recordParser)}
|
onRowAdd={hasPermission('AdminWell.edit') && makeActionHandler('insert', handlerProps, recordParser)}
|
||||||
onRowEdit={makeActionHandler('put', handlerProps, recordParser)}
|
onRowEdit={hasPermission('AdminWell.edit') && makeActionHandler('put', handlerProps, recordParser)}
|
||||||
onRowDelete={makeActionHandler('delete', handlerProps)}
|
onRowDelete={hasPermission('AdminWell.delete') && makeActionHandler('delete', handlerProps)}
|
||||||
//additionalButtons={addititonalButtons}
|
//additionalButtons={addititonalButtons}
|
||||||
buttonsWidth={95}
|
buttonsWidth={95}
|
||||||
/>
|
/>
|
||||||
|
@ -1,76 +1,68 @@
|
|||||||
import { Layout, Menu } from 'antd'
|
import { Layout, Menu } from 'antd'
|
||||||
import { lazy, Suspense } from 'react'
|
import { lazy, Suspense } from 'react'
|
||||||
import { Switch, Link, useParams, Redirect, Route } from 'react-router-dom'
|
import { Switch, useParams } from 'react-router-dom'
|
||||||
import { PrivateMenuItem, PrivateRoute } from '../../components/Private'
|
|
||||||
import { SuspenseFallback } from '../SuspenseFallback'
|
|
||||||
|
|
||||||
const ClusterController = lazy(() => import('./ClusterController'))
|
import { PrivateMenuItem, PrivateRoute, PrivateDefaultRoute } from '@components/Private'
|
||||||
const CompanyController = lazy(() => import('./CompanyController'))
|
|
||||||
const DepositController = lazy(() => import('./DepositController'))
|
import { SuspenseFallback } from '@pages/SuspenseFallback'
|
||||||
const UserController = lazy(() => import('./UserController'))
|
|
||||||
const WellController = lazy(() => import('./WellController'))
|
const ClusterController = lazy(() => import( './ClusterController'))
|
||||||
const RoleController = lazy(() => import('./RoleController'))
|
const CompanyController = lazy(() => import( './CompanyController'))
|
||||||
|
const DepositController = lazy(() => import( './DepositController'))
|
||||||
|
const UserController = lazy(() => import( './UserController'))
|
||||||
|
const WellController = lazy(() => import( './WellController'))
|
||||||
|
const RoleController = lazy(() => import( './RoleController'))
|
||||||
const CompanyTypeController = lazy(() => import('./CompanyTypeController'))
|
const CompanyTypeController = lazy(() => import('./CompanyTypeController'))
|
||||||
const PermissionController = lazy(() => import('./PermissionController'))
|
const PermissionController = lazy(() => import( './PermissionController'))
|
||||||
const TelemetryController = lazy(() => import('./TelemetryController'))
|
const TelemetryController = lazy(() => import( './TelemetryController'))
|
||||||
const VisitLog = lazy(() => import('./VisitLog'))
|
const VisitLog = lazy(() => import( './VisitLog'))
|
||||||
|
|
||||||
|
const rootPath = '/admin'
|
||||||
|
|
||||||
export const AdminPanel = () => {
|
export const AdminPanel = () => {
|
||||||
const { tab } = useParams()
|
const { tab } = useParams()
|
||||||
const rootPath = '/admin'
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Layout>
|
<Layout>
|
||||||
<Menu mode={'horizontal'} selectable={true} selectedKeys={[tab]}>
|
<Menu mode={'horizontal'} selectable={true} selectedKeys={[tab]}>
|
||||||
<PrivateMenuItem key={'deposit'} permission={'deposit_editor'}>
|
<PrivateMenuItem.Link root={rootPath} key={'deposit' } path={'deposit' } title={'Месторождения' } />
|
||||||
<Link to={`${rootPath}/deposit`}>Месторождения</Link>
|
<PrivateMenuItem.Link root={rootPath} key={'cluster' } path={'cluster' } title={'Кусты' } />
|
||||||
</PrivateMenuItem>
|
<PrivateMenuItem.Link root={rootPath} key={'well' } path={'well' } title={'Скважины' } />
|
||||||
<PrivateMenuItem key={'cluster'} permission={'cluster_editor'}>
|
<PrivateMenuItem.Link root={rootPath} key={'user' } path={'user' } title={'Пользователи' } />
|
||||||
<Link to={`${rootPath}/cluster`}>Кусты</Link>
|
<PrivateMenuItem.Link root={rootPath} key={'company' } path={'company' } title={'Компании' } />
|
||||||
</PrivateMenuItem>
|
<PrivateMenuItem.Link root={rootPath} key={'company_type'} path={'company_type'} title={'Типы компаний' } />
|
||||||
<PrivateMenuItem key={'well'} permission={'well_editor'}>
|
<PrivateMenuItem.Link root={rootPath} key={'role' } path={'role' } title={'Роли' } />
|
||||||
<Link to={`${rootPath}/well`}>Скважины</Link>
|
<PrivateMenuItem.Link root={rootPath} key={'permission' } path={'permission' } title={'Разрешения' } />
|
||||||
</PrivateMenuItem>
|
<PrivateMenuItem.Link root={rootPath} key={'telemetry' } path={'telemetry' } title={'Телеметрии' } />
|
||||||
<PrivateMenuItem key={'user'} permission={'user_editor'}>
|
<PrivateMenuItem.Link root={rootPath} key={'visit_log' } path={'visit_log' } title={'Журнал посещений'} />
|
||||||
<Link to={`${rootPath}/user`}>Пользователи</Link>
|
|
||||||
</PrivateMenuItem>
|
|
||||||
<PrivateMenuItem key={'company'} permission={'company_editor'}>
|
|
||||||
<Link to={`${rootPath}/company`}>Компании</Link>
|
|
||||||
</PrivateMenuItem>
|
|
||||||
<PrivateMenuItem key={'company_type'}>
|
|
||||||
<Link to={`${rootPath}/company_type`}>Типы компаний</Link>
|
|
||||||
</PrivateMenuItem>
|
|
||||||
<PrivateMenuItem key={'role'} permission={'role_editor'}>
|
|
||||||
<Link to={`${rootPath}/role`}>Роли</Link>
|
|
||||||
</PrivateMenuItem>
|
|
||||||
<PrivateMenuItem key={'permission'} permission={'permission_editor'}>
|
|
||||||
<Link to={`${rootPath}/permission`}>Разрешения</Link>
|
|
||||||
</PrivateMenuItem>
|
|
||||||
<PrivateMenuItem key={'telemetry'}>
|
|
||||||
<Link to={`${rootPath}/telemetry`}>Телеметрия</Link>
|
|
||||||
</PrivateMenuItem>
|
|
||||||
<PrivateMenuItem key={'visit_log'}>
|
|
||||||
<Link to={`${rootPath}/visit_log`}>Журнал посещений</Link>
|
|
||||||
</PrivateMenuItem>
|
|
||||||
</Menu>
|
</Menu>
|
||||||
|
|
||||||
<Layout>
|
<Layout>
|
||||||
<Layout.Content className={'site-layout-background'}>
|
<Layout.Content className={'site-layout-background'}>
|
||||||
<Suspense fallback={<SuspenseFallback />}>
|
<Suspense fallback={<SuspenseFallback />}>
|
||||||
<Switch>
|
<Switch>
|
||||||
<PrivateRoute permission={ 'deposit_editor'} path={`${rootPath}/deposit` } component={ DepositController} />
|
<PrivateRoute path={`${rootPath}/deposit` } component={ DepositController} />
|
||||||
<PrivateRoute permission={ 'cluster_editor'} path={`${rootPath}/cluster` } component={ ClusterController} />
|
<PrivateRoute path={`${rootPath}/cluster` } component={ ClusterController} />
|
||||||
<PrivateRoute permission={ 'well_editor'} path={`${rootPath}/well` } component={ WellController} />
|
<PrivateRoute path={`${rootPath}/well` } component={ WellController} />
|
||||||
<PrivateRoute permission={ 'user_editor'} path={`${rootPath}/user` } component={ UserController} />
|
<PrivateRoute path={`${rootPath}/user` } component={ UserController} />
|
||||||
<PrivateRoute permission={ 'company_editor'} path={`${rootPath}/company` } component={ CompanyController} />
|
<PrivateRoute path={`${rootPath}/company` } component={ CompanyController} />
|
||||||
<PrivateRoute path={`${rootPath}/company_type`} component={CompanyTypeController} />
|
<PrivateRoute path={`${rootPath}/company_type`} component={CompanyTypeController} />
|
||||||
<PrivateRoute permission={ 'role_editor'} path={`${rootPath}/role` } component={ RoleController} />
|
<PrivateRoute path={`${rootPath}/role` } component={ RoleController} />
|
||||||
<PrivateRoute permission={'permission_editor'} path={`${rootPath}/permission`} component={PermissionController} />
|
<PrivateRoute path={`${rootPath}/permission` } component={ PermissionController} />
|
||||||
<PrivateRoute path={`${rootPath}/telemetry`} component={TelemetryController} />
|
<PrivateRoute path={`${rootPath}/telemetry` } component={ TelemetryController} />
|
||||||
<PrivateRoute path={`${rootPath}/visit_log`} component={VisitLog} />
|
<PrivateRoute path={`${rootPath}/visit_log` } component={VisitLog} />
|
||||||
<Route path={'/'}>
|
<PrivateDefaultRoute urls={[
|
||||||
<Redirect to={`${rootPath}/visit_log`}/>
|
`${rootPath}/deposit`,
|
||||||
</Route>
|
`${rootPath}/cluster`,
|
||||||
|
`${rootPath}/well`,
|
||||||
|
`${rootPath}/user`,
|
||||||
|
`${rootPath}/company`,
|
||||||
|
`${rootPath}/company_type`,
|
||||||
|
`${rootPath}/role`,
|
||||||
|
`${rootPath}/permission`,
|
||||||
|
`${rootPath}/telemetry`,
|
||||||
|
`${rootPath}/visit_log`,
|
||||||
|
]}/>
|
||||||
</Switch>
|
</Switch>
|
||||||
</Suspense>
|
</Suspense>
|
||||||
</Layout.Content>
|
</Layout.Content>
|
||||||
|
@ -3,6 +3,7 @@ import { useState, useEffect } from 'react'
|
|||||||
import { DatePicker, Button, Input } from 'antd'
|
import { DatePicker, Button, Input } from 'antd'
|
||||||
|
|
||||||
import { FileService } from '@api'
|
import { FileService } from '@api'
|
||||||
|
import { hasPermission } from '@utils/permissions'
|
||||||
import LoaderPortal from '@components/LoaderPortal'
|
import LoaderPortal from '@components/LoaderPortal'
|
||||||
import { UploadForm } from '@components/UploadForm'
|
import { UploadForm } from '@components/UploadForm'
|
||||||
import { CompanyView, UserView } from '@components/views'
|
import { CompanyView, UserView } from '@components/views'
|
||||||
@ -145,6 +146,7 @@ export const DocumentsTemplate = ({ idCategory, idWell, accept, headerChild, cus
|
|||||||
</datalist>
|
</datalist>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{hasPermission(`File.edit${idCategory}`) && (
|
||||||
<div>
|
<div>
|
||||||
<span>Загрузка</span>
|
<span>Загрузка</span>
|
||||||
<UploadForm
|
<UploadForm
|
||||||
@ -154,6 +156,7 @@ export const DocumentsTemplate = ({ idCategory, idWell, accept, headerChild, cus
|
|||||||
onUploadComplete={handleUploadComplete}
|
onUploadComplete={handleUploadComplete}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
{headerChild}
|
{headerChild}
|
||||||
</div>
|
</div>
|
||||||
@ -167,7 +170,7 @@ export const DocumentsTemplate = ({ idCategory, idWell, accept, headerChild, cus
|
|||||||
showSizeChanger: false,
|
showSizeChanger: false,
|
||||||
onChange: (page) => setPage(page),
|
onChange: (page) => setPage(page),
|
||||||
}}
|
}}
|
||||||
onRowDelete={handleFileDelete}
|
onRowDelete={hasPermission(`File.edit${idCategory}`) && handleFileDelete}
|
||||||
rowKey={(record) => record.id}
|
rowKey={(record) => record.id}
|
||||||
/>
|
/>
|
||||||
</LoaderPortal>
|
</LoaderPortal>
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
import path from 'path'
|
|
||||||
import { memo } from 'react'
|
import { memo } from 'react'
|
||||||
import { Layout, Menu } from 'antd'
|
import { Layout, Menu } from 'antd'
|
||||||
import { FolderOutlined } from '@ant-design/icons'
|
import { FolderOutlined } from '@ant-design/icons'
|
||||||
import { Switch, useParams, Link, Route } from 'react-router-dom'
|
import { Switch, useParams } from 'react-router-dom'
|
||||||
import { PrivateMenuItem } from '../../components/Private'
|
|
||||||
import { isInRole } from '../../utils/permissions'
|
import { PrivateDefaultRoute, PrivateMenuItem, PrivateRoute } from '@components/Private'
|
||||||
|
|
||||||
import DocumentsTemplate from './DocumentsTemplate'
|
import DocumentsTemplate from './DocumentsTemplate'
|
||||||
|
|
||||||
const { Content } = Layout
|
const { Content } = Layout
|
||||||
@ -22,45 +22,33 @@ export const documentCategories = [
|
|||||||
{ id: 9, key: 'closingService', title: 'Сервис по заканчиванию скважины' },
|
{ id: 9, key: 'closingService', title: 'Сервис по заканчиванию скважины' },
|
||||||
]
|
]
|
||||||
|
|
||||||
const getUserCategories = () => documentCategories.filter(cat => isInRole(cat.roles))
|
|
||||||
|
|
||||||
export const makeMenuItems = (root, cats) => (cats ?? getUserCategories()).map(category => (
|
|
||||||
<PrivateMenuItem
|
|
||||||
key={`${category.key}`}
|
|
||||||
className={'ant-menu-item'}
|
|
||||||
icon={<FolderOutlined/>}
|
|
||||||
permission={category.permission}
|
|
||||||
roles={category.roles}
|
|
||||||
>
|
|
||||||
<Link to={{ pathname: `${root}/${category.key}` }}>{category.title}</Link>
|
|
||||||
</PrivateMenuItem>
|
|
||||||
))
|
|
||||||
|
|
||||||
export const MenuDocuments = memo(({ idWell }) => {
|
export const MenuDocuments = memo(({ idWell }) => {
|
||||||
const { category } = useParams()
|
const { category } = useParams()
|
||||||
const rootPath = `/well/${idWell}`
|
const root = `/well/${idWell}/document`
|
||||||
|
|
||||||
const root = path.join(rootPath, '/document')
|
|
||||||
const categories = getUserCategories()
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Menu
|
<Menu mode={'horizontal'} selectable={true} className={'well_menu'} selectedKeys={[category]}>
|
||||||
mode={'horizontal'}
|
{documentCategories.map(category => (
|
||||||
selectable={true}
|
<PrivateMenuItem.Link
|
||||||
className={'well_menu'}
|
root={root}
|
||||||
selectedKeys={[category]}
|
key={`${category.key}`}
|
||||||
>
|
path={`${category.key}`}
|
||||||
{makeMenuItems(root, categories)}
|
className={'ant-menu-item'}
|
||||||
|
icon={<FolderOutlined/>}
|
||||||
|
title={category.title}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
</Menu>
|
</Menu>
|
||||||
<Layout>
|
<Layout>
|
||||||
<Content className={'site-layout-background'}>
|
<Content className={'site-layout-background'}>
|
||||||
<Switch>
|
<Switch>
|
||||||
{categories.map(category => (
|
{documentCategories.map(category => (
|
||||||
<Route path={`${root}/${category.key}`} key={`${category.key}`}>
|
<PrivateRoute path={`${root}/${category.key}`} key={`${category.key}`}>
|
||||||
<DocumentsTemplate idCategory={category.id} idWell={idWell}/>
|
<DocumentsTemplate idCategory={category.id} idWell={idWell}/>
|
||||||
</Route>
|
</PrivateRoute>
|
||||||
))}
|
))}
|
||||||
|
<PrivateDefaultRoute urls={documentCategories.map((cat) => `${root}/${cat.key}`)}/>
|
||||||
</Switch>
|
</Switch>
|
||||||
</Content>
|
</Content>
|
||||||
</Layout>
|
</Layout>
|
||||||
|
@ -1,37 +1,42 @@
|
|||||||
import { Redirect, Route, Switch } from 'react-router-dom'
|
import { memo } from 'react'
|
||||||
import { PrivateRoute } from '../components/Private'
|
import { Route, Switch } from 'react-router-dom'
|
||||||
import { AdminLayoutPortal, LayoutPortal } from '../components/Layout'
|
|
||||||
import Deposit from './Deposit'
|
|
||||||
import Cluster from './Cluster'
|
|
||||||
import Well from './Well'
|
|
||||||
import AdminPanel from './AdminPanel'
|
|
||||||
|
|
||||||
export const Main = () => (
|
import { AdminLayoutPortal, LayoutPortal } from '@components/Layout'
|
||||||
|
import { PrivateDefaultRoute, PrivateRoute } from '@components/Private'
|
||||||
|
|
||||||
|
import Well from './Well'
|
||||||
|
import Cluster from './Cluster'
|
||||||
|
import Deposit from './Deposit'
|
||||||
|
import AdminPanel from './AdminPanel'
|
||||||
|
import AccessDenied from './AccessDenied'
|
||||||
|
|
||||||
|
export const Main = memo(() => (
|
||||||
<Switch>
|
<Switch>
|
||||||
<PrivateRoute path={'/admin/:tab?'} permission={'admin_panel'}>
|
<PrivateRoute path={'/admin/:tab?'}>
|
||||||
<AdminLayoutPortal title={'Администраторская панель'}>
|
<AdminLayoutPortal title={'Администраторская панель'}>
|
||||||
<AdminPanel />
|
<AdminPanel />
|
||||||
</AdminLayoutPortal>
|
</AdminLayoutPortal>
|
||||||
</PrivateRoute>
|
</PrivateRoute>
|
||||||
<Route path={'/deposit'}>
|
<PrivateRoute path={'/deposit'}>
|
||||||
<LayoutPortal noSheet title='Месторождение'>
|
<LayoutPortal noSheet title='Месторождение'>
|
||||||
<Deposit />
|
<Deposit />
|
||||||
</LayoutPortal>
|
</LayoutPortal>
|
||||||
</Route>
|
</PrivateRoute>
|
||||||
<Route path={'/cluster/:idClaster/:tab?'}>
|
<PrivateRoute path={'/cluster/:idCluster'}>
|
||||||
<LayoutPortal title={'Анализ скважин куста'}>
|
<LayoutPortal title={'Анализ скважин куста'}>
|
||||||
<Cluster />
|
<Cluster />
|
||||||
</LayoutPortal>
|
</LayoutPortal>
|
||||||
</Route>
|
</PrivateRoute>
|
||||||
<Route path={'/well/:idWell/:tab?'}>
|
<PrivateRoute path={'/well/:idWell/:tab?'}>
|
||||||
<LayoutPortal>
|
<LayoutPortal>
|
||||||
<Well />
|
<Well />
|
||||||
</LayoutPortal>
|
</LayoutPortal>
|
||||||
|
</PrivateRoute>
|
||||||
|
<Route path={'/access_denied'}>
|
||||||
|
<AccessDenied />
|
||||||
</Route>
|
</Route>
|
||||||
<Route path={'/'}>
|
<PrivateDefaultRoute urls={['/deposit']} />
|
||||||
<Redirect to={{ pathname: `/deposit` }} />
|
|
||||||
</Route>
|
|
||||||
</Switch>
|
</Switch>
|
||||||
)
|
))
|
||||||
|
|
||||||
export default Main
|
export default Main
|
||||||
|
@ -1,56 +1,57 @@
|
|||||||
import {Layout, Menu} from "antd";
|
import { memo } from 'react'
|
||||||
import {Switch, Link, Route, useParams, Redirect} from "react-router-dom";
|
import { Layout, Menu } from 'antd'
|
||||||
import { FolderOutlined } from "@ant-design/icons";
|
import { FolderOutlined } from '@ant-design/icons'
|
||||||
import TelemetryAnalysisOperationsSummary from "./TelemetryAnalysisOperationsSummary";
|
import { Switch, useParams } from 'react-router-dom'
|
||||||
import TelemetryAnalysisOperationsToInterval from "./TelemetryAnalysisOperationsToInterval";
|
|
||||||
|
import { PrivateDefaultRoute, PrivateRoute } from '@components/Private'
|
||||||
|
import { PrivateMenuItemLink } from '@components/Private/PrivateMenuItem'
|
||||||
|
|
||||||
import TelemetryAnalysisDepthToDay from './TelemetryAnalysisDepthToDay'
|
import TelemetryAnalysisDepthToDay from './TelemetryAnalysisDepthToDay'
|
||||||
import TelemetryAnalysisDepthToInterval from './TelemetryAnalysisDepthToInterval'
|
import TelemetryAnalysisDepthToInterval from './TelemetryAnalysisDepthToInterval'
|
||||||
|
import TelemetryAnalysisOperationsSummary from './TelemetryAnalysisOperationsSummary'
|
||||||
|
import TelemetryAnalysisOperationsToInterval from './TelemetryAnalysisOperationsToInterval'
|
||||||
|
|
||||||
const { Content } = Layout
|
const { Content } = Layout
|
||||||
|
|
||||||
export default function TelemetryAnalysis({idWell}) {
|
export const TelemetryAnalysis = memo(({ idWell }) => {
|
||||||
let {tab} = useParams()
|
const { tab } = useParams()
|
||||||
const rootPath = `/well/${idWell}/telemetryAnalysis`;
|
const rootPath = `/well/${idWell}/telemetryAnalysis`
|
||||||
|
|
||||||
return (<>
|
return (
|
||||||
<Menu
|
<>
|
||||||
mode={'horizontal'}
|
<Menu mode={'horizontal'} selectable={true} className={'well_menu'} selectedKeys={[tab]}>
|
||||||
selectable={true}
|
<PrivateMenuItemLink root={rootPath} icon={<FolderOutlined />} key={'depthToDay'} path={'depthToDay'} title={'Глубина-день'} />
|
||||||
className={'well_menu'}
|
<PrivateMenuItemLink root={rootPath} icon={<FolderOutlined />} key={'depthToInterval'} path={'depthToInterval'} title={'Глубина-интервал'} />
|
||||||
selectedKeys={[tab]}>
|
<PrivateMenuItemLink root={rootPath} icon={<FolderOutlined />} key={'operationsSummary'} path={'operationsSummary'} title={'Все операции'} />
|
||||||
<Menu.Item key={'depthToDay'} icon={<FolderOutlined />}>
|
<PrivateMenuItemLink root={rootPath} icon={<FolderOutlined />} key={'operationsToInterval'} path={'operationsToInterval'} title={'Операции-интервал'} />
|
||||||
<Link to={`${rootPath}/depthToDay`}>Глубина-день</Link>
|
|
||||||
</Menu.Item>
|
|
||||||
<Menu.Item key={'depthToInterval'} icon={<FolderOutlined />}>
|
|
||||||
<Link to={`${rootPath}/depthToInterval`}>Глубина-интервал</Link>
|
|
||||||
</Menu.Item>
|
|
||||||
<Menu.Item key={'operationsSummary'} icon={<FolderOutlined />}>
|
|
||||||
<Link to={`${rootPath}/operationsSummary`}>Все операции</Link>
|
|
||||||
</Menu.Item>
|
|
||||||
<Menu.Item key={'operationsToInterval'} icon={<FolderOutlined />}>
|
|
||||||
<Link to={`${rootPath}/operationsToInterval`}>Операции-интервал</Link>
|
|
||||||
</Menu.Item>
|
|
||||||
</Menu>
|
</Menu>
|
||||||
|
|
||||||
<Layout>
|
<Layout>
|
||||||
<Content className={'site-layout-background'}>
|
<Content className={'site-layout-background'}>
|
||||||
<Switch>
|
<Switch>
|
||||||
<Route path={`${rootPath}/depthToDay`}>
|
<PrivateRoute root={rootPath} path={'depthToDay'}>
|
||||||
<TelemetryAnalysisDepthToDay idWell={idWell}/>
|
<TelemetryAnalysisDepthToDay idWell={idWell}/>
|
||||||
</Route>
|
</PrivateRoute>
|
||||||
<Route path={`${rootPath}/depthToInterval`}>
|
<PrivateRoute root={rootPath} path={'depthToInterval'}>
|
||||||
<TelemetryAnalysisDepthToInterval idWell={idWell}/>
|
<TelemetryAnalysisDepthToInterval idWell={idWell}/>
|
||||||
</Route>
|
</PrivateRoute>
|
||||||
<Route path={`${rootPath}/operationsSummary`}>
|
<PrivateRoute root={rootPath} path={'operationsSummary'}>
|
||||||
<TelemetryAnalysisOperationsSummary idWell={idWell}/>
|
<TelemetryAnalysisOperationsSummary idWell={idWell}/>
|
||||||
</Route>
|
</PrivateRoute>
|
||||||
<Route path={`${rootPath}/operationsToInterval`}>
|
<PrivateRoute root={rootPath} path={'operationsToInterval'}>
|
||||||
<TelemetryAnalysisOperationsToInterval idWell={idWell}/>
|
<TelemetryAnalysisOperationsToInterval idWell={idWell}/>
|
||||||
</Route>
|
</PrivateRoute>
|
||||||
<Route path={`/`}>
|
<PrivateDefaultRoute urls={[
|
||||||
<Redirect to={`${rootPath}/depthToDay`} />
|
`${rootPath}/depthToDay`,
|
||||||
</Route>
|
`${rootPath}/depthToInterval`,
|
||||||
|
`${rootPath}/operationsSummary`,
|
||||||
|
`${rootPath}/operationsToInterval`,
|
||||||
|
]}/>
|
||||||
</Switch>
|
</Switch>
|
||||||
</Content>
|
</Content>
|
||||||
</Layout>
|
</Layout>
|
||||||
</>)
|
</>
|
||||||
}
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
export default TelemetryAnalysis
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { Layout, Menu } from 'antd'
|
import { memo } from 'react'
|
||||||
import {
|
import {
|
||||||
FolderOutlined,
|
FolderOutlined,
|
||||||
FundViewOutlined,
|
FundViewOutlined,
|
||||||
@ -8,9 +8,10 @@ import {
|
|||||||
ExperimentOutlined,
|
ExperimentOutlined,
|
||||||
FundProjectionScreenOutlined,
|
FundProjectionScreenOutlined,
|
||||||
} from '@ant-design/icons'
|
} from '@ant-design/icons'
|
||||||
import { Link, Redirect, Route, Switch, useParams } from 'react-router-dom'
|
import { Layout, Menu } from 'antd'
|
||||||
|
import { Switch, useParams } from 'react-router-dom'
|
||||||
|
|
||||||
import { PrivateMenuItem } from '@components/Private'
|
import { PrivateRoute, PrivateDefaultRoute, PrivateMenuItem } from '@components/Private'
|
||||||
|
|
||||||
import Report from './Report'
|
import Report from './Report'
|
||||||
import Archive from './Archive'
|
import Archive from './Archive'
|
||||||
@ -18,102 +19,76 @@ import Measure from './Measure'
|
|||||||
import Messages from './Messages'
|
import Messages from './Messages'
|
||||||
import Documents from './Documents'
|
import Documents from './Documents'
|
||||||
import TelemetryView from './TelemetryView'
|
import TelemetryView from './TelemetryView'
|
||||||
import { makeMenuItems } from './Documents'
|
|
||||||
import WellOperations from './WellOperations'
|
import WellOperations from './WellOperations'
|
||||||
import DrillingProgram from './DrillingProgram'
|
import DrillingProgram from './DrillingProgram'
|
||||||
import TelemetryAnalysis from './TelemetryAnalysis'
|
import TelemetryAnalysis from './TelemetryAnalysis'
|
||||||
|
|
||||||
const { Content } = Layout
|
const { Content } = Layout
|
||||||
const { SubMenu } = Menu
|
|
||||||
|
|
||||||
export const Well = () => {
|
export const Well = memo(() => {
|
||||||
const { idWell, tab } = useParams()
|
const { idWell, tab } = useParams()
|
||||||
const rootPath = `/well/${idWell}`
|
const rootPath = `/well/${idWell}`
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Layout>
|
<Layout>
|
||||||
<Menu
|
<Menu mode={'horizontal'} selectable={true} selectedKeys={[tab]} className={'well_menu'}>
|
||||||
mode={'horizontal'}
|
<PrivateMenuItem.Link root={rootPath} key={'telemetry'} path={'telemetry'} icon={<FundViewOutlined />} title={'Мониторинг'}/>
|
||||||
selectable={true}
|
<PrivateMenuItem.Link root={rootPath} key={'message'} path={'message'} icon={<AlertOutlined/>} title={'Сообщения'} />
|
||||||
selectedKeys={[tab]}
|
<PrivateMenuItem.Link root={rootPath} key={'report'} path={'report'} icon={<FilePdfOutlined />} title={'Рапорт'} />
|
||||||
className={'well_menu'}
|
<PrivateMenuItem.Link root={rootPath} key={'operations'} path={'operations'} icon={<FolderOutlined />} title={'Операции по скважине'} />
|
||||||
>
|
<PrivateMenuItem.Link root={rootPath} key={'archive'} path={'archive'} icon={<DatabaseOutlined />} title={'Архив'} />
|
||||||
<PrivateMenuItem key={'telemetry'} icon={<FundViewOutlined />}>
|
<PrivateMenuItem.Link root={rootPath} key={'telemetryAnalysis'} path={'telemetryAnalysis'} icon={<FundProjectionScreenOutlined />} title={'Операции по телеметрии'} />
|
||||||
<Link to={`${rootPath}/telemetry`}>Мониторинг</Link>
|
<PrivateMenuItem.Link root={rootPath} key={'document'} path={'document'} icon={<FolderOutlined />} title={'Документы'} />
|
||||||
</PrivateMenuItem>
|
<PrivateMenuItem.Link root={rootPath} key={'measure'} path={'measure'} icon={<ExperimentOutlined />} title={'Измерения'} />
|
||||||
<PrivateMenuItem key={'message'} icon={<AlertOutlined/>}>
|
<PrivateMenuItem.Link root={rootPath} key={'drillingProgram'} path={'drillingProgram'} icon={<FolderOutlined />} title={'Программа бурения'} />
|
||||||
<Link to={`${rootPath}/message`}>Сообщения</Link>
|
|
||||||
</PrivateMenuItem>
|
|
||||||
<PrivateMenuItem key={'report'} icon={<FilePdfOutlined />}>
|
|
||||||
<Link to={`${rootPath}/report`}>Рапорт</Link>
|
|
||||||
</PrivateMenuItem>
|
|
||||||
<PrivateMenuItem key={'operations'} icon={<FolderOutlined />}>
|
|
||||||
<Link to={`${rootPath}/operations`}>Операции по скважине</Link>
|
|
||||||
</PrivateMenuItem>
|
|
||||||
<PrivateMenuItem key={'archive'} icon={<DatabaseOutlined />}>
|
|
||||||
<Link to={`${rootPath}/archive`}>Архив</Link>
|
|
||||||
</PrivateMenuItem>
|
|
||||||
<PrivateMenuItem key={'telemetryAnalysis'} icon={<FundProjectionScreenOutlined />} roles={'admin'}>
|
|
||||||
<Link to={`${rootPath}/telemetryAnalysis/depthToDay`}>Операции по телеметрии</Link>
|
|
||||||
</PrivateMenuItem>
|
|
||||||
<SubMenu
|
|
||||||
key={'document'}
|
|
||||||
title={
|
|
||||||
<Link to={`${rootPath}/document/fluidService`} className={'linkDocuments'}>
|
|
||||||
Документы
|
|
||||||
</Link>
|
|
||||||
}
|
|
||||||
icon={<FolderOutlined />}
|
|
||||||
selectable={true}
|
|
||||||
>
|
|
||||||
{makeMenuItems(`${rootPath}/document`)}
|
|
||||||
</SubMenu>
|
|
||||||
<PrivateMenuItem key={'measure'} icon={<ExperimentOutlined />}>
|
|
||||||
<Link to={`${rootPath}/measure`}>Измерения</Link>
|
|
||||||
</PrivateMenuItem>
|
|
||||||
<PrivateMenuItem key={'drillingProgram'} icon={<FolderOutlined />}>
|
|
||||||
<Link to={`${rootPath}/drillingProgram`}>Программа бурения</Link>
|
|
||||||
</PrivateMenuItem>
|
|
||||||
</Menu>
|
</Menu>
|
||||||
|
|
||||||
<Layout>
|
<Layout>
|
||||||
<Content className={'site-layout-background'}>
|
<Content className={'site-layout-background'}>
|
||||||
<Switch>
|
<Switch>
|
||||||
<Route path={'/well/:idWell/telemetry'}>
|
<PrivateRoute path={`${rootPath}/telemetry`}>
|
||||||
<TelemetryView idWell={idWell} />
|
<TelemetryView idWell={idWell} />
|
||||||
</Route>
|
</PrivateRoute>
|
||||||
<Route path={'/well/:idWell/message'}>
|
<PrivateRoute path={`${rootPath}/message`}>
|
||||||
<Messages idWell={idWell} />
|
<Messages idWell={idWell} />
|
||||||
</Route>
|
</PrivateRoute>
|
||||||
<Route path={'/well/:idWell/report'}>
|
<PrivateRoute path={`${rootPath}/report`}>
|
||||||
<Report idWell={idWell} />
|
<Report idWell={idWell} />
|
||||||
</Route>
|
</PrivateRoute>
|
||||||
<Route path={'/well/:idWell/operations/:tab?'}>
|
<PrivateRoute path={`${rootPath}/operations/:tab?`}>
|
||||||
<WellOperations idWell={idWell} />
|
<WellOperations idWell={idWell} />
|
||||||
</Route>
|
</PrivateRoute>
|
||||||
<Route path={'/well/:idWell/archive'}>
|
<PrivateRoute path={`${rootPath}/archive`}>
|
||||||
<Archive idWell={idWell} />
|
<Archive idWell={idWell} />
|
||||||
</Route>
|
</PrivateRoute>
|
||||||
<Route path={'/well/:idWell/telemetryAnalysis/:tab'}>
|
<PrivateRoute path={`${rootPath}/telemetryAnalysis/:tab`}>
|
||||||
<TelemetryAnalysis idWell={idWell} />
|
<TelemetryAnalysis idWell={idWell} />
|
||||||
</Route>
|
</PrivateRoute>
|
||||||
<Route path={'/well/:idWell/document/:category'}>
|
<PrivateRoute path={`${rootPath}/document/:category`}>
|
||||||
<Documents idWell={idWell} />
|
<Documents idWell={idWell} />
|
||||||
</Route>
|
</PrivateRoute>
|
||||||
<Route path={'/well/:id/measure'}>
|
<PrivateRoute path={`${rootPath}/measure`}>
|
||||||
<Measure idWell={idWell}/>
|
<Measure idWell={idWell}/>
|
||||||
</Route>
|
</PrivateRoute>
|
||||||
<Route path={'/well/:id/drillingProgram'}>
|
<PrivateRoute path={`${rootPath}/drillingProgram`}>
|
||||||
<DrillingProgram idWell={idWell}/>
|
<DrillingProgram idWell={idWell}/>
|
||||||
</Route>
|
</PrivateRoute>
|
||||||
<Route path={'/'}>
|
<PrivateDefaultRoute urls={[
|
||||||
<Redirect to={`${rootPath}/telemetry`} />
|
`${rootPath}/telemetry`,
|
||||||
</Route>
|
`${rootPath}/message`,
|
||||||
|
`${rootPath}/report`,
|
||||||
|
`${rootPath}/operations`,
|
||||||
|
`${rootPath}/archive`,
|
||||||
|
`${rootPath}/telemetryAnalysis`,
|
||||||
|
`${rootPath}/document`,
|
||||||
|
`${rootPath}/measure`,
|
||||||
|
`${rootPath}/drillingProgram`,
|
||||||
|
]}/>
|
||||||
</Switch>
|
</Switch>
|
||||||
</Content>
|
</Content>
|
||||||
</Layout>
|
</Layout>
|
||||||
</Layout>
|
</Layout>
|
||||||
)
|
)
|
||||||
}
|
})
|
||||||
|
|
||||||
export default Well
|
export default Well
|
||||||
|
@ -1,13 +1,15 @@
|
|||||||
import { useState, useEffect } from 'react'
|
import { useState, useEffect, memo } from 'react'
|
||||||
|
|
||||||
import {
|
import {
|
||||||
EditableTable,
|
EditableTable,
|
||||||
makeNumericMinMax,
|
makeNumericMinMax,
|
||||||
makeNumericStartEnd,
|
makeNumericStartEnd,
|
||||||
} from '../../components/Table'
|
} from '@components/Table'
|
||||||
import LoaderPortal from '../../components/LoaderPortal'
|
import { DrillFlowChartService } from '@api'
|
||||||
import { invokeWebApiWrapperAsync } from '../../components/factory'
|
import LoaderPortal from '@components/LoaderPortal'
|
||||||
import { DrillFlowChartService } from '../../services/api'
|
import { invokeWebApiWrapperAsync } from '@components/factory'
|
||||||
import { arrayOrDefault } from '../../utils'
|
import { hasPermission } from '@utils/permissions'
|
||||||
|
import { arrayOrDefault } from '@utils'
|
||||||
|
|
||||||
const columns = [
|
const columns = [
|
||||||
makeNumericStartEnd('Глубина, м', 'depth'),
|
makeNumericStartEnd('Глубина, м', 'depth'),
|
||||||
@ -18,7 +20,7 @@ const columns = [
|
|||||||
makeNumericMinMax('Расход, л/с', 'flow')
|
makeNumericMinMax('Расход, л/с', 'flow')
|
||||||
]
|
]
|
||||||
|
|
||||||
export const DrillProcessFlow = ({ idWell }) => {
|
export const DrillProcessFlow = memo(({ idWell }) => {
|
||||||
const [flows, setFlows] = useState([])
|
const [flows, setFlows] = useState([])
|
||||||
const [showLoader, setShowLoader] = useState(false)
|
const [showLoader, setShowLoader] = useState(false)
|
||||||
|
|
||||||
@ -59,11 +61,13 @@ export const DrillProcessFlow = ({ idWell }) => {
|
|||||||
bordered
|
bordered
|
||||||
columns={columns}
|
columns={columns}
|
||||||
dataSource={flows}
|
dataSource={flows}
|
||||||
onRowAdd={onAdd}
|
onRowAdd={hasPermission('DrillFlowChart.edit') && onAdd}
|
||||||
onRowEdit={onEdit}
|
onRowEdit={hasPermission('DrillFlowChart.edit') && onEdit}
|
||||||
onRowDelete={onDelete}
|
onRowDelete={hasPermission('DrillFlowChart.delete') && onDelete}
|
||||||
pagination={false}
|
pagination={false}
|
||||||
/>
|
/>
|
||||||
</LoaderPortal>
|
</LoaderPortal>
|
||||||
)
|
)
|
||||||
}
|
})
|
||||||
|
|
||||||
|
export default DrillProcessFlow
|
||||||
|
@ -1,12 +1,14 @@
|
|||||||
|
import { memo, useState } from 'react'
|
||||||
import { Button, Tooltip, Modal } from 'antd'
|
import { Button, Tooltip, Modal } from 'antd'
|
||||||
import {useState} from 'react'
|
|
||||||
import { FileOutlined, ImportOutlined, ExportOutlined } from '@ant-design/icons'
|
import { FileOutlined, ImportOutlined, ExportOutlined } from '@ant-design/icons'
|
||||||
import { download } from '../../components/factory'
|
|
||||||
|
import { download } from '@components/factory'
|
||||||
|
|
||||||
import { ImportOperations } from './ImportOperations'
|
import { ImportOperations } from './ImportOperations'
|
||||||
|
|
||||||
const style = {margin:4}
|
const style = { margin: 4 }
|
||||||
|
|
||||||
export const ImportExportBar = ({idWell, onImported, disabled}) =>{
|
export const ImportExportBar = memo(({ idWell, onImported, disabled }) => {
|
||||||
const [isImportModalVisible, setIsImportModalVisible] = useState(false)
|
const [isImportModalVisible, setIsImportModalVisible] = useState(false)
|
||||||
|
|
||||||
const downloadTemplate = async () => download(`/api/well/${idWell}/wellOperations/template`)
|
const downloadTemplate = async () => download(`/api/well/${idWell}/wellOperations/template`)
|
||||||
@ -14,20 +16,20 @@ export const ImportExportBar = ({idWell, onImported, disabled}) =>{
|
|||||||
|
|
||||||
const onDone = () => {
|
const onDone = () => {
|
||||||
setIsImportModalVisible(false)
|
setIsImportModalVisible(false)
|
||||||
if(onImported)
|
onImported?.()
|
||||||
onImported()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return <>
|
return (
|
||||||
<Tooltip title = 'Импорт - загрузить файл с операциями на сервер'>
|
<>
|
||||||
|
<Tooltip title={'Импорт - загрузить файл с операциями на сервер'}>
|
||||||
<Button
|
<Button
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
icon={<ImportOutlined/>}
|
icon={<ImportOutlined/>}
|
||||||
style={style}
|
style={style}
|
||||||
onClick={_=>setIsImportModalVisible(true)}/>
|
onClick={() => setIsImportModalVisible(true)}/>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
|
|
||||||
<Tooltip title = 'Экспорт - скачать файл с операциями по скважине'>
|
<Tooltip title={'Экспорт - скачать файл с операциями по скважине'}>
|
||||||
<Button
|
<Button
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
icon={<ExportOutlined/>}
|
icon={<ExportOutlined/>}
|
||||||
@ -35,23 +37,20 @@ export const ImportExportBar = ({idWell, onImported, disabled}) =>{
|
|||||||
onClick={downloadExport}/>
|
onClick={downloadExport}/>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
|
|
||||||
<Tooltip title = 'Скачать шаблон для импорта операций'>
|
<Tooltip title={'Скачать шаблон для импорта операций'}>
|
||||||
<Button
|
<Button disabled={disabled} icon={<FileOutlined />} style={style} onClick={downloadTemplate} />
|
||||||
disabled={disabled}
|
|
||||||
icon={<FileOutlined/>}
|
|
||||||
style={style}
|
|
||||||
onClick={downloadTemplate}/>
|
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
|
|
||||||
<Modal
|
<Modal
|
||||||
title='Импорт операций'
|
title={'Импорт операций'}
|
||||||
visible={isImportModalVisible}
|
visible={isImportModalVisible}
|
||||||
onCancel={_=>setIsImportModalVisible(false)}
|
onCancel={() => setIsImportModalVisible(false)}
|
||||||
|
footer={null}
|
||||||
footer={null}>
|
>
|
||||||
<ImportOperations
|
<ImportOperations idWell={idWell} onDone={onDone} />
|
||||||
idWell={idWell}
|
</Modal>
|
||||||
onDone={onDone}/>
|
|
||||||
</Modal >
|
|
||||||
</>
|
</>
|
||||||
}
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
export default ImportExportBar
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
import { Switch } from 'antd'
|
||||||
import { memo, useState, useRef, useEffect } from 'react'
|
import { memo, useState, useRef, useEffect } from 'react'
|
||||||
|
|
||||||
import {
|
import {
|
||||||
@ -13,12 +14,42 @@ import 'chartjs-adapter-moment'
|
|||||||
import zoomPlugin from 'chartjs-plugin-zoom'
|
import zoomPlugin from 'chartjs-plugin-zoom'
|
||||||
import ChartDataLabels from 'chartjs-plugin-datalabels'
|
import ChartDataLabels from 'chartjs-plugin-datalabels'
|
||||||
|
|
||||||
import { invokeWebApiWrapperAsync } from '@components/factory'
|
|
||||||
import { getOperations } from '@pages/Cluster/functions'
|
|
||||||
import LoaderPortal from '@components/LoaderPortal'
|
import LoaderPortal from '@components/LoaderPortal'
|
||||||
|
import { invokeWebApiWrapperAsync } from '@components/factory'
|
||||||
|
|
||||||
|
import { getOperations } from '@pages/Cluster/functions'
|
||||||
|
|
||||||
Chart.register(TimeScale, LinearScale, LineController, LineElement, PointElement, Legend, ChartDataLabels, zoomPlugin)
|
Chart.register(TimeScale, LinearScale, LineController, LineElement, PointElement, Legend, ChartDataLabels, zoomPlugin)
|
||||||
|
|
||||||
|
const scaleTypes = {
|
||||||
|
day: {
|
||||||
|
min: 0,
|
||||||
|
type: 'linear',
|
||||||
|
display: true,
|
||||||
|
title: { display: false, text: '' },
|
||||||
|
ticks: { stepSize: 1 }
|
||||||
|
},
|
||||||
|
date: {
|
||||||
|
display: true,
|
||||||
|
title: { display: true },
|
||||||
|
type: 'time',
|
||||||
|
time: {
|
||||||
|
unit: 'hour',
|
||||||
|
displayFormats: { 'hour': 'MM.DD' }
|
||||||
|
},
|
||||||
|
grid: { drawTicks: true },
|
||||||
|
ticks: {
|
||||||
|
stepSize: 3,
|
||||||
|
major: { enabled: true },
|
||||||
|
z: 1,
|
||||||
|
display: true,
|
||||||
|
textStrokeColor: '#fff',
|
||||||
|
textStrokeWidth: 2,
|
||||||
|
color: '#000',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const defaultOptions = {
|
const defaultOptions = {
|
||||||
responsive: true,
|
responsive: true,
|
||||||
aspectRatio: 2.6,
|
aspectRatio: 2.6,
|
||||||
@ -27,20 +58,8 @@ const defaultOptions = {
|
|||||||
mode: 'index',
|
mode: 'index',
|
||||||
},
|
},
|
||||||
scales: {
|
scales: {
|
||||||
x: {
|
x: scaleTypes.day,
|
||||||
min: 0,
|
y: {
|
||||||
type: 'linear',
|
|
||||||
display: true,
|
|
||||||
title: {
|
|
||||||
display: false,
|
|
||||||
text: '',
|
|
||||||
},
|
|
||||||
ticks: {
|
|
||||||
stepSize: 1,
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
y:{
|
|
||||||
type: 'linear',
|
type: 'linear',
|
||||||
position: 'top',
|
position: 'top',
|
||||||
reverse: true,
|
reverse: true,
|
||||||
@ -90,7 +109,8 @@ const makeDataset = (data, label, color, borderWidth = 1.5, borderDash) => ({
|
|||||||
|
|
||||||
export const Tvd = memo(({ idWell, title }) => {
|
export const Tvd = memo(({ idWell, title }) => {
|
||||||
const [operations, setOperations] = useState([])
|
const [operations, setOperations] = useState([])
|
||||||
const [showLoader, setShowLoader] = useState(false)
|
const [isLoading, setIsLoading] = useState(false)
|
||||||
|
const [xLabel, setXLabel] = useState('day')
|
||||||
const [chart, setChart] = useState()
|
const [chart, setChart] = useState()
|
||||||
|
|
||||||
const chartRef = useRef(null)
|
const chartRef = useRef(null)
|
||||||
@ -101,7 +121,7 @@ export const Tvd = memo(({ idWell, title }) => {
|
|||||||
const operations = await getOperations(idWell)
|
const operations = await getOperations(idWell)
|
||||||
setOperations(operations)
|
setOperations(operations)
|
||||||
},
|
},
|
||||||
setShowLoader,
|
setIsLoading,
|
||||||
`Не удалось загрузить операции по скважине "${idWell}"`,
|
`Не удалось загрузить операции по скважине "${idWell}"`,
|
||||||
)
|
)
|
||||||
}, [idWell])
|
}, [idWell])
|
||||||
@ -118,6 +138,8 @@ export const Tvd = memo(({ idWell, title }) => {
|
|||||||
if (chartRef.current && !chart) {
|
if (chartRef.current && !chart) {
|
||||||
const thisOptions = {}
|
const thisOptions = {}
|
||||||
Object.assign(thisOptions, defaultOptions)
|
Object.assign(thisOptions, defaultOptions)
|
||||||
|
thisOptions.scales.x = scaleTypes[xLabel]
|
||||||
|
thisOptions.parsing.xAxisKey = xLabel
|
||||||
|
|
||||||
const newChart = new Chart(chartRef.current, {
|
const newChart = new Chart(chartRef.current, {
|
||||||
type: 'line',
|
type: 'line',
|
||||||
@ -130,9 +152,11 @@ export const Tvd = memo(({ idWell, title }) => {
|
|||||||
return () => chart?.destroy()
|
return () => chart?.destroy()
|
||||||
} else {
|
} else {
|
||||||
chart.data = data
|
chart.data = data
|
||||||
|
chart.options.scales.x = scaleTypes[xLabel]
|
||||||
|
chart.options.parsing.xAxisKey = xLabel
|
||||||
chart.update()
|
chart.update()
|
||||||
}
|
}
|
||||||
}, [chart, operations])
|
}, [chart, operations, xLabel])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={'container'}>
|
<div className={'container'}>
|
||||||
@ -140,10 +164,20 @@ export const Tvd = memo(({ idWell, title }) => {
|
|||||||
{title || (
|
{title || (
|
||||||
<h2 className={'mt-20px'}>График Глубина-день</h2>
|
<h2 className={'mt-20px'}>График Глубина-день</h2>
|
||||||
)}
|
)}
|
||||||
<LoaderPortal show={showLoader}>
|
<LoaderPortal show={isLoading}>
|
||||||
<canvas ref={chartRef} />
|
<canvas ref={chartRef} />
|
||||||
|
<div style={{ display: 'flex', justifyContent: 'center', width: '100%' }}>
|
||||||
|
<Switch
|
||||||
|
checkedChildren={'Дата'}
|
||||||
|
unCheckedChildren={'Дни со старта'}
|
||||||
|
loading={isLoading}
|
||||||
|
onChange={(checked) => setXLabel(checked ? 'date' : 'day')}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
</LoaderPortal>
|
</LoaderPortal>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
export default Tvd
|
||||||
|
@ -1,20 +1,20 @@
|
|||||||
|
import { Link } from 'react-router-dom'
|
||||||
|
import { useState, useEffect, memo } from 'react'
|
||||||
import { LineChartOutlined, ProfileOutlined } from '@ant-design/icons'
|
import { LineChartOutlined, ProfileOutlined } from '@ant-design/icons'
|
||||||
import { Table, Tag, Button, Badge, Divider, Modal, Row, Col, Popconfirm } from 'antd'
|
import { Table, Tag, Button, Badge, Divider, Modal, Row, Col, Popconfirm } from 'antd'
|
||||||
import { Link } from 'react-router-dom'
|
|
||||||
import { useState, useEffect } from 'react'
|
|
||||||
|
|
||||||
import { makeTextColumn, makeNumericColumnPlanFact } from '../../../components/Table'
|
import { CompanyView } from '@components/views'
|
||||||
import { DrillParamsService, WellCompositeService } from '../../../services/api'
|
import LoaderPortal from '@components/LoaderPortal'
|
||||||
import LoaderPortal from '../../../components/LoaderPortal'
|
import { invokeWebApiWrapperAsync } from '@components/factory'
|
||||||
import { invokeWebApiWrapperAsync } from '../../../components/factory'
|
import { makeTextColumn, makeNumericColumnPlanFact } from '@components/Table'
|
||||||
import { CompanyView } from '../../../components/views'
|
import { DrillParamsService, WellCompositeService } from '@api'
|
||||||
|
|
||||||
import {
|
import {
|
||||||
calcAndUpdateStatsBySections,
|
calcAndUpdateStatsBySections,
|
||||||
makeFilterMinMaxFunction,
|
makeFilterMinMaxFunction,
|
||||||
getOperations
|
getOperations
|
||||||
} from '../../Cluster/functions'
|
} from '@pages/Cluster/functions'
|
||||||
import WellOperationsTable from '../../Cluster/WellOperationsTable'
|
import WellOperationsTable from '@pages/Cluster/WellOperationsTable'
|
||||||
import { Tvd } from '../Tvd'
|
import { Tvd } from '../Tvd'
|
||||||
import { getColumns } from '../WellDrillParams'
|
import { getColumns } from '../WellDrillParams'
|
||||||
|
|
||||||
@ -27,7 +27,7 @@ const filtersMinMax = [
|
|||||||
const filtersSectionsType = []
|
const filtersSectionsType = []
|
||||||
const DAY_IN_MS = 1000 * 60 * 60 * 24
|
const DAY_IN_MS = 1000 * 60 * 60 * 24
|
||||||
|
|
||||||
export const WellCompositeSections = ({ idWell, statsWells, selectedSections }) => {
|
export const WellCompositeSections = memo(({ idWell, statsWells, selectedSections }) => {
|
||||||
const [rows, setRows] = useState([])
|
const [rows, setRows] = useState([])
|
||||||
const [params, setParams] = useState([])
|
const [params, setParams] = useState([])
|
||||||
const [paramsColumns, setParamsColumns] = useState([])
|
const [paramsColumns, setParamsColumns] = useState([])
|
||||||
@ -288,4 +288,6 @@ export const WellCompositeSections = ({ idWell, statsWells, selectedSections })
|
|||||||
</Modal>
|
</Modal>
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
}
|
})
|
||||||
|
|
||||||
|
export default WellCompositeSections
|
||||||
|
@ -1,22 +1,23 @@
|
|||||||
import { useState, useEffect } from 'react'
|
import { useState, useEffect, memo } from 'react'
|
||||||
import { Redirect, Route, Switch, Link, useParams } from 'react-router-dom'
|
import { Switch, useParams } from 'react-router-dom'
|
||||||
import { Col, Layout, Menu, Row, Tag, TreeSelect } from 'antd'
|
import { Col, Layout, Menu, Row, Tag, TreeSelect } from 'antd'
|
||||||
|
|
||||||
import LoaderPortal from '../../../components/LoaderPortal'
|
|
||||||
import { invokeWebApiWrapperAsync } from '../../../components/factory'
|
|
||||||
import {
|
import {
|
||||||
DepositService,
|
DepositService,
|
||||||
OperationStatService,
|
OperationStatService,
|
||||||
WellCompositeService,
|
WellCompositeService,
|
||||||
} from '../../../services/api'
|
} from '@api'
|
||||||
import { arrayOrDefault } from '../../../utils'
|
import { arrayOrDefault } from '@utils'
|
||||||
|
import LoaderPortal from '@components/LoaderPortal'
|
||||||
|
import { invokeWebApiWrapperAsync } from '@components/factory'
|
||||||
|
import { PrivateDefaultRoute, PrivateMenuItemLink, PrivateRoute } from '@components/Private'
|
||||||
|
|
||||||
import ClusterWells from '../../Cluster/ClusterWells'
|
import ClusterWells from '@pages/Cluster/ClusterWells'
|
||||||
import { WellCompositeSections } from './WellCompositeSections'
|
import { WellCompositeSections } from './WellCompositeSections'
|
||||||
|
|
||||||
const { Content } = Layout
|
const { Content } = Layout
|
||||||
|
|
||||||
export const WellCompositeEditor = ({ idWell }) => {
|
export const WellCompositeEditor = memo(({ idWell }) => {
|
||||||
const rootPath = `/well/${idWell}/operations/composite`
|
const rootPath = `/well/${idWell}/operations/composite`
|
||||||
const { tab } = useParams()
|
const { tab } = useParams()
|
||||||
|
|
||||||
@ -94,7 +95,7 @@ export const WellCompositeEditor = ({ idWell }) => {
|
|||||||
treeLine={{ showLeafIcon: false }}
|
treeLine={{ showLeafIcon: false }}
|
||||||
onChange={(value) => setSelectedIdWells(value)}
|
onChange={(value) => setSelectedIdWells(value)}
|
||||||
size={'middle'}
|
size={'middle'}
|
||||||
style={{width: '100%'}}
|
style={{ width: '100%' }}
|
||||||
value={selectedIdWells}
|
value={selectedIdWells}
|
||||||
placeholder={'Выберите скважины'}
|
placeholder={'Выберите скважины'}
|
||||||
tagRender={(props) => (
|
tagRender={(props) => (
|
||||||
@ -103,18 +104,9 @@ export const WellCompositeEditor = ({ idWell }) => {
|
|||||||
/>
|
/>
|
||||||
</Col>
|
</Col>
|
||||||
<Col span={6}>
|
<Col span={6}>
|
||||||
<Menu
|
<Menu mode={'horizontal'} selectable={true} className={'well_menu'} selectedKeys={[tab]}>
|
||||||
mode={'horizontal'}
|
<PrivateMenuItemLink root={rootPath} key={'wells'} path={'wells'} title={'Статистика по скважинам'} />
|
||||||
selectable={true}
|
<PrivateMenuItemLink root={rootPath} key={'sections'} path={'sections'} title={'Статистика по секциям'} />
|
||||||
className={'well_menu'}
|
|
||||||
selectedKeys={[tab]}
|
|
||||||
>
|
|
||||||
<Menu.Item key={'wells'}>
|
|
||||||
<Link to={`${rootPath}/wells`}>Статистика по скважинам</Link>
|
|
||||||
</Menu.Item>
|
|
||||||
<Menu.Item key={'sections'}>
|
|
||||||
<Link to={`${rootPath}/sections`}>Статистика по секциям</Link>
|
|
||||||
</Menu.Item>
|
|
||||||
</Menu>
|
</Menu>
|
||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
@ -122,23 +114,23 @@ export const WellCompositeEditor = ({ idWell }) => {
|
|||||||
<Content className={'site-layout-background'}>
|
<Content className={'site-layout-background'}>
|
||||||
<LoaderPortal show={showTabLoader}>
|
<LoaderPortal show={showTabLoader}>
|
||||||
<Switch>
|
<Switch>
|
||||||
<Route path={`${rootPath}/wells`}>
|
<PrivateRoute path={`${rootPath}/wells`}>
|
||||||
<ClusterWells statsWells={statsWells}/>
|
<ClusterWells statsWells={statsWells}/>
|
||||||
</Route>
|
</PrivateRoute>
|
||||||
<Route path={`${rootPath}/sections`}>
|
<PrivateRoute path={`${rootPath}/sections`}>
|
||||||
<WellCompositeSections
|
<WellCompositeSections
|
||||||
idWell={idWell}
|
idWell={idWell}
|
||||||
statsWells={statsWells}
|
statsWells={statsWells}
|
||||||
selectedSections={selectedSections}
|
selectedSections={selectedSections}
|
||||||
/>
|
/>
|
||||||
</Route>
|
</PrivateRoute>
|
||||||
<Route path={rootPath}>
|
<PrivateDefaultRoute urls={[`${rootPath}/wells`, `${rootPath}/sections`]}/>
|
||||||
<Redirect to={`${rootPath}/wells`}/>
|
|
||||||
</Route>
|
|
||||||
</Switch>
|
</Switch>
|
||||||
</LoaderPortal>
|
</LoaderPortal>
|
||||||
</Content>
|
</Content>
|
||||||
</Layout>
|
</Layout>
|
||||||
</LoaderPortal>
|
</LoaderPortal>
|
||||||
)
|
)
|
||||||
}
|
})
|
||||||
|
|
||||||
|
export default WellCompositeEditor
|
||||||
|
@ -1,15 +1,16 @@
|
|||||||
import { useState, useEffect, useCallback } from 'react'
|
import { useState, useEffect, useCallback, memo } from 'react'
|
||||||
|
|
||||||
import { DrillParamsService, WellOperationService } from '../../services/api'
|
|
||||||
import LoaderPortal from '../../components/LoaderPortal'
|
|
||||||
import { invokeWebApiWrapperAsync } from '../../components/factory'
|
|
||||||
import {
|
import {
|
||||||
EditableTable,
|
EditableTable,
|
||||||
makeSelectColumn,
|
makeSelectColumn,
|
||||||
makeActionHandler,
|
makeActionHandler,
|
||||||
makeNumericAvgRange,
|
makeNumericAvgRange,
|
||||||
} from '../../components/Table'
|
} from '@components/Table'
|
||||||
import { arrayOrDefault } from '../../utils'
|
import LoaderPortal from '@components/LoaderPortal'
|
||||||
|
import { invokeWebApiWrapperAsync } from '@components/factory'
|
||||||
|
import { DrillParamsService, WellOperationService } from '@api'
|
||||||
|
import { hasPermission } from '@utils/permissions'
|
||||||
|
import { arrayOrDefault } from '@utils'
|
||||||
|
|
||||||
export const getColumns = async (idWell) => {
|
export const getColumns = async (idWell) => {
|
||||||
let sectionTypes = await WellOperationService.getSectionTypes(idWell)
|
let sectionTypes = await WellOperationService.getSectionTypes(idWell)
|
||||||
@ -31,7 +32,7 @@ export const getColumns = async (idWell) => {
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
export const WellDrillParams = ({ idWell }) => {
|
export const WellDrillParams = memo(({ idWell }) => {
|
||||||
const [params, setParams] = useState([])
|
const [params, setParams] = useState([])
|
||||||
const [showLoader, setShowLoader] = useState(false)
|
const [showLoader, setShowLoader] = useState(false)
|
||||||
const [columns, setColumns] = useState([])
|
const [columns, setColumns] = useState([])
|
||||||
@ -69,11 +70,13 @@ export const WellDrillParams = ({ idWell }) => {
|
|||||||
bordered
|
bordered
|
||||||
columns={columns}
|
columns={columns}
|
||||||
dataSource={params}
|
dataSource={params}
|
||||||
onRowAdd={makeActionHandler('insert', handlerProps, recordParser)}
|
onRowAdd={hasPermission('DrillParams.edit') && makeActionHandler('insert', handlerProps, recordParser)}
|
||||||
onRowEdit={makeActionHandler('update', handlerProps, recordParser)}
|
onRowEdit={hasPermission('DrillParams.edit') && makeActionHandler('update', handlerProps, recordParser)}
|
||||||
onRowDelete={makeActionHandler('delete', handlerProps, recordParser)}
|
onRowDelete={hasPermission('DrillParams.delete') && makeActionHandler('delete', handlerProps, recordParser)}
|
||||||
pagination={false}
|
pagination={false}
|
||||||
/>
|
/>
|
||||||
</LoaderPortal>
|
</LoaderPortal>
|
||||||
)
|
)
|
||||||
}
|
})
|
||||||
|
|
||||||
|
export default WellDrillParams
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import moment from 'moment'
|
import moment from 'moment'
|
||||||
import { Input } from 'antd'
|
import { Input } from 'antd'
|
||||||
import { useState, useEffect } from 'react'
|
import { useState, useEffect, memo } from 'react'
|
||||||
|
|
||||||
import {
|
import {
|
||||||
EditableTable,
|
EditableTable,
|
||||||
@ -10,11 +10,12 @@ import {
|
|||||||
makeNumericColumnOptions,
|
makeNumericColumnOptions,
|
||||||
makeSelectColumn,
|
makeSelectColumn,
|
||||||
makeActionHandler,
|
makeActionHandler,
|
||||||
} from '../../components/Table'
|
} from '@components/Table'
|
||||||
import LoaderPortal from '../../components/LoaderPortal'
|
import { WellOperationService} from '@api'
|
||||||
import { invokeWebApiWrapperAsync } from '../../components/factory'
|
import LoaderPortal from '@components/LoaderPortal'
|
||||||
import { WellOperationService} from '../../services/api'
|
import { invokeWebApiWrapperAsync } from '@components/factory'
|
||||||
import { formatDate } from '../../utils'
|
import { hasPermission } from '@utils/permissions'
|
||||||
|
import { formatDate } from '@utils'
|
||||||
|
|
||||||
const { TextArea } = Input
|
const { TextArea } = Input
|
||||||
|
|
||||||
@ -52,7 +53,7 @@ const defaultColumns = [
|
|||||||
makeColumn('Комментарий', 'comment', { editable: true, input: <TextArea/> }),
|
makeColumn('Комментарий', 'comment', { editable: true, input: <TextArea/> }),
|
||||||
]
|
]
|
||||||
|
|
||||||
export const WellOperationsEditor = ({idWell, idType}) => {
|
export const WellOperationsEditor = memo(({ idWell, idType, ...other }) => {
|
||||||
const [pageNumAndPageSize, setPageNumAndPageSize] = useState({current:1, pageSize:basePageSize})
|
const [pageNumAndPageSize, setPageNumAndPageSize] = useState({current:1, pageSize:basePageSize})
|
||||||
const [paginationTotal, setPaginationTotal] = useState(0)
|
const [paginationTotal, setPaginationTotal] = useState(0)
|
||||||
const [operations, setOperations] = useState([])
|
const [operations, setOperations] = useState([])
|
||||||
@ -113,13 +114,14 @@ export const WellOperationsEditor = ({idWell, idType}) => {
|
|||||||
return (
|
return (
|
||||||
<LoaderPortal show={showLoader}>
|
<LoaderPortal show={showLoader}>
|
||||||
<EditableTable
|
<EditableTable
|
||||||
size={'small'}
|
{...other}
|
||||||
bordered
|
bordered
|
||||||
|
size={'small'}
|
||||||
columns={columns}
|
columns={columns}
|
||||||
dataSource={operations}
|
dataSource={operations}
|
||||||
onRowAdd={makeActionHandler('insertRange', handlerProps, recordParser)}
|
onRowAdd={hasPermission('WellOperation.edit') && makeActionHandler('insertRange', handlerProps, recordParser)}
|
||||||
onRowEdit={makeActionHandler('update', handlerProps, recordParser)}
|
onRowEdit={hasPermission('WellOperation.edit') && makeActionHandler('update', handlerProps, recordParser)}
|
||||||
onRowDelete={makeActionHandler('delete', handlerProps)}
|
onRowDelete={hasPermission('WellOperation.delete') && makeActionHandler('delete', handlerProps)}
|
||||||
pagination={{
|
pagination={{
|
||||||
current: pageNumAndPageSize.current,
|
current: pageNumAndPageSize.current,
|
||||||
pageSize: pageNumAndPageSize.pageSize,
|
pageSize: pageNumAndPageSize.pageSize,
|
||||||
@ -130,4 +132,6 @@ export const WellOperationsEditor = ({idWell, idType}) => {
|
|||||||
/>
|
/>
|
||||||
</LoaderPortal>
|
</LoaderPortal>
|
||||||
)
|
)
|
||||||
}
|
})
|
||||||
|
|
||||||
|
export default WellOperationsEditor
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import {Layout, Menu} from "antd";
|
import { memo } from 'react'
|
||||||
import {Switch, Link, Route, Redirect, useParams, useHistory} from "react-router-dom";
|
import { Layout, Menu } from 'antd'
|
||||||
|
import { Switch, useParams, useHistory } from 'react-router-dom'
|
||||||
import {
|
import {
|
||||||
BarChartOutlined,
|
BarChartOutlined,
|
||||||
BuildOutlined,
|
BuildOutlined,
|
||||||
@ -7,84 +8,79 @@ import {
|
|||||||
DeploymentUnitOutlined,
|
DeploymentUnitOutlined,
|
||||||
LineChartOutlined,
|
LineChartOutlined,
|
||||||
TableOutlined,
|
TableOutlined,
|
||||||
} from "@ant-design/icons";
|
} from '@ant-design/icons'
|
||||||
|
|
||||||
|
import { PrivateDefaultRoute, PrivateRoute, PrivateMenuItemLink } from '@components/Private'
|
||||||
|
|
||||||
|
import { Tvd } from './Tvd'
|
||||||
|
import { ImportExportBar } from './ImportExportBar'
|
||||||
import { WellDrillParams } from './WellDrillParams'
|
import { WellDrillParams } from './WellDrillParams'
|
||||||
|
import { DrillProcessFlow } from './DrillProcessFlow'
|
||||||
import { WellSectionsStat } from './WellSectionsStat'
|
import { WellSectionsStat } from './WellSectionsStat'
|
||||||
import { WellCompositeEditor } from './WellCompositeEditor'
|
import { WellCompositeEditor } from './WellCompositeEditor'
|
||||||
import { WellOperationsEditor } from './WellOperationsEditor'
|
import { WellOperationsEditor } from './WellOperationsEditor'
|
||||||
import { Tvd } from './Tvd'
|
|
||||||
import { ImportExportBar } from "./ImportExportBar";
|
|
||||||
import { DrillProcessFlow } from "./DrillProcessFlow";
|
|
||||||
|
|
||||||
const { Content } = Layout
|
const { Content } = Layout
|
||||||
|
|
||||||
export default function WellOperations({idWell}) {
|
export const WellOperations = memo(({ idWell }) => {
|
||||||
let {tab} = useParams()
|
const { tab } = useParams()
|
||||||
let history = useHistory()
|
const history = useHistory()
|
||||||
const rootPath = `/well/${idWell}/operations`
|
const rootPath = `/well/${idWell}/operations`
|
||||||
|
|
||||||
const onImported = () => history.push(`${rootPath}`)
|
const onImported = () => history.push(`${rootPath}`)
|
||||||
|
|
||||||
const isIEBarDisabled = !["plan", "fact"].includes(tab)
|
const isIEBarDisabled = !['plan', 'fact'].includes(tab)
|
||||||
|
|
||||||
return(<>
|
return(
|
||||||
<Menu
|
<>
|
||||||
mode="horizontal"
|
<Menu mode={'horizontal'} selectable={true} className={'well_menu'} selectedKeys={[tab]}>
|
||||||
selectable={true}
|
<PrivateMenuItemLink root={rootPath} icon={<LineChartOutlined />} key={'tvd'} path={'tvd'} title={'TVD'} />
|
||||||
className="well_menu"
|
<PrivateMenuItemLink root={rootPath} icon={<BuildOutlined />} key={'sections'} path={'sections'} title={'Секции'} />
|
||||||
selectedKeys={[tab]}>
|
<PrivateMenuItemLink root={rootPath} icon={<TableOutlined />} key={'plan'} path={'plan'} title={'План'} />
|
||||||
<Menu.Item key="tvd" icon={<LineChartOutlined />}>
|
<PrivateMenuItemLink root={rootPath} icon={<TableOutlined />} key={'fact'} path={'fact'} title={'Факт'} />
|
||||||
<Link to={`${rootPath}/tvd`}>TVD</Link>
|
<PrivateMenuItemLink root={rootPath} icon={<BarChartOutlined />} key={'drillProcessFlow'} path={'drillProcessFlow'} title={'РТК'} />
|
||||||
</Menu.Item>
|
<PrivateMenuItemLink root={rootPath} icon={<ControlOutlined />} key={'params'} path={'params'} title={'Режимы'} />
|
||||||
<Menu.Item key="sections" icon={<BuildOutlined />}>
|
<PrivateMenuItemLink root={rootPath} icon={<DeploymentUnitOutlined />} key={'composite'} path={'composite'} title={'Аналитика'} />
|
||||||
<Link to={`${rootPath}/sections`}>Секции</Link>
|
|
||||||
</Menu.Item>
|
|
||||||
<Menu.Item key="plan" icon={<TableOutlined />}>
|
|
||||||
<Link to={`${rootPath}/plan`}>План</Link>
|
|
||||||
</Menu.Item>
|
|
||||||
<Menu.Item key="fact" icon={<TableOutlined />}>
|
|
||||||
<Link to={`${rootPath}/fact`}>Факт</Link>
|
|
||||||
</Menu.Item>
|
|
||||||
<Menu.Item key="drillProcessFlow" icon={<BarChartOutlined />}>
|
|
||||||
<Link to={`${rootPath}/drillProcessFlow`}>РТК</Link>
|
|
||||||
</Menu.Item>
|
|
||||||
<Menu.Item key="params" icon={<ControlOutlined />}>
|
|
||||||
<Link to={`${rootPath}/params`}>Режимы</Link>
|
|
||||||
</Menu.Item>
|
|
||||||
<Menu.Item key="composite" icon={<DeploymentUnitOutlined />}>
|
|
||||||
<Link to={`${rootPath}/composite`}>Аналитика</Link>
|
|
||||||
</Menu.Item>
|
|
||||||
<ImportExportBar idWell={idWell} disabled={isIEBarDisabled} onImported={onImported}/>
|
<ImportExportBar idWell={idWell} disabled={isIEBarDisabled} onImported={onImported}/>
|
||||||
</Menu>
|
</Menu>
|
||||||
<Layout>
|
<Layout>
|
||||||
<Content className="site-layout-background">
|
<Content className={'site-layout-background'}>
|
||||||
<Switch>
|
<Switch>
|
||||||
<Route path={`${rootPath}/tvd`}>
|
<PrivateRoute path={`${rootPath}/tvd`}>
|
||||||
<Tvd idWell={idWell}/>
|
<Tvd idWell={idWell}/>
|
||||||
</Route>
|
</PrivateRoute>
|
||||||
<Route path={`${rootPath}/sections`}>
|
<PrivateRoute path={`${rootPath}/sections`}>
|
||||||
<WellSectionsStat idWell={idWell}/>
|
<WellSectionsStat idWell={idWell}/>
|
||||||
</Route>
|
</PrivateRoute>
|
||||||
<Route path={`${rootPath}/plan`}>
|
<PrivateRoute path={`${rootPath}/plan`}>
|
||||||
<WellOperationsEditor idWell={idWell} idType={0}/>
|
<WellOperationsEditor idWell={idWell} idType={0} tableName={'well_operations_plan'} showSettingsChanger />
|
||||||
</Route>
|
</PrivateRoute>
|
||||||
<Route path={`${rootPath}/fact`}>
|
<PrivateRoute path={`${rootPath}/fact`}>
|
||||||
<WellOperationsEditor idWell={idWell} idType={1}/>
|
<WellOperationsEditor idWell={idWell} idType={1} tableName={'well_operations_fact'}/>
|
||||||
</Route>
|
</PrivateRoute>
|
||||||
<Route path={`${rootPath}/drillProcessFlow`}>
|
<PrivateRoute path={`${rootPath}/drillProcessFlow`}>
|
||||||
<DrillProcessFlow idWell={idWell} />
|
<DrillProcessFlow idWell={idWell} />
|
||||||
</Route>
|
</PrivateRoute>
|
||||||
<Route path={`${rootPath}/params`}>
|
<PrivateRoute path={`${rootPath}/params`}>
|
||||||
<WellDrillParams idWell={idWell}/>
|
<WellDrillParams idWell={idWell}/>
|
||||||
</Route>
|
</PrivateRoute>
|
||||||
<Route path={`${rootPath}/composite/:tab?`}>
|
<PrivateRoute path={`${rootPath}/composite/:tab?`}>
|
||||||
<WellCompositeEditor idWell={idWell}/>
|
<WellCompositeEditor idWell={idWell}/>
|
||||||
</Route>
|
</PrivateRoute>
|
||||||
<Route path={rootPath}>
|
<PrivateDefaultRoute urls={[
|
||||||
<Redirect to={`${rootPath}/plan`}/>
|
`${rootPath}/plan`,
|
||||||
</Route>
|
`${rootPath}/fact`,
|
||||||
|
`${rootPath}/tvd`,
|
||||||
|
`${rootPath}/sections`,
|
||||||
|
`${rootPath}/drillProcessFlow`,
|
||||||
|
`${rootPath}/params`,
|
||||||
|
`${rootPath}/composite`
|
||||||
|
]}/>
|
||||||
</Switch>
|
</Switch>
|
||||||
</Content>
|
</Content>
|
||||||
</Layout>
|
</Layout>
|
||||||
</>)
|
</>
|
||||||
}
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
export default WellOperations
|
||||||
|
@ -3,10 +3,13 @@ import { getUserPermissions, getUserRoles } from './storage'
|
|||||||
export type Role = string
|
export type Role = string
|
||||||
export type Permission = string
|
export type Permission = string
|
||||||
|
|
||||||
export const hasPermission = (permission?: Permission): boolean => {
|
export const hasPermission = (permission?: Permission | Permission[], userPermissions?: Permission[]): boolean => {
|
||||||
if (typeof permission !== 'string') return true
|
if (!Array.isArray(permission) && typeof permission !== 'string')
|
||||||
|
return true
|
||||||
return getUserPermissions().includes(permission)
|
const userPerms = userPermissions ?? getUserPermissions()
|
||||||
|
if (typeof permission === 'string')
|
||||||
|
permission = [permission]
|
||||||
|
return permission.every((perm) => userPerms.includes(perm))
|
||||||
}
|
}
|
||||||
|
|
||||||
export const isInRole = (roles?: Role[] | Role): boolean => {
|
export const isInRole = (roles?: Role[] | Role): boolean => {
|
||||||
@ -15,43 +18,104 @@ export const isInRole = (roles?: Role[] | Role): boolean => {
|
|||||||
if (!roles?.length) return true
|
if (!roles?.length) return true
|
||||||
|
|
||||||
const user_roles = getUserRoles()
|
const user_roles = getUserRoles()
|
||||||
return roles.some((role) => role in user_roles)
|
return roles.some((role) => user_roles.includes(role))
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
const sectionAvailable = (section: PermissionRecord, userPermission: Permission[] = getUserPermissions()) => {
|
||||||
deposit
|
for (const child of Object.values(section)) {
|
||||||
cluster
|
if (!child) continue
|
||||||
well (R)
|
if (Array.isArray(child)) {
|
||||||
well/archive (R)
|
if (hasPermission(child, userPermission)) return true
|
||||||
well/message (R)
|
} else {
|
||||||
well/report (R)
|
if (sectionAvailable(child, userPermission)) return true
|
||||||
well/measure (RW)
|
}
|
||||||
well/drillingProgram (RU согласовать)
|
}
|
||||||
well/telemetry (R)
|
return false
|
||||||
well/telemetry:status (RW)
|
}
|
||||||
well/telemetry:rop (RW)
|
|
||||||
well/operations (R)
|
export const isURLAvailable = (path: string, userPermissions?: Permission[]) => {
|
||||||
well/operations/tvd (R)
|
const pathParts = path.replaceAll('/', ' ').trim().split(' ')
|
||||||
well/operations/sections (R)
|
if (pathParts.length <= 0) return false
|
||||||
well/operations/plan (RW)
|
|
||||||
well/operations/fact (RW)
|
let perms: PermissionRecord | string[] | null = requirements
|
||||||
well/operations/drillProccesFlow (RW)
|
for (let i = 0; i < pathParts.length; i++) {
|
||||||
well/operations/params (RW)
|
if (!perms) return false
|
||||||
well/operations/composite (R)
|
if (Array.isArray(perms)) break
|
||||||
well/operations/composite/wells (R)
|
if (pathParts[i] in perms) {
|
||||||
well/operations/composite/sections (RW)
|
if (!perms[pathParts[i]]) return false
|
||||||
well/document (R)
|
perms = perms[pathParts[i]]
|
||||||
well/document/fluidService (RU)
|
} else if ('*' in perms) {
|
||||||
well/document/cementing (RU)
|
perms = perms['*']
|
||||||
well/document/nnb (RU)
|
} else {
|
||||||
well/document/gti (RU)
|
if(i + 1 < pathParts.length || pathParts[i][0] !== ':') return false
|
||||||
well/document/documentsForWell (RU)
|
// Если последним аргументом указан параметр, считаем, что началась секция
|
||||||
well/document/supervisor (RU)
|
break
|
||||||
well/document/master (RU)
|
}
|
||||||
admin (R)
|
}
|
||||||
admin/deposit (RAED)
|
|
||||||
admin/cluster (RAED)
|
if (!perms) return false
|
||||||
admin/well (RAED)
|
const userPerms: string[] = userPermissions ?? getUserPermissions()
|
||||||
admin/user (RAED)
|
if (Array.isArray(perms)) {
|
||||||
admin/company (RAED)
|
return perms.every((perm) => userPerms.includes(perm))
|
||||||
*/
|
}
|
||||||
|
|
||||||
|
return sectionAvailable(perms, userPerms)
|
||||||
|
}
|
||||||
|
|
||||||
|
interface PermissionRecord extends Record<string, string[] | PermissionRecord | null> {}
|
||||||
|
|
||||||
|
export const requirements: PermissionRecord = {
|
||||||
|
'': [],
|
||||||
|
login: [], // ['Auth.edit']
|
||||||
|
register: [], // ['Auth.edit']
|
||||||
|
admin: {
|
||||||
|
user: ['AdminCompany.get', 'AdminUserRole.get', 'AdminUser.get'],
|
||||||
|
well: ['AdminCompany.get', 'AdminCluster.get', 'AdminTelemetry.get', 'AdminWell.get'],
|
||||||
|
cluster: ['AdminCluster.get', 'AdminDeposit.get'],
|
||||||
|
company: ['AdminCompany.get', 'AdminCompanyType.get'],
|
||||||
|
company_type: ['AdminCompanyType.get'],
|
||||||
|
deposit: ['AdminDeposit.get'],
|
||||||
|
permission: ['AdminPermission.get'],
|
||||||
|
role: ['AdminUserRole.get', 'AdminPermission.get'],
|
||||||
|
visit_log: ['RequerstTracker.get'],
|
||||||
|
telemetry: ['AdminTelemetry.get'],
|
||||||
|
},
|
||||||
|
deposit: ['Deposit.get', 'Cluster.get'],
|
||||||
|
cluster: {
|
||||||
|
'*': ['Deposit.get', 'Cluster.get', 'OperationStat.get'],
|
||||||
|
},
|
||||||
|
well: {
|
||||||
|
'*': {
|
||||||
|
document: {
|
||||||
|
'*': ['Deposit.get', 'File.get'],
|
||||||
|
},
|
||||||
|
archive: ['Deposit.get', 'TelemetryDataSaub.get'],
|
||||||
|
telemetry: ['Deposit.get', 'DrillFlowChart.get', 'TelemetryDataSaub.get', 'TelemetryDataSpin.get'],
|
||||||
|
message: ['Deposit.get', 'TelemetryDataSaub.get'],
|
||||||
|
report: ['Deposit.get', 'Report.get'],
|
||||||
|
operations: {
|
||||||
|
tvd: ['Deposit.get', 'OperationStat.get'],
|
||||||
|
sections: ['Deposit.get', 'OperationStat.get'],
|
||||||
|
plan: ['Deposit.get', 'WellOperation.get'],
|
||||||
|
fact: ['Deposit.get', 'WellOperation.get'],
|
||||||
|
drillProcessFlow: ['Deposit.get', 'DrillFlowChart.get'],
|
||||||
|
params: ['Deposit.get', 'WellOperation.get', 'DrillParams.get'],
|
||||||
|
composite: {
|
||||||
|
wells: ['Deposit.get', 'OperationStat.get', 'WellComposite.get'],
|
||||||
|
sections: ['Deposit.get', 'OperationStat.get', 'WellComposite.get', 'DrillParams.get'],
|
||||||
|
}
|
||||||
|
},
|
||||||
|
telemetryAnalysis: {
|
||||||
|
depthToDay: ['Deposit.get', 'TelemetryAnalytics.get'],
|
||||||
|
depthToInterval: ['Deposit.get', 'TelemetryAnalytics.get'],
|
||||||
|
operationsSummary: ['Deposit.get', 'TelemetryAnalytics.get'],
|
||||||
|
operationsToInterval: ['Deposit.get'], // Не имеет собственных требований
|
||||||
|
},
|
||||||
|
measure: ['Deposit.get', 'Measure.get'],
|
||||||
|
drillingProgram: ['Deposit.get', 'Well.get', 'DrillingProgram.get'],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Страницы Login и Register используют Auth.edit, однако не учитываются, так как считается, что их использует аноним
|
||||||
|
// Для всех страниц, на которых в PageHeader используется WellTreeSelector небходим доступ к Deposit.get
|
||||||
|
Loading…
Reference in New Issue
Block a user