From c4b3a3f9808bb2bb81015e2ae75c2b5dd08a7bb9 Mon Sep 17 00:00:00 2001 From: goodmice Date: Thu, 14 Oct 2021 11:07:11 +0500 Subject: [PATCH] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB=D0=B5?= =?UTF-8?q?=D0=BD=D0=BE=20=D0=BE=D1=82=D0=BE=D0=B1=D1=80=D0=B0=D0=B6=D0=B5?= =?UTF-8?q?=D0=BD=D0=B8=D0=B5=20=D1=81=D0=B5=D0=BA=D1=86=D0=B8=D0=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../WellCompositeSections.jsx | 293 ++++++++++++++++++ .../WellCompositeEditor/index.jsx | 186 ++++++----- 2 files changed, 398 insertions(+), 81 deletions(-) create mode 100644 src/pages/WellOperations/WellCompositeEditor/WellCompositeSections.jsx diff --git a/src/pages/WellOperations/WellCompositeEditor/WellCompositeSections.jsx b/src/pages/WellOperations/WellCompositeEditor/WellCompositeSections.jsx new file mode 100644 index 0000000..a2582b8 --- /dev/null +++ b/src/pages/WellOperations/WellCompositeEditor/WellCompositeSections.jsx @@ -0,0 +1,293 @@ +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' +import { DrillParamsService } from '../../../services/api' +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, + 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(() => { + + }, [selectedSections]) + + const columns = [ + makeTextColumn("скв №", "caption", null, null, + (text, item) => {text ?? '-'} + ), + 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) => , + align: 'center' + }, + { + title: "Операции", + render: (value) => , + align: 'center' + }, + { + title: "Подрядчики", + dataIndex: "companies", + render: (item) => + item?.map((company) => {company.caption}), + }, + ] + + const paramsColumns = [ + makeColumn('Конструкция секции','idWellSectionType', { + editable:true, + input:, + width:160, + render:(_, record)=>getByKeyOrReturnKey(dictionarySectionType, record.idWellSectionType) + }), + // makeNumericStartEnd('Глубина', 'depth'), + makeNumericAvgRange('Нагрузка', 'axialLoad'), + makeNumericAvgRange('Давление', 'pressure'), + makeNumericAvgRange('Момент на ВПС', 'rotorTorque'), + makeNumericAvgRange('Обороты на ВПС', 'rotorSpeed'), + makeNumericAvgRange('Расход', 'flow') +] + + const rowSelection = { + selectedRowKeys: selectedWellsKeys, + onChange: (keys, items) => { + setSelectedWells(items) + setSelectedWellsKeys(keys) + }, + } + + 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 ( + <> + + + +

Выбранные секции

+
+
+ + + + + setIsTVDModalVisible(false)} + width={1500} + footer={null} + > + + + + + + setIsOpsModalVisible(false)} + width={1500} + footer={null} + > + + + + + + setIsParamsModalVisible(false)} + width={1700} + footer={ + + } + > + +
+ + + + ); +} diff --git a/src/pages/WellOperations/WellCompositeEditor/index.jsx b/src/pages/WellOperations/WellCompositeEditor/index.jsx index 03774b9..58f68de 100644 --- a/src/pages/WellOperations/WellCompositeEditor/index.jsx +++ b/src/pages/WellOperations/WellCompositeEditor/index.jsx @@ -1,12 +1,12 @@ -import { Layout, Menu, TreeSelect } from 'antd' +import { Col, Layout, Menu, Row, Tag, TreeSelect } from 'antd' import { useState, useEffect } from 'react' import { Redirect, Route, Switch, Link, useParams } from 'react-router-dom' -import { DepositService } from '../../../services/api' +import { DepositService, WellCompositeService } from '../../../services/api' import { invokeWebApiWrapperAsync } from '../../../components/factory' import LoaderPortal from '../../../components/LoaderPortal' -import { WellCompositeInfo } from './WellCompositeInfo' import { WellCompositeSections } from './WellCompositeSections' -import WellOperationsTable from '../../Cluster/WellOperationsTable' +import { WellOperationStatService } from '../../../services/api' +import ClusterWells from '../../Cluster/ClusterWells' const { Content } = Layout @@ -16,98 +16,122 @@ export const WellCompositeEditor = ({idWell}) => { const [wellsTree, setWellsTree] = useState([]) const [showLoader, setShowLoader] = useState(false) + const [showTabLoader, setShowTabLoader] = useState(false) const [selectedWells, setSelectedWells] = useState([]) const [selectedIdWells, setSelectedIdWells] = useState([]) + const [statsWells, setStatsWells] = useState([]) + const [selectedSections, setSelectedSections] = useState([]) + const [wellLabels, setWellLabels] = useState([]) + + useEffect(() => { + invokeWebApiWrapperAsync( + async () => { + const deposits = await DepositService.getDeposits() + const labels = {} + 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 => { + labels[well.id] = `${deposit.caption}.${cluster.caption}.${well.caption}` + + return ({ + title: well.caption, + key: well.id, + value: well.id, + }) + }), + })) + })) + setWellsTree(wellsTree) + setWellLabels(labels) + + try { + const selected = await WellCompositeService.get(idWell) + setSelectedSections(selected) + } catch(e) { + setSelectedSections([]) + } + }, + setShowLoader, + 'Не удалось загрузить список скважин' + ) + }, [idWell]) useEffect(() => invokeWebApiWrapperAsync( async () => { - const deposits = await DepositService.getDeposits() - const wellsTree = deposits.map((deposit, dIdx) => ({ - title: deposit.caption, - key: `${dIdx}`, - value: `${dIdx}`, - children: deposit.clusters.map((cluster, cIdx) => ({ - title: cluster.caption, - key: `${dIdx}-${cIdx}`, - value: `${dIdx}-${cIdx}`, - children: cluster.wells.map(well => ({ - title: well.caption, - key: `${dIdx}-${cIdx}-${well.id}`, - value: `${dIdx}-${cIdx}-${well.id}`, - })), - })) - })) - setWellsTree(wellsTree) + const stats = await WellOperationStatService.getWellsStat(selectedIdWells) + setStatsWells(stats) }, - setShowLoader, - 'Не удалось загрузить список скважин' - ), [idWell]) - - const expandIdx = (idx) => { - const res = /^(\d+)(?:-(\d+))?(?:-(\d+))?$/g.exec(idx) - - if (res === null) return undefined - if (res[1] && res[2] && res[3]) - return parseInt(res[3]) - - const depositIdx = parseInt(res[1]) - if (res[2]) { - const clusterIdx = parseInt(res[2]) - return wellsTree[depositIdx].children[clusterIdx].children.map(well => expandIdx(well.key)).flat() - } - - return wellsTree[depositIdx].children.map(cluster => expandIdx(cluster.key)).flat() - } + setShowTabLoader, + 'Не удалось загрузить статистику по скважинам/секциям' + ), [selectedIdWells]) const onWellChanged = (value) => { setSelectedWells(value) - setSelectedIdWells(value.map(item => expandIdx(item)).flat()) + setSelectedIdWells(value) } + const tagRender = (props) => {wellLabels[props.value] ?? props.label} + return ( -
- Скважины: - - - - Сводка по скважинам - - - Сводка по секциям - - -
+ +
+ + + + + + Статистика по скважинам + + + Статистика по секциям + + + + - - - - - - - - - - - + + + + + + + + + + + + +