diff --git a/src/components/selectors/WellSelector.jsx b/src/components/selectors/WellSelector.jsx index c0e18bd..1894021 100755 --- a/src/components/selectors/WellSelector.jsx +++ b/src/components/selectors/WellSelector.jsx @@ -59,6 +59,7 @@ export const WellSelector = memo(({ value, onChange, treeData, treeLabels, ...ot { - if (!key || key.trim() === '') return null - const keys = key.split('.') - let out = data - while (keys.length > 0) { - if (!(keys[0] in out)) return null - out = out[keys[0]] - keys.splice(0, 1) - } - return out -} - -const makeNumericSorter = (keys) => (a, b) => getDeepValue(a, keys) - getDeepValue(b, keys) - -const numericRender = makeNumericRender(1) -const makeNumericColumn = (title, dataIndex, render, other) => makeColumn(title, dataIndex, { - sorter: makeNumericSorter(dataIndex), - render: (_, record, index) => { - const func = render ?? ((value) => <>{value}) - const item = getDeepValue(record, dataIndex) - return func(item, record, index) - }, - align: 'right', - ...other, -}) - -const makeAvgRender = (dataIndex) => (avg, record) => { - const max = record[dataIndex]?.max - const fillW = (max - avg) / max * 100 - return ( -
-
-
- {numericRender(avg)} -
-
- ) -} - -const makeNumericAvgRange = (title, dataIndex, defaultRender = false) => makeGroupColumn(title, [ - makeNumericColumn('мин', `${dataIndex}.min`), - makeNumericColumn('сред', `${dataIndex}.avg`, defaultRender ? undefined : makeAvgRender(dataIndex)), - makeNumericColumn('макс', `${dataIndex}.max`), -]) - -export const getColumns = async (idWell) => { - let sectionTypes = await WellOperationService.getSectionTypes(idWell) - sectionTypes = Object.entries(sectionTypes).map(([id, value]) => ({ - label: value, - value: id, - })) - - return [ - makeSelectColumn('Конструкция секции','idWellSectionType', sectionTypes, null, { - width: 160, - sorter: makeNumericSorter('idWellSectionType'), - }), - makeNumericAvgRange('Нагрузка, т', 'axialLoad'), - makeNumericAvgRange('Давление, атм', 'pressure'), - makeNumericAvgRange('Момент на ВСП, кН·м', 'rotorTorque', true), - makeNumericAvgRange('Обороты на ВСП, об/мин', 'rotorSpeed'), - makeNumericAvgRange('Расход, л/с', 'flow'), - ] -} - -export const NewParamsTable = memo(({ selectedWellsKeys }) => { - const [params, setParams] = useState([]) - const [paramsColumns, setParamsColumns] = useState([]) - const [showParamsLoader, setShowParamsLoader] = useState(false) - const [isParamsModalVisible, setIsParamsModalVisible] = useState(false) - - const [well] = useWell() - - useEffect(() => { - invokeWebApiWrapperAsync(async () => setParamsColumns(await getColumns(well.id))) - }, [well]) - - const onParamButtonClick = useCallback(() => invokeWebApiWrapperAsync( - async () => { - setIsParamsModalVisible(true) - const params = await DrillParamsService.getCompositeAll(well.id) - setParams(params) - }, - setShowParamsLoader, - `Не удалось загрузить список режимов`, - { actionName: 'Получение списка режимов скважины', well } - ), [well]) - - const onParamsAddClick = useCallback(() => invokeWebApiWrapperAsync( - async () => { - await DrillParamsService.save(well.id, params) - setIsParamsModalVisible(false) - }, - setShowParamsLoader, - `Не удалось добавить режимы в список`, - { actionName: 'Добавление режима скважины', well } - ), [well, params]) - - return ( - <> - - setIsParamsModalVisible(false)} - width={1700} - footer={( - - - - )} - > - - - - - - ) -}) - -export default NewParamsTable diff --git a/src/pages/Well/Analytics/WellCompositeEditor/WellCompositeSections.jsx b/src/pages/Well/Analytics/WellCompositeEditor/WellCompositeSections.jsx index 44f8062..9747b6c 100644 --- a/src/pages/Well/Analytics/WellCompositeEditor/WellCompositeSections.jsx +++ b/src/pages/Well/Analytics/WellCompositeEditor/WellCompositeSections.jsx @@ -1,7 +1,7 @@ import { Link, useLocation } from 'react-router-dom' import { useState, useEffect, memo, useMemo, lazy, Suspense } from 'react' import { LineChartOutlined, ProfileOutlined, TeamOutlined } from '@ant-design/icons' -import { Button, Badge, Divider, Modal, Row, Col } from 'antd' +import { Button, Badge, Divider, Modal } from 'antd' import { useWell } from '@asb/context' import LoaderPortal from '@components/LoaderPortal' @@ -17,7 +17,6 @@ import { getOperations } from '@utils' -import NewParamsTable from './NewParamsTable' const Tvd = lazy(() => import('@pages/Well/WellOperations/Tvd')) const CompaniesTable = lazy(() => import('@pages/Cluster/CompaniesTable')) @@ -217,9 +216,6 @@ const WellCompositeSections = memo(({ statsWells, selectedSections }) => { scroll={{ x: true, y: '30vh' }} pagination={false} /> - - - data?.map(item => ({ const dateSorter = makeDateSorter('date') const defaultDate = () => new Date(Date.now() - defaultPeriod * 1000) -const makeSubjectSubsription = (subject$, handler) => { - const subscribtion = subject$.pipe( +const makeSubjectSubscription = (subject$, handler) => { + const subscription = subject$.pipe( buffer(subject$.pipe(throttleTime(700))) ).subscribe((data) => handler(data.flat().filter(Boolean))) - return () => subscribtion.unsubscribe() + return () => subscription.unsubscribe() } const getRowDate = (row) => row && isRawDate(row.date) ? new Date(row.date) : null @@ -81,7 +80,6 @@ const TelemetryView = memo(() => { const [dataSaub, setDataSaub] = useState([]) const [dataSpin, setDataSpin] = useState([]) const [showLoader, setShowLoader] = useState(false) - const [flowChartData, setFlowChartData] = useState([]) const [rop, setRop] = useState(null) const [chartMethods, setChartMethods] = useState() @@ -147,7 +145,6 @@ const TelemetryView = memo(() => { const spinSubject$ = useMemo(() => new BehaviorSubject(), []) const filteredData = useMemo(() => cutData(dataSaub, domain.min, domain.max), [dataSaub, domain]) - const flowData = useMemo(() => calcFlowData(dataSaub, flowChartData), [dataSaub, flowChartData]) const chartGroups = useMemo(() => makeChartGroups(), []) useEffect(() => { @@ -170,8 +167,8 @@ const TelemetryView = memo(() => { setSearchParams(params) }, [archiveMode, endDate, chartInterval]) - useEffect(() => makeSubjectSubsription(saubSubject$, handleDataSaub), [saubSubject$, handleDataSaub]) - useEffect(() => makeSubjectSubsription(spinSubject$, handleDataSpin), [spinSubject$, handleDataSpin]) + useEffect(() => makeSubjectSubscription(saubSubject$, handleDataSaub), [saubSubject$, handleDataSaub]) + useEffect(() => makeSubjectSubscription(spinSubject$, handleDataSpin), [spinSubject$, handleDataSpin]) useEffect(() => { if (archiveMode) return @@ -233,8 +230,6 @@ const TelemetryView = memo(() => { useEffect(() => { invokeWebApiWrapperAsync( async () => { - const flowChart = await DrillFlowChartService.getByIdWell(well.id) - setFlowChartData(flowChart ?? []) const rop = await OperationStatService.getClusterRopStatByIdWell(well.id) setRop(rop) let dates = await TelemetryDataSaubService.getDataDatesRange(well.id) @@ -312,7 +307,6 @@ const TelemetryView = memo(() => { {...chartProps} yDomain={domain} data={filteredData} - flowData={flowData} methods={setChartMethods} datasetGroups={chartGroups} onWheel={onWheel} diff --git a/src/pages/Well/WellNavigationMenu.jsx b/src/pages/Well/WellNavigationMenu.jsx index b69037c..60df78f 100644 --- a/src/pages/Well/WellNavigationMenu.jsx +++ b/src/pages/Well/WellNavigationMenu.jsx @@ -40,7 +40,6 @@ export const menuItems = [ makeItem('План', 'plan', [], ), makeItem('Факт', 'fact', [], ), makeItem('РТК', 'drillProcessFlow', [], ), - makeItem('Режимы', 'params', [], ), ]), makeItem('Документы', 'document', [], , [ makeItem('Растворный сервис', 'fluidService', [], ), diff --git a/src/pages/Well/WellOperations/DrillProcessFlow.jsx b/src/pages/Well/WellOperations/DrillProcessFlow.jsx index 354b32b..a89ec3e 100644 --- a/src/pages/Well/WellOperations/DrillProcessFlow.jsx +++ b/src/pages/Well/WellOperations/DrillProcessFlow.jsx @@ -1,44 +1,83 @@ import { useState, useEffect, memo, useMemo, useCallback } from 'react' import { useWell } from '@asb/context' +import { + EditableTable, + makeGroupColumn, + makeNumericColumn, + makeNumericColumnPlanFact, + makeNumericRender, + makeNumericSorter, + makeSelectColumn, +} from '@components/Table' import LoaderPortal from '@components/LoaderPortal' import { invokeWebApiWrapperAsync } from '@components/factory' -import { EditableTable, makeNumericMinMax, makeNumericStartEnd } from '@components/Table' -import { DrillFlowChartService } from '@api' +import { ProcessMapService, WellOperationService } from '@api' import { arrayOrDefault } from '@utils' -const columns = [ - makeNumericStartEnd('Глубина, м', 'depth'), - makeNumericMinMax('Нагрузка, т', 'axialLoad'), - makeNumericMinMax('Перепад давления, атм', 'pressure'), - makeNumericMinMax('Момент на ВСП, кН·м', 'rotorTorque'), - makeNumericMinMax('Обороты на ВСП, об/мин', 'rotorSpeed'), - makeNumericMinMax('Расход, л/с', 'flow') -] +const numericRender = makeNumericRender(2) + +export const getColumns = async (idWell) => { + let sectionTypes = await WellOperationService.getSectionTypes(idWell) + sectionTypes = Object.entries(sectionTypes).map(([id, value]) => ({ + label: value, + value: id, + })) + + return [ + makeSelectColumn('Конструкция секции','idWellSectionType', sectionTypes, null, { + width: 160, + sorter: makeNumericSorter('idWellSectionType'), + }), + makeGroupColumn('Интервал бурения, м', [ + makeNumericColumn('От', 'depthStart', numericRender), + makeNumericColumn('До', 'depthEnd', numericRender), + ]), + makeNumericColumnPlanFact('Перепад давления, атм', 'pressure', numericRender), + makeNumericColumnPlanFact('Нагрузка, т', 'axialLoad', numericRender), + makeNumericColumnPlanFact('Момент на ВСП, кН·м', 'topDriveTorque', numericRender), + makeNumericColumnPlanFact('Обороты на ВСП, об/мин', 'topDriveSpeed', numericRender), + makeNumericColumnPlanFact('Расход, л/с', 'flow', numericRender), + makeNumericColumn('Плановая механическая скорость, м/ч', 'ropPlan', numericRender), + ] +} export const DrillProcessFlow = memo(() => { const [flows, setFlows] = useState([]) const [showLoader, setShowLoader] = useState(false) + const [columns, setColumns] = useState([]) const [well] = useWell() const updateFlows = useCallback(() => invokeWebApiWrapperAsync( async () => { - const flows = await DrillFlowChartService.getByIdWell(well.id) + const flows = await ProcessMapService.getByIdWell(well.id) setFlows(arrayOrDefault(flows)) }, setShowLoader, `Не удалось загрузить режимно-технологическую карту`, - { actionName: 'Получение режимно-технологической карты', well } + { actionName: 'Получение режимно-технологической карты', well }, ), [well]) + useEffect(() => { + invokeWebApiWrapperAsync( + async () => { + const columns = await getColumns(well.id) + setColumns(columns) + }, + setShowLoader, + `Не удалось загрузить список конструкций секций`, + { actionName: 'Получение списка конструкций секций', well }, + ) + }, [well]) + useEffect(() => { updateFlows() }, [well]) const tableHandlers = useMemo(() => { const handlerProps = { - service: DrillFlowChartService, + service: ProcessMapService, setLoader: setShowLoader, onComplete: updateFlows, permission: 'DrillFlowChart.edit', diff --git a/src/pages/Well/WellOperations/WellDrillParams.jsx b/src/pages/Well/WellOperations/WellDrillParams.jsx deleted file mode 100644 index 57b1ba8..0000000 --- a/src/pages/Well/WellOperations/WellDrillParams.jsx +++ /dev/null @@ -1,98 +0,0 @@ -import { useState, useEffect, useCallback, memo, useMemo } from 'react' - -import { useWell } from '@asb/context' -import { - EditableTable, - makeSelectColumn, - makeNumericSorter, - makeNumericAvgRange, -} from '@components/Table' -import LoaderPortal from '@components/LoaderPortal' -import { invokeWebApiWrapperAsync } from '@components/factory' -import { DrillParamsService, WellOperationService } from '@api' -import { arrayOrDefault } from '@utils' - -export const getColumns = async (idWell) => { - let sectionTypes = await WellOperationService.getSectionTypes(idWell) - sectionTypes = Object.entries(sectionTypes).map(([id, value]) => ({ - label: value, - value: id, - })) - - return [ - makeSelectColumn('Конструкция секции','idWellSectionType', sectionTypes, null, { - editable: true, - width: 160, - sorter: makeNumericSorter('idWellSectionType'), - }), - makeNumericAvgRange('Нагрузка, т', 'axialLoad', 1), - makeNumericAvgRange('Перепад давления, атм', 'pressure', 1), - makeNumericAvgRange('Момент на ВСП, кН·м', 'rotorTorque', 1), - makeNumericAvgRange('Обороты на ВСП, об/мин', 'rotorSpeed', 1), - makeNumericAvgRange('Расход, л/с', 'flow', 1), - ] -} - -export const WellDrillParams = memo(() => { - const [params, setParams] = useState([]) - const [showLoader, setShowLoader] = useState(false) - const [columns, setColumns] = useState([]) - - const [well] = useWell() - - const updateParams = useCallback(async () => await invokeWebApiWrapperAsync( - async () => { - const params = arrayOrDefault(await DrillParamsService.getAll(well.id)) - // Typescript против использования числа в качестве типа значения select - params.forEach((param) => param.idWellSectionType = `${param.idWellSectionType}`) - setParams(params) - }, - setShowLoader, - `Не удалось загрузить список режимов бурения`, - { actionName: 'Получение списка режимов бурения скважины', well } - ), [well]) - - useEffect(() => { - (async () => { - setColumns(await getColumns(well.id)) - await updateParams() - })() - }, [well.id, updateParams]) - - const recordParser = useCallback((record) => ({ ...record, idWell: well.id }), [well.id]) - - const tableHandlers = useMemo(() => { - const handlerProps = { - service: DrillParamsService, - setLoader: setShowLoader, - onComplete: updateParams, - permission: 'DrillParams.edit', - idWell: well.id, - idRecord: true, - } - - return { - add: { ...handlerProps, action: 'insert', actionName: 'Добавление режима бурения', recordParser }, - edit: { ...handlerProps, action: 'update', actionName: 'Редактирование режима бурения', recordParser }, - delete: { ...handlerProps, action: 'delete', actionName: 'Удаление режима бурения', permission: 'DrillParams.delete' }, - } - }, [well.id, updateParams, recordParser]) - - return ( - - - - ) -}) - -export default WellDrillParams diff --git a/src/pages/Well/index.jsx b/src/pages/Well/index.jsx index 322dbf8..61a42a7 100644 --- a/src/pages/Well/index.jsx +++ b/src/pages/Well/index.jsx @@ -1,5 +1,5 @@ import { lazy, memo, useCallback, useEffect, useMemo, useState } from 'react' -import { Navigate, Route, Routes, useLocation, useParams } from 'react-router-dom' +import { Navigate, Route, Routes, useParams } from 'react-router-dom' import { WellContext, RootPathContext, useRootPath, useLayoutProps, TopRightBlockContext } from '@asb/context' import { FastRunMenu } from '@components/FastRunMenu' @@ -22,7 +22,6 @@ const WellOperations = lazy(() => import('./WellOperations')) const DrillingProgram = lazy(() => import('./DrillingProgram')) const Tvd = lazy(() => import('./WellOperations/Tvd')) -const WellDrillParams = lazy(() => import('./WellOperations/WellDrillParams')) const DrillProcessFlow = lazy(() => import('./WellOperations/DrillProcessFlow')) const WellSectionsStat = lazy(() => import('./WellOperations/WellSectionsStat')) const WellOperationsEditorFact = lazy(() => import('./WellOperations/OperationEditor/Fact')) @@ -45,8 +44,6 @@ const breadcrumb = makeMenuBreadcrumbItemsRender(menuItems, /^\/well\/[^\/#?]+\/ const Well = memo(() => { const { idWell } = useParams() - const location = useLocation() - const [well, setWell] = useState({ id: idWell }) const [topRightBlock, setTopRightBlock] = useState() @@ -130,7 +127,6 @@ const Well = memo(() => { } /> } /> } /> - } /> } /> } />