forked from ddrilling/asb_cloud_front
244 lines
8.9 KiB
JavaScript
Executable File
244 lines
8.9 KiB
JavaScript
Executable File
import { Link, useLocation } from 'react-router-dom'
|
||
import { useState, useEffect, memo, useMemo } from 'react'
|
||
import { LineChartOutlined, ProfileOutlined } from '@ant-design/icons'
|
||
import { Table, Tag, Button, Badge, Divider, Modal, Row, Col } from 'antd'
|
||
|
||
import { CompanyView } from '@components/views'
|
||
import LoaderPortal from '@components/LoaderPortal'
|
||
import { invokeWebApiWrapperAsync } from '@components/factory'
|
||
import { makeTextColumn, makeNumericColumnPlanFact } from '@components/Table'
|
||
import { WellCompositeService } from '@api'
|
||
import { hasPermission } from '@utils/permissions'
|
||
import {
|
||
calcAndUpdateStatsBySections,
|
||
makeFilterMinMaxFunction,
|
||
getOperations
|
||
} from '@utils/functions'
|
||
|
||
import { Tvd } from '@pages/WellOperations/Tvd'
|
||
import WellOperationsTable from '@pages/Cluster/WellOperationsTable'
|
||
import NewParamsTable from './NewParamsTable'
|
||
|
||
const filtersMinMax = [
|
||
{ text: 'min', value: 'min' },
|
||
{ text: 'max', value: 'max' },
|
||
]
|
||
|
||
const sortBySectionId = (a, b) => a.sectionId - b.sectionId
|
||
|
||
const filtersSectionsType = []
|
||
const DAY_IN_MS = 1000 * 60 * 60 * 24
|
||
|
||
export const WellCompositeSections = memo(({ idWell, statsWells, selectedSections }) => {
|
||
const [selectedWells, setSelectedWells] = useState([])
|
||
const [wellOperations, setWellOperations] = useState([])
|
||
const [selectedWellsKeys, setSelectedWellsKeys] = useState([])
|
||
const [selectedWellId, setSelectedWellId] = useState(0)
|
||
const [showLoader, setShowLoader] = useState(false)
|
||
const [isTVDModalVisible, setIsTVDModalVisible] = useState(false)
|
||
const [isOpsModalVisible, setIsOpsModalVisible] = useState(false)
|
||
|
||
const location = useLocation()
|
||
|
||
const rows = useMemo(() => {
|
||
const rows = []
|
||
statsWells?.forEach((well) => {
|
||
well.sections?.forEach((section) => {
|
||
if (!filtersSectionsType.some((el) => el.text === section.caption))
|
||
filtersSectionsType.push({ text: section.caption, value: section.caption })
|
||
|
||
const row = {
|
||
key: well.caption + section.id,
|
||
id: well.id,
|
||
sectionId: section.id,
|
||
caption: well.caption,
|
||
sectionType: section.caption,
|
||
sectionWellDepthPlan: section.plan?.wellDepthEnd,
|
||
sectionWellDepthFact: section.fact?.wellDepthEnd,
|
||
sectionBuildDaysPlan: (new Date(section.plan?.end) - new Date(section.plan?.start)) / DAY_IN_MS,
|
||
sectionBuildDaysFact: (new Date(section.fact?.end) - new Date(section.fact?.start)) / DAY_IN_MS,
|
||
sectionRateOfPenetrationPlan: section.plan?.rop,
|
||
sectionRateOfPenetrationFact: section.fact?.rop,
|
||
sectionRouteSpeedPlan: section.plan?.routeSpeed,
|
||
sectionRouteSpeedFact: section.fact?.routeSpeed,
|
||
sectionBhaDownSpeedPlan: section.plan?.bhaDownSpeed,
|
||
sectionBhaDownSpeedFact: section.fact?.bhaDownSpeed,
|
||
sectionBhaUpSpeedPlan: section.plan?.bhaUpSpeed,
|
||
sectionBhaUpSpeedFact: section.fact?.bhaUpSpeed,
|
||
sectionCasingDownSpeedPlan: section.plan?.casingDownSpeed,
|
||
sectionCasingDownSpeedFact: section.fact?.casingDownSpeed,
|
||
nonProductiveTimePlan: section.plan?.nonProductiveHours,
|
||
nonProductiveTimeFact: section.fact?.nonProductiveHours,
|
||
companies: well.companies,
|
||
}
|
||
|
||
rows.push(row)
|
||
})
|
||
})
|
||
|
||
calcAndUpdateStatsBySections(rows ?? [], [
|
||
'sectionWellDepthPlan',
|
||
'sectionWellDepthFact',
|
||
'sectionBuildDaysPlan',
|
||
'sectionBuildDaysFact',
|
||
'sectionRateOfPenetrationPlan',
|
||
'sectionRateOfPenetrationFact',
|
||
'sectionRouteSpeedPlan',
|
||
'sectionRouteSpeedFact',
|
||
'sectionBhaDownSpeedPlan',
|
||
'sectionBhaDownSpeedFact',
|
||
'sectionBhaUpSpeedPlan',
|
||
'sectionBhaUpSpeedFact',
|
||
'sectionCasingDownSpeedPlan',
|
||
'sectionCasingDownSpeedFact',
|
||
'nonProductiveTimePlan',
|
||
'nonProductiveTimeFact',
|
||
])
|
||
|
||
return rows
|
||
}, [statsWells])
|
||
|
||
useEffect(() => {
|
||
if (isOpsModalVisible || selectedWellId <= 0) return
|
||
invokeWebApiWrapperAsync(
|
||
async () => {
|
||
const { operations } = await getOperations(selectedWellId)
|
||
setWellOperations(operations)
|
||
},
|
||
setShowLoader,
|
||
`Не удалось загрузить операции по скважине "${selectedWellId}"`,
|
||
)
|
||
}, [selectedWellId, isOpsModalVisible])
|
||
|
||
useEffect(() => {
|
||
const selected = rows.filter((row) => selectedSections.some(section => (
|
||
section.idWellSrc === row.id && section.idWellSectionType === row.sectionId
|
||
)))
|
||
|
||
setSelectedWells(selected)
|
||
setSelectedWellsKeys(selected.map((row) => row.key))
|
||
}, [rows, selectedSections])
|
||
|
||
const rowSelection = useMemo(() => hasPermission('WellOperation.edit') && {
|
||
selectedRowKeys: selectedWellsKeys,
|
||
onChange: (keys, items) => invokeWebApiWrapperAsync(
|
||
async () => {
|
||
const selectedSections = items.map((row) => ({idWell, idWellSrc: row.id, idWellSectionType: row.sectionId}))
|
||
await WellCompositeService.save(idWell, selectedSections)
|
||
|
||
setSelectedWells(items)
|
||
setSelectedWellsKeys(keys)
|
||
},
|
||
setShowLoader,
|
||
`Не удалось сохранить изменения выбранных секций для композитной скважины "${idWell}"`,
|
||
'Изменение выбранных секций скважины'
|
||
)
|
||
}, [idWell, selectedWellsKeys])
|
||
|
||
const columns = useMemo(() => [
|
||
makeTextColumn('скв №', 'caption', null, null,
|
||
(text, item) => <Link to={{ pathname: `/well/${item?.id}`, state: { from: location.pathname }}}>{text ?? '-'}</Link>
|
||
),
|
||
makeTextColumn('Секция', 'sectionType', filtersSectionsType, sortBySectionId, (text) => text ?? '-'),
|
||
makeNumericColumnPlanFact('Глубина, м', 'sectionWellDepth', filtersMinMax, makeFilterMinMaxFunction),
|
||
makeNumericColumnPlanFact('Продолжительность, ч', 'sectionBuildDays', filtersMinMax, makeFilterMinMaxFunction),
|
||
makeNumericColumnPlanFact('МСП, м/ч', 'sectionRateOfPenetration', filtersMinMax, makeFilterMinMaxFunction),
|
||
makeNumericColumnPlanFact('Рейсовая скорость, м/ч', 'sectionRouteSpeed', filtersMinMax, makeFilterMinMaxFunction),
|
||
makeNumericColumnPlanFact('Спуск КНБК, м/ч', 'sectionBhaDownSpeed', filtersMinMax, makeFilterMinMaxFunction),
|
||
makeNumericColumnPlanFact('Подъем КНБК, м/ч', 'sectionBhaUpSpeed', filtersMinMax, makeFilterMinMaxFunction),
|
||
makeNumericColumnPlanFact('Скорость спуска ОК, м/ч', 'sectionCasingDownSpeed', filtersMinMax, makeFilterMinMaxFunction),
|
||
makeNumericColumnPlanFact('НПВ, сут', 'nonProductiveTime', filtersMinMax, makeFilterMinMaxFunction, null, '70px'),
|
||
{
|
||
title: 'TVD',
|
||
render: (value) => (
|
||
<Button onClick={() => {
|
||
setSelectedWellId(value.id)
|
||
setIsTVDModalVisible(true)
|
||
}}>
|
||
<LineChartOutlined />
|
||
</Button>
|
||
),
|
||
align: 'center'
|
||
},
|
||
{
|
||
title: 'Операции',
|
||
render: (value) => (
|
||
<Button onClick={()=> {
|
||
setSelectedWellId(value.id)
|
||
setIsOpsModalVisible(true)
|
||
}}>
|
||
<ProfileOutlined />
|
||
</Button>
|
||
),
|
||
align: 'center'
|
||
},
|
||
{
|
||
title: 'Участники',
|
||
dataIndex: 'companies',
|
||
render: (item) => item?.map((company) => (
|
||
<Tag key={company.caption} color={'blue'}>
|
||
<CompanyView company={company} />
|
||
</Tag>
|
||
)) ?? '-',
|
||
},
|
||
], [location.pathname])
|
||
|
||
return (
|
||
<>
|
||
<Table
|
||
columns={columns}
|
||
dataSource={rows}
|
||
size={'small'}
|
||
bordered
|
||
scroll={{ x: true, y: 620 }}
|
||
rowSelection={rowSelection}
|
||
pagination={false}
|
||
/>
|
||
<Divider />
|
||
<Badge.Ribbon text={'комбинированная скважина'} color={'gray'}>
|
||
<h3>Выбранные секции</h3>
|
||
</Badge.Ribbon>
|
||
<Table
|
||
columns={columns}
|
||
dataSource={selectedWells}
|
||
rowSelection={rowSelection}
|
||
size={'small'}
|
||
bordered
|
||
scroll={{ x: true }}
|
||
pagination={false}
|
||
/>
|
||
<Row justify={'end'} style={{ margin: '1rem 0' }}>
|
||
<Col>
|
||
<NewParamsTable idWell={idWell} selectedWellsKeys={selectedWellsKeys} />
|
||
</Col>
|
||
</Row>
|
||
|
||
<Modal
|
||
title={'TVD'}
|
||
centered
|
||
visible={isTVDModalVisible}
|
||
onCancel={() => setIsTVDModalVisible(false)}
|
||
width={1500}
|
||
footer={null}
|
||
>
|
||
<Tvd idWell={selectedWellId} style={{ height: '80vh' }} />
|
||
</Modal>
|
||
|
||
<Modal
|
||
title={'Операции'}
|
||
centered
|
||
visible={isOpsModalVisible}
|
||
onCancel={() => setIsOpsModalVisible(false)}
|
||
width={1500}
|
||
footer={null}
|
||
>
|
||
<LoaderPortal show={showLoader}>
|
||
<WellOperationsTable wellOperations={wellOperations} />
|
||
</LoaderPortal>
|
||
</Modal>
|
||
</>
|
||
)
|
||
})
|
||
|
||
export default WellCompositeSections
|