2021-10-14 11:07:11 +05:00
|
|
|
|
import { LineChartOutlined, ProfileOutlined } from '@ant-design/icons'
|
|
|
|
|
import { Table, Tag, Button, Badge, Divider, Modal, Row, Col } from 'antd'
|
|
|
|
|
import { Link } from 'react-router-dom'
|
|
|
|
|
import { useState, useEffect } from 'react'
|
|
|
|
|
import {
|
|
|
|
|
makeColumn,
|
|
|
|
|
makeTextColumn,
|
|
|
|
|
makeNumericColumnPlanFact,
|
|
|
|
|
makeNumericAvgRange,
|
|
|
|
|
SelectFromDictionary
|
|
|
|
|
} from '../../../components/Table'
|
|
|
|
|
import {
|
|
|
|
|
calcAndUpdateStatsBySections,
|
|
|
|
|
makeFilterMinMaxFunction,
|
|
|
|
|
getOperations
|
|
|
|
|
} from '../../Cluster/functions'
|
|
|
|
|
import ChartTvD from '../ChartTvD'
|
2021-10-14 16:56:29 +05:00
|
|
|
|
import { DrillParamsService, WellCompositeService } from '../../../services/api'
|
2021-10-14 11:07:11 +05:00
|
|
|
|
import LoaderPortal from '../../../components/LoaderPortal'
|
|
|
|
|
import WellOperationsTable from '../../Cluster/WellOperationsTable'
|
|
|
|
|
import { invokeWebApiWrapperAsync } from '../../../components/factory'
|
|
|
|
|
import { dictionarySectionType, getByKeyOrReturnKey } from '../dictionary'
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const filtersMinMax = [
|
|
|
|
|
{ text: "min", value: "min" },
|
|
|
|
|
{ text: "max", value: "max" },
|
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
const filtersSectionsType = []
|
|
|
|
|
const DAY_IN_MS = 1000 * 60 * 60 * 24
|
|
|
|
|
|
|
|
|
|
export const WellCompositeSections = ({idWell, statsWells, selectedSections}) => {
|
|
|
|
|
|
|
|
|
|
const [showLoader, setShowLoader] = useState(false)
|
|
|
|
|
const [selectedWellId, setSelectedWellId] = useState(0)
|
|
|
|
|
const [selectedWells, setSelectedWells] = useState([])
|
|
|
|
|
const [selectedWellsKeys, setSelectedWellsKeys] = useState([])
|
|
|
|
|
const [isTVDModalVisible, setIsTVDModalVisible] = useState(false)
|
|
|
|
|
const [isOpsModalVisible, setIsOpsModalVisible] = useState(false)
|
|
|
|
|
const [isParamsModalVisible, setIsParamsModalVisible] = useState(false)
|
|
|
|
|
const [tvdDataPlan, setTvdDataPlan] = useState([])
|
|
|
|
|
const [tvdDataFact, setTvdDataFact] = useState([])
|
|
|
|
|
const [tvdDataForecast, setTvdDataForecast] = useState([])
|
|
|
|
|
const [wellOperations, setWellOperations] = useState([])
|
|
|
|
|
const [rows, setRows] = useState([])
|
|
|
|
|
const [params, setParams] = useState([])
|
|
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
|
if (selectedWellId > 0) {
|
|
|
|
|
invokeWebApiWrapperAsync(
|
|
|
|
|
async () => {
|
|
|
|
|
const operations = await getOperations(selectedWellId);
|
|
|
|
|
|
|
|
|
|
setWellOperations(operations.operations)
|
|
|
|
|
setTvdDataPlan(operations.plan)
|
|
|
|
|
setTvdDataFact(operations.fact)
|
|
|
|
|
setTvdDataForecast(operations.predict)
|
|
|
|
|
},
|
|
|
|
|
setShowLoader,
|
|
|
|
|
`Не удалось загрузить операции по скважине "${selectedWellId}"`,
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
}, [selectedWellId])
|
|
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
|
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 })
|
|
|
|
|
|
|
|
|
|
let row = {
|
|
|
|
|
key: well.caption + section.id,
|
|
|
|
|
id: well.id,
|
2021-10-14 16:56:29 +05:00
|
|
|
|
sectionId: section.id,
|
2021-10-14 11:07:11 +05:00
|
|
|
|
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",
|
|
|
|
|
])
|
|
|
|
|
|
|
|
|
|
setRows(rows)
|
|
|
|
|
}, [statsWells])
|
|
|
|
|
|
|
|
|
|
useEffect(() => {
|
2021-10-14 16:56:29 +05:00
|
|
|
|
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])
|
2021-10-14 11:07:11 +05:00
|
|
|
|
|
|
|
|
|
const columns = [
|
|
|
|
|
makeTextColumn("скв №", "caption", null, null,
|
|
|
|
|
(text, item) => <Link to={`/well/${item?.id}`}>{text ?? '-'}</Link>
|
|
|
|
|
),
|
|
|
|
|
makeTextColumn("Секция", "sectionType", filtersSectionsType, null, (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">{company.caption}</Tag>),
|
|
|
|
|
},
|
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
const paramsColumns = [
|
|
|
|
|
makeColumn('Конструкция секции','idWellSectionType', {
|
|
|
|
|
editable:true,
|
|
|
|
|
input:<SelectFromDictionary dictionary={dictionarySectionType}/>,
|
|
|
|
|
width:160,
|
|
|
|
|
render:(_, record)=>getByKeyOrReturnKey(dictionarySectionType, record.idWellSectionType)
|
|
|
|
|
}),
|
|
|
|
|
// makeNumericStartEnd('Глубина', 'depth'),
|
|
|
|
|
makeNumericAvgRange('Нагрузка', 'axialLoad'),
|
|
|
|
|
makeNumericAvgRange('Давление', 'pressure'),
|
|
|
|
|
makeNumericAvgRange('Момент на ВПС', 'rotorTorque'),
|
|
|
|
|
makeNumericAvgRange('Обороты на ВПС', 'rotorSpeed'),
|
|
|
|
|
makeNumericAvgRange('Расход', 'flow')
|
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
const rowSelection = {
|
|
|
|
|
selectedRowKeys: selectedWellsKeys,
|
2021-10-14 16:56:29 +05:00
|
|
|
|
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,
|
|
|
|
|
'Не удалось сохранить изменения выбранных секций для композитной скважины'
|
|
|
|
|
)
|
2021-10-14 11:07:11 +05:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const onParamButtonClick = () => invokeWebApiWrapperAsync(
|
|
|
|
|
async () => {
|
|
|
|
|
const params = await DrillParamsService.getCompositeAll(idWell)
|
|
|
|
|
setParams(params)
|
|
|
|
|
setIsParamsModalVisible(true)
|
|
|
|
|
},
|
|
|
|
|
setShowLoader,
|
|
|
|
|
`Не удалось загрузить список режимов для скважины ${idWell}`
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
const onParamsAddClick = () => invokeWebApiWrapperAsync(
|
|
|
|
|
async () => {
|
|
|
|
|
await DrillParamsService.insertRange(idWell, params)
|
|
|
|
|
setIsParamsModalVisible(false)
|
|
|
|
|
},
|
|
|
|
|
setShowLoader,
|
|
|
|
|
`Не удалось добавить режимы в список скважины ${idWell}`
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
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>
|
|
|
|
|
<Button
|
|
|
|
|
size={'large'}
|
|
|
|
|
disabled={selectedWells.length <= 0}
|
|
|
|
|
onClick={onParamButtonClick}
|
|
|
|
|
>Режимы</Button>
|
|
|
|
|
</Col></Row>
|
|
|
|
|
|
|
|
|
|
<Modal
|
|
|
|
|
title='TVD'
|
|
|
|
|
centered
|
|
|
|
|
visible={isTVDModalVisible}
|
|
|
|
|
onCancel={() => setIsTVDModalVisible(false)}
|
|
|
|
|
width={1500}
|
|
|
|
|
footer={null}
|
|
|
|
|
>
|
|
|
|
|
<LoaderPortal show={showLoader}>
|
|
|
|
|
<ChartTvD
|
|
|
|
|
dataPlan={tvdDataPlan}
|
|
|
|
|
dataFact={tvdDataFact}
|
|
|
|
|
dataPredict={tvdDataForecast} />
|
|
|
|
|
</LoaderPortal>
|
|
|
|
|
</Modal>
|
|
|
|
|
|
|
|
|
|
<Modal
|
|
|
|
|
title='Операции'
|
|
|
|
|
centered
|
|
|
|
|
visible={isOpsModalVisible}
|
|
|
|
|
onCancel={() => setIsOpsModalVisible(false)}
|
|
|
|
|
width={1500}
|
|
|
|
|
footer={null}
|
|
|
|
|
>
|
|
|
|
|
<LoaderPortal show={showLoader}>
|
|
|
|
|
<WellOperationsTable wellOperations={wellOperations} />
|
|
|
|
|
</LoaderPortal>
|
|
|
|
|
</Modal>
|
|
|
|
|
|
|
|
|
|
<Modal
|
|
|
|
|
title={'Режимы'}
|
|
|
|
|
centered
|
|
|
|
|
visible={isParamsModalVisible}
|
|
|
|
|
onCancel={() => setIsParamsModalVisible(false)}
|
|
|
|
|
width={1700}
|
|
|
|
|
footer={
|
|
|
|
|
<Button
|
|
|
|
|
size={'large'}
|
|
|
|
|
disabled={params.length <= 0}
|
|
|
|
|
onClick={onParamsAddClick}
|
|
|
|
|
>Добавить</Button>
|
|
|
|
|
}
|
|
|
|
|
>
|
|
|
|
|
<LoaderPortal show={showLoader}>
|
|
|
|
|
<Table
|
|
|
|
|
size={'small'}
|
|
|
|
|
bordered
|
|
|
|
|
columns={paramsColumns}
|
|
|
|
|
dataSource={params}
|
|
|
|
|
pagination={false}
|
|
|
|
|
/>
|
|
|
|
|
</LoaderPortal>
|
|
|
|
|
</Modal>
|
|
|
|
|
</>
|
|
|
|
|
);
|
|
|
|
|
}
|