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",
|
||||
|
||||
"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_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 '@styles/index.css'
|
||||
import '@styles/components/download_link.less'
|
||||
|
||||
export type DownloadLinkProps = LinkProps & {
|
||||
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>
|
||||
|
||||
@ -36,7 +38,7 @@ export const GridItem = memo<GridItemProps>(({ children, row, col, rowSpan, colS
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={`asb-grid-item ${className || ''}`} style={gridItemStyle} {...other}>
|
||||
<div className={`dd-grid-item ${className || ''}`} style={gridItemStyle} {...other}>
|
||||
{children}
|
||||
</div>
|
||||
)
|
||||
|
@ -55,6 +55,8 @@ const _LayoutPortal = memo(() => {
|
||||
|
||||
const setLayoutProps = useCallback((props: LayoutPortalProps) => setProps({ ...defaultProps, ...props}), [])
|
||||
|
||||
const layoutPropsValue = useMemo(() => ({ setLayoutProps, openWellTreeSelector: () => setWellsTreeOpen(true) }), [setLayoutProps])
|
||||
|
||||
useEffect(() => {
|
||||
if (typeof showSelector === 'boolean')
|
||||
setWellsTreeOpen(showSelector)
|
||||
@ -72,7 +74,7 @@ const _LayoutPortal = memo(() => {
|
||||
return (
|
||||
<Layout className={`page-layout ${isAdmin ? 'page-layout-admin' : ''}`}>
|
||||
{(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'}>
|
||||
<button className={'sider-toogle'} onClick={() => setMenuCollapsed((prev) => !prev)}>
|
||||
<Logo onlyIcon={menuCollapsed} />
|
||||
@ -123,7 +125,7 @@ const _LayoutPortal = memo(() => {
|
||||
{topRightBlock}
|
||||
</div>
|
||||
)}
|
||||
<LayoutPropsContext.Provider value={setLayoutProps}>
|
||||
<LayoutPropsContext.Provider value={layoutPropsValue}>
|
||||
<Suspense fallback={fallback ?? <SuspenseFallback style={{ minHeight: '100%' }} />}>
|
||||
<Outlet />
|
||||
</Suspense>
|
||||
|
@ -1,7 +1,8 @@
|
||||
import { memo, ReactNode, useCallback, useEffect, useState } from 'react'
|
||||
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 { ColumnProps, DataType, makeColumn } from '.'
|
||||
@ -67,7 +68,9 @@ export const makeTagColumn = <T extends DataType>(
|
||||
return makeColumn(title, dataIndex, {
|
||||
editable: true,
|
||||
...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} />,
|
||||
})
|
||||
}
|
||||
|
@ -8,7 +8,7 @@ import TableSettingsChanger from './TableSettingsChanger'
|
||||
import type { OmitExtends } from '@utils/types'
|
||||
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 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 { BaseDataType, MinMax } from '@components/d3/types'
|
||||
import { ColorPicker, Color } from '@components/ColorPicker'
|
||||
import { ColorPicker, Color } from '@components/input/ColorPicker'
|
||||
|
||||
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})`}>
|
||||
<rect width={sizes.inlineWidth} height={sizes.chartsHeight} fill={backgroundColor} />
|
||||
</g>
|
||||
<g stroke={'black'}>
|
||||
<g stroke={'white'}>
|
||||
{d3.range(1, groups.length).map((i) => {
|
||||
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} />
|
||||
|
@ -16,10 +16,10 @@ export interface PointerIconProps {
|
||||
}
|
||||
|
||||
const defaultColors: PointerIconColors = {
|
||||
online: 'red',
|
||||
active: 'black',
|
||||
inactive: 'gray',
|
||||
unknown: 'gray',
|
||||
online: '#C32828',
|
||||
active: 'white',
|
||||
inactive: '#A7A7A7',
|
||||
unknown: '#7B7B7B',
|
||||
}
|
||||
|
||||
const defaultProps: PointerIconProps = {
|
||||
|
@ -16,10 +16,10 @@ export type WellIconProps = React.SVGProps<SVGSVGElement> & {
|
||||
}
|
||||
|
||||
const defaultColors: WellIconColors = {
|
||||
online: 'red',
|
||||
active: 'black',
|
||||
inactive: 'gray',
|
||||
unknown: 'gray',
|
||||
online: 'white',
|
||||
active: 'white',
|
||||
inactive: '#A7A7A7',
|
||||
unknown: '#7B7B7B',
|
||||
}
|
||||
|
||||
const defaultProps: WellIconProps = {
|
||||
@ -34,7 +34,7 @@ export const WellIcon = React.memo(({ width, height, state, online, colors, ...o
|
||||
return (
|
||||
<svg
|
||||
version={'1.1'}
|
||||
viewBox={'12 .64 9.2 9.2'}
|
||||
viewBox={'12 0 9 9'}
|
||||
xmlns={'http://www.w3.org/2000/svg'}
|
||||
xmlnsXlink={'http://www.w3.org/1999/xlink'}
|
||||
|
||||
@ -46,17 +46,15 @@ export const WellIcon = React.memo(({ width, height, state, online, colors, ...o
|
||||
|
||||
width={width}
|
||||
height={height}
|
||||
color={colors[state ?? 'unknown']}
|
||||
color={colors[state || 'unknown']}
|
||||
{...other}
|
||||
>
|
||||
<g>
|
||||
<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={'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'}/>
|
||||
</g>
|
||||
{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={'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'} />
|
||||
|
@ -2,7 +2,7 @@ import { memo, useCallback, useEffect, useMemo, useState } from 'react'
|
||||
import { Input, Popover, Slider } from 'antd'
|
||||
import { CopyOutlined } from '@ant-design/icons'
|
||||
|
||||
import { copyToClipboard } from './factory'
|
||||
import { copyToClipboard } from '@components/factory'
|
||||
|
||||
import '@styles/components/color_picker.less'
|
||||
|
@ -7,10 +7,10 @@ import { WellIcon, WellIconState } from '@components/icons'
|
||||
import { DepositDto, WellDto } from '@api'
|
||||
import { isRawDate } from '@utils'
|
||||
|
||||
import { ReactComponent as DepositIcon } from '@images/DepositIcon.svg'
|
||||
import { ReactComponent as ClusterIcon } from '@images/ClusterIcon.svg'
|
||||
import { ReactComponent as DepositIcon } from '@images/components/well_tree_selector/DepositIcon.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}`
|
||||
@ -175,6 +175,7 @@ export const WellTreeSelector = memo<WellTreeSelectorProps>(({ expand, current,
|
||||
<Drawer open={open} mask={false} onClose={onClose} title={'Список скважин'}>
|
||||
<Tree
|
||||
{...other}
|
||||
className={'well-tree-selector'}
|
||||
showIcon
|
||||
selectedKeys={selected}
|
||||
treeData={wellsTree}
|
||||
|
@ -1,9 +1,10 @@
|
||||
import { memo } from 'react'
|
||||
import { Tag, Tooltip } from 'antd'
|
||||
import { Tooltip } from 'antd'
|
||||
|
||||
import { UserRoleDto } from '@api'
|
||||
import { Grid, GridItem } from '@components/Grid'
|
||||
import PermissionView from './PermissionView'
|
||||
import TagList from '../TagList'
|
||||
|
||||
export type RoleViewProps = {
|
||||
role?: UserRoleDto
|
||||
@ -26,12 +27,8 @@ export const RoleView = memo<RoleViewProps>(({ role }) => {
|
||||
|
||||
<GridItem row={2} col={1}>Включённые роли:</GridItem>
|
||||
{hasIncludedRoles ? (
|
||||
<GridItem row={3} col={1} colSpan={3}>
|
||||
{role.roles?.map((role, i) => (
|
||||
<Tag key={i} color={'blue'}>
|
||||
<RoleView role={role} />
|
||||
</Tag>
|
||||
))}
|
||||
<GridItem row={3} col={1} colSpan={3} style={{ display: 'flex', flexWrap: 'wrap', gap: 5 }}>
|
||||
<TagList items={role.roles} render={(role) => <RoleView role={role} />} />
|
||||
</GridItem>
|
||||
) : (
|
||||
<GridItem row={2} col={2}>Отсутствуют</GridItem>
|
||||
@ -42,12 +39,8 @@ export const RoleView = memo<RoleViewProps>(({ role }) => {
|
||||
|
||||
<GridItem row={4 + hasIncludedRoles} col={1}>Разрешения:</GridItem>
|
||||
{hasPermissions ? (
|
||||
<GridItem row={5 + hasIncludedRoles} col={1} colSpan={3}>
|
||||
{role.permissions?.map((permission, i) => (
|
||||
<Tag key={i} color={'blue'}>
|
||||
<PermissionView info={permission} />
|
||||
</Tag>
|
||||
))}
|
||||
<GridItem row={5 + hasIncludedRoles} col={1} colSpan={3} style={{ display: 'flex', flexWrap: 'wrap', gap: 5 }}>
|
||||
<TagList items={role.permissions} render={(permission) => <PermissionView info={permission} />} />
|
||||
</GridItem>
|
||||
) : (
|
||||
<GridItem row={4 + hasIncludedRoles} col={2}>Отсутствуют</GridItem>
|
||||
|
@ -28,9 +28,9 @@ export const defaultSettings: WidgetSettings = {
|
||||
label: 'Виджет',
|
||||
formatter: defaultFormatter,
|
||||
|
||||
labelColor: '#000000',
|
||||
valueColor: '#000000',
|
||||
backgroundColor: '#f6f6f6',
|
||||
labelColor: '#FFFFFF',
|
||||
valueColor: '#FFFFFF',
|
||||
backgroundColor: '#2F2F2F',
|
||||
unitColor: '#a0a0a0',
|
||||
}
|
||||
|
||||
|
@ -2,22 +2,30 @@ import { createContext, useContext, useEffect } from 'react'
|
||||
|
||||
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 Получить метод задания параметров заголовка и меню
|
||||
*/
|
||||
export const useLayoutProps = (props?: LayoutPortalProps) => {
|
||||
const setLayoutProps = useContext(LayoutPropsContext)
|
||||
export const useLayoutProps = (props?: LayoutPortalProps): LayoutPropsContext => {
|
||||
const { setLayoutProps, ...other } = useContext(LayoutPropsContext)
|
||||
|
||||
useEffect(() => {
|
||||
if (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 '@styles/include/antd_theme.less'
|
||||
import '@styles/index.css'
|
||||
import '@styles/index.less'
|
||||
|
||||
// OpenAPI.BASE = 'http://localhost:3000'
|
||||
// TODO: Удалить взятие из 'token' в следующем релизе, вставлено для совместимости
|
||||
|
@ -18,15 +18,13 @@ export const TelemetryInfo = memo(({ info, danger, ...other }) => (
|
||||
bordered
|
||||
column={1}
|
||||
size={'small'}
|
||||
style={{ background: 'white' }}
|
||||
className={'telemetry_merger_info'}
|
||||
{...other}
|
||||
>
|
||||
{Object.keys({ ...lables, ...info }).map(key => (
|
||||
<Item
|
||||
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>
|
||||
))}
|
||||
</Descriptions>
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { Button, Input, Tag } from 'antd'
|
||||
import { Button, Input } from 'antd'
|
||||
import { UserSwitchOutlined } from '@ant-design/icons'
|
||||
import { memo, useCallback, useEffect, useMemo, useState } from 'react'
|
||||
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 RoleTag from './RoleTag'
|
||||
import TagList from '@components/TagList'
|
||||
|
||||
const SEARCH_TIMEOUT = 400
|
||||
|
||||
@ -107,25 +108,20 @@ const UserController = memo(() => {
|
||||
const filters = makeTextFilters(users, ['surname', 'name', 'patronymic', 'email'])
|
||||
const roleFilters = [{ text: 'Без роли', value: null }, ...roles.map((role) => ({ text: role.caption, value: role.caption }))]
|
||||
|
||||
const rolesRender = (item) => item?.map((elm) => (
|
||||
<Tag key={elm} color={'blue'}>
|
||||
const rolesRender = (item) => (
|
||||
<TagList
|
||||
items={item}
|
||||
render={(elm) => (
|
||||
<RoleView role={roles.find((role) => role.caption === elm)} />
|
||||
</Tag>
|
||||
)) ?? '-'
|
||||
)}
|
||||
/>
|
||||
)
|
||||
|
||||
setColumns([
|
||||
makeTextColumn('Логин', 'login', null, null, null, {
|
||||
formItemRules: [
|
||||
{ required: true },
|
||||
...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, {
|
||||
|
@ -1,13 +1,16 @@
|
||||
import { memo, useMemo, useCallback } from 'react'
|
||||
import { Link, useLocation } from 'react-router-dom'
|
||||
import { Map as PigeonMap, Overlay } from 'pigeon-maps'
|
||||
import { Popover, Badge } from 'antd'
|
||||
import { Popover, Button } from 'antd'
|
||||
|
||||
import { useDepositList } from '@asb/context'
|
||||
import { PointerIcon } from '@components/icons'
|
||||
import { useDepositList, useLayoutProps } from '@asb/context'
|
||||
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)
|
||||
|
||||
@ -39,18 +42,19 @@ const calcViewParams = (clusters) => {
|
||||
const Map = memo(() => {
|
||||
const deposits = useDepositList()
|
||||
const location = useLocation()
|
||||
const { openWellTreeSelector } = useLayoutProps()
|
||||
|
||||
const makeDepositLinks = useCallback((clusters) => (
|
||||
const makeClusterLinks = useCallback((wells) => (
|
||||
<div>
|
||||
{clusters.map(cluster => (
|
||||
{wells.map(well => (
|
||||
<Link
|
||||
key={cluster.id}
|
||||
key={well.id}
|
||||
to={{
|
||||
pathname: `/cluster/${cluster.id}`,
|
||||
pathname: `/well/${well.id}`,
|
||||
state: { from: location.pathname }
|
||||
}}
|
||||
>
|
||||
<div>{cluster.caption}</div>
|
||||
<div>{well.caption}</div>
|
||||
</Link>
|
||||
))}
|
||||
</div>
|
||||
@ -61,31 +65,39 @@ const Map = memo(() => {
|
||||
return (
|
||||
<div className={'deposit-page'}>
|
||||
<PigeonMap {...viewParams}>
|
||||
{deposits.map(deposit => {
|
||||
const anchor = [deposit.latitude, deposit.longitude]
|
||||
const links = makeDepositLinks(deposit.clusters)
|
||||
{deposits.map(deposit => deposit.clusters.map(cluster => {
|
||||
const anchor = [cluster.latitude, cluster.longitude]
|
||||
const count = cluster.wells.length
|
||||
const title = `${deposit.caption} / ${cluster.caption}`
|
||||
const links = makeClusterLinks(cluster.wells)
|
||||
|
||||
return (
|
||||
<Overlay width={32} anchor={anchor} key={anchor.join(' ')}>
|
||||
<Overlay width={65} anchor={anchor} key={anchor.join(' ')}>
|
||||
<Popover
|
||||
content={links}
|
||||
trigger={['click']}
|
||||
title={(
|
||||
<Link to={{ pathname: `/deposit/${deposit.id}` }}>
|
||||
{deposit.caption}
|
||||
<Link to={{ pathname: `/cluster/${cluster.id}` }}>
|
||||
{title}
|
||||
</Link>
|
||||
)}
|
||||
>
|
||||
<div className={'pointer'}>
|
||||
<Badge count={deposit.clusters.length}>
|
||||
<PointerIcon state={'active'} width={48} height={59} />
|
||||
</Badge>
|
||||
<div className={'pointer'} title={title}>
|
||||
{count <= 1 ? (
|
||||
<WellMapIcon />
|
||||
) : (
|
||||
<ClusterMapIcon count={count} />
|
||||
)}
|
||||
</div>
|
||||
</Popover>
|
||||
</Overlay>
|
||||
)
|
||||
})}
|
||||
}))}
|
||||
</PigeonMap>
|
||||
<button className={'dd-deposit-open-selector-btn'} onClick={openWellTreeSelector}>
|
||||
<MapPointer />
|
||||
<span>Выберите месторождение</span>
|
||||
</button>
|
||||
</div>
|
||||
)
|
||||
})
|
||||
|
@ -16,7 +16,7 @@ const breadcrumb = makeMenuBreadcrumbItemsRender(menuItems, /^\/deposit\/[^\/#?]
|
||||
const Deposit = memo(() => {
|
||||
const { '*': param } = useParams()
|
||||
|
||||
const setLayoutProps = useLayoutProps()
|
||||
const { setLayoutProps } = useLayoutProps()
|
||||
const deposits = useDepositList()
|
||||
|
||||
const root = useRootPath()
|
||||
|
@ -9,7 +9,6 @@ import { makeGroupColumn, makeNumericColumn, makeNumericRender, makeTextColumn,
|
||||
import { OperationStatService, WellOperationService } from '@api'
|
||||
import { arrayOrDefault, withPermissions } from '@utils'
|
||||
|
||||
import '@styles/index.css'
|
||||
import '@styles/pages/statistics.less'
|
||||
|
||||
const { Text } = Typography
|
||||
|
@ -17,7 +17,6 @@ import { MeasureService } from '@api'
|
||||
|
||||
import { View } from './View'
|
||||
|
||||
import '@styles/index.css'
|
||||
import '@styles/pages/measure.css'
|
||||
|
||||
const createEditingColumns = (cols, renderDelegate) =>
|
||||
|
@ -3,7 +3,6 @@ import { Empty, Form } from 'antd'
|
||||
|
||||
import { Grid, GridItem } from '@components/Grid'
|
||||
|
||||
import '@styles/index.css'
|
||||
import '@styles/pages/measure.css'
|
||||
|
||||
export const View = memo(({ columns, item }) => !item || !columns?.length ? (
|
||||
|
@ -118,15 +118,16 @@ const DashboardNNB = memo(({ enableEditing = false }) => {
|
||||
const navigate = useNavigate()
|
||||
const selectedGroup = getTabname()
|
||||
|
||||
if (!selectedGroup && groups?.length > 0)
|
||||
navigate(`${rootPath}/${groups[0].id}`)
|
||||
|
||||
|
||||
const group = useMemo(() => ({
|
||||
editable: true,
|
||||
...groups.find(({ id }) => `${id}` === selectedGroup),
|
||||
}), [groups, selectedGroup])
|
||||
|
||||
useEffect(() => {
|
||||
if (!selectedGroup && groups?.length > 0)
|
||||
navigate(`${rootPath}/${groups[0].id}`)
|
||||
}, [selectedGroup, groups, rootPath, navigate])
|
||||
|
||||
useEffect(() => {
|
||||
invokeWebApiWrapperAsync(
|
||||
async () => {
|
||||
@ -249,7 +250,7 @@ const DashboardNNB = memo(({ enableEditing = false }) => {
|
||||
/>
|
||||
))}
|
||||
<WidgetSettingsWindow
|
||||
visible={!!selectedSettings}
|
||||
open={!!selectedSettings}
|
||||
onCancel={() => setSelectedSettings(null)}
|
||||
settings={selectedSettings}
|
||||
onEdit={onEdit}
|
||||
|
@ -28,7 +28,7 @@ const categoryDictionary = {
|
||||
|
||||
// Конфигурация таблицы
|
||||
export const makeMessageColumns = (idWell) => [
|
||||
makeDateColumn('Дата', 'date', undefined, undefined, { width: '120px' }),
|
||||
makeDateColumn('Дата', 'date', undefined, undefined, { width: 130 }),
|
||||
makeNumericColumn('Глубина, м', 'wellDepth', (depth, item) => (
|
||||
<Tooltip title={'Нажмите для перехода в архив'}>
|
||||
<Link
|
||||
|
@ -13,15 +13,15 @@ import { useElementSize } from '@utils'
|
||||
|
||||
import { makeGetColor } from '@pages/Well/WellOperations/Tvd'
|
||||
|
||||
import '@styles/limiting_parameter_statistics.less'
|
||||
import '@styles/pages/limiting_parameter_statistics.less'
|
||||
|
||||
const columns = [
|
||||
makeColumn('Цвет', 'color', { width: 50, render: (d) => (
|
||||
<div style={{ backgroundColor: d, padding: '5px 0' }} />
|
||||
) }),
|
||||
makeTextColumn('Уставка', 'nameFeedRegulator'),
|
||||
makeNumericColumn('Проходка, м', 'depth'),
|
||||
makeNumericColumn('Кол-во включений', 'numberInclusions', undefined, undefined, makeNumericRender(0)),
|
||||
makeNumericColumn('Проходка, м', 'depth', undefined, undefined, 140),
|
||||
makeNumericColumn('Кол-во включений', 'numberInclusions', makeNumericRender(0), undefined, 150),
|
||||
]
|
||||
|
||||
export const LimitingParameterStatistics = memo(() => {
|
||||
@ -59,16 +59,16 @@ export const LimitingParameterStatistics = memo(() => {
|
||||
}
|
||||
}
|
||||
if (record.idFeedRegulator === selectedRegulator)
|
||||
out.style = { background: '#FAFAFA', fontSize: '16px', fontWeight: '600' }
|
||||
out.className = 'dd-selected-row'
|
||||
return out
|
||||
}, [selectedRegulator])
|
||||
|
||||
const onPieOver = useCallback(function (e, d) {
|
||||
const onPieOver = useCallback(function (_, d) { // Стрелочная функция не подойдёт из-за использования `this`
|
||||
setSelectedRegulator(d.data.idFeedRegulator)
|
||||
d3.select(this).attr('transform', 'scale(1.05)')
|
||||
}, [])
|
||||
|
||||
const onPieOut = useCallback(function (e, d) {
|
||||
const onPieOut = useCallback(function () { // Стрелочная функция не подойдёт из-за использования `this`
|
||||
setSelectedRegulator(null)
|
||||
d3.select(this).attr('transform', 'scale(1)')
|
||||
}, [])
|
||||
@ -181,15 +181,15 @@ export const LimitingParameterStatistics = memo(() => {
|
||||
<Button onClick={() => setIsOpen(true)}>Статистика использования уставок</Button>
|
||||
<Modal
|
||||
centered
|
||||
width={1024}
|
||||
width={950}
|
||||
footer={false}
|
||||
title={'Статистика использования уставок'}
|
||||
onCancel={() => setIsOpen(false)}
|
||||
open={isOpen}
|
||||
>
|
||||
<LoaderPortal show={isLoading}>
|
||||
<LoaderPortal show={isLoading} className={'limit-parameter-stats-page'}>
|
||||
<div className={'filter-groups'}>
|
||||
<Input.Group compact style={{ flex: 1 }}>
|
||||
<Input.Group compact style={{ flex: 2 }}>
|
||||
<Input
|
||||
addonBefore={(
|
||||
<Radio
|
||||
@ -203,7 +203,7 @@ export const LimitingParameterStatistics = memo(() => {
|
||||
disabled={mode !== 'depth'}
|
||||
prefix={'От'}
|
||||
suffix={'м'}
|
||||
style={{ width: 'calc(50% + 113px / 2)', textAlign: 'right' }}
|
||||
style={{ width: 'calc(50% + 128px / 2)', textAlign: 'right' }}
|
||||
onChange={(e) => onDepthChanged(e, 'from')}
|
||||
value={depthFilter.from}
|
||||
/>
|
||||
@ -212,12 +212,12 @@ export const LimitingParameterStatistics = memo(() => {
|
||||
disabled={mode !== 'depth'}
|
||||
prefix={'До'}
|
||||
suffix={'м'}
|
||||
style={{ width: 'calc(50% - 113px / 2)', textAlign: 'right' }}
|
||||
style={{ width: 'calc(50% - 128px / 2)', textAlign: 'right' }}
|
||||
onChange={(e) => onDepthChanged(e, 'to')}
|
||||
value={depthFilter.to}
|
||||
/>
|
||||
</Input.Group>
|
||||
<Input.Group compact style={{ flex: 1 }}>
|
||||
<Input.Group compact style={{ flex: 3 }}>
|
||||
<Input style={{ width: 128 }} addonBefore={(
|
||||
<Radio
|
||||
checked={mode === 'time'}
|
||||
@ -240,9 +240,9 @@ export const LimitingParameterStatistics = memo(() => {
|
||||
{data ? (
|
||||
<svg ref={setSvgRef} width={'100%'} height={'100%'}>
|
||||
<g transform={`translate(${width / 2}, ${height / 2})`}>
|
||||
<g className={'slices'} stroke={'#0005'} />
|
||||
<g className={'labels'} fill={'black'} />
|
||||
<g className={'lines'} fill={'none'} stroke={'black'} />
|
||||
<g className={'slices'} />
|
||||
<g className={'labels'} />
|
||||
<g className={'lines'} />
|
||||
</g>
|
||||
</svg>
|
||||
) : (
|
||||
|
@ -1,7 +1,6 @@
|
||||
import { Button, Modal } from 'antd'
|
||||
import { useState, useEffect, memo, useCallback, useMemo } from 'react'
|
||||
|
||||
import { useWell } from '@asb/context'
|
||||
import { Table } from '@components/Table'
|
||||
import { UserView } from '@components/views'
|
||||
import LoaderPortal from '@components/LoaderPortal'
|
||||
@ -12,7 +11,7 @@ import { SetpointsService } from '@api'
|
||||
import SetpointSender from './SetpointSender'
|
||||
import { SetpointViewer, getSetpointStatus } from './SetpointViewer'
|
||||
|
||||
export const Setpoints = memo(({ ...other }) => {
|
||||
export const Setpoints = memo(({ well, ...other }) => {
|
||||
const [isModalVisible, setIsModalVisible] = useState(false)
|
||||
const [isSenderVisible, setIsSenderVisible] = useState(false)
|
||||
const [isViewerVisible, setIsViewerVisible] = useState(false)
|
||||
@ -21,8 +20,6 @@ export const Setpoints = memo(({ ...other }) => {
|
||||
const [selected, setSelected] = useState(null)
|
||||
const [setpointNames, setSetpointNames] = useState([])
|
||||
|
||||
const [well] = useWell()
|
||||
|
||||
useEffect(() => {
|
||||
invokeWebApiWrapperAsync(
|
||||
async () => {
|
||||
|
@ -1,17 +1,14 @@
|
||||
import { memo, useCallback, useEffect, useState } from 'react'
|
||||
|
||||
import { useWell } from '@asb/context'
|
||||
import { WirelineView } from '@components/views'
|
||||
import { invokeWebApiWrapperAsync } from '@components/factory'
|
||||
import { TelemetryWirelineRunOutService } from '@api'
|
||||
|
||||
|
||||
export const WirelineRunOut = memo(() => {
|
||||
export const WirelineRunOut = memo(({ well }) => {
|
||||
const [twro, setTwro] = useState({})
|
||||
const [isLoading, setIsLoading] = useState(false)
|
||||
|
||||
const [well] = useWell()
|
||||
|
||||
const update = useCallback(() => invokeWebApiWrapperAsync(
|
||||
async () => {
|
||||
const twro = await TelemetryWirelineRunOutService.getData(well.id)
|
||||
|
@ -3,7 +3,7 @@ import { BehaviorSubject, buffer, throttleTime } from 'rxjs'
|
||||
import { useSearchParams } from 'react-router-dom'
|
||||
import { Alert, Button, Select } from 'antd'
|
||||
|
||||
import { useWell } from '@asb/context'
|
||||
import { useTopRightBlock, useWell } from '@asb/context'
|
||||
import LoaderPortal from '@components/LoaderPortal'
|
||||
import { CopyUrlButton } from '@components/CopyUrl'
|
||||
import { D3MonitoringCharts } from '@components/d3/monitoring'
|
||||
@ -27,10 +27,8 @@ import WirelineRunOut from './WirelineRunOut'
|
||||
import { Setpoints } from './Setpoints'
|
||||
import { cursorRender } from './cursorRender'
|
||||
|
||||
import MomentStabPicEnabled from '@images/DempherOn.png'
|
||||
import MomentStabPicDisabled from '@images/DempherOff.png'
|
||||
import SpinPicEnabled from '@images/SpinEnabled.png'
|
||||
import SpinPicDisabled from '@images/SpinDisabled.png'
|
||||
import { ReactComponent as DempherIcon } from '@images/pages/well/telemetry/monitoring/DempherIcon.svg'
|
||||
import { ReactComponent as SpinIcon } from '@images/pages/well/telemetry/monitoring/SpinIcon.svg'
|
||||
|
||||
import '@styles/pages/telemetry_view.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 [well, updateWell] = useWell()
|
||||
const setTopRightBlock = useTopRightBlock()
|
||||
const [searchParams, setSearchParams] = useSearchParams()
|
||||
|
||||
const [dataSaub, setDataSaub] = useState([])
|
||||
@ -91,6 +90,7 @@ const TelemetryView = memo(() => {
|
||||
|
||||
const [archiveMode, setArchiveMode] = useState(false)
|
||||
|
||||
|
||||
const onStatusChanged = useCallback((value) => updateWell({ idState: value }), [well])
|
||||
|
||||
const handleDataSaub = useCallback((data, replace = false) => {
|
||||
@ -251,6 +251,17 @@ const TelemetryView = memo(() => {
|
||||
setEndDate(new Date(saubLast.date))
|
||||
}, [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 (
|
||||
<LoaderPortal show={showLoader} style={{ flexGrow: 1 }}>
|
||||
<div className={'telemetry-view-page'}>
|
||||
@ -265,13 +276,11 @@ const TelemetryView = memo(() => {
|
||||
<Option value={2}>Завершено</Option>
|
||||
</Select>
|
||||
</div>
|
||||
<Setpoints />
|
||||
<LimitingParameterStatistics />
|
||||
<WirelineRunOut />
|
||||
<div className={'icons'}>
|
||||
<img src={isTorqueStabEnabled(spinLast) ? MomentStabPicEnabled : MomentStabPicDisabled} alt={'TorqueMaster'} />
|
||||
<img src={isSpinEnabled(spinLast) ? SpinPicEnabled : SpinPicDisabled} alt={'SpinMaster'} />
|
||||
<h2 style={{ marginBottom: 0, fontWeight: 'bold', color: isMseEnabled(saubLast) ? 'green' : 'lightgrey' }}>MSE</h2>
|
||||
<DempherIcon color={isTorqueStabEnabled(spinLast) ? '#24DE6E' : '#4F4F4F'} />
|
||||
<SpinIcon color={isSpinEnabled(spinLast) ? '#24DE6E' : '#4F4F4F'} />
|
||||
<spin style={{ fontSize: 24, fontWeight: 900, color: isMseEnabled(saubLast) ? '#24DE6E' : '#4F4F4F' }}>MSE</spin>
|
||||
</div>
|
||||
</div>
|
||||
{archiveMode && (
|
||||
@ -300,10 +309,6 @@ const TelemetryView = memo(() => {
|
||||
<PeriodPicker value={chartInterval / 1000} onChange={(value) => setChartInterval(value * 1000)} />
|
||||
</div>
|
||||
<Button onClick={() => chartMethods?.setSettingsVisible(true)}>Настроить графики</Button>
|
||||
<Button onClick={() => setArchiveMode((prev) => !prev)} danger={archiveMode}>
|
||||
{archiveMode ? 'Выйти из архива' : 'Войти в архив'}
|
||||
</Button>
|
||||
{archiveMode && <CopyUrlButton />}
|
||||
</div>
|
||||
<D3MonitoringCharts
|
||||
{...chartProps}
|
||||
|
@ -4,8 +4,6 @@ import { memo, useMemo } from 'react'
|
||||
import { RootPathContext, useRootPath } from '@asb/context'
|
||||
import { withPermissions } from '@utils'
|
||||
|
||||
import '@styles/index.css'
|
||||
|
||||
const Telemetry = memo(() => {
|
||||
const root = useRootPath()
|
||||
const rootPath = useMemo(() => `${root}/telemetry`, [root])
|
||||
|
@ -17,7 +17,6 @@ import StatExport from './StatExport'
|
||||
import NetGraphExport from './NetGraphExport'
|
||||
import AdditionalTables from './AdditionalTables'
|
||||
|
||||
import '@styles/index.css'
|
||||
import '@styles/pages/tvd.less'
|
||||
|
||||
const operationsColors = [
|
||||
|
@ -10,8 +10,6 @@ import { WellService } from '@api'
|
||||
|
||||
import { WellNavigationMenu, menuItems } from './WellNavigationMenu'
|
||||
|
||||
import '@styles/index.css'
|
||||
|
||||
const Measure = lazy(() => import('./Measure'))
|
||||
const Reports = lazy(() => import('./Reports'))
|
||||
const WellCase = lazy(() => import('./WellCase'))
|
||||
@ -50,7 +48,7 @@ const Well = memo(() => {
|
||||
const root = useRootPath()
|
||||
const rootPath = useMemo(() => `${root}/well/${idWell}`, [root, idWell])
|
||||
|
||||
const setLayoutProps = useLayoutProps()
|
||||
const { setLayoutProps } = useLayoutProps()
|
||||
|
||||
const updateWell = useCallback((data) => invokeWebApiWrapperAsync(
|
||||
async () => {
|
||||
|
@ -11,7 +11,7 @@ import { AuthService } from '@api'
|
||||
|
||||
import Logo from '@images/Logo'
|
||||
|
||||
import '@styles/index.css'
|
||||
import '@styles/pages/login.less'
|
||||
|
||||
const Login = memo(() => {
|
||||
const [showLoader, setShowLoader] = useState(false)
|
||||
@ -36,10 +36,10 @@ const Login = memo(() => {
|
||||
<div style={{ display: 'flex', flexDirection: 'column' }}>
|
||||
<Logo style={{ marginBottom: '10px' }} />
|
||||
<LoaderPortal show={showLoader}>
|
||||
<Card bordered title={'Система мониторинга'} className={'shadow'} style={{ width: 350 }}>
|
||||
<Card bordered title={'Вход в ЕЦП'} className={'shadow'} style={{ width: 350 }}>
|
||||
<Form onFinish={handleLogin}>
|
||||
<Form.Item name={'login'} rules={loginRules}>
|
||||
<Input placeholder={'Пользователь'} prefix={<UserOutlined />} />
|
||||
<Input placeholder={'Логин'} prefix={<UserOutlined />} />
|
||||
</Form.Item>
|
||||
<Form.Item name={'password'} rules={passwordRules}>
|
||||
<Input.Password placeholder={'Пароль'} prefix={<LockOutlined />} />
|
||||
|
@ -8,7 +8,6 @@ import {
|
||||
EyeTwoTone
|
||||
} from '@ant-design/icons'
|
||||
|
||||
import { AuthService } from '@api'
|
||||
import LoaderPortal from '@components/LoaderPortal'
|
||||
import { invokeWebApiWrapperAsync } from '@components/factory'
|
||||
import {
|
||||
@ -21,9 +20,12 @@ import {
|
||||
phoneRules
|
||||
} from '@utils/validationRules'
|
||||
import { withPermissions } from '@utils'
|
||||
import { AuthService } from '@api'
|
||||
|
||||
import Logo from '@images/Logo'
|
||||
|
||||
import '@styles/pages/login.less'
|
||||
|
||||
const surnameRules = [...nameRules, { required: true, message: 'Пожалуйста, введите фамилию!' }]
|
||||
const regEmailRules = [{ required: true, message: 'Пожалуйста, введите email!' }, ...emailRules]
|
||||
const confirmPasswordRules = [
|
||||
@ -38,7 +40,6 @@ const confirmPasswordRules = [
|
||||
})
|
||||
]
|
||||
|
||||
const logoIcon = <Logo width={130} />
|
||||
const showPasswordIcon = visible => (visible ? <EyeTwoTone /> : <EyeInvisibleOutlined />)
|
||||
|
||||
const createInput = (name, placeholder, rules, isPassword, dependencies) => (
|
||||
@ -66,10 +67,13 @@ export const Register = memo(() => {
|
||||
), [navigate])
|
||||
|
||||
return (
|
||||
<LoaderPortal show={showLoader} className={'loader-container login_page shadow'}>
|
||||
<Card title={'Система мониторинга'} className={'shadow'} bordered={true} style={{ width: 350 }} extra={logoIcon}>
|
||||
<div className={'login_page shadow'}>
|
||||
<div style={{ display: 'flex', flexDirection: 'column' }}>
|
||||
<Logo style={{ marginBottom: '10px' }} />
|
||||
<LoaderPortal show={showLoader}>
|
||||
<Card title={'Оставить заявку на регистрацию'} className={'shadow'} style={{ width: 350 }}>
|
||||
<Form onFinish={handleRegister}>
|
||||
{createInput('login', 'Пользователь', [...loginRules, ...createLoginRules])}
|
||||
{createInput('login', 'Логин', [...loginRules, ...createLoginRules])}
|
||||
{createInput('password', 'Пароль', [...passwordRules, ...createPasswordRules], true, null)}
|
||||
{createInput('confirmPassword', 'Подтверждение пароля', confirmPasswordRules, true, ['password'])}
|
||||
{createInput('name', 'Имя', nameRules)}
|
||||
@ -89,6 +93,8 @@ export const Register = memo(() => {
|
||||
</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;
|
||||
@admin-bg: #900;
|
||||
@admin-active-bg: #413f3d;
|
||||
@bg-color: #232323;
|
||||
@text-color: white - @bg-color;
|
||||
|
||||
.no-select {
|
||||
-webkit-user-select: none;
|
||||
@ -25,7 +27,7 @@
|
||||
|
||||
height: 100vh;
|
||||
|
||||
& .menu-sider {
|
||||
& .dd-menu-sider {
|
||||
overflow-x: hidden;
|
||||
overflow-y: auto;
|
||||
height: 100%;
|
||||
@ -86,7 +88,8 @@
|
||||
|
||||
& .page-content {
|
||||
overflow-y: auto;
|
||||
background: white;
|
||||
background: @bg-color;
|
||||
color: @text-color;
|
||||
|
||||
& .breadcrumb-block {
|
||||
display: flex;
|
||||
@ -115,11 +118,11 @@
|
||||
background-color: @admin-bg;
|
||||
}
|
||||
|
||||
.menu-sider {
|
||||
.dd-menu-sider {
|
||||
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;
|
||||
& .ant-menu-title-content > a {
|
||||
color: white;
|
||||
@ -128,10 +131,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
.site-layout-background {
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 1280px) {
|
||||
.page-layout {
|
||||
--sheet-padding: 10px;
|
||||
|
@ -1,20 +1,25 @@
|
||||
/* original from https://loading.io/css/ */
|
||||
|
||||
@loader-bg: rgba(255, 255, 255, 0.1);
|
||||
@loader-color: rgb(226, 29, 29);
|
||||
|
||||
.lds-ripple {
|
||||
display: inline-block;
|
||||
position: absolute;
|
||||
width: 80px;
|
||||
height: 80px;
|
||||
}
|
||||
.lds-ripple div {
|
||||
|
||||
& div {
|
||||
position: absolute;
|
||||
border: 4px solid rgb(226, 29, 29);
|
||||
border: 4px solid @loader-color;
|
||||
opacity: 1;
|
||||
border-radius: 50%;
|
||||
animation: lds-ripple 1s cubic-bezier(0, 0.2, 0.8, 1) infinite;
|
||||
}
|
||||
.lds-ripple div:nth-child(2) {
|
||||
}
|
||||
|
||||
& div:nth-child(2) {
|
||||
animation-delay: -0.5s;
|
||||
}
|
||||
}
|
||||
@keyframes lds-ripple {
|
||||
0% {
|
||||
@ -33,12 +38,12 @@
|
||||
}
|
||||
}
|
||||
|
||||
.loader-container{
|
||||
.loader-container {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr 1fr;
|
||||
}
|
||||
|
||||
.loader-content{
|
||||
.loader-content {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
@ -46,14 +51,14 @@
|
||||
grid-column-start: 1;
|
||||
grid-column-end: span 3;
|
||||
grid-row-start: 1;
|
||||
}
|
||||
|
||||
.loader-content.loader-content-fill {
|
||||
&.loader-content-fill {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.loader-overlay{
|
||||
.loader-overlay {
|
||||
grid-column-start: 1;
|
||||
grid-column-end: span 3;
|
||||
grid-row-start: 1;
|
||||
@ -66,13 +71,13 @@
|
||||
border-radius: 40px;
|
||||
}
|
||||
|
||||
.loader-fade{
|
||||
.loader-fade {
|
||||
grid-column-start: 1;
|
||||
grid-column-end: span 3;
|
||||
grid-row-start: 1;
|
||||
background-color: rgba(255, 255, 255, 0.4);
|
||||
background-color: @loader-bg;
|
||||
align-self: stretch;
|
||||
justify-self: stretch;
|
||||
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';
|
||||
/*
|
||||
* ЭТО ФАЙЛ НАСТРОЙКИ ТЕМЫ И КОМПОНЕНТОВ ТЕМЫ.
|
||||
* НЕ ПИШИТЕ ТУТ СТИЛИ ДЛЯ КАСТОМНЫХ КОМПОНЕНТОВ.
|
||||
*/
|
||||
|
||||
// Переменные для темы тут:
|
||||
// https://github.com/ant-design/ant-design/blob/master/components/style/themes/default.less
|
||||
@main: #222629;
|
||||
@main-dark: #191C1E;
|
||||
@main-light: #2E3338;
|
||||
@text: #ddd;
|
||||
@text-light: #fff;
|
||||
@text-dark: #222;
|
||||
@text-disabled: #999;
|
||||
|
||||
@primary-color: #C32828; // rgb(195, 40, 40)
|
||||
@layout-header-background:#413F3D; // rgb(65, 63, 61)
|
||||
@primary: #C32828;
|
||||
@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{
|
||||
min-height:100%;
|
||||
@ -25,17 +25,6 @@ html {
|
||||
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{
|
||||
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;
|
||||
}
|
||||
|
||||
.event_message_3 {
|
||||
color: #c0c0c0;
|
||||
background: #505060;
|
||||
}
|
||||
|
||||
td.ant-table-column-sort {
|
||||
color: black;
|
||||
background-color: #fafafa;
|
||||
}
|
||||
|
||||
.ant-table-tbody > tr > td.ant-table-cell-row-hover {
|
||||
color: black;
|
||||
color: white;
|
||||
}
|
||||
|
@ -22,10 +22,8 @@
|
||||
|
||||
& .icons {
|
||||
display: flex;
|
||||
|
||||
& > * {
|
||||
margin-left: 15px;
|
||||
}
|
||||
align-items: center;
|
||||
gap: 15px;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -7,8 +7,8 @@
|
||||
align-items: stretch;
|
||||
margin: 10px;
|
||||
padding: 5px 10px;
|
||||
border-radius: 5px;
|
||||
background: #00000009;
|
||||
border-radius: 6px;
|
||||
background: #2F2F2F;
|
||||
height: @size;
|
||||
min-width: @size * 1.75;
|
||||
|
||||
|
@ -15,7 +15,7 @@ export const createLoginRules: Readonly<Rule[]> = [_min1, {
|
||||
|
||||
export const loginRules: Readonly<Rule[]> = [...createLoginRules, {
|
||||
required: true,
|
||||
message: 'Пожалуйста, введите логин',
|
||||
message: 'Пожалуйста, введите логин!',
|
||||
}]
|
||||
|
||||
export const nameRules: Readonly<Rule[]> = [_min1, {
|
||||
|