forked from ddrilling/asb_cloud_front
Добавлена страница Оценки по ЦБ
This commit is contained in:
parent
6a09ab9af3
commit
afed418b56
@ -1,6 +1,6 @@
|
|||||||
import { memo, useCallback, useEffect, useState, ReactNode } from 'react'
|
import { memo, useCallback, useEffect, useState } from 'react'
|
||||||
import { Table as RawTable, TableProps } from 'antd'
|
|
||||||
import { ColumnGroupType, ColumnType } from 'antd/lib/table'
|
import { ColumnGroupType, ColumnType } from 'antd/lib/table'
|
||||||
|
import { Table as RawTable, TableProps } from 'antd'
|
||||||
|
|
||||||
import { OmitExtends } from '@utils'
|
import { OmitExtends } from '@utils'
|
||||||
import { getTableSettings, setTableSettings } from '@utils/storage'
|
import { getTableSettings, setTableSettings } from '@utils/storage'
|
||||||
@ -9,50 +9,50 @@ import { applySettings, ColumnSettings, TableSettings } from '@utils/table_setti
|
|||||||
import TableSettingsChanger from './TableSettingsChanger'
|
import TableSettingsChanger from './TableSettingsChanger'
|
||||||
import { tryAddKeys } from './EditableTable'
|
import { tryAddKeys } from './EditableTable'
|
||||||
|
|
||||||
|
import '@styles/index.css'
|
||||||
|
|
||||||
export type BaseTableColumn<T = any> = ColumnGroupType<T> | ColumnType<T>
|
export type BaseTableColumn<T = any> = ColumnGroupType<T> | ColumnType<T>
|
||||||
export type TableColumns<T = any> = OmitExtends<BaseTableColumn<T>, ColumnSettings>[]
|
export type TableColumns<T = any> = OmitExtends<BaseTableColumn<T>, ColumnSettings>[]
|
||||||
|
|
||||||
export type TableContainer = TableProps<any> & {
|
export type TableContainer = TableProps<any> & {
|
||||||
columns: TableColumns
|
columns: TableColumns
|
||||||
dataSource: any[]
|
dataSource: any[]
|
||||||
tableName?: string
|
tableName?: string
|
||||||
showSettingsChanger?: boolean
|
showSettingsChanger?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
export const Table = memo<TableContainer>(({ columns, dataSource, tableName, showSettingsChanger, ...other }) => {
|
export const Table = memo<TableContainer>(({ columns, dataSource, tableName, showSettingsChanger, ...other }) => {
|
||||||
const [newColumns, setNewColumns] = useState<TableColumns>([])
|
const [newColumns, setNewColumns] = useState<TableColumns>([])
|
||||||
const [settings, setSettings] = useState<TableSettings>({})
|
const [settings, setSettings] = useState<TableSettings>({})
|
||||||
|
|
||||||
const onSettingsChanged = useCallback((settings?: TableSettings | null) => {
|
const onSettingsChanged = useCallback((settings?: TableSettings | null) => {
|
||||||
if (tableName)
|
if (tableName)
|
||||||
setTableSettings(tableName, settings)
|
setTableSettings(tableName, settings)
|
||||||
setSettings(settings ?? {})
|
setSettings(settings ?? {})
|
||||||
}, [tableName])
|
}, [tableName])
|
||||||
|
|
||||||
useEffect(() => setSettings(tableName ? getTableSettings(tableName) : {}), [tableName])
|
useEffect(() => setSettings(tableName ? getTableSettings(tableName) : {}), [tableName])
|
||||||
useEffect(() => setNewColumns(() => {
|
useEffect(() => setNewColumns(() => {
|
||||||
const newColumns = applySettings(columns, settings)
|
const newColumns = applySettings(columns, settings)
|
||||||
if (tableName && showSettingsChanger) {
|
if (tableName && showSettingsChanger) {
|
||||||
const oldTitle = newColumns[0].title
|
const oldTitle = newColumns[0].title
|
||||||
newColumns[0].title = (props) => (
|
newColumns[0].title = (props) => (
|
||||||
<div style={{ display: 'flex', flexDirection: 'column', alignItems: 'stretch', justifyContent: 'space-between', position: 'relative', padding: '16px 0' }}>
|
<div className={'first-column-title'}>
|
||||||
<TableSettingsChanger columns={columns} settings={settings} onChange={onSettingsChanged}/>
|
<TableSettingsChanger columns={columns} settings={settings} onChange={onSettingsChanged}/>
|
||||||
<div>
|
<div>{typeof oldTitle === 'function' ? oldTitle(props) : oldTitle}</div>
|
||||||
{typeof oldTitle === 'function' ? oldTitle(props) : oldTitle}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
)
|
||||||
)
|
}
|
||||||
}
|
return newColumns
|
||||||
return newColumns
|
}), [settings, columns, onSettingsChanged, showSettingsChanger, tableName])
|
||||||
}), [settings, columns, onSettingsChanged, showSettingsChanger, tableName])
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<RawTable
|
<RawTable
|
||||||
columns={newColumns}
|
columns={newColumns}
|
||||||
dataSource={tryAddKeys(dataSource)}
|
dataSource={tryAddKeys(dataSource)}
|
||||||
{...other}
|
{...other}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
export default Table
|
export default Table
|
||||||
|
77
src/components/WellSelector.jsx
Normal file
77
src/components/WellSelector.jsx
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
import { Tag, TreeSelect } from 'antd'
|
||||||
|
import { memo, useEffect, useState } from 'react'
|
||||||
|
|
||||||
|
import { invokeWebApiWrapperAsync } from '@components/factory'
|
||||||
|
import { hasPermission } from '@utils/permissions'
|
||||||
|
import { DepositService } from '@api'
|
||||||
|
|
||||||
|
export const getTreeData = async () => {
|
||||||
|
const deposits = await DepositService.getDeposits()
|
||||||
|
const wellsTree = deposits.map((deposit, dIdx) => ({
|
||||||
|
title: deposit.caption,
|
||||||
|
key: `0-${dIdx}`,
|
||||||
|
value: `0-${dIdx}`,
|
||||||
|
children: deposit.clusters.map((cluster, cIdx) => ({
|
||||||
|
title: cluster.caption,
|
||||||
|
key: `0-${dIdx}-${cIdx}`,
|
||||||
|
value: `0-${dIdx}-${cIdx}`,
|
||||||
|
children: cluster.wells.map(well => ({
|
||||||
|
title: well.caption,
|
||||||
|
key: well.id,
|
||||||
|
value: well.id,
|
||||||
|
})),
|
||||||
|
})),
|
||||||
|
}))
|
||||||
|
|
||||||
|
return wellsTree
|
||||||
|
}
|
||||||
|
|
||||||
|
export const getTreeLabels = (treeData) => {
|
||||||
|
const labels = {}
|
||||||
|
treeData.forEach((deposit) =>
|
||||||
|
deposit?.children?.forEach((cluster) =>
|
||||||
|
cluster?.children?.forEach((well) => {
|
||||||
|
labels[well.value] = `${deposit.title}.${cluster.title}.${well.title}`
|
||||||
|
})))
|
||||||
|
return labels
|
||||||
|
}
|
||||||
|
|
||||||
|
export const WellSelector = memo(({ idWell, value, onChange, treeData, treeLabels, ...other }) => {
|
||||||
|
const [wellsTree, setWellsTree] = useState([])
|
||||||
|
const [wellLabels, setWellLabels] = useState([])
|
||||||
|
|
||||||
|
useEffect(() => invokeWebApiWrapperAsync(
|
||||||
|
async () => {
|
||||||
|
const wellsTree = treeData ?? await getTreeData()
|
||||||
|
const labels = treeLabels ?? getTreeLabels(wellsTree)
|
||||||
|
setWellsTree(wellsTree)
|
||||||
|
setWellLabels(labels)
|
||||||
|
},
|
||||||
|
null,
|
||||||
|
'Не удалось загрузить список скважин',
|
||||||
|
'Получение списка скважин'
|
||||||
|
), [idWell, treeData])
|
||||||
|
|
||||||
|
return (
|
||||||
|
<TreeSelect
|
||||||
|
multiple
|
||||||
|
treeCheckable
|
||||||
|
showCheckedStrategy={TreeSelect.SHOW_CHILD}
|
||||||
|
treeDefaultExpandAll
|
||||||
|
treeData={wellsTree}
|
||||||
|
treeLine={{ showLeafIcon: false }}
|
||||||
|
size={'middle'}
|
||||||
|
style={{ width: '100%' }}
|
||||||
|
value={value}
|
||||||
|
onChange={onChange}
|
||||||
|
placeholder={'Выберите скважины'}
|
||||||
|
tagRender={(props) => (
|
||||||
|
<Tag {...props}>{wellLabels[props.value] ?? props.label}</Tag>
|
||||||
|
)}
|
||||||
|
disabled={wellsTree.length <= 0 || !hasPermission('WellOperation.edit')}
|
||||||
|
{...other}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
export default WellSelector
|
218
src/pages/Analytics/Statistics.jsx
Normal file
218
src/pages/Analytics/Statistics.jsx
Normal file
@ -0,0 +1,218 @@
|
|||||||
|
import { Table as RawTable, Typography } from 'antd'
|
||||||
|
import { Fragment, memo, useCallback, useEffect, useState } from 'react'
|
||||||
|
|
||||||
|
import LoaderPortal from '@components/LoaderPortal'
|
||||||
|
import { getTreeData, getTreeLabels, WellSelector } from '@components/WellSelector'
|
||||||
|
import { invokeWebApiWrapperAsync } from '@components/factory'
|
||||||
|
import { makeGroupColumn, makeNumericColumn, makeNumericRender, makeTextColumn, Table } from '@components/Table'
|
||||||
|
import { OperationStatService, WellOperationService } from '@api'
|
||||||
|
import { arrayOrDefault } from '@utils'
|
||||||
|
|
||||||
|
import '@styles/index.css'
|
||||||
|
import '@styles/statistics.less'
|
||||||
|
|
||||||
|
const { Text } = Typography
|
||||||
|
const { Summary } = RawTable
|
||||||
|
const { Cell, Row } = Summary
|
||||||
|
|
||||||
|
const numericRender = makeNumericRender()
|
||||||
|
const speedNumericRender = (section) => numericRender(section?.speed)
|
||||||
|
|
||||||
|
export const makeSectionColumn = (title, key, { speedRender } = {}) => makeGroupColumn(title, [
|
||||||
|
makeNumericColumn('Проходка', key, null, null, (section => numericRender(section?.depth)), 100),
|
||||||
|
makeNumericColumn('Время', key, null, null, (section => numericRender(section?.time)), 100),
|
||||||
|
makeNumericColumn((<>V<sub>рейсовая</sub></>), key, null, null, speedRender ?? speedNumericRender, 100),
|
||||||
|
])
|
||||||
|
|
||||||
|
export const defaultColumns = [
|
||||||
|
//makeTextColumn('Куст', 'cluster', null, null, null, { fixed: 'left', width: 100 }),
|
||||||
|
makeTextColumn('Скважина', 'caption', null, null, null, { fixed: 'left', width: 100 }),
|
||||||
|
]
|
||||||
|
|
||||||
|
const scrollSettings = { scrollToFirstRowOnChange: true, x: 100, y: 200 }
|
||||||
|
const summaryColSpan = 1 /// TODO: Когда добавится куст изменить на 2
|
||||||
|
|
||||||
|
const getWellData = async (wellsList) => {
|
||||||
|
const stats = arrayOrDefault(await OperationStatService.getWellsStat(wellsList))
|
||||||
|
const wellData = stats.map((well) => {
|
||||||
|
const stat = {
|
||||||
|
// cluster: null,
|
||||||
|
caption: well.caption,
|
||||||
|
}
|
||||||
|
|
||||||
|
well.sections?.forEach(({ id, fact }) => {
|
||||||
|
if (!fact) return
|
||||||
|
stat[`section_${id}`] = {
|
||||||
|
time: (+new Date(fact.end) - +new Date(fact.start)) / 3600_000,
|
||||||
|
depth: fact.wellDepthEnd - fact.wellDepthStart,
|
||||||
|
speed: fact.routeSpeed,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
return stat
|
||||||
|
})
|
||||||
|
|
||||||
|
return wellData
|
||||||
|
}
|
||||||
|
|
||||||
|
export const Statistics = memo(({ idWell }) => {
|
||||||
|
const [sectionTypes, setSectionTypes] = useState([])
|
||||||
|
const [avgColumns, setAvgColumns] = useState(defaultColumns)
|
||||||
|
const [cmpColumns, setCmpColumns] = useState(defaultColumns)
|
||||||
|
const [isAvgTableLoading, setIsAvgTableLoading] = useState(false)
|
||||||
|
const [isCmpTableLoading, setIsCmpTableLoading] = useState(false)
|
||||||
|
const [isPageLoading, setIsPageLoading] = useState(false)
|
||||||
|
const [avgWells, setAvgWells] = useState([])
|
||||||
|
const [cmpWells, setCmpWells] = useState([])
|
||||||
|
const [filteredCmpWells, setFilteredCmpWells] = useState([])
|
||||||
|
const [avgData, setAvgData] = useState([])
|
||||||
|
const [cmpData, setCmpData] = useState([])
|
||||||
|
const [avgRow, setAvgRow] = useState({})
|
||||||
|
|
||||||
|
const cmpSpeedRender = useCallback((key) => (section) => {
|
||||||
|
let spanClass = ''
|
||||||
|
// Дополнительная проверка на "null" необходима, чтобы значение "0" не стало исключением
|
||||||
|
if ((avgRow[key]?.speed ?? null) !== null && (section?.speed ?? null) !== null) {
|
||||||
|
const avgSpeed = avgRow[key].speed - section.speed
|
||||||
|
if (avgSpeed < 0)
|
||||||
|
spanClass = 'high-efficienty'
|
||||||
|
else if (avgSpeed > 0)
|
||||||
|
spanClass = 'low-efficienty'
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<span className={spanClass}>
|
||||||
|
{numericRender(section?.speed)}
|
||||||
|
</span>
|
||||||
|
)
|
||||||
|
}, [avgRow])
|
||||||
|
|
||||||
|
useEffect(() => invokeWebApiWrapperAsync(
|
||||||
|
async () => {
|
||||||
|
const types = await WellOperationService.getSectionTypes(idWell)
|
||||||
|
setSectionTypes(Object.entries(types))
|
||||||
|
setAvgColumns([
|
||||||
|
...defaultColumns,
|
||||||
|
...Object.entries(types).map(([id, name]) => makeSectionColumn(name, `section_${id}`)),
|
||||||
|
])
|
||||||
|
setCmpColumns([
|
||||||
|
...defaultColumns,
|
||||||
|
...Object.entries(types).map(([id, name]) => makeSectionColumn(name, `section_${id}`, {
|
||||||
|
speedRender: cmpSpeedRender(`section_${id}`)
|
||||||
|
}))
|
||||||
|
])
|
||||||
|
},
|
||||||
|
setIsPageLoading,
|
||||||
|
`Не удалось получить типы секции`,
|
||||||
|
`Получение списка возможных секций`,
|
||||||
|
), [idWell, cmpSpeedRender])
|
||||||
|
|
||||||
|
useEffect(() => invokeWebApiWrapperAsync(
|
||||||
|
async () => {
|
||||||
|
const avgData = await getWellData(avgWells)
|
||||||
|
setAvgData(avgData)
|
||||||
|
|
||||||
|
const avgRow = {}
|
||||||
|
|
||||||
|
avgData.forEach((row) => row && Object.keys(row).forEach((key) => {
|
||||||
|
if (!key.startsWith('section_')) return
|
||||||
|
if (!avgRow[key]) avgRow[key] = { depth: 0, time: 0, speed: 0, count: 0 }
|
||||||
|
avgRow[key].depth += row[key].depth ?? 0
|
||||||
|
avgRow[key].time += row[key].time ?? 0
|
||||||
|
avgRow[key].speed += row[key].speed ?? 0
|
||||||
|
avgRow[key].count++
|
||||||
|
}))
|
||||||
|
|
||||||
|
Object.values(avgRow).forEach((section) => section.speed /= section.count)
|
||||||
|
|
||||||
|
setAvgRow(avgRow)
|
||||||
|
},
|
||||||
|
setIsAvgTableLoading,
|
||||||
|
'Не удалось загрузить данные для расчёта средних значений',
|
||||||
|
), [avgWells])
|
||||||
|
|
||||||
|
useEffect(() => invokeWebApiWrapperAsync(
|
||||||
|
async () => {
|
||||||
|
const cmpData = await getWellData(cmpWells)
|
||||||
|
setCmpData(cmpData)
|
||||||
|
},
|
||||||
|
setIsCmpTableLoading,
|
||||||
|
'Не удалось получить скважины для сравнения',
|
||||||
|
), [cmpWells])
|
||||||
|
|
||||||
|
const getStatisticsAvgSummary = useCallback((data) => (
|
||||||
|
<Summary fixed={'bottom'}>
|
||||||
|
<Row>
|
||||||
|
<Cell index={0} colSpan={summaryColSpan}>
|
||||||
|
<Text>Итого:</Text>
|
||||||
|
</Cell>
|
||||||
|
{sectionTypes.map(([id, _], i) => (
|
||||||
|
<Fragment key={id ?? i}>
|
||||||
|
<Cell index={3 * i + summaryColSpan}>
|
||||||
|
<Text>{numericRender(avgRow[`section_${id}`]?.depth)}</Text>
|
||||||
|
</Cell>
|
||||||
|
<Cell index={3 * i + summaryColSpan + 1}>
|
||||||
|
<Text>{numericRender(avgRow[`section_${id}`]?.time)}</Text>
|
||||||
|
</Cell>
|
||||||
|
<Cell index={3 * i + summaryColSpan + 2}>
|
||||||
|
<Text>{numericRender(avgRow[`section_${id}`]?.speed)}</Text>
|
||||||
|
</Cell>
|
||||||
|
</Fragment>
|
||||||
|
))}
|
||||||
|
</Row>
|
||||||
|
</Summary>
|
||||||
|
), [avgRow, sectionTypes])
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={'statistics-page'}>
|
||||||
|
<LoaderPortal show={isPageLoading}>
|
||||||
|
<h2 style={{ padding: '10px' }}>Расчёт средних значений без Цифровой буровой</h2>
|
||||||
|
<div className={'average-table'}>
|
||||||
|
<div className={'well-selector'}>
|
||||||
|
<span className={'well-selector-label'}>Выберите скважины для расчёта средних значений:</span>
|
||||||
|
<WellSelector
|
||||||
|
idWell={idWell}
|
||||||
|
value={avgWells}
|
||||||
|
style={{ flex: 100 }}
|
||||||
|
onChange={setAvgWells}
|
||||||
|
placeholder={'Ничего не выбрано'}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<Table
|
||||||
|
bordered
|
||||||
|
size={'small'}
|
||||||
|
pagination={false}
|
||||||
|
columns={avgColumns}
|
||||||
|
dataSource={avgData}
|
||||||
|
scroll={scrollSettings}
|
||||||
|
loading={isAvgTableLoading}
|
||||||
|
summary={getStatisticsAvgSummary}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className={'compare-table'}>
|
||||||
|
<div className={'well-selector'}>
|
||||||
|
<span className={'well-selector-label'}>Выберите скважины сравнения:</span>
|
||||||
|
<WellSelector
|
||||||
|
idWell={idWell}
|
||||||
|
value={cmpWells}
|
||||||
|
style={{ flex: 100 }}
|
||||||
|
onChange={setCmpWells}
|
||||||
|
placeholder={'Ничего не выбрано'}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<Table
|
||||||
|
bordered
|
||||||
|
size={'small'}
|
||||||
|
pagination={false}
|
||||||
|
columns={cmpColumns}
|
||||||
|
dataSource={cmpData}
|
||||||
|
scroll={scrollSettings}
|
||||||
|
loading={isCmpTableLoading}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</LoaderPortal>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
export default Statistics
|
@ -86,7 +86,7 @@ export const WellCompositeEditor = memo(({ idWell, rootPath }) => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<LoaderPortal show={showLoader}>
|
<LoaderPortal show={showLoader}>
|
||||||
<Row align={'middle'} justify={'space-between'} wrap={false}>
|
<Row align={'middle'} justify={'space-between'} wrap={false} style={{ backgroundColor: 'white' }}>
|
||||||
<Col span={18}>
|
<Col span={18}>
|
||||||
<TreeSelect
|
<TreeSelect
|
||||||
multiple
|
multiple
|
37
src/pages/Analytics/index.jsx
Normal file
37
src/pages/Analytics/index.jsx
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
import { memo } from 'react'
|
||||||
|
import { Layout, Menu } from 'antd'
|
||||||
|
import { Switch, useParams } from 'react-router-dom'
|
||||||
|
|
||||||
|
import { PrivateDefaultRoute, PrivateMenuItemLink, PrivateRoute } from '@components/Private'
|
||||||
|
|
||||||
|
import WellCompositeEditor from './WellCompositeEditor'
|
||||||
|
import Statistics from './Statistics'
|
||||||
|
|
||||||
|
export const Analytics = memo(({ idWell }) => {
|
||||||
|
const { tab } = useParams()
|
||||||
|
const rootPath = `/well/${idWell}/analytics`
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Layout>
|
||||||
|
<Menu mode={'horizontal'} selectable={true} className={'well_menu'} selectedKeys={[tab]}>
|
||||||
|
<PrivateMenuItemLink root={rootPath} key={'composite'} path={'composite'} title={'Композитная скважина'} />
|
||||||
|
<PrivateMenuItemLink root={rootPath} key={'statistics'} path={'statistics'} title={'Оценка по ЦБ'} />
|
||||||
|
</Menu>
|
||||||
|
<Layout>
|
||||||
|
<Layout.Content>
|
||||||
|
<Switch>
|
||||||
|
<PrivateRoute path={`${rootPath}/composite/:tab?`}>
|
||||||
|
<WellCompositeEditor idWell={idWell} rootPath={`${rootPath}/composite`} />
|
||||||
|
</PrivateRoute>
|
||||||
|
<PrivateRoute path={`${rootPath}/statistics`}>
|
||||||
|
<Statistics idWell={idWell} />
|
||||||
|
</PrivateRoute>
|
||||||
|
<PrivateDefaultRoute urls={[`${rootPath}/composite`]}/>
|
||||||
|
</Switch>
|
||||||
|
</Layout.Content>
|
||||||
|
</Layout>
|
||||||
|
</Layout>
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
export default Analytics
|
@ -17,12 +17,12 @@ import Report from './Report'
|
|||||||
import Archive from './Archive'
|
import Archive from './Archive'
|
||||||
import Measure from './Measure'
|
import Measure from './Measure'
|
||||||
import Messages from './Messages'
|
import Messages from './Messages'
|
||||||
|
import Analytics from './Analytics'
|
||||||
import Documents from './Documents'
|
import Documents from './Documents'
|
||||||
import TelemetryView from './TelemetryView'
|
import TelemetryView from './TelemetryView'
|
||||||
import WellOperations from './WellOperations'
|
import WellOperations from './WellOperations'
|
||||||
import DrillingProgram from './DrillingProgram'
|
import DrillingProgram from './DrillingProgram'
|
||||||
import TelemetryAnalysis from './TelemetryAnalysis'
|
import TelemetryAnalysis from './TelemetryAnalysis'
|
||||||
import WellCompositeEditor from './WellCompositeEditor'
|
|
||||||
|
|
||||||
import '@styles/index.css'
|
import '@styles/index.css'
|
||||||
|
|
||||||
@ -38,7 +38,7 @@ export const Well = memo(() => {
|
|||||||
<PrivateMenuItem.Link root={rootPath} key={'telemetry'} path={'telemetry'} icon={<FundViewOutlined />} title={'Мониторинг'}/>
|
<PrivateMenuItem.Link root={rootPath} key={'telemetry'} path={'telemetry'} icon={<FundViewOutlined />} title={'Мониторинг'}/>
|
||||||
<PrivateMenuItem.Link root={rootPath} key={'message'} path={'message'} icon={<AlertOutlined/>} title={'Сообщения'} />
|
<PrivateMenuItem.Link root={rootPath} key={'message'} path={'message'} icon={<AlertOutlined/>} title={'Сообщения'} />
|
||||||
<PrivateMenuItem.Link root={rootPath} key={'report'} path={'report'} icon={<FilePdfOutlined />} title={'Рапорт'} />
|
<PrivateMenuItem.Link root={rootPath} key={'report'} path={'report'} icon={<FilePdfOutlined />} title={'Рапорт'} />
|
||||||
<PrivateMenuItem.Link root={rootPath} key={'composite'} path={'composite'} icon={<DeploymentUnitOutlined />} title={'Аналитика'} />
|
<PrivateMenuItem.Link root={rootPath} key={'analytics'} path={'analytics'} icon={<DeploymentUnitOutlined />} title={'Аналитика'} />
|
||||||
<PrivateMenuItem.Link root={rootPath} key={'operations'} path={'operations'} icon={<FolderOutlined />} title={'Операции по скважине'} />
|
<PrivateMenuItem.Link root={rootPath} key={'operations'} path={'operations'} icon={<FolderOutlined />} title={'Операции по скважине'} />
|
||||||
<PrivateMenuItem.Link root={rootPath} key={'archive'} path={'archive'} icon={<DatabaseOutlined />} title={'Архив'} />
|
<PrivateMenuItem.Link root={rootPath} key={'archive'} path={'archive'} icon={<DatabaseOutlined />} title={'Архив'} />
|
||||||
{/* <PrivateMenuItem.Link root={rootPath} key={'telemetryAnalysis'} path={'telemetryAnalysis'} icon={<FundProjectionScreenOutlined />} title={'Операции по телеметрии'} /> */}
|
{/* <PrivateMenuItem.Link root={rootPath} key={'telemetryAnalysis'} path={'telemetryAnalysis'} icon={<FundProjectionScreenOutlined />} title={'Операции по телеметрии'} /> */}
|
||||||
@ -59,8 +59,8 @@ export const Well = memo(() => {
|
|||||||
<PrivateRoute path={`${rootPath}/report`}>
|
<PrivateRoute path={`${rootPath}/report`}>
|
||||||
<Report idWell={idWell} />
|
<Report idWell={idWell} />
|
||||||
</PrivateRoute>
|
</PrivateRoute>
|
||||||
<PrivateRoute path={`${rootPath}/composite/:tab?`}>
|
<PrivateRoute path={`${rootPath}/analytics/:tab?`}>
|
||||||
<WellCompositeEditor idWell={idWell} rootPath={`${rootPath}/composite`}/>
|
<Analytics idWell={idWell} rootPath={`${rootPath}/analytics`}/>
|
||||||
</PrivateRoute>
|
</PrivateRoute>
|
||||||
<PrivateRoute path={`${rootPath}/operations/:tab?`}>
|
<PrivateRoute path={`${rootPath}/operations/:tab?`}>
|
||||||
<WellOperations idWell={idWell} />
|
<WellOperations idWell={idWell} />
|
||||||
@ -84,7 +84,7 @@ export const Well = memo(() => {
|
|||||||
`${rootPath}/telemetry`,
|
`${rootPath}/telemetry`,
|
||||||
`${rootPath}/message`,
|
`${rootPath}/message`,
|
||||||
`${rootPath}/report`,
|
`${rootPath}/report`,
|
||||||
`${rootPath}/composite`,
|
`${rootPath}/analytics`,
|
||||||
`${rootPath}/operations`,
|
`${rootPath}/operations`,
|
||||||
`${rootPath}/archive`,
|
`${rootPath}/archive`,
|
||||||
`${rootPath}/telemetryAnalysis`,
|
`${rootPath}/telemetryAnalysis`,
|
||||||
|
@ -75,6 +75,10 @@ body {
|
|||||||
height: calc(100vh - 64px);
|
height: calc(100vh - 64px);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.p-10 {
|
||||||
|
padding: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
.vertical-align-center {
|
.vertical-align-center {
|
||||||
vertical-align: center;
|
vertical-align: center;
|
||||||
}
|
}
|
||||||
@ -115,3 +119,11 @@ code {
|
|||||||
margin: auto;
|
margin: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.first-column-title {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: stretch;
|
||||||
|
justify-content: space-between;
|
||||||
|
position: relative;
|
||||||
|
padding: 16px 0;
|
||||||
|
}
|
||||||
|
25
src/styles/statistics.less
Normal file
25
src/styles/statistics.less
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
.statistics-page {
|
||||||
|
background-color: white;
|
||||||
|
|
||||||
|
.well-selector {
|
||||||
|
display: flex;
|
||||||
|
padding: 10px 0 10px 10px;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
> .well-selector-label {
|
||||||
|
flex: auto;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.compare-table {
|
||||||
|
.high-efficienty {
|
||||||
|
color: limegreen;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.low-efficienty {
|
||||||
|
color: red;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -93,9 +93,12 @@ export const requirements: PermissionRecord = {
|
|||||||
telemetry: ['Deposit.get', 'DrillFlowChart.get', 'TelemetryDataSaub.get', 'TelemetryDataSpin.get'],
|
telemetry: ['Deposit.get', 'DrillFlowChart.get', 'TelemetryDataSaub.get', 'TelemetryDataSpin.get'],
|
||||||
message: ['Deposit.get', 'TelemetryDataSaub.get'],
|
message: ['Deposit.get', 'TelemetryDataSaub.get'],
|
||||||
report: ['Deposit.get', 'Report.get'],
|
report: ['Deposit.get', 'Report.get'],
|
||||||
composite: {
|
analytics: {
|
||||||
wells: ['Deposit.get', 'OperationStat.get', 'WellComposite.get'],
|
composite: {
|
||||||
sections: ['Deposit.get', 'OperationStat.get', 'WellComposite.get', 'DrillParams.get'],
|
wells: ['Deposit.get', 'OperationStat.get', 'WellComposite.get'],
|
||||||
|
sections: ['Deposit.get', 'OperationStat.get', 'WellComposite.get', 'DrillParams.get'],
|
||||||
|
},
|
||||||
|
statistics: ['Deposit.get', 'WellOperation.get'],
|
||||||
},
|
},
|
||||||
operations: {
|
operations: {
|
||||||
tvd: ['Deposit.get', 'OperationStat.get'],
|
tvd: ['Deposit.get', 'OperationStat.get'],
|
||||||
|
Loading…
Reference in New Issue
Block a user