Compare commits
28 Commits
dev
...
feature/ne
Author | SHA1 | Date | |
---|---|---|---|
|
609cd2cf45 | ||
|
a6fa931b04 | ||
|
ea44e8adc2 | ||
|
6a81db11b6 | ||
|
842e1773b4 | ||
|
cf87354cd1 | ||
|
b1b4283bc5 | ||
|
5b4ba6c6f2 | ||
|
b7ceee2fca | ||
|
1c56368435 | ||
|
0f2251b8d0 | ||
|
e9cc5f14e7 | ||
|
1ba9ce59db | ||
|
85e12263cd | ||
|
c834db3048 | ||
|
f4749094b1 | ||
|
e417f93a61 | ||
|
31b97855e8 | ||
|
1e31f2f2c1 | ||
|
cbbe992966 | ||
|
ad59f4b840 | ||
|
e3ecf7f8f3 | ||
|
1885a48d06 | ||
|
7a242ab59c | ||
|
dde32f737a | ||
|
b3954c1091 | ||
|
a01d0fb095 | ||
|
92526907fa |
@ -24,7 +24,7 @@
|
|||||||
"dev": "webpack-dev-server --env=\"ENV=dev\" --open --hot",
|
"dev": "webpack-dev-server --env=\"ENV=dev\" --open --hot",
|
||||||
|
|
||||||
"oul": "npx openapi -i http://127.0.0.1:5000/swagger/v1/swagger.json -o src/services/api",
|
"oul": "npx openapi -i http://127.0.0.1:5000/swagger/v1/swagger.json -o src/services/api",
|
||||||
"oud": "npx openapi -i http://192.168.1.10:5000/swagger/v1/swagger.json -o src/services/api",
|
"oud": "npx openapi -i http://192.168.0.10:5000/swagger/v1/swagger.json -o src/services/api",
|
||||||
"oug": "npx openapi -i https://cloud.digitaldrilling.ru/swagger/v1/swagger.json -o src/services/api",
|
"oug": "npx openapi -i https://cloud.digitaldrilling.ru/swagger/v1/swagger.json -o src/services/api",
|
||||||
"oug_dev": "npx openapi -i http://46.146.207.184/swagger/v1/swagger.json -o src/services/api"
|
"oug_dev": "npx openapi -i http://46.146.207.184/swagger/v1/swagger.json -o src/services/api"
|
||||||
},
|
},
|
||||||
|
@ -7,7 +7,7 @@ import { downloadFile } from './factory'
|
|||||||
|
|
||||||
import { getLinkToFile } from '@pages/FileDownload'
|
import { getLinkToFile } from '@pages/FileDownload'
|
||||||
|
|
||||||
import '@styles/index.css'
|
import '@styles/components/download_link.less'
|
||||||
|
|
||||||
export type DownloadLinkProps = LinkProps & {
|
export type DownloadLinkProps = LinkProps & {
|
||||||
file?: FileInfoDto
|
file?: FileInfoDto
|
||||||
|
@ -1,4 +1,6 @@
|
|||||||
import React, { HTMLAttributes, memo } from 'react'
|
import { HTMLAttributes, memo } from 'react'
|
||||||
|
|
||||||
|
import '@styles/components/grid.less'
|
||||||
|
|
||||||
export type ComponentProps = HTMLAttributes<HTMLDivElement>
|
export type ComponentProps = HTMLAttributes<HTMLDivElement>
|
||||||
|
|
||||||
@ -36,7 +38,7 @@ export const GridItem = memo<GridItemProps>(({ children, row, col, rowSpan, colS
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={`asb-grid-item ${className || ''}`} style={gridItemStyle} {...other}>
|
<div className={`dd-grid-item ${className || ''}`} style={gridItemStyle} {...other}>
|
||||||
{children}
|
{children}
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
@ -55,6 +55,8 @@ const _LayoutPortal = memo(() => {
|
|||||||
|
|
||||||
const setLayoutProps = useCallback((props: LayoutPortalProps) => setProps({ ...defaultProps, ...props}), [])
|
const setLayoutProps = useCallback((props: LayoutPortalProps) => setProps({ ...defaultProps, ...props}), [])
|
||||||
|
|
||||||
|
const layoutPropsValue = useMemo(() => ({ setLayoutProps, openWellTreeSelector: () => setWellsTreeOpen(true) }), [setLayoutProps])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (typeof showSelector === 'boolean')
|
if (typeof showSelector === 'boolean')
|
||||||
setWellsTreeOpen(showSelector)
|
setWellsTreeOpen(showSelector)
|
||||||
@ -72,7 +74,7 @@ const _LayoutPortal = memo(() => {
|
|||||||
return (
|
return (
|
||||||
<Layout className={`page-layout ${isAdmin ? 'page-layout-admin' : ''}`}>
|
<Layout className={`page-layout ${isAdmin ? 'page-layout-admin' : ''}`}>
|
||||||
{(sider || siderProps) && (
|
{(sider || siderProps) && (
|
||||||
<Sider {...siderProps} collapsedWidth={50} collapsed={menuCollapsed} trigger={null} collapsible className={`menu-sider ${siderProps?.className || ''}`}>
|
<Sider {...siderProps} collapsedWidth={50} collapsed={menuCollapsed} trigger={null} collapsible className={`dd-menu-sider ${siderProps?.className || ''}`}>
|
||||||
<div className={'sider-content'}>
|
<div className={'sider-content'}>
|
||||||
<button className={'sider-toogle'} onClick={() => setMenuCollapsed((prev) => !prev)}>
|
<button className={'sider-toogle'} onClick={() => setMenuCollapsed((prev) => !prev)}>
|
||||||
<Logo onlyIcon={menuCollapsed} />
|
<Logo onlyIcon={menuCollapsed} />
|
||||||
@ -123,7 +125,7 @@ const _LayoutPortal = memo(() => {
|
|||||||
{topRightBlock}
|
{topRightBlock}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
<LayoutPropsContext.Provider value={setLayoutProps}>
|
<LayoutPropsContext.Provider value={layoutPropsValue}>
|
||||||
<Suspense fallback={fallback ?? <SuspenseFallback style={{ minHeight: '100%' }} />}>
|
<Suspense fallback={fallback ?? <SuspenseFallback style={{ minHeight: '100%' }} />}>
|
||||||
<Outlet />
|
<Outlet />
|
||||||
</Suspense>
|
</Suspense>
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
import { memo, ReactNode, useCallback, useEffect, useState } from 'react'
|
import { memo, ReactNode, useCallback, useEffect, useState } from 'react'
|
||||||
import { DefaultOptionType, SelectValue } from 'antd/lib/select'
|
import { DefaultOptionType, SelectValue } from 'antd/lib/select'
|
||||||
import { Select, SelectProps, Tag } from 'antd'
|
import { Select, SelectProps } from 'antd'
|
||||||
|
|
||||||
|
import TagList from '@components/TagList'
|
||||||
import type { OmitExtends } from '@utils/types'
|
import type { OmitExtends } from '@utils/types'
|
||||||
|
|
||||||
import { ColumnProps, DataType, makeColumn } from '.'
|
import { ColumnProps, DataType, makeColumn } from '.'
|
||||||
@ -67,7 +68,9 @@ export const makeTagColumn = <T extends DataType>(
|
|||||||
return makeColumn(title, dataIndex, {
|
return makeColumn(title, dataIndex, {
|
||||||
editable: true,
|
editable: true,
|
||||||
...other,
|
...other,
|
||||||
render: (item: T[] | undefined, dataset, index) => item?.map((elm: T) => <Tag key={elm[label_key]} color={'blue'}>{other?.render?.(elm, dataset, index) ?? elm[label_key]}</Tag>) ?? '-',
|
render: (item: T[] | undefined, dataset, index) => (
|
||||||
|
<TagList items={item} render={(elm) => other?.render?.(elm, dataset, index) ?? elm[label_key]} />
|
||||||
|
),
|
||||||
input: <InputComponent {...tagOther} options={options} />,
|
input: <InputComponent {...tagOther} options={options} />,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,7 @@ import TableSettingsChanger from './TableSettingsChanger'
|
|||||||
import type { OmitExtends } from '@utils/types'
|
import type { OmitExtends } from '@utils/types'
|
||||||
import { applyTableSettings, getTableSettings, setTableSettings, TableColumnSettings, TableSettings } from '@utils'
|
import { applyTableSettings, getTableSettings, setTableSettings, TableColumnSettings, TableSettings } from '@utils'
|
||||||
|
|
||||||
import '@styles/index.css'
|
import '@styles/components/table.less'
|
||||||
|
|
||||||
export type BaseTableColumn<T> = ColumnGroupType<T> | ColumnType<T>
|
export type BaseTableColumn<T> = ColumnGroupType<T> | ColumnType<T>
|
||||||
export type TableColumn<T> = OmitExtends<BaseTableColumn<T>, TableColumnSettings>
|
export type TableColumn<T> = OmitExtends<BaseTableColumn<T>, TableColumnSettings>
|
||||||
|
25
src/components/TagList.tsx
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
import { memo, ReactNode } from 'react'
|
||||||
|
import { Tag } from 'antd'
|
||||||
|
|
||||||
|
import '@styles/components/tag_list.less'
|
||||||
|
|
||||||
|
export type TagListProps<T> = {
|
||||||
|
items?: T[] | null
|
||||||
|
render: (item: T) => ReactNode
|
||||||
|
}
|
||||||
|
|
||||||
|
const _TagList = <T,>({ items, render }: TagListProps<T>) => {
|
||||||
|
if (!items || items.length <= 0) return <>-</>
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={'dd-tag-list'}>
|
||||||
|
{items.map((item, i) => (
|
||||||
|
<Tag key={`${i}`}>{render(item)}</Tag>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export const TagList = memo(_TagList) as typeof _TagList
|
||||||
|
|
||||||
|
export default TagList
|
@ -2,7 +2,7 @@ import { Button, Checkbox, Form, FormItemProps, Input, InputNumber, Select, Tool
|
|||||||
import { memo, useCallback, useEffect, useMemo } from 'react'
|
import { memo, useCallback, useEffect, useMemo } from 'react'
|
||||||
|
|
||||||
import { BaseDataType, MinMax } from '@components/d3/types'
|
import { BaseDataType, MinMax } from '@components/d3/types'
|
||||||
import { ColorPicker, Color } from '@components/ColorPicker'
|
import { ColorPicker, Color } from '@components/input/ColorPicker'
|
||||||
|
|
||||||
import { ExtendedChartDataset } from './D3MonitoringCharts'
|
import { ExtendedChartDataset } from './D3MonitoringCharts'
|
||||||
|
|
||||||
|
@ -545,7 +545,7 @@ const _D3MonitoringCharts = <DataType extends Record<string, unknown>>({
|
|||||||
<g ref={setChartAreaRef} className={'chart-area'} transform={`translate(${offset.left}, ${sizes.chartsTop})`}>
|
<g ref={setChartAreaRef} className={'chart-area'} transform={`translate(${offset.left}, ${sizes.chartsTop})`}>
|
||||||
<rect width={sizes.inlineWidth} height={sizes.chartsHeight} fill={backgroundColor} />
|
<rect width={sizes.inlineWidth} height={sizes.chartsHeight} fill={backgroundColor} />
|
||||||
</g>
|
</g>
|
||||||
<g stroke={'black'}>
|
<g stroke={'white'}>
|
||||||
{d3.range(1, groups.length).map((i) => {
|
{d3.range(1, groups.length).map((i) => {
|
||||||
const x = offset.left + (sizes.groupWidth + spaceBetweenGroups) * i - spaceBetweenGroups / 2
|
const x = offset.left + (sizes.groupWidth + spaceBetweenGroups) * i - spaceBetweenGroups / 2
|
||||||
return <line key={`${i}`} x1={x} x2={x} y1={sizes.chartsTop} y2={offset.top + sizes.inlineHeight} />
|
return <line key={`${i}`} x1={x} x2={x} y1={sizes.chartsTop} y2={offset.top + sizes.inlineHeight} />
|
||||||
|
@ -16,10 +16,10 @@ export interface PointerIconProps {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const defaultColors: PointerIconColors = {
|
const defaultColors: PointerIconColors = {
|
||||||
online: 'red',
|
online: '#C32828',
|
||||||
active: 'black',
|
active: 'white',
|
||||||
inactive: 'gray',
|
inactive: '#A7A7A7',
|
||||||
unknown: 'gray',
|
unknown: '#7B7B7B',
|
||||||
}
|
}
|
||||||
|
|
||||||
const defaultProps: PointerIconProps = {
|
const defaultProps: PointerIconProps = {
|
||||||
|
@ -16,10 +16,10 @@ export type WellIconProps = React.SVGProps<SVGSVGElement> & {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const defaultColors: WellIconColors = {
|
const defaultColors: WellIconColors = {
|
||||||
online: 'red',
|
online: 'white',
|
||||||
active: 'black',
|
active: 'white',
|
||||||
inactive: 'gray',
|
inactive: '#A7A7A7',
|
||||||
unknown: 'gray',
|
unknown: '#7B7B7B',
|
||||||
}
|
}
|
||||||
|
|
||||||
const defaultProps: WellIconProps = {
|
const defaultProps: WellIconProps = {
|
||||||
@ -34,7 +34,7 @@ export const WellIcon = React.memo(({ width, height, state, online, colors, ...o
|
|||||||
return (
|
return (
|
||||||
<svg
|
<svg
|
||||||
version={'1.1'}
|
version={'1.1'}
|
||||||
viewBox={'12 .64 9.2 9.2'}
|
viewBox={'12 0 9 9'}
|
||||||
xmlns={'http://www.w3.org/2000/svg'}
|
xmlns={'http://www.w3.org/2000/svg'}
|
||||||
xmlnsXlink={'http://www.w3.org/1999/xlink'}
|
xmlnsXlink={'http://www.w3.org/1999/xlink'}
|
||||||
|
|
||||||
@ -46,17 +46,15 @@ export const WellIcon = React.memo(({ width, height, state, online, colors, ...o
|
|||||||
|
|
||||||
width={width}
|
width={width}
|
||||||
height={height}
|
height={height}
|
||||||
color={colors[state ?? 'unknown']}
|
color={colors[state || 'unknown']}
|
||||||
{...other}
|
{...other}
|
||||||
>
|
>
|
||||||
<g>
|
<path d={'m12 7.9 2.6-6.6v-1.3h1.3v1.3l2.6 6.6'}/>
|
||||||
<path d={'m12 7.9 2.6-6.6v-1.3h1.3v1.3l2.6 6.6'}/>
|
<path d={'m12 6.4h6.6v-0.53h-6.6z'} fill={'currentColor'}/>
|
||||||
<path d={'m12 6.4h6.6v-0.53h-6.6z'} fill={'currentColor'}/>
|
<path d={'m14 0.79v0.53h2.9v-0.53z'} fill={'currentColor'}/>
|
||||||
<path d={'m14 0.79v0.53h2.9v-0.53z'} fill={'currentColor'}/>
|
<path d={'m12 7.9 5-4-2.4-2.6h1.3l-2.4 2.6 5 4'}/>
|
||||||
<path d={'m12 7.9 5-4-2.4-2.6h1.3l-2.4 2.6 5 4'}/>
|
|
||||||
</g>
|
|
||||||
{online && ( // Полоски, показывающие наличие свежей телеметрии
|
{online && ( // Полоски, показывающие наличие свежей телеметрии
|
||||||
<g stroke={colors.online}>
|
<g stroke={colors.online} strokeWidth={.4}>
|
||||||
<path d={'m18.4 0.0662a2 2 0 0 1 0.141 1.7 2 2 0 0 1-1.22 1.19'} />
|
<path d={'m18.4 0.0662a2 2 0 0 1 0.141 1.7 2 2 0 0 1-1.22 1.19'} />
|
||||||
<path d={'m19.5 0.0402a3 3 0 0 1-1.79 3.85'} />
|
<path d={'m19.5 0.0402a3 3 0 0 1-1.79 3.85'} />
|
||||||
<path d={'m20.5 0.031a4 4 0 0 1-2.5 4.79'} />
|
<path d={'m20.5 0.031a4 4 0 0 1-2.5 4.79'} />
|
||||||
|
@ -2,7 +2,7 @@ import { memo, useCallback, useEffect, useMemo, useState } from 'react'
|
|||||||
import { Input, Popover, Slider } from 'antd'
|
import { Input, Popover, Slider } from 'antd'
|
||||||
import { CopyOutlined } from '@ant-design/icons'
|
import { CopyOutlined } from '@ant-design/icons'
|
||||||
|
|
||||||
import { copyToClipboard } from './factory'
|
import { copyToClipboard } from '@components/factory'
|
||||||
|
|
||||||
import '@styles/components/color_picker.less'
|
import '@styles/components/color_picker.less'
|
||||||
|
|
@ -7,10 +7,10 @@ import { WellIcon, WellIconState } from '@components/icons'
|
|||||||
import { DepositDto, WellDto } from '@api'
|
import { DepositDto, WellDto } from '@api'
|
||||||
import { isRawDate } from '@utils'
|
import { isRawDate } from '@utils'
|
||||||
|
|
||||||
import { ReactComponent as DepositIcon } from '@images/DepositIcon.svg'
|
import { ReactComponent as DepositIcon } from '@images/components/well_tree_selector/DepositIcon.svg'
|
||||||
import { ReactComponent as ClusterIcon } from '@images/ClusterIcon.svg'
|
import { ReactComponent as ClusterIcon } from '@images/components/well_tree_selector/ClusterIcon.svg'
|
||||||
|
|
||||||
import '@styles/components/well_tree_select.css'
|
import '@styles/components/well_tree_select.less'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Для поиска в URL текущего раздела по шаблону `/{type}/{id}`
|
* Для поиска в URL текущего раздела по шаблону `/{type}/{id}`
|
||||||
@ -175,6 +175,7 @@ export const WellTreeSelector = memo<WellTreeSelectorProps>(({ expand, current,
|
|||||||
<Drawer open={open} mask={false} onClose={onClose} title={'Список скважин'}>
|
<Drawer open={open} mask={false} onClose={onClose} title={'Список скважин'}>
|
||||||
<Tree
|
<Tree
|
||||||
{...other}
|
{...other}
|
||||||
|
className={'well-tree-selector'}
|
||||||
showIcon
|
showIcon
|
||||||
selectedKeys={selected}
|
selectedKeys={selected}
|
||||||
treeData={wellsTree}
|
treeData={wellsTree}
|
||||||
|
@ -1,9 +1,10 @@
|
|||||||
import { memo } from 'react'
|
import { memo } from 'react'
|
||||||
import { Tag, Tooltip } from 'antd'
|
import { Tooltip } from 'antd'
|
||||||
|
|
||||||
import { UserRoleDto } from '@api'
|
import { UserRoleDto } from '@api'
|
||||||
import { Grid, GridItem } from '@components/Grid'
|
import { Grid, GridItem } from '@components/Grid'
|
||||||
import PermissionView from './PermissionView'
|
import PermissionView from './PermissionView'
|
||||||
|
import TagList from '../TagList'
|
||||||
|
|
||||||
export type RoleViewProps = {
|
export type RoleViewProps = {
|
||||||
role?: UserRoleDto
|
role?: UserRoleDto
|
||||||
@ -26,12 +27,8 @@ export const RoleView = memo<RoleViewProps>(({ role }) => {
|
|||||||
|
|
||||||
<GridItem row={2} col={1}>Включённые роли:</GridItem>
|
<GridItem row={2} col={1}>Включённые роли:</GridItem>
|
||||||
{hasIncludedRoles ? (
|
{hasIncludedRoles ? (
|
||||||
<GridItem row={3} col={1} colSpan={3}>
|
<GridItem row={3} col={1} colSpan={3} style={{ display: 'flex', flexWrap: 'wrap', gap: 5 }}>
|
||||||
{role.roles?.map((role, i) => (
|
<TagList items={role.roles} render={(role) => <RoleView role={role} />} />
|
||||||
<Tag key={i} color={'blue'}>
|
|
||||||
<RoleView role={role} />
|
|
||||||
</Tag>
|
|
||||||
))}
|
|
||||||
</GridItem>
|
</GridItem>
|
||||||
) : (
|
) : (
|
||||||
<GridItem row={2} col={2}>Отсутствуют</GridItem>
|
<GridItem row={2} col={2}>Отсутствуют</GridItem>
|
||||||
@ -42,12 +39,8 @@ export const RoleView = memo<RoleViewProps>(({ role }) => {
|
|||||||
|
|
||||||
<GridItem row={4 + hasIncludedRoles} col={1}>Разрешения:</GridItem>
|
<GridItem row={4 + hasIncludedRoles} col={1}>Разрешения:</GridItem>
|
||||||
{hasPermissions ? (
|
{hasPermissions ? (
|
||||||
<GridItem row={5 + hasIncludedRoles} col={1} colSpan={3}>
|
<GridItem row={5 + hasIncludedRoles} col={1} colSpan={3} style={{ display: 'flex', flexWrap: 'wrap', gap: 5 }}>
|
||||||
{role.permissions?.map((permission, i) => (
|
<TagList items={role.permissions} render={(permission) => <PermissionView info={permission} />} />
|
||||||
<Tag key={i} color={'blue'}>
|
|
||||||
<PermissionView info={permission} />
|
|
||||||
</Tag>
|
|
||||||
))}
|
|
||||||
</GridItem>
|
</GridItem>
|
||||||
) : (
|
) : (
|
||||||
<GridItem row={4 + hasIncludedRoles} col={2}>Отсутствуют</GridItem>
|
<GridItem row={4 + hasIncludedRoles} col={2}>Отсутствуют</GridItem>
|
||||||
|
@ -28,9 +28,9 @@ export const defaultSettings: WidgetSettings = {
|
|||||||
label: 'Виджет',
|
label: 'Виджет',
|
||||||
formatter: defaultFormatter,
|
formatter: defaultFormatter,
|
||||||
|
|
||||||
labelColor: '#000000',
|
labelColor: '#FFFFFF',
|
||||||
valueColor: '#000000',
|
valueColor: '#FFFFFF',
|
||||||
backgroundColor: '#f6f6f6',
|
backgroundColor: '#2F2F2F',
|
||||||
unitColor: '#a0a0a0',
|
unitColor: '#a0a0a0',
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,22 +2,30 @@ import { createContext, useContext, useEffect } from 'react'
|
|||||||
|
|
||||||
import { LayoutPortalProps } from '@components/LayoutPortal'
|
import { LayoutPortalProps } from '@components/LayoutPortal'
|
||||||
|
|
||||||
|
export type LayoutPropsContext = {
|
||||||
|
setLayoutProps: (props: LayoutPortalProps) => void
|
||||||
|
openWellTreeSelector: () => void
|
||||||
|
}
|
||||||
|
|
||||||
/** Контекст метода редактирования параметров заголовка и меню */
|
/** Контекст метода редактирования параметров заголовка и меню */
|
||||||
export const LayoutPropsContext = createContext<(props: LayoutPortalProps) => void>(() => {})
|
export const LayoutPropsContext = createContext<LayoutPropsContext>({
|
||||||
|
setLayoutProps: () => {},
|
||||||
|
openWellTreeSelector: () => {},
|
||||||
|
})
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Получить метод задания параметров заголовка и меню
|
* Получить метод задания параметров заголовка и меню
|
||||||
*
|
*
|
||||||
* @returns Получить метод задания параметров заголовка и меню
|
* @returns Получить метод задания параметров заголовка и меню
|
||||||
*/
|
*/
|
||||||
export const useLayoutProps = (props?: LayoutPortalProps) => {
|
export const useLayoutProps = (props?: LayoutPortalProps): LayoutPropsContext => {
|
||||||
const setLayoutProps = useContext(LayoutPropsContext)
|
const { setLayoutProps, ...other } = useContext(LayoutPropsContext)
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (props) setLayoutProps(props)
|
if (props) setLayoutProps(props)
|
||||||
}, [setLayoutProps, props])
|
}, [setLayoutProps, props])
|
||||||
|
|
||||||
return setLayoutProps
|
return { setLayoutProps, ...other }
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Контекст для блока справа от крошек на страницах скважин и админки */
|
/** Контекст для блока справа от крошек на страницах скважин и админки */
|
||||||
|
Before Width: | Height: | Size: 974 B |
Before Width: | Height: | Size: 1.2 KiB |
Before Width: | Height: | Size: 1.5 KiB |
Before Width: | Height: | Size: 1.9 KiB |
0
src/images/ClusterIcon.svg → src/images/components/well_tree_selector/ClusterIcon.svg
Executable file → Normal file
Before Width: | Height: | Size: 514 B After Width: | Height: | Size: 514 B |
0
src/images/DepositIcon.svg → src/images/components/well_tree_selector/DepositIcon.svg
Executable file → Normal file
Before Width: | Height: | Size: 729 B After Width: | Height: | Size: 729 B |
Before Width: | Height: | Size: 8.4 KiB |
Before Width: | Height: | Size: 965 B |
Before Width: | Height: | Size: 4.7 KiB |
49
src/images/pages/deposit/ClusterMapIcon.tsx
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
import { memo, useMemo } from 'react'
|
||||||
|
|
||||||
|
import '@styles/components/icons/cluster-map-icon.less'
|
||||||
|
|
||||||
|
export type ClusterMapIconProps = {
|
||||||
|
width?: number | string
|
||||||
|
height?: number | string
|
||||||
|
count?: number
|
||||||
|
showBadge?: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
const defaultWidth = 65
|
||||||
|
const defaultHeight = 73
|
||||||
|
const ratio = defaultWidth / defaultHeight
|
||||||
|
|
||||||
|
export const ClusterMapIcon = memo<ClusterMapIconProps>(({ width, height, count, showBadge }) => {
|
||||||
|
const { w, h } = useMemo(() => {
|
||||||
|
const hasW = typeof width !== 'undefined' && width !== null
|
||||||
|
const hasH = typeof height !== 'undefined' && height !== null
|
||||||
|
const out: Record<string, string | number> = { w: defaultWidth, h: defaultHeight }
|
||||||
|
if (hasW) out.w = width
|
||||||
|
else if (typeof height === 'number') out.w = height / ratio
|
||||||
|
if (hasH) out.h = height
|
||||||
|
else if (typeof width === 'number') out.h = width * ratio
|
||||||
|
return out
|
||||||
|
}, [width, height])
|
||||||
|
|
||||||
|
return (
|
||||||
|
<svg className={'dd-cluster-map-icon'} overflow={'visible'} width={w} height={h} viewBox={'0 0 65 73'} xmlns={'http://www.w3.org/2000/svg'} fill={'white'}>
|
||||||
|
<path d={'M6 51.0897V21.9103L32.5 6.2024L59 21.9103V51.0897L32.5 66.7976L6 51.0897Z'} />
|
||||||
|
<g fill-rule={'evenodd'} clip-rule={'evenodd'}>
|
||||||
|
<path d={'M6 21.9103V51.0897L32.5 66.7976L59 51.0897V21.9103L32.5 6.2024L6 21.9103ZM59.6088 50.7288L59.6073 50.7297L59.6088 50.7288ZM5.39116 22.2712L5.39262 22.2703L5.39116 22.2712ZM0 51.7966V21.2034C0 19.5226 0.88635 17.9666 2.33174 17.1098L30.0756 0.664577C31.5705 -0.221525 33.4295 -0.221526 34.9244 0.664576L62.6683 17.1098C64.1137 17.9666 65 19.5227 65 21.2034V51.7966C65 53.4774 64.1137 55.0334 62.6683 55.8902L34.9244 72.3354C33.4295 73.2215 31.5705 73.2215 30.0756 72.3354L2.33174 55.8902C0.88635 55.0334 0 53.4774 0 51.7966Z'} />
|
||||||
|
<g fill={'#306AFD'}>
|
||||||
|
<path d={'M12 26.8557V46.1444C12 47.2041 12.5591 48.1852 13.4708 48.7254L30.9708 59.094C31.9137 59.6527 33.0863 59.6527 34.0292 59.094L51.5292 48.7254C52.4409 48.1852 53 47.2041 53 46.1444V26.8557C53 25.7959 52.4409 24.8148 51.5292 24.2747L34.0292 13.9061C33.0863 13.3474 31.9137 13.3474 30.9708 13.9061L13.4708 24.2747C12.5591 24.8148 12 25.7959 12 26.8557Z'} />
|
||||||
|
<path d={'M18 28.5652V44.4348L32.5 53.026L47 44.4348V28.5652L32.5 19.9741L18 28.5652ZM34.0292 19.0681C34.0286 19.0684 34.028 19.0688 34.0274 19.0691L34.0292 19.0681ZM12 46.1444V26.8557C12 25.7959 12.5591 24.8148 13.4708 24.2747L30.9708 13.9061C31.9137 13.3474 33.0863 13.3474 34.0292 13.9061L51.5292 24.2747C52.4409 24.8148 53 25.7959 53 26.8557V46.1444C53 47.2041 52.4409 48.1852 51.5292 48.7254L34.0292 59.094C33.0863 59.6527 31.9137 59.6527 30.9708 59.094L13.4708 48.7254C12.5591 48.1852 12 47.2041 12 46.1444Z'} />
|
||||||
|
<path d={'M6 21.9103V51.0897L32.5 66.7976L59 51.0897V21.9103L32.5 6.2024L6 21.9103ZM59.6088 50.7288L59.6073 50.7297L59.6088 50.7288ZM5.39116 22.2712L5.39262 22.2703L5.39116 22.2712ZM0 51.7966V21.2034C0 19.5226 0.88635 17.9666 2.33174 17.1098L30.0756 0.664577C31.5705 -0.221525 33.4295 -0.221526 34.9244 0.664576L62.6683 17.1098C64.1137 17.9666 65 19.5227 65 21.2034V51.7966C65 53.4774 64.1137 55.0334 62.6683 55.8902L34.9244 72.3354C33.4295 73.2215 31.5705 73.2215 30.0756 72.3354L2.33174 55.8902C0.88635 55.0334 0 53.4774 0 51.7966Z'} />
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
{typeof count === 'number' && (
|
||||||
|
<text className={'dd-cluster-map-icon-count'} textAnchor={'middle'} dominantBaseline={'middle'} style={{ fontSize: 22 }} x={'50%'} y={'50%'}>{count}</text>
|
||||||
|
)}
|
||||||
|
{showBadge && (
|
||||||
|
<circle className={'dd-cluster-map-icon-badge'} cx={59} cy={20} r={10.5} fill={'#FF2323'} stroke={'white'} stroke-width={'3'} />
|
||||||
|
)}
|
||||||
|
</svg>
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
export default ClusterMapIcon
|
3
src/images/pages/deposit/MapPointer.svg
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
<svg width="16" height="20" viewBox="0 0 16 20" fill="currentColor" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M8.00016 0.833252C3.70375 0.833252 0.208496 4.3285 0.208496 8.62492C0.208496 10.4748 0.872621 12.27 2.08445 13.6886C2.22287 13.8458 5.4885 17.5565 6.57933 18.5964C6.97762 18.9764 7.48866 19.1666 8.00016 19.1666C8.51166 19.1666 9.0227 18.9764 9.42145 18.5964C10.6897 17.3869 13.7866 13.8366 13.9223 13.6808C15.1277 12.27 15.7918 10.4748 15.7918 8.62492C15.7918 4.3285 12.2966 0.833252 8.00016 0.833252ZM8.00016 10.9166C6.7347 10.9166 5.7085 9.89038 5.7085 8.62492C5.7085 7.35946 6.7347 6.33325 8.00016 6.33325C9.26562 6.33325 10.2918 7.35946 10.2918 8.62492C10.2918 9.89038 9.26562 10.9166 8.00016 10.9166Z"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 729 B |
10
src/images/pages/deposit/WellMapIcon.svg
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
<svg width="44" height="49" viewBox="0 0 44 49" fill="white" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M39.9385 12.0881V21.7588L30.1374 33.5092L22 43.4487L13.8626 33.5092L4.06154 21.7588V12.0881L12.3728 4.06154H31.6272L39.9385 12.0881Z"/>
|
||||||
|
<g fill-rule="evenodd" clip-rule="evenodd">
|
||||||
|
<path d="M13.8626 33.5092L22 43.4487L30.1374 33.5092L39.9385 21.7588V12.0881L31.6272 4.06154H12.3728L4.06154 12.0881V21.7588L13.8626 33.5092ZM33.2683 36.0965L24.4356 46.8852C23.1516 48.4536 20.8484 48.4536 19.5644 46.8852L10.7317 36.0965L0.803482 24.1936C0.285669 23.5728 0 22.7739 0 21.9467V11.8619C0 10.9077 0.379815 9.99739 1.04667 9.35338L9.80913 0.890989C10.4026 0.317847 11.1777 0 11.982 0H32.018C32.8223 0 33.5974 0.317846 34.1909 0.890988L42.9533 9.35337C43.6202 9.99739 44 10.9077 44 11.8619V21.9467C44 22.7739 43.7143 23.5728 43.1965 24.1936L33.2683 36.0965Z"/>
|
||||||
|
<g fill="#306AFD">
|
||||||
|
<path d="M8.12354 14.532V20.5563C8.12354 21.0505 8.30373 21.5277 8.63035 21.8985L14.8928 29.0088L20.4642 35.4536C21.2741 36.3905 22.7268 36.3905 23.5368 35.4536L29.1081 29.0088L35.3706 21.8985C35.6972 21.5277 35.8774 21.0505 35.8774 20.5563V14.532C35.8774 13.962 35.6378 13.4182 35.2172 13.0335L29.6901 7.97841C29.3157 7.63604 28.8268 7.44617 28.3195 7.44617H15.6814C15.1741 7.44617 14.6852 7.63604 14.3108 7.97841L8.78374 13.0335C8.36311 13.4182 8.12354 13.962 8.12354 14.532Z"/>
|
||||||
|
<path d="M13.8626 33.5092L22 43.4487L30.1374 33.5092L39.9385 21.7588V12.0881L31.6272 4.06154H12.3728L4.06154 12.0881V21.7588L13.8626 33.5092ZM33.2683 36.0965L24.4356 46.8852C23.1516 48.4536 20.8484 48.4536 19.5644 46.8852L10.7317 36.0965L0.803482 24.1936C0.285669 23.5728 0 22.7739 0 21.9467V11.8619C0 10.9077 0.379815 9.99739 1.04667 9.35338L9.80913 0.890989C10.4026 0.317847 11.1777 0 11.982 0H32.018C32.8223 0 33.5974 0.317846 34.1909 0.890988L42.9533 9.35337C43.6202 9.99739 44 10.9077 44 11.8619V21.9467C44 22.7739 43.7143 23.5728 43.1965 24.1936L33.2683 36.0965Z"/>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 2.0 KiB |
@ -0,0 +1,6 @@
|
|||||||
|
<svg width="28" height="28" viewBox="0 0 28 28" fill="currentColor" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M0.669171 5.0337e-06C0.299013 -0.00141788 -0.00141788 0.299013 5.0337e-06 0.669171V7.7807H1.33834V1.33834H12.8917V7.7807H14.2235V0.669171C14.2249 0.299013 13.9245 -0.00141778 13.5543 5.0337e-06H0.669171Z" />
|
||||||
|
<path d="M15.7647 7.78092C15.5905 7.78539 15.4249 7.85795 15.3035 7.98303C15.1821 8.10811 15.1145 8.27577 15.1152 8.45008V28.0002H16.447V11.2645L20.5145 19.4126C20.5679 19.5207 20.6496 19.6123 20.7509 19.6777C20.8522 19.743 20.9694 19.7796 21.0899 19.7837C21.2104 19.7877 21.3297 19.759 21.4352 19.7006C21.5407 19.6422 21.6283 19.5562 21.6888 19.452L26.6682 10.9103V28.0002H28V8.45008C27.9988 8.30448 27.9499 8.16328 27.8609 8.04806C27.7719 7.93283 27.6476 7.84992 27.507 7.81198C27.3665 7.77405 27.2173 7.78319 27.0824 7.83799C26.9476 7.8928 26.8343 7.99027 26.76 8.1155L21.1574 17.7134L16.3748 8.1483C16.3183 8.03564 16.231 7.94133 16.123 7.8763C16.015 7.81127 15.8908 7.7782 15.7647 7.78092Z" />
|
||||||
|
<path d="M6.22588 5.77979V7.55767L1.30554 9.61109C1.18522 9.66228 1.08261 9.74772 1.01048 9.85679C0.938359 9.96586 0.899902 10.0937 0.899902 10.2245C0.899902 10.3552 0.938359 10.4831 1.01048 10.5922C1.08261 10.7013 1.18522 10.7867 1.30554 10.8379L10.4902 14.6692L1.30554 18.5005C1.18522 18.5517 1.08261 18.6371 1.01048 18.7462C0.938359 18.8553 0.899902 18.9831 0.899902 19.1139C0.899902 19.2447 0.938359 19.3725 1.01048 19.4816C1.08261 19.5907 1.18522 19.6761 1.30554 19.7273L10.4967 23.5586L6.63919 25.1659C6.51794 25.2157 6.41407 25.3001 6.34056 25.4087C6.26705 25.5172 6.22716 25.645 6.22588 25.776V28H7.55765V26.2221L12.4845 24.1687C12.6049 24.1175 12.7075 24.0321 12.7796 23.923C12.8517 23.8139 12.8902 23.6861 12.8902 23.5553C12.8902 23.4246 12.8517 23.2967 12.7796 23.1876C12.7075 23.0786 12.6049 22.9931 12.4845 22.9419L3.29336 19.1172L12.4845 15.2859C12.6069 15.2357 12.7115 15.1502 12.7851 15.0404C12.8587 14.9306 12.898 14.8014 12.898 14.6692C12.898 14.537 12.8587 14.4078 12.7851 14.298C12.7115 14.1881 12.6069 14.1027 12.4845 14.0525L3.29336 10.2278L7.1509 8.62046C7.27195 8.56922 7.37514 8.48334 7.44751 8.37362C7.51989 8.26389 7.5582 8.13522 7.55765 8.00378V5.77979H6.22588Z" />
|
||||||
|
<path d="M6.89322 1.33838L4.22705 5.78199H9.55938L6.89322 1.33838Z" />
|
||||||
|
</svg>
|
After Width: | Height: | Size: 2.2 KiB |
8
src/images/pages/well/telemetry/monitoring/SpinIcon.svg
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
<svg width="26" height="30" viewBox="0 0 26 30" fill="currentColor" xmlns="http://www.w3.org/2000/svg" fill-rule="evenodd" clip-rule="evenodd">
|
||||||
|
<path d="M13.0014 8.64857C9.53838 8.64857 6.73109 11.4559 6.73109 14.9188C6.73109 18.3818 9.53838 21.1891 13.0014 21.1891C16.4643 21.1891 19.2716 18.3818 19.2716 14.9188C19.2716 11.4559 16.4643 8.64857 13.0014 8.64857ZM5.32568 14.9188C5.32568 10.6797 8.7622 7.24316 13.0014 7.24316C17.2405 7.24316 20.677 10.6797 20.677 14.9188C20.677 19.158 17.2405 22.5945 13.0014 22.5945C8.7622 22.5945 5.32568 19.158 5.32568 14.9188Z" />
|
||||||
|
<path d="M12.5692 26.7031L8.13672 30.0004V23.4058L12.5692 26.7031Z" />
|
||||||
|
<path d="M13.3801 26.7031L17.8125 30.0004V23.4058L13.3801 26.7031Z" />
|
||||||
|
<path d="M12.5692 3.2973L8.13672 6.59459V0L12.5692 3.2973Z" />
|
||||||
|
<path d="M13.3801 3.2973L17.8125 6.59459V0L13.3801 3.2973Z" />
|
||||||
|
<path d="M16.0016 25.5888L16.2719 26.9725C21.5818 25.5353 25.4881 20.6832 25.4881 14.9186C25.4881 9.15407 21.5818 4.3019 16.2719 2.86475V4.328C20.7955 5.72323 24.0827 9.93704 24.0827 14.9186C24.0827 19.9989 20.664 24.2806 16.0016 25.5888ZM9.73135 26.9725L10.353 25.6812C5.51204 24.4939 1.92054 20.1257 1.92054 14.9186C1.92054 9.71158 5.51204 5.34337 10.353 4.15607L9.38 2.96543C4.25001 4.51767 0.515137 9.28198 0.515137 14.9186C0.515137 20.6832 4.42143 25.5353 9.73135 26.9725Z" />
|
||||||
|
</svg>
|
After Width: | Height: | Size: 1.3 KiB |
@ -8,8 +8,7 @@ import { OpenAPI } from '@api'
|
|||||||
|
|
||||||
import App from './App'
|
import App from './App'
|
||||||
|
|
||||||
import '@styles/include/antd_theme.less'
|
import '@styles/index.less'
|
||||||
import '@styles/index.css'
|
|
||||||
|
|
||||||
// OpenAPI.BASE = 'http://localhost:3000'
|
// OpenAPI.BASE = 'http://localhost:3000'
|
||||||
// TODO: Удалить взятие из 'token' в следующем релизе, вставлено для совместимости
|
// TODO: Удалить взятие из 'token' в следующем релизе, вставлено для совместимости
|
||||||
|
@ -18,15 +18,13 @@ export const TelemetryInfo = memo(({ info, danger, ...other }) => (
|
|||||||
bordered
|
bordered
|
||||||
column={1}
|
column={1}
|
||||||
size={'small'}
|
size={'small'}
|
||||||
style={{ background: 'white' }}
|
|
||||||
className={'telemetry_merger_info'}
|
|
||||||
{...other}
|
{...other}
|
||||||
>
|
>
|
||||||
{Object.keys({ ...lables, ...info }).map(key => (
|
{Object.keys({ ...lables, ...info }).map(key => (
|
||||||
<Item
|
<Item
|
||||||
key={key}
|
key={key}
|
||||||
label={lables[key] ?? key}
|
label={lables[key] ?? key}
|
||||||
style={{ color: danger === true || danger?.includes(key) ? 'red' : 'black' }}
|
style={{ color: danger === true || danger?.includes(key) ? 'red' : '#ddd' }}
|
||||||
>{info?.[key] ?? '-'}</Item>
|
>{info?.[key] ?? '-'}</Item>
|
||||||
))}
|
))}
|
||||||
</Descriptions>
|
</Descriptions>
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { Button, Input, Tag } from 'antd'
|
import { Button, Input } from 'antd'
|
||||||
import { UserSwitchOutlined } from '@ant-design/icons'
|
import { UserSwitchOutlined } from '@ant-design/icons'
|
||||||
import { memo, useCallback, useEffect, useMemo, useState } from 'react'
|
import { memo, useCallback, useEffect, useMemo, useState } from 'react'
|
||||||
import { BehaviorSubject, debounceTime, distinctUntilChanged, filter, map } from 'rxjs'
|
import { BehaviorSubject, debounceTime, distinctUntilChanged, filter, map } from 'rxjs'
|
||||||
@ -20,6 +20,7 @@ import { makeTextOnFilter, makeTextFilters, makeArrayOnFilter } from '@utils/fil
|
|||||||
import { arrayOrDefault, withPermissions } from '@utils'
|
import { arrayOrDefault, withPermissions } from '@utils'
|
||||||
|
|
||||||
import RoleTag from './RoleTag'
|
import RoleTag from './RoleTag'
|
||||||
|
import TagList from '@components/TagList'
|
||||||
|
|
||||||
const SEARCH_TIMEOUT = 400
|
const SEARCH_TIMEOUT = 400
|
||||||
|
|
||||||
@ -107,25 +108,20 @@ const UserController = memo(() => {
|
|||||||
const filters = makeTextFilters(users, ['surname', 'name', 'patronymic', 'email'])
|
const filters = makeTextFilters(users, ['surname', 'name', 'patronymic', 'email'])
|
||||||
const roleFilters = [{ text: 'Без роли', value: null }, ...roles.map((role) => ({ text: role.caption, value: role.caption }))]
|
const roleFilters = [{ text: 'Без роли', value: null }, ...roles.map((role) => ({ text: role.caption, value: role.caption }))]
|
||||||
|
|
||||||
const rolesRender = (item) => item?.map((elm) => (
|
const rolesRender = (item) => (
|
||||||
<Tag key={elm} color={'blue'}>
|
<TagList
|
||||||
<RoleView role={roles.find((role) => role.caption === elm)} />
|
items={item}
|
||||||
</Tag>
|
render={(elm) => (
|
||||||
)) ?? '-'
|
<RoleView role={roles.find((role) => role.caption === elm)} />
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
|
||||||
setColumns([
|
setColumns([
|
||||||
makeTextColumn('Логин', 'login', null, null, null, {
|
makeTextColumn('Логин', 'login', null, null, null, {
|
||||||
formItemRules: [
|
formItemRules: [
|
||||||
{ required: true },
|
{ required: true },
|
||||||
...createLoginRules,
|
...createLoginRules,
|
||||||
// () => ({
|
|
||||||
// validator(_, value) {
|
|
||||||
// if (!value || users.findIndex((user) => user.login === value) < 0)
|
|
||||||
// return Promise.resolve()
|
|
||||||
// return Promise.reject(new Error('Логин уже занят!'))
|
|
||||||
// }
|
|
||||||
// })
|
|
||||||
// TODO: Для проверки уникальности логина необходимо исключить из выборки логин выбранного пользователя
|
|
||||||
],
|
],
|
||||||
}),
|
}),
|
||||||
makeTextColumn('Фамилия', 'surname', filters.surname, null, null, {
|
makeTextColumn('Фамилия', 'surname', filters.surname, null, null, {
|
||||||
|
@ -1,13 +1,16 @@
|
|||||||
import { memo, useMemo, useCallback } from 'react'
|
import { memo, useMemo, useCallback } from 'react'
|
||||||
import { Link, useLocation } from 'react-router-dom'
|
import { Link, useLocation } from 'react-router-dom'
|
||||||
import { Map as PigeonMap, Overlay } from 'pigeon-maps'
|
import { Map as PigeonMap, Overlay } from 'pigeon-maps'
|
||||||
import { Popover, Badge } from 'antd'
|
import { Popover, Button } from 'antd'
|
||||||
|
|
||||||
import { useDepositList } from '@asb/context'
|
import { useDepositList, useLayoutProps } from '@asb/context'
|
||||||
import { PointerIcon } from '@components/icons'
|
|
||||||
import { limitValue, withPermissions } from '@utils'
|
import { limitValue, withPermissions } from '@utils'
|
||||||
|
|
||||||
import '@styles/index.css'
|
import { ClusterMapIcon } from '@images/pages/deposit/ClusterMapIcon'
|
||||||
|
import { ReactComponent as MapPointer } from '@images/pages/deposit/MapPointer.svg'
|
||||||
|
import { ReactComponent as WellMapIcon } from '@images/pages/deposit/WellMapIcon.svg'
|
||||||
|
|
||||||
|
import '@styles/pages/deposit_map.less'
|
||||||
|
|
||||||
const zoomLimit = limitValue(5, 15)
|
const zoomLimit = limitValue(5, 15)
|
||||||
|
|
||||||
@ -39,18 +42,19 @@ const calcViewParams = (clusters) => {
|
|||||||
const Map = memo(() => {
|
const Map = memo(() => {
|
||||||
const deposits = useDepositList()
|
const deposits = useDepositList()
|
||||||
const location = useLocation()
|
const location = useLocation()
|
||||||
|
const { openWellTreeSelector } = useLayoutProps()
|
||||||
|
|
||||||
const makeDepositLinks = useCallback((clusters) => (
|
const makeClusterLinks = useCallback((wells) => (
|
||||||
<div>
|
<div>
|
||||||
{clusters.map(cluster => (
|
{wells.map(well => (
|
||||||
<Link
|
<Link
|
||||||
key={cluster.id}
|
key={well.id}
|
||||||
to={{
|
to={{
|
||||||
pathname: `/cluster/${cluster.id}`,
|
pathname: `/well/${well.id}`,
|
||||||
state: { from: location.pathname }
|
state: { from: location.pathname }
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div>{cluster.caption}</div>
|
<div>{well.caption}</div>
|
||||||
</Link>
|
</Link>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
@ -61,31 +65,39 @@ const Map = memo(() => {
|
|||||||
return (
|
return (
|
||||||
<div className={'deposit-page'}>
|
<div className={'deposit-page'}>
|
||||||
<PigeonMap {...viewParams}>
|
<PigeonMap {...viewParams}>
|
||||||
{deposits.map(deposit => {
|
{deposits.map(deposit => deposit.clusters.map(cluster => {
|
||||||
const anchor = [deposit.latitude, deposit.longitude]
|
const anchor = [cluster.latitude, cluster.longitude]
|
||||||
const links = makeDepositLinks(deposit.clusters)
|
const count = cluster.wells.length
|
||||||
|
const title = `${deposit.caption} / ${cluster.caption}`
|
||||||
|
const links = makeClusterLinks(cluster.wells)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Overlay width={32} anchor={anchor} key={anchor.join(' ')}>
|
<Overlay width={65} anchor={anchor} key={anchor.join(' ')}>
|
||||||
<Popover
|
<Popover
|
||||||
content={links}
|
content={links}
|
||||||
trigger={['click']}
|
trigger={['click']}
|
||||||
title={(
|
title={(
|
||||||
<Link to={{ pathname: `/deposit/${deposit.id}` }}>
|
<Link to={{ pathname: `/cluster/${cluster.id}` }}>
|
||||||
{deposit.caption}
|
{title}
|
||||||
</Link>
|
</Link>
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<div className={'pointer'}>
|
<div className={'pointer'} title={title}>
|
||||||
<Badge count={deposit.clusters.length}>
|
{count <= 1 ? (
|
||||||
<PointerIcon state={'active'} width={48} height={59} />
|
<WellMapIcon />
|
||||||
</Badge>
|
) : (
|
||||||
|
<ClusterMapIcon count={count} />
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</Popover>
|
</Popover>
|
||||||
</Overlay>
|
</Overlay>
|
||||||
)
|
)
|
||||||
})}
|
}))}
|
||||||
</PigeonMap>
|
</PigeonMap>
|
||||||
|
<button className={'dd-deposit-open-selector-btn'} onClick={openWellTreeSelector}>
|
||||||
|
<MapPointer />
|
||||||
|
<span>Выберите месторождение</span>
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
@ -16,7 +16,7 @@ const breadcrumb = makeMenuBreadcrumbItemsRender(menuItems, /^\/deposit\/[^\/#?]
|
|||||||
const Deposit = memo(() => {
|
const Deposit = memo(() => {
|
||||||
const { '*': param } = useParams()
|
const { '*': param } = useParams()
|
||||||
|
|
||||||
const setLayoutProps = useLayoutProps()
|
const { setLayoutProps } = useLayoutProps()
|
||||||
const deposits = useDepositList()
|
const deposits = useDepositList()
|
||||||
|
|
||||||
const root = useRootPath()
|
const root = useRootPath()
|
||||||
|
@ -9,7 +9,6 @@ import { makeGroupColumn, makeNumericColumn, makeNumericRender, makeTextColumn,
|
|||||||
import { OperationStatService, WellOperationService } from '@api'
|
import { OperationStatService, WellOperationService } from '@api'
|
||||||
import { arrayOrDefault, withPermissions } from '@utils'
|
import { arrayOrDefault, withPermissions } from '@utils'
|
||||||
|
|
||||||
import '@styles/index.css'
|
|
||||||
import '@styles/pages/statistics.less'
|
import '@styles/pages/statistics.less'
|
||||||
|
|
||||||
const { Text } = Typography
|
const { Text } = Typography
|
||||||
|
@ -17,7 +17,6 @@ import { MeasureService } from '@api'
|
|||||||
|
|
||||||
import { View } from './View'
|
import { View } from './View'
|
||||||
|
|
||||||
import '@styles/index.css'
|
|
||||||
import '@styles/pages/measure.css'
|
import '@styles/pages/measure.css'
|
||||||
|
|
||||||
const createEditingColumns = (cols, renderDelegate) =>
|
const createEditingColumns = (cols, renderDelegate) =>
|
||||||
|
@ -3,7 +3,6 @@ import { Empty, Form } from 'antd'
|
|||||||
|
|
||||||
import { Grid, GridItem } from '@components/Grid'
|
import { Grid, GridItem } from '@components/Grid'
|
||||||
|
|
||||||
import '@styles/index.css'
|
|
||||||
import '@styles/pages/measure.css'
|
import '@styles/pages/measure.css'
|
||||||
|
|
||||||
export const View = memo(({ columns, item }) => !item || !columns?.length ? (
|
export const View = memo(({ columns, item }) => !item || !columns?.length ? (
|
||||||
|
@ -118,15 +118,16 @@ const DashboardNNB = memo(({ enableEditing = false }) => {
|
|||||||
const navigate = useNavigate()
|
const navigate = useNavigate()
|
||||||
const selectedGroup = getTabname()
|
const selectedGroup = getTabname()
|
||||||
|
|
||||||
if (!selectedGroup && groups?.length > 0)
|
|
||||||
navigate(`${rootPath}/${groups[0].id}`)
|
|
||||||
|
|
||||||
|
|
||||||
const group = useMemo(() => ({
|
const group = useMemo(() => ({
|
||||||
editable: true,
|
editable: true,
|
||||||
...groups.find(({ id }) => `${id}` === selectedGroup),
|
...groups.find(({ id }) => `${id}` === selectedGroup),
|
||||||
}), [groups, selectedGroup])
|
}), [groups, selectedGroup])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!selectedGroup && groups?.length > 0)
|
||||||
|
navigate(`${rootPath}/${groups[0].id}`)
|
||||||
|
}, [selectedGroup, groups, rootPath, navigate])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
invokeWebApiWrapperAsync(
|
invokeWebApiWrapperAsync(
|
||||||
async () => {
|
async () => {
|
||||||
@ -249,7 +250,7 @@ const DashboardNNB = memo(({ enableEditing = false }) => {
|
|||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
<WidgetSettingsWindow
|
<WidgetSettingsWindow
|
||||||
visible={!!selectedSettings}
|
open={!!selectedSettings}
|
||||||
onCancel={() => setSelectedSettings(null)}
|
onCancel={() => setSelectedSettings(null)}
|
||||||
settings={selectedSettings}
|
settings={selectedSettings}
|
||||||
onEdit={onEdit}
|
onEdit={onEdit}
|
||||||
|
@ -28,7 +28,7 @@ const categoryDictionary = {
|
|||||||
|
|
||||||
// Конфигурация таблицы
|
// Конфигурация таблицы
|
||||||
export const makeMessageColumns = (idWell) => [
|
export const makeMessageColumns = (idWell) => [
|
||||||
makeDateColumn('Дата', 'date', undefined, undefined, { width: '120px' }),
|
makeDateColumn('Дата', 'date', undefined, undefined, { width: 130 }),
|
||||||
makeNumericColumn('Глубина, м', 'wellDepth', (depth, item) => (
|
makeNumericColumn('Глубина, м', 'wellDepth', (depth, item) => (
|
||||||
<Tooltip title={'Нажмите для перехода в архив'}>
|
<Tooltip title={'Нажмите для перехода в архив'}>
|
||||||
<Link
|
<Link
|
||||||
|
@ -13,15 +13,15 @@ import { useElementSize } from '@utils'
|
|||||||
|
|
||||||
import { makeGetColor } from '@pages/Well/WellOperations/Tvd'
|
import { makeGetColor } from '@pages/Well/WellOperations/Tvd'
|
||||||
|
|
||||||
import '@styles/limiting_parameter_statistics.less'
|
import '@styles/pages/limiting_parameter_statistics.less'
|
||||||
|
|
||||||
const columns = [
|
const columns = [
|
||||||
makeColumn('Цвет', 'color', { width: 50, render: (d) => (
|
makeColumn('Цвет', 'color', { width: 50, render: (d) => (
|
||||||
<div style={{ backgroundColor: d, padding: '5px 0' }} />
|
<div style={{ backgroundColor: d, padding: '5px 0' }} />
|
||||||
) }),
|
) }),
|
||||||
makeTextColumn('Уставка', 'nameFeedRegulator'),
|
makeTextColumn('Уставка', 'nameFeedRegulator'),
|
||||||
makeNumericColumn('Проходка, м', 'depth'),
|
makeNumericColumn('Проходка, м', 'depth', undefined, undefined, 140),
|
||||||
makeNumericColumn('Кол-во включений', 'numberInclusions', undefined, undefined, makeNumericRender(0)),
|
makeNumericColumn('Кол-во включений', 'numberInclusions', makeNumericRender(0), undefined, 150),
|
||||||
]
|
]
|
||||||
|
|
||||||
export const LimitingParameterStatistics = memo(() => {
|
export const LimitingParameterStatistics = memo(() => {
|
||||||
@ -59,16 +59,16 @@ export const LimitingParameterStatistics = memo(() => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (record.idFeedRegulator === selectedRegulator)
|
if (record.idFeedRegulator === selectedRegulator)
|
||||||
out.style = { background: '#FAFAFA', fontSize: '16px', fontWeight: '600' }
|
out.className = 'dd-selected-row'
|
||||||
return out
|
return out
|
||||||
}, [selectedRegulator])
|
}, [selectedRegulator])
|
||||||
|
|
||||||
const onPieOver = useCallback(function (e, d) {
|
const onPieOver = useCallback(function (_, d) { // Стрелочная функция не подойдёт из-за использования `this`
|
||||||
setSelectedRegulator(d.data.idFeedRegulator)
|
setSelectedRegulator(d.data.idFeedRegulator)
|
||||||
d3.select(this).attr('transform', 'scale(1.05)')
|
d3.select(this).attr('transform', 'scale(1.05)')
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
const onPieOut = useCallback(function (e, d) {
|
const onPieOut = useCallback(function () { // Стрелочная функция не подойдёт из-за использования `this`
|
||||||
setSelectedRegulator(null)
|
setSelectedRegulator(null)
|
||||||
d3.select(this).attr('transform', 'scale(1)')
|
d3.select(this).attr('transform', 'scale(1)')
|
||||||
}, [])
|
}, [])
|
||||||
@ -181,15 +181,15 @@ export const LimitingParameterStatistics = memo(() => {
|
|||||||
<Button onClick={() => setIsOpen(true)}>Статистика использования уставок</Button>
|
<Button onClick={() => setIsOpen(true)}>Статистика использования уставок</Button>
|
||||||
<Modal
|
<Modal
|
||||||
centered
|
centered
|
||||||
width={1024}
|
width={950}
|
||||||
footer={false}
|
footer={false}
|
||||||
title={'Статистика использования уставок'}
|
title={'Статистика использования уставок'}
|
||||||
onCancel={() => setIsOpen(false)}
|
onCancel={() => setIsOpen(false)}
|
||||||
open={isOpen}
|
open={isOpen}
|
||||||
>
|
>
|
||||||
<LoaderPortal show={isLoading}>
|
<LoaderPortal show={isLoading} className={'limit-parameter-stats-page'}>
|
||||||
<div className={'filter-groups'}>
|
<div className={'filter-groups'}>
|
||||||
<Input.Group compact style={{ flex: 1 }}>
|
<Input.Group compact style={{ flex: 2 }}>
|
||||||
<Input
|
<Input
|
||||||
addonBefore={(
|
addonBefore={(
|
||||||
<Radio
|
<Radio
|
||||||
@ -203,7 +203,7 @@ export const LimitingParameterStatistics = memo(() => {
|
|||||||
disabled={mode !== 'depth'}
|
disabled={mode !== 'depth'}
|
||||||
prefix={'От'}
|
prefix={'От'}
|
||||||
suffix={'м'}
|
suffix={'м'}
|
||||||
style={{ width: 'calc(50% + 113px / 2)', textAlign: 'right' }}
|
style={{ width: 'calc(50% + 128px / 2)', textAlign: 'right' }}
|
||||||
onChange={(e) => onDepthChanged(e, 'from')}
|
onChange={(e) => onDepthChanged(e, 'from')}
|
||||||
value={depthFilter.from}
|
value={depthFilter.from}
|
||||||
/>
|
/>
|
||||||
@ -212,12 +212,12 @@ export const LimitingParameterStatistics = memo(() => {
|
|||||||
disabled={mode !== 'depth'}
|
disabled={mode !== 'depth'}
|
||||||
prefix={'До'}
|
prefix={'До'}
|
||||||
suffix={'м'}
|
suffix={'м'}
|
||||||
style={{ width: 'calc(50% - 113px / 2)', textAlign: 'right' }}
|
style={{ width: 'calc(50% - 128px / 2)', textAlign: 'right' }}
|
||||||
onChange={(e) => onDepthChanged(e, 'to')}
|
onChange={(e) => onDepthChanged(e, 'to')}
|
||||||
value={depthFilter.to}
|
value={depthFilter.to}
|
||||||
/>
|
/>
|
||||||
</Input.Group>
|
</Input.Group>
|
||||||
<Input.Group compact style={{ flex: 1 }}>
|
<Input.Group compact style={{ flex: 3 }}>
|
||||||
<Input style={{ width: 128 }} addonBefore={(
|
<Input style={{ width: 128 }} addonBefore={(
|
||||||
<Radio
|
<Radio
|
||||||
checked={mode === 'time'}
|
checked={mode === 'time'}
|
||||||
@ -240,9 +240,9 @@ export const LimitingParameterStatistics = memo(() => {
|
|||||||
{data ? (
|
{data ? (
|
||||||
<svg ref={setSvgRef} width={'100%'} height={'100%'}>
|
<svg ref={setSvgRef} width={'100%'} height={'100%'}>
|
||||||
<g transform={`translate(${width / 2}, ${height / 2})`}>
|
<g transform={`translate(${width / 2}, ${height / 2})`}>
|
||||||
<g className={'slices'} stroke={'#0005'} />
|
<g className={'slices'} />
|
||||||
<g className={'labels'} fill={'black'} />
|
<g className={'labels'} />
|
||||||
<g className={'lines'} fill={'none'} stroke={'black'} />
|
<g className={'lines'} />
|
||||||
</g>
|
</g>
|
||||||
</svg>
|
</svg>
|
||||||
) : (
|
) : (
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
import { Button, Modal } from 'antd'
|
import { Button, Modal } from 'antd'
|
||||||
import { useState, useEffect, memo, useCallback, useMemo } from 'react'
|
import { useState, useEffect, memo, useCallback, useMemo } from 'react'
|
||||||
|
|
||||||
import { useWell } from '@asb/context'
|
|
||||||
import { Table } from '@components/Table'
|
import { Table } from '@components/Table'
|
||||||
import { UserView } from '@components/views'
|
import { UserView } from '@components/views'
|
||||||
import LoaderPortal from '@components/LoaderPortal'
|
import LoaderPortal from '@components/LoaderPortal'
|
||||||
@ -12,7 +11,7 @@ import { SetpointsService } from '@api'
|
|||||||
import SetpointSender from './SetpointSender'
|
import SetpointSender from './SetpointSender'
|
||||||
import { SetpointViewer, getSetpointStatus } from './SetpointViewer'
|
import { SetpointViewer, getSetpointStatus } from './SetpointViewer'
|
||||||
|
|
||||||
export const Setpoints = memo(({ ...other }) => {
|
export const Setpoints = memo(({ well, ...other }) => {
|
||||||
const [isModalVisible, setIsModalVisible] = useState(false)
|
const [isModalVisible, setIsModalVisible] = useState(false)
|
||||||
const [isSenderVisible, setIsSenderVisible] = useState(false)
|
const [isSenderVisible, setIsSenderVisible] = useState(false)
|
||||||
const [isViewerVisible, setIsViewerVisible] = useState(false)
|
const [isViewerVisible, setIsViewerVisible] = useState(false)
|
||||||
@ -21,8 +20,6 @@ export const Setpoints = memo(({ ...other }) => {
|
|||||||
const [selected, setSelected] = useState(null)
|
const [selected, setSelected] = useState(null)
|
||||||
const [setpointNames, setSetpointNames] = useState([])
|
const [setpointNames, setSetpointNames] = useState([])
|
||||||
|
|
||||||
const [well] = useWell()
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
invokeWebApiWrapperAsync(
|
invokeWebApiWrapperAsync(
|
||||||
async () => {
|
async () => {
|
||||||
|
@ -1,17 +1,14 @@
|
|||||||
import { memo, useCallback, useEffect, useState } from 'react'
|
import { memo, useCallback, useEffect, useState } from 'react'
|
||||||
|
|
||||||
import { useWell } from '@asb/context'
|
|
||||||
import { WirelineView } from '@components/views'
|
import { WirelineView } from '@components/views'
|
||||||
import { invokeWebApiWrapperAsync } from '@components/factory'
|
import { invokeWebApiWrapperAsync } from '@components/factory'
|
||||||
import { TelemetryWirelineRunOutService } from '@api'
|
import { TelemetryWirelineRunOutService } from '@api'
|
||||||
|
|
||||||
|
|
||||||
export const WirelineRunOut = memo(() => {
|
export const WirelineRunOut = memo(({ well }) => {
|
||||||
const [twro, setTwro] = useState({})
|
const [twro, setTwro] = useState({})
|
||||||
const [isLoading, setIsLoading] = useState(false)
|
const [isLoading, setIsLoading] = useState(false)
|
||||||
|
|
||||||
const [well] = useWell()
|
|
||||||
|
|
||||||
const update = useCallback(() => invokeWebApiWrapperAsync(
|
const update = useCallback(() => invokeWebApiWrapperAsync(
|
||||||
async () => {
|
async () => {
|
||||||
const twro = await TelemetryWirelineRunOutService.getData(well.id)
|
const twro = await TelemetryWirelineRunOutService.getData(well.id)
|
||||||
|
@ -3,7 +3,7 @@ import { BehaviorSubject, buffer, throttleTime } from 'rxjs'
|
|||||||
import { useSearchParams } from 'react-router-dom'
|
import { useSearchParams } from 'react-router-dom'
|
||||||
import { Alert, Button, Select } from 'antd'
|
import { Alert, Button, Select } from 'antd'
|
||||||
|
|
||||||
import { useWell } from '@asb/context'
|
import { useTopRightBlock, useWell } from '@asb/context'
|
||||||
import LoaderPortal from '@components/LoaderPortal'
|
import LoaderPortal from '@components/LoaderPortal'
|
||||||
import { CopyUrlButton } from '@components/CopyUrl'
|
import { CopyUrlButton } from '@components/CopyUrl'
|
||||||
import { D3MonitoringCharts } from '@components/d3/monitoring'
|
import { D3MonitoringCharts } from '@components/d3/monitoring'
|
||||||
@ -27,10 +27,8 @@ import WirelineRunOut from './WirelineRunOut'
|
|||||||
import { Setpoints } from './Setpoints'
|
import { Setpoints } from './Setpoints'
|
||||||
import { cursorRender } from './cursorRender'
|
import { cursorRender } from './cursorRender'
|
||||||
|
|
||||||
import MomentStabPicEnabled from '@images/DempherOn.png'
|
import { ReactComponent as DempherIcon } from '@images/pages/well/telemetry/monitoring/DempherIcon.svg'
|
||||||
import MomentStabPicDisabled from '@images/DempherOff.png'
|
import { ReactComponent as SpinIcon } from '@images/pages/well/telemetry/monitoring/SpinIcon.svg'
|
||||||
import SpinPicEnabled from '@images/SpinEnabled.png'
|
|
||||||
import SpinPicDisabled from '@images/SpinDisabled.png'
|
|
||||||
|
|
||||||
import '@styles/pages/telemetry_view.less'
|
import '@styles/pages/telemetry_view.less'
|
||||||
import '@styles/pages/message.less'
|
import '@styles/pages/message.less'
|
||||||
@ -76,6 +74,7 @@ const getRowDate = (row) => row && isRawDate(row.date) ? new Date(row.date) : nu
|
|||||||
|
|
||||||
const TelemetryView = memo(() => {
|
const TelemetryView = memo(() => {
|
||||||
const [well, updateWell] = useWell()
|
const [well, updateWell] = useWell()
|
||||||
|
const setTopRightBlock = useTopRightBlock()
|
||||||
const [searchParams, setSearchParams] = useSearchParams()
|
const [searchParams, setSearchParams] = useSearchParams()
|
||||||
|
|
||||||
const [dataSaub, setDataSaub] = useState([])
|
const [dataSaub, setDataSaub] = useState([])
|
||||||
@ -91,6 +90,7 @@ const TelemetryView = memo(() => {
|
|||||||
|
|
||||||
const [archiveMode, setArchiveMode] = useState(false)
|
const [archiveMode, setArchiveMode] = useState(false)
|
||||||
|
|
||||||
|
|
||||||
const onStatusChanged = useCallback((value) => updateWell({ idState: value }), [well])
|
const onStatusChanged = useCallback((value) => updateWell({ idState: value }), [well])
|
||||||
|
|
||||||
const handleDataSaub = useCallback((data, replace = false) => {
|
const handleDataSaub = useCallback((data, replace = false) => {
|
||||||
@ -251,6 +251,17 @@ const TelemetryView = memo(() => {
|
|||||||
setEndDate(new Date(saubLast.date))
|
setEndDate(new Date(saubLast.date))
|
||||||
}, [archiveMode, saubLast])
|
}, [archiveMode, saubLast])
|
||||||
|
|
||||||
|
useEffect(() => setTopRightBlock((well) => (
|
||||||
|
<div style={{ display: 'flex', gap: 5 }}>
|
||||||
|
<Setpoints well={well} />
|
||||||
|
<WirelineRunOut well={well} />
|
||||||
|
<Button onClick={() => setArchiveMode((prev) => !prev)} danger={archiveMode}>
|
||||||
|
{archiveMode ? 'Выйти из архива' : 'Войти в архив'}
|
||||||
|
</Button>
|
||||||
|
{archiveMode && <CopyUrlButton />}
|
||||||
|
</div>
|
||||||
|
)), [setTopRightBlock, archiveMode])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<LoaderPortal show={showLoader} style={{ flexGrow: 1 }}>
|
<LoaderPortal show={showLoader} style={{ flexGrow: 1 }}>
|
||||||
<div className={'telemetry-view-page'}>
|
<div className={'telemetry-view-page'}>
|
||||||
@ -265,13 +276,11 @@ const TelemetryView = memo(() => {
|
|||||||
<Option value={2}>Завершено</Option>
|
<Option value={2}>Завершено</Option>
|
||||||
</Select>
|
</Select>
|
||||||
</div>
|
</div>
|
||||||
<Setpoints />
|
|
||||||
<LimitingParameterStatistics />
|
<LimitingParameterStatistics />
|
||||||
<WirelineRunOut />
|
|
||||||
<div className={'icons'}>
|
<div className={'icons'}>
|
||||||
<img src={isTorqueStabEnabled(spinLast) ? MomentStabPicEnabled : MomentStabPicDisabled} alt={'TorqueMaster'} />
|
<DempherIcon color={isTorqueStabEnabled(spinLast) ? '#24DE6E' : '#4F4F4F'} />
|
||||||
<img src={isSpinEnabled(spinLast) ? SpinPicEnabled : SpinPicDisabled} alt={'SpinMaster'} />
|
<SpinIcon color={isSpinEnabled(spinLast) ? '#24DE6E' : '#4F4F4F'} />
|
||||||
<h2 style={{ marginBottom: 0, fontWeight: 'bold', color: isMseEnabled(saubLast) ? 'green' : 'lightgrey' }}>MSE</h2>
|
<spin style={{ fontSize: 24, fontWeight: 900, color: isMseEnabled(saubLast) ? '#24DE6E' : '#4F4F4F' }}>MSE</spin>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{archiveMode && (
|
{archiveMode && (
|
||||||
@ -300,10 +309,6 @@ const TelemetryView = memo(() => {
|
|||||||
<PeriodPicker value={chartInterval / 1000} onChange={(value) => setChartInterval(value * 1000)} />
|
<PeriodPicker value={chartInterval / 1000} onChange={(value) => setChartInterval(value * 1000)} />
|
||||||
</div>
|
</div>
|
||||||
<Button onClick={() => chartMethods?.setSettingsVisible(true)}>Настроить графики</Button>
|
<Button onClick={() => chartMethods?.setSettingsVisible(true)}>Настроить графики</Button>
|
||||||
<Button onClick={() => setArchiveMode((prev) => !prev)} danger={archiveMode}>
|
|
||||||
{archiveMode ? 'Выйти из архива' : 'Войти в архив'}
|
|
||||||
</Button>
|
|
||||||
{archiveMode && <CopyUrlButton />}
|
|
||||||
</div>
|
</div>
|
||||||
<D3MonitoringCharts
|
<D3MonitoringCharts
|
||||||
{...chartProps}
|
{...chartProps}
|
||||||
|
@ -4,8 +4,6 @@ import { memo, useMemo } from 'react'
|
|||||||
import { RootPathContext, useRootPath } from '@asb/context'
|
import { RootPathContext, useRootPath } from '@asb/context'
|
||||||
import { withPermissions } from '@utils'
|
import { withPermissions } from '@utils'
|
||||||
|
|
||||||
import '@styles/index.css'
|
|
||||||
|
|
||||||
const Telemetry = memo(() => {
|
const Telemetry = memo(() => {
|
||||||
const root = useRootPath()
|
const root = useRootPath()
|
||||||
const rootPath = useMemo(() => `${root}/telemetry`, [root])
|
const rootPath = useMemo(() => `${root}/telemetry`, [root])
|
||||||
|
@ -17,7 +17,6 @@ import StatExport from './StatExport'
|
|||||||
import NetGraphExport from './NetGraphExport'
|
import NetGraphExport from './NetGraphExport'
|
||||||
import AdditionalTables from './AdditionalTables'
|
import AdditionalTables from './AdditionalTables'
|
||||||
|
|
||||||
import '@styles/index.css'
|
|
||||||
import '@styles/pages/tvd.less'
|
import '@styles/pages/tvd.less'
|
||||||
|
|
||||||
const operationsColors = [
|
const operationsColors = [
|
||||||
|
@ -10,8 +10,6 @@ import { WellService } from '@api'
|
|||||||
|
|
||||||
import { WellNavigationMenu, menuItems } from './WellNavigationMenu'
|
import { WellNavigationMenu, menuItems } from './WellNavigationMenu'
|
||||||
|
|
||||||
import '@styles/index.css'
|
|
||||||
|
|
||||||
const Measure = lazy(() => import('./Measure'))
|
const Measure = lazy(() => import('./Measure'))
|
||||||
const Reports = lazy(() => import('./Reports'))
|
const Reports = lazy(() => import('./Reports'))
|
||||||
const WellCase = lazy(() => import('./WellCase'))
|
const WellCase = lazy(() => import('./WellCase'))
|
||||||
@ -50,7 +48,7 @@ const Well = memo(() => {
|
|||||||
const root = useRootPath()
|
const root = useRootPath()
|
||||||
const rootPath = useMemo(() => `${root}/well/${idWell}`, [root, idWell])
|
const rootPath = useMemo(() => `${root}/well/${idWell}`, [root, idWell])
|
||||||
|
|
||||||
const setLayoutProps = useLayoutProps()
|
const { setLayoutProps } = useLayoutProps()
|
||||||
|
|
||||||
const updateWell = useCallback((data) => invokeWebApiWrapperAsync(
|
const updateWell = useCallback((data) => invokeWebApiWrapperAsync(
|
||||||
async () => {
|
async () => {
|
||||||
|
@ -11,7 +11,7 @@ import { AuthService } from '@api'
|
|||||||
|
|
||||||
import Logo from '@images/Logo'
|
import Logo from '@images/Logo'
|
||||||
|
|
||||||
import '@styles/index.css'
|
import '@styles/pages/login.less'
|
||||||
|
|
||||||
const Login = memo(() => {
|
const Login = memo(() => {
|
||||||
const [showLoader, setShowLoader] = useState(false)
|
const [showLoader, setShowLoader] = useState(false)
|
||||||
@ -36,10 +36,10 @@ const Login = memo(() => {
|
|||||||
<div style={{ display: 'flex', flexDirection: 'column' }}>
|
<div style={{ display: 'flex', flexDirection: 'column' }}>
|
||||||
<Logo style={{ marginBottom: '10px' }} />
|
<Logo style={{ marginBottom: '10px' }} />
|
||||||
<LoaderPortal show={showLoader}>
|
<LoaderPortal show={showLoader}>
|
||||||
<Card bordered title={'Система мониторинга'} className={'shadow'} style={{ width: 350 }}>
|
<Card bordered title={'Вход в ЕЦП'} className={'shadow'} style={{ width: 350 }}>
|
||||||
<Form onFinish={handleLogin}>
|
<Form onFinish={handleLogin}>
|
||||||
<Form.Item name={'login'} rules={loginRules}>
|
<Form.Item name={'login'} rules={loginRules}>
|
||||||
<Input placeholder={'Пользователь'} prefix={<UserOutlined />} />
|
<Input placeholder={'Логин'} prefix={<UserOutlined />} />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item name={'password'} rules={passwordRules}>
|
<Form.Item name={'password'} rules={passwordRules}>
|
||||||
<Input.Password placeholder={'Пароль'} prefix={<LockOutlined />} />
|
<Input.Password placeholder={'Пароль'} prefix={<LockOutlined />} />
|
||||||
|
@ -8,7 +8,6 @@ import {
|
|||||||
EyeTwoTone
|
EyeTwoTone
|
||||||
} from '@ant-design/icons'
|
} from '@ant-design/icons'
|
||||||
|
|
||||||
import { AuthService } from '@api'
|
|
||||||
import LoaderPortal from '@components/LoaderPortal'
|
import LoaderPortal from '@components/LoaderPortal'
|
||||||
import { invokeWebApiWrapperAsync } from '@components/factory'
|
import { invokeWebApiWrapperAsync } from '@components/factory'
|
||||||
import {
|
import {
|
||||||
@ -21,9 +20,12 @@ import {
|
|||||||
phoneRules
|
phoneRules
|
||||||
} from '@utils/validationRules'
|
} from '@utils/validationRules'
|
||||||
import { withPermissions } from '@utils'
|
import { withPermissions } from '@utils'
|
||||||
|
import { AuthService } from '@api'
|
||||||
|
|
||||||
import Logo from '@images/Logo'
|
import Logo from '@images/Logo'
|
||||||
|
|
||||||
|
import '@styles/pages/login.less'
|
||||||
|
|
||||||
const surnameRules = [...nameRules, { required: true, message: 'Пожалуйста, введите фамилию!' }]
|
const surnameRules = [...nameRules, { required: true, message: 'Пожалуйста, введите фамилию!' }]
|
||||||
const regEmailRules = [{ required: true, message: 'Пожалуйста, введите email!' }, ...emailRules]
|
const regEmailRules = [{ required: true, message: 'Пожалуйста, введите email!' }, ...emailRules]
|
||||||
const confirmPasswordRules = [
|
const confirmPasswordRules = [
|
||||||
@ -38,7 +40,6 @@ const confirmPasswordRules = [
|
|||||||
})
|
})
|
||||||
]
|
]
|
||||||
|
|
||||||
const logoIcon = <Logo width={130} />
|
|
||||||
const showPasswordIcon = visible => (visible ? <EyeTwoTone /> : <EyeInvisibleOutlined />)
|
const showPasswordIcon = visible => (visible ? <EyeTwoTone /> : <EyeInvisibleOutlined />)
|
||||||
|
|
||||||
const createInput = (name, placeholder, rules, isPassword, dependencies) => (
|
const createInput = (name, placeholder, rules, isPassword, dependencies) => (
|
||||||
@ -66,29 +67,34 @@ export const Register = memo(() => {
|
|||||||
), [navigate])
|
), [navigate])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<LoaderPortal show={showLoader} className={'loader-container login_page shadow'}>
|
<div className={'login_page shadow'}>
|
||||||
<Card title={'Система мониторинга'} className={'shadow'} bordered={true} style={{ width: 350 }} extra={logoIcon}>
|
<div style={{ display: 'flex', flexDirection: 'column' }}>
|
||||||
<Form onFinish={handleRegister}>
|
<Logo style={{ marginBottom: '10px' }} />
|
||||||
{createInput('login', 'Пользователь', [...loginRules, ...createLoginRules])}
|
<LoaderPortal show={showLoader}>
|
||||||
{createInput('password', 'Пароль', [...passwordRules, ...createPasswordRules], true, null)}
|
<Card title={'Оставить заявку на регистрацию'} className={'shadow'} style={{ width: 350 }}>
|
||||||
{createInput('confirmPassword', 'Подтверждение пароля', confirmPasswordRules, true, ['password'])}
|
<Form onFinish={handleRegister}>
|
||||||
{createInput('name', 'Имя', nameRules)}
|
{createInput('login', 'Логин', [...loginRules, ...createLoginRules])}
|
||||||
{createInput('surName', 'Фамилия', surnameRules)}
|
{createInput('password', 'Пароль', [...passwordRules, ...createPasswordRules], true, null)}
|
||||||
{createInput('patronymic', 'Отчество', nameRules)}
|
{createInput('confirmPassword', 'Подтверждение пароля', confirmPasswordRules, true, ['password'])}
|
||||||
{createInput('email', 'Email', regEmailRules)}
|
{createInput('name', 'Имя', nameRules)}
|
||||||
{createInput('phone', 'Номер телефона', phoneRules)}
|
{createInput('surName', 'Фамилия', surnameRules)}
|
||||||
{createInput('position', 'Должность')}
|
{createInput('patronymic', 'Отчество', nameRules)}
|
||||||
<Form.Item>
|
{createInput('email', 'Email', regEmailRules)}
|
||||||
<div className={'register-button'}>
|
{createInput('phone', 'Номер телефона', phoneRules)}
|
||||||
<Button type={'primary'} htmlType={'submit'}>Зарегистрироваться</Button>
|
{createInput('position', 'Должность')}
|
||||||
</div>
|
<Form.Item>
|
||||||
</Form.Item>
|
<div className={'register-button'}>
|
||||||
<div className={'text-align-center'}>
|
<Button type={'primary'} htmlType={'submit'}>Зарегистрироваться</Button>
|
||||||
<Link to={`/login`}>Назад</Link>
|
</div>
|
||||||
</div>
|
</Form.Item>
|
||||||
</Form>
|
<div className={'text-align-center'}>
|
||||||
</Card>
|
<Link to={`/login`}>Назад</Link>
|
||||||
</LoaderPortal>
|
</div>
|
||||||
|
</Form>
|
||||||
|
</Card>
|
||||||
|
</LoaderPortal>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
4
src/styles/components/download_link.less
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
.download-link {
|
||||||
|
height: 32px;
|
||||||
|
padding: 4px 15px;
|
||||||
|
}
|
3
src/styles/components/grid.less
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
.dd-grid-item {
|
||||||
|
padding: 4px;
|
||||||
|
}
|
6
src/styles/components/icons/cluster-map-icon.less
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
.dd-cluster-map-icon {
|
||||||
|
& .dd-cluster-map-icon-count {
|
||||||
|
font-size: 22px;
|
||||||
|
font-weight: 700;
|
||||||
|
}
|
||||||
|
}
|
@ -2,6 +2,8 @@
|
|||||||
@active-bg: #c32828;
|
@active-bg: #c32828;
|
||||||
@admin-bg: #900;
|
@admin-bg: #900;
|
||||||
@admin-active-bg: #413f3d;
|
@admin-active-bg: #413f3d;
|
||||||
|
@bg-color: #232323;
|
||||||
|
@text-color: white - @bg-color;
|
||||||
|
|
||||||
.no-select {
|
.no-select {
|
||||||
-webkit-user-select: none;
|
-webkit-user-select: none;
|
||||||
@ -25,7 +27,7 @@
|
|||||||
|
|
||||||
height: 100vh;
|
height: 100vh;
|
||||||
|
|
||||||
& .menu-sider {
|
& .dd-menu-sider {
|
||||||
overflow-x: hidden;
|
overflow-x: hidden;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
@ -86,7 +88,8 @@
|
|||||||
|
|
||||||
& .page-content {
|
& .page-content {
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
background: white;
|
background: @bg-color;
|
||||||
|
color: @text-color;
|
||||||
|
|
||||||
& .breadcrumb-block {
|
& .breadcrumb-block {
|
||||||
display: flex;
|
display: flex;
|
||||||
@ -115,11 +118,11 @@
|
|||||||
background-color: @admin-bg;
|
background-color: @admin-bg;
|
||||||
}
|
}
|
||||||
|
|
||||||
.menu-sider {
|
.dd-menu-sider {
|
||||||
background-color: @admin-bg;
|
background-color: @admin-bg;
|
||||||
}
|
}
|
||||||
|
|
||||||
& .menu-sider .ant-menu-submenu-selected.ant-menu-submenu-inline .ant-menu-submenu-title {
|
& .dd-menu-sider .ant-menu-submenu-selected.ant-menu-submenu-inline .ant-menu-submenu-title {
|
||||||
color: white;
|
color: white;
|
||||||
& .ant-menu-title-content > a {
|
& .ant-menu-title-content > a {
|
||||||
color: white;
|
color: white;
|
||||||
@ -128,10 +131,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.site-layout-background {
|
|
||||||
background: #fff;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media only screen and (max-width: 1280px) {
|
@media only screen and (max-width: 1280px) {
|
||||||
.page-layout {
|
.page-layout {
|
||||||
--sheet-padding: 10px;
|
--sheet-padding: 10px;
|
||||||
|
@ -1,20 +1,25 @@
|
|||||||
/* original from https://loading.io/css/ */
|
/* original from https://loading.io/css/ */
|
||||||
|
|
||||||
|
@loader-bg: rgba(255, 255, 255, 0.1);
|
||||||
|
@loader-color: rgb(226, 29, 29);
|
||||||
|
|
||||||
.lds-ripple {
|
.lds-ripple {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
width: 80px;
|
width: 80px;
|
||||||
height: 80px;
|
height: 80px;
|
||||||
}
|
|
||||||
.lds-ripple div {
|
& div {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
border: 4px solid rgb(226, 29, 29);
|
border: 4px solid @loader-color;
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
animation: lds-ripple 1s cubic-bezier(0, 0.2, 0.8, 1) infinite;
|
animation: lds-ripple 1s cubic-bezier(0, 0.2, 0.8, 1) infinite;
|
||||||
}
|
}
|
||||||
.lds-ripple div:nth-child(2) {
|
|
||||||
animation-delay: -0.5s;
|
& div:nth-child(2) {
|
||||||
|
animation-delay: -0.5s;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@keyframes lds-ripple {
|
@keyframes lds-ripple {
|
||||||
0% {
|
0% {
|
||||||
@ -33,12 +38,12 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.loader-container{
|
.loader-container {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: 1fr 1fr 1fr;
|
grid-template-columns: 1fr 1fr 1fr;
|
||||||
}
|
}
|
||||||
|
|
||||||
.loader-content{
|
.loader-content {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
display: flex;
|
display: flex;
|
||||||
@ -46,14 +51,14 @@
|
|||||||
grid-column-start: 1;
|
grid-column-start: 1;
|
||||||
grid-column-end: span 3;
|
grid-column-end: span 3;
|
||||||
grid-row-start: 1;
|
grid-row-start: 1;
|
||||||
|
|
||||||
|
&.loader-content-fill {
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.loader-content.loader-content-fill {
|
.loader-overlay {
|
||||||
height: 100%;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.loader-overlay{
|
|
||||||
grid-column-start: 1;
|
grid-column-start: 1;
|
||||||
grid-column-end: span 3;
|
grid-column-end: span 3;
|
||||||
grid-row-start: 1;
|
grid-row-start: 1;
|
||||||
@ -66,13 +71,13 @@
|
|||||||
border-radius: 40px;
|
border-radius: 40px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.loader-fade{
|
.loader-fade {
|
||||||
grid-column-start: 1;
|
grid-column-start: 1;
|
||||||
grid-column-end: span 3;
|
grid-column-end: span 3;
|
||||||
grid-row-start: 1;
|
grid-row-start: 1;
|
||||||
background-color: rgba(255, 255, 255, 0.4);
|
background-color: @loader-bg;
|
||||||
align-self: stretch;
|
align-self: stretch;
|
||||||
justify-self: stretch;
|
justify-self: stretch;
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
box-shadow: 0px 0px 6px 5px rgba(255, 254, 254, 0.4);
|
box-shadow: 0px 0px 6px 5px @loader-bg;
|
||||||
}
|
}
|
13
src/styles/components/table.less
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
.first-column-title {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: stretch;
|
||||||
|
justify-content: space-between;
|
||||||
|
position: relative;
|
||||||
|
padding: 16px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.text-align-r-container {
|
||||||
|
width: 100%;
|
||||||
|
text-align: right;
|
||||||
|
}
|
9
src/styles/components/tag_list.less
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
.dd-tag-list {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 5px;
|
||||||
|
|
||||||
|
& > .ant-tag {
|
||||||
|
margin-right: 0;
|
||||||
|
}
|
||||||
|
}
|
@ -1,19 +0,0 @@
|
|||||||
.header-tree-select {
|
|
||||||
width: 300px
|
|
||||||
}
|
|
||||||
|
|
||||||
.header-tree-select *{
|
|
||||||
color: #fff;
|
|
||||||
font-size: 1rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.header-tree-select{
|
|
||||||
width: 300px;
|
|
||||||
border: 1px solid rgba(255, 255, 255, 0.2);
|
|
||||||
background-color: rgba(0, 0, 0, 0.3);
|
|
||||||
}
|
|
||||||
|
|
||||||
.header-tree-select:hover{
|
|
||||||
border: 1px solid rgba(255, 255, 255, 0.8);
|
|
||||||
background-color: rgba(0, 0, 0, 0.5);
|
|
||||||
}
|
|
26
src/styles/components/well_tree_select.less
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
.well-tree-selector {
|
||||||
|
&.ant-tree .ant-tree-node-content-wrapper.ant-tree-node-selected {
|
||||||
|
background-color: #C32828;
|
||||||
|
color: white;
|
||||||
|
|
||||||
|
& svg {
|
||||||
|
color: white !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-tree-select{
|
||||||
|
width: 300px;
|
||||||
|
border: 1px solid rgba(255, 255, 255, 0.2);
|
||||||
|
background-color: rgba(0, 0, 0, 0.3);
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
border: 1px solid rgba(255, 255, 255, 0.8);
|
||||||
|
background-color: rgba(0, 0, 0, 0.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
& * {
|
||||||
|
color: #fff;
|
||||||
|
font-size: 1rem;
|
||||||
|
}
|
||||||
|
}
|
4
src/styles/fonts.less
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
@font-face {
|
||||||
|
font-family: 'Jost';
|
||||||
|
src: url('fonts/Jost-VariableFont_wght.ttf') format('truetype');
|
||||||
|
}
|
BIN
src/styles/fonts/Jost-VariableFont_wght.ttf
Normal file
@ -1,11 +1,90 @@
|
|||||||
@import '~antd/dist/antd.less';
|
@import '~antd/dist/antd.less';
|
||||||
/*
|
|
||||||
* ЭТО ФАЙЛ НАСТРОЙКИ ТЕМЫ И КОМПОНЕНТОВ ТЕМЫ.
|
|
||||||
* НЕ ПИШИТЕ ТУТ СТИЛИ ДЛЯ КАСТОМНЫХ КОМПОНЕНТОВ.
|
|
||||||
*/
|
|
||||||
|
|
||||||
// Переменные для темы тут:
|
@main: #222629;
|
||||||
// https://github.com/ant-design/ant-design/blob/master/components/style/themes/default.less
|
@main-dark: #191C1E;
|
||||||
|
@main-light: #2E3338;
|
||||||
|
@text: #ddd;
|
||||||
|
@text-light: #fff;
|
||||||
|
@text-dark: #222;
|
||||||
|
@text-disabled: #999;
|
||||||
|
|
||||||
@primary-color: #C32828; // rgb(195, 40, 40)
|
@primary: #C32828;
|
||||||
@layout-header-background:#413F3D; // rgb(65, 63, 61)
|
@info: @primary;
|
||||||
|
@success: #06D6A0;
|
||||||
|
@error: #EF476F;
|
||||||
|
@warn: #fff200;
|
||||||
|
|
||||||
|
@layout-header-height: 48px;
|
||||||
|
|
||||||
|
@primary-color: @primary;
|
||||||
|
@processing-color: @info;
|
||||||
|
@info-color: @info;
|
||||||
|
@success-color: @success;
|
||||||
|
@error-color: @error;
|
||||||
|
@highlight-color: @error;
|
||||||
|
@warning-color: @warn;
|
||||||
|
@text-color: @text;
|
||||||
|
@text-color-dark: @text-dark;
|
||||||
|
@disabled-color: @text-disabled;
|
||||||
|
@text-color-secondary: @text-disabled;
|
||||||
|
@heading-color: @text-light;
|
||||||
|
@heading-color-dark: @text-dark;
|
||||||
|
@link-color: lighten(@primary, 10%);
|
||||||
|
|
||||||
|
@body-background: @main;
|
||||||
|
@component-background: @main-light;
|
||||||
|
@item-active-bg: @primary;
|
||||||
|
@item-hover-bg: @primary;
|
||||||
|
@menu-highlight-color: @text;
|
||||||
|
@table-row-hover-bg: darken(@primary, 10%);
|
||||||
|
@table-selected-row-bg: darken(@primary, 20%);
|
||||||
|
|
||||||
|
@descriptions-bg: @main-light;
|
||||||
|
@menu-bg: transparent;
|
||||||
|
|
||||||
|
@border-color-base: @main-dark;
|
||||||
|
@border-color-split: lighten(@main-light, 2%);
|
||||||
|
|
||||||
|
@background-color-light: @main-light;
|
||||||
|
@background-color-base: @main-light;
|
||||||
|
|
||||||
|
@checkbox-check-color: @main-light;
|
||||||
|
|
||||||
|
@layout-header-background: @main-dark;
|
||||||
|
@layout-body-background: @main;
|
||||||
|
|
||||||
|
// Alert
|
||||||
|
@alert-success-border-color: @success;
|
||||||
|
@alert-success-bg-color: darken(@success, 30%);
|
||||||
|
@alert-success-icon-color: @success;
|
||||||
|
|
||||||
|
@alert-info-border-color: @info;
|
||||||
|
@alert-info-bg-color: darken(@info, 30%);
|
||||||
|
@alert-info-icon-color: @info;
|
||||||
|
|
||||||
|
@alert-warning-border-color: @warn;
|
||||||
|
@alert-warning-bg-color: darken(@warn, 30%);
|
||||||
|
@alert-warning-icon-color: @warn;
|
||||||
|
|
||||||
|
@alert-error-border-color: @error;
|
||||||
|
@alert-error-bg-color: darken(@error, 30%);
|
||||||
|
@alert-error-icon-color: @error;
|
||||||
|
|
||||||
|
@select-item-selected-bg: darken(@primary, 10%); // Цвет выбранного элемента списка
|
||||||
|
@picker-basic-cell-active-with-range-color: darken(@primary, 10%); // Цвет выделения диапазона на селекторе дат
|
||||||
|
|
||||||
|
// Segmented
|
||||||
|
@segmented-label-color: @text;
|
||||||
|
@segmented-label-hover-color: @text;
|
||||||
|
@segmented-hover-bg: lighten(@main-light, 10%);
|
||||||
|
@segmented-bg: lighten(@main-light, 2%);
|
||||||
|
@segmented-selected-bg: darken(@primary, 10%);
|
||||||
|
|
||||||
|
|
||||||
|
.ant-menu-item:active, .ant-menu-submenu-title:active {
|
||||||
|
background-color: darken(@primary, 10%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-menu:not(.ant-menu-horizontal) .ant-menu-item-selected {
|
||||||
|
background-color: @primary;
|
||||||
|
}
|
||||||
|
@ -1,169 +0,0 @@
|
|||||||
body {
|
|
||||||
margin: 0;
|
|
||||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
|
|
||||||
'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
|
|
||||||
sans-serif;
|
|
||||||
-webkit-font-smoothing: antialiased;
|
|
||||||
-moz-osx-font-smoothing: grayscale;
|
|
||||||
}
|
|
||||||
|
|
||||||
.d-flex {
|
|
||||||
display: flex;
|
|
||||||
}
|
|
||||||
|
|
||||||
.flex-direction-column {
|
|
||||||
flex-direction: column;
|
|
||||||
}
|
|
||||||
|
|
||||||
.d-inline {
|
|
||||||
display: inline;
|
|
||||||
}
|
|
||||||
|
|
||||||
.d-none {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.flex-1 {
|
|
||||||
flex: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
.w-15 {
|
|
||||||
width: 15%
|
|
||||||
}
|
|
||||||
|
|
||||||
.w-33 {
|
|
||||||
width: 33%
|
|
||||||
}
|
|
||||||
|
|
||||||
.w-50 {
|
|
||||||
width: 50%
|
|
||||||
}
|
|
||||||
|
|
||||||
.w-100 {
|
|
||||||
width: 100%
|
|
||||||
}
|
|
||||||
|
|
||||||
.m-0 {
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mt-8px {
|
|
||||||
margin-top: 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mt-20px {
|
|
||||||
margin-top: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mb-20px {
|
|
||||||
margin-bottom: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.ml-5px {
|
|
||||||
margin-left: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.ml-10px {
|
|
||||||
margin-left: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.ml-30px {
|
|
||||||
margin-left: 30px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.h-100vh {
|
|
||||||
height: 100vh;
|
|
||||||
}
|
|
||||||
|
|
||||||
.p-10 {
|
|
||||||
padding: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.vertical-align-center {
|
|
||||||
vertical-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.text-align-center {
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.text-align-r-container {
|
|
||||||
width: 100%;
|
|
||||||
text-align: right;
|
|
||||||
}
|
|
||||||
|
|
||||||
code {
|
|
||||||
font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
|
|
||||||
monospace;
|
|
||||||
}
|
|
||||||
|
|
||||||
.linkDocuments {
|
|
||||||
color: #000;
|
|
||||||
}
|
|
||||||
|
|
||||||
.linkDocuments:hover {
|
|
||||||
color: #c32828;
|
|
||||||
}
|
|
||||||
|
|
||||||
.container{
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.login-button {
|
|
||||||
width: 20%;
|
|
||||||
margin: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
.register-button {
|
|
||||||
width: 50%;
|
|
||||||
margin: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
.first-column-title {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
align-items: stretch;
|
|
||||||
justify-content: space-between;
|
|
||||||
position: relative;
|
|
||||||
padding: 16px 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.noselect {
|
|
||||||
-webkit-touch-callout: none; /* iOS Safari */
|
|
||||||
-webkit-user-select: none; /* Safari */
|
|
||||||
-khtml-user-select: none; /* Konqueror HTML */
|
|
||||||
-moz-user-select: none; /* Old versions of Firefox */
|
|
||||||
-ms-user-select: none; /* Internet Explorer/Edge */
|
|
||||||
user-select: none; /* Non-prefixed version, currently
|
|
||||||
supported by Chrome, Edge, Opera and Firefox */
|
|
||||||
}
|
|
||||||
|
|
||||||
.download-link {
|
|
||||||
height: 32px;
|
|
||||||
padding: 4px 15px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.ant-table-cell:has(.color-pale-green) {
|
|
||||||
background-color: #98fb98;
|
|
||||||
}
|
|
||||||
|
|
||||||
.ant-table-tbody > tr > td.ant-table-cell-row-hover:has( > div.color-pale-green) {
|
|
||||||
background: #98fb98;
|
|
||||||
}
|
|
||||||
|
|
||||||
.color-pale-green {
|
|
||||||
background-color: #98fb98;
|
|
||||||
}
|
|
||||||
|
|
||||||
.asb-grid-item {
|
|
||||||
padding: 4px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.pointer {
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
.deposit-page {
|
|
||||||
height: 100vh;
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
51
src/styles/index.less
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
@import './include/antd_theme.less';
|
||||||
|
@import './fonts';
|
||||||
|
@import './mixins';
|
||||||
|
|
||||||
|
body {
|
||||||
|
margin: 0;
|
||||||
|
font-family: 'Jost', -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
|
||||||
|
'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
|
||||||
|
sans-serif;
|
||||||
|
-webkit-font-smoothing: antialiased;
|
||||||
|
-moz-osx-font-smoothing: grayscale;
|
||||||
|
background: #232323;
|
||||||
|
}
|
||||||
|
|
||||||
|
.d-none { display: none }
|
||||||
|
.d-flex { display: flex }
|
||||||
|
.d-inline { display: inline }
|
||||||
|
|
||||||
|
.flex-direction-column { flex-direction: column }
|
||||||
|
|
||||||
|
.flex-1 { flex: 1 }
|
||||||
|
|
||||||
|
.w-15 { width: 15% }
|
||||||
|
.w-33 { width: 33% }
|
||||||
|
.w-50 { width: 50% }
|
||||||
|
.w-100 { width: 100% }
|
||||||
|
.h-100vh { height: 100vh }
|
||||||
|
|
||||||
|
.m-0 { margin: 0 }
|
||||||
|
.mt-8px { margin-top: 8px }
|
||||||
|
.mt-20px { margin-top: 20px }
|
||||||
|
.mb-20px { margin-bottom: 20px }
|
||||||
|
.ml-5px { margin-left: 5px }
|
||||||
|
.ml-10px { margin-left: 10px }
|
||||||
|
.ml-30px { margin-left: 30px }
|
||||||
|
|
||||||
|
.p-10 { padding: 10px }
|
||||||
|
|
||||||
|
.text-align-center {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.container {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pointer { cursor: pointer }
|
||||||
|
|
||||||
|
.no-select {
|
||||||
|
.no-select();
|
||||||
|
}
|
@ -1,29 +0,0 @@
|
|||||||
.filter-groups {
|
|
||||||
display: flex;
|
|
||||||
gap: 10px;
|
|
||||||
|
|
||||||
& .filter-label {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
& .date-filter {
|
|
||||||
display: flex;
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.modal-label {
|
|
||||||
width: 100%;
|
|
||||||
margin: 20px 0;
|
|
||||||
font-size: 1rem;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.lps-pie-chart {
|
|
||||||
min-height: 30vh;
|
|
||||||
max-height: 50vh;
|
|
||||||
}
|
|
13
src/styles/mixins.less
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
.no-select () {
|
||||||
|
-webkit-touch-callout: none; /* iOS Safari */
|
||||||
|
-webkit-user-select: none; /* Safari */
|
||||||
|
-khtml-user-select: none; /* Konqueror HTML */
|
||||||
|
-moz-user-select: none; /* Old versions of Firefox */
|
||||||
|
-ms-user-select: none; /* Internet Explorer/Edge */
|
||||||
|
user-select: none; /* Non-prefixed version, currently
|
||||||
|
supported by Chrome, Edge, Opera and Firefox */
|
||||||
|
}
|
||||||
|
|
||||||
|
.no-events () {
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
@ -1,4 +1,4 @@
|
|||||||
@import '../components/loader.css';
|
@import '../components/loader.less';
|
||||||
|
|
||||||
#root, .app{
|
#root, .app{
|
||||||
min-height:100%;
|
min-height:100%;
|
||||||
@ -25,17 +25,6 @@ html {
|
|||||||
margin-left: 30px;
|
margin-left: 30px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.login_page {
|
|
||||||
position: absolute;
|
|
||||||
height: 100%;
|
|
||||||
width: 100%;
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
padding: 24px;
|
|
||||||
background-color: #9d9d9d;
|
|
||||||
}
|
|
||||||
|
|
||||||
.shadow{
|
.shadow{
|
||||||
box-shadow: 1px 1px 4px #00000033;
|
box-shadow: 1px 1px 4px #00000033;
|
||||||
}
|
}
|
||||||
|
50
src/styles/pages/deposit_map.less
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
.deposit-page {
|
||||||
|
@bg-color: #232323;
|
||||||
|
|
||||||
|
height: 100vh;
|
||||||
|
overflow: hidden;
|
||||||
|
|
||||||
|
& > div[dir="ltr"] {
|
||||||
|
background: @bg-color !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
& .pigeon-tiles-box > .pigeon-tiles > * {
|
||||||
|
filter: brightness(0.6) invert(1) contrast(3) hue-rotate(200deg) saturate(0.3) brightness(0.7) grayscale(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
& .pigeon-attribution {
|
||||||
|
background: fade(@bg-color, 70%) !important;
|
||||||
|
color: white !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
& .dd-deposit-open-selector-btn {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
cursor: pointer;
|
||||||
|
padding: 10px 25px;
|
||||||
|
color: white;
|
||||||
|
font-weight: 700;
|
||||||
|
font-size: 16px;
|
||||||
|
font-style: normal;
|
||||||
|
position: absolute;
|
||||||
|
gap: 10px;
|
||||||
|
top: 35px;
|
||||||
|
right: 60px;
|
||||||
|
border: 1px solid #4A4A4A;
|
||||||
|
background: @bg-color;
|
||||||
|
border-radius: 6px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
transition: all .1s ease-in-out;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
color: @bg-color;
|
||||||
|
background: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:active {
|
||||||
|
background: rgba(255,255,255,.6);
|
||||||
|
color: @bg-color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
54
src/styles/pages/limiting_parameter_statistics.less
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
@import '../include/antd_theme';
|
||||||
|
@import '../mixins';
|
||||||
|
|
||||||
|
.limit-parameter-stats-page {
|
||||||
|
& .filter-groups {
|
||||||
|
display: flex;
|
||||||
|
gap: 10px;
|
||||||
|
|
||||||
|
& .filter-label {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
& .date-filter {
|
||||||
|
display: flex;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
& .modal-label {
|
||||||
|
width: 100%;
|
||||||
|
margin: 20px 0;
|
||||||
|
font-size: 1rem;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dd-selected-row {
|
||||||
|
background: @primary;
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
& .lps-pie-chart {
|
||||||
|
min-height: 30vh;
|
||||||
|
max-height: 50vh;
|
||||||
|
|
||||||
|
& .slices {
|
||||||
|
stroke: #0005;
|
||||||
|
}
|
||||||
|
|
||||||
|
& .labels {
|
||||||
|
fill: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
& .lines {
|
||||||
|
fill: none;
|
||||||
|
stroke: white;
|
||||||
|
.no-events();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
20
src/styles/pages/login.less
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
.login-button {
|
||||||
|
width: 20%;
|
||||||
|
margin: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.register-button {
|
||||||
|
width: 50%;
|
||||||
|
margin: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login_page {
|
||||||
|
position: absolute;
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
padding: 24px;
|
||||||
|
background-color: #232323;
|
||||||
|
}
|
@ -34,16 +34,11 @@
|
|||||||
background: gold;
|
background: gold;
|
||||||
}
|
}
|
||||||
|
|
||||||
.event_message_3 {
|
|
||||||
color: #c0c0c0;
|
|
||||||
background: #505060;
|
|
||||||
}
|
|
||||||
|
|
||||||
td.ant-table-column-sort {
|
td.ant-table-column-sort {
|
||||||
color: black;
|
color: black;
|
||||||
background-color: #fafafa;
|
background-color: #fafafa;
|
||||||
}
|
}
|
||||||
|
|
||||||
.ant-table-tbody > tr > td.ant-table-cell-row-hover {
|
.ant-table-tbody > tr > td.ant-table-cell-row-hover {
|
||||||
color: black;
|
color: white;
|
||||||
}
|
}
|
||||||
|
@ -22,10 +22,8 @@
|
|||||||
|
|
||||||
& .icons {
|
& .icons {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
& > * {
|
gap: 15px;
|
||||||
margin-left: 15px;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7,8 +7,8 @@
|
|||||||
align-items: stretch;
|
align-items: stretch;
|
||||||
margin: 10px;
|
margin: 10px;
|
||||||
padding: 5px 10px;
|
padding: 5px 10px;
|
||||||
border-radius: 5px;
|
border-radius: 6px;
|
||||||
background: #00000009;
|
background: #2F2F2F;
|
||||||
height: @size;
|
height: @size;
|
||||||
min-width: @size * 1.75;
|
min-width: @size * 1.75;
|
||||||
|
|
||||||
|
@ -15,7 +15,7 @@ export const createLoginRules: Readonly<Rule[]> = [_min1, {
|
|||||||
|
|
||||||
export const loginRules: Readonly<Rule[]> = [...createLoginRules, {
|
export const loginRules: Readonly<Rule[]> = [...createLoginRules, {
|
||||||
required: true,
|
required: true,
|
||||||
message: 'Пожалуйста, введите логин',
|
message: 'Пожалуйста, введите логин!',
|
||||||
}]
|
}]
|
||||||
|
|
||||||
export const nameRules: Readonly<Rule[]> = [_min1, {
|
export const nameRules: Readonly<Rule[]> = [_min1, {
|
||||||
|