Обновлена страница куста (убрана вкладка секций)

This commit is contained in:
goodmice 2021-10-13 16:32:01 +05:00
parent e64092881c
commit 9e1dcbf5b0
5 changed files with 105 additions and 478 deletions

View File

@ -1,272 +0,0 @@
import { Table, Tag, Button, Badge, Divider, Modal } from "antd";
import { Link } from "react-router-dom";
import { LineChartOutlined, ProfileOutlined } from "@ant-design/icons";
import { useState, useEffect } from "react";
import {
makeTextColumn,
makeNumericColumnPlanFact
} from "../../components/Table";
import { invokeWebApiWrapperAsync } from '../../components/factory';
import ChartTvD from '../WellOperations/ChartTvD';
import WellOperationsTable from './WellOperationsTable'
import {
calcAndUpdateStatsBySections,
makeFilterMinMaxFunction,
getOperations
} from "./functions";
const filtersMinMax = [
{
text: "min",
value: "min",
},
{
text: "max",
value: "max",
},
];
const filtersSectionsType = [];
export default function ClusterSections({ clusterData }) {
const [selectedWellId, setSelectedWellId] = useState(0)
const [selectedWells, setSelectedWells] = useState([]);
const [selectedWellsKeys, setSelectedWellsKeys] = useState([]);
const [isTVDModalVisible, setIsTVDModalVisible] = useState(false)
const [isOpsModalVisible, setIsOpsModalVisible] = useState(false)
const [tvdDataPlan, setTvdDataPlan] = useState([]);
const [tvdDataFact, setTvdDataFact] = useState([]);
const [tvdDataForecast, setTvdDataForecast] = useState([]);
const [wellOperations, setWellOperations] = useState([]);
useEffect(() => {
if (selectedWellId > 0) {
invokeWebApiWrapperAsync(
async () => {
const operations = await getOperations(selectedWellId);
setWellOperations(operations.operations)
setTvdDataPlan(operations.plan)
setTvdDataFact(operations.fact)
setTvdDataForecast(operations.predict)
},
null,
`Не удалось загрузить операции по скважине "${selectedWellId}"`,
);
}
}, [selectedWellId]);
let rows = [];
clusterData.statsWells?.forEach((well) => {
well.sections?.forEach((section) => {
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)) /
(1000 * 60 * 60 * 24)
),
sectionBuildDaysFact: (
(new Date(section.fact?.end) - new Date(section.fact?.start)) /
(1000 * 60 * 60 * 24)
),
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);
if (!filtersSectionsType.some((el) => el.text === section.caption))
filtersSectionsType.push({
text: section.caption,
value: section.caption,
});
});
});
calcAndUpdateStatsBySections(rows ?? [], [
"sectionWellDepthPlan",
"sectionWellDepthFact",
"sectionBuildDaysPlan",
"sectionBuildDaysFact",
"sectionRateOfPenetrationPlan",
"sectionRateOfPenetrationFact",
"sectionRouteSpeedPlan",
"sectionRouteSpeedFact",
"sectionBhaDownSpeedPlan",
"sectionBhaDownSpeedFact",
"sectionBhaUpSpeedPlan",
"sectionBhaUpSpeedFact",
"sectionCasingDownSpeedPlan",
"sectionCasingDownSpeedFact",
"nonProductiveTimePlan",
"nonProductiveTimeFact",
]);
const columns = [
makeTextColumn("скв №", "caption", null, null,
(text, item) => <Link to={`/well/${item?.id}`}>{text ?? '-'}</Link>
),
makeTextColumn("Секция", "sectionType", filtersSectionsType, null,
(text, item) => 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 rowSelection = {
selectedRowKeys: selectedWellsKeys,
onChange: (keys, items) => {
setSelectedWells(items);
setSelectedWellsKeys(keys);
},
};
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}
/>
<Modal
title='TVD'
centered
visible={isTVDModalVisible}
onCancel={() => setIsTVDModalVisible(false)}
width={1500}
footer={null}
>
<ChartTvD
dataPlan={tvdDataPlan}
dataFact={tvdDataFact}
dataPredict={tvdDataForecast} />
</Modal>
<Modal
title='Операции'
centered
visible={isOpsModalVisible}
onCancel={() => setIsOpsModalVisible(false)}
width={1500}
footer={null}
>
<WellOperationsTable
wellOperations={wellOperations}
/>
</Modal>
</>
);
}

View File

@ -8,11 +8,12 @@ import {
makeColumn, makeColumn,
makeDateSorter, makeDateSorter,
makeNumericColumnPlanFact} from "../../components/Table"; makeNumericColumnPlanFact} from "../../components/Table";
import { calcAndUpdateStatsBySections, makeFilterMinMaxFunction } from "./functions"; import { calcAndUpdateStatsBySections, makeFilterMinMaxFunction, getPrecision } from "./functions";
import { invokeWebApiWrapperAsync } from '../../components/factory'; import { invokeWebApiWrapperAsync } from '../../components/factory';
import ChartTvD from '../WellOperations/ChartTvD'; import ChartTvD from '../WellOperations/ChartTvD';
import WellOperationsTable from './WellOperationsTable' import WellOperationsTable from './WellOperationsTable'
import { getOperations } from "./functions"; import { getOperations } from "./functions";
import LoaderPortal from "../../components/LoaderPortal";
const filtersMinMax = [ const filtersMinMax = [
{ {
@ -26,8 +27,9 @@ const filtersMinMax = [
]; ];
const filtersWellsType = []; const filtersWellsType = [];
const DAY_IN_MS = 1000 * 60 * 60 * 24;
export default function ClusterWells({clusterData}) { export default function ClusterWells({statsWells}) {
const [selectedWellId, setSelectedWellId] = useState(0) const [selectedWellId, setSelectedWellId] = useState(0)
const [isTVDModalVisible, setIsTVDModalVisible] = useState(false) const [isTVDModalVisible, setIsTVDModalVisible] = useState(false)
@ -36,34 +38,32 @@ export default function ClusterWells({clusterData}) {
const [tvdDataFact, setTvdDataFact] = useState([]); const [tvdDataFact, setTvdDataFact] = useState([]);
const [tvdDataForecast, setTvdDataForecast] = useState([]); const [tvdDataForecast, setTvdDataForecast] = useState([]);
const [wellOperations, setWellOperations] = useState([]); const [wellOperations, setWellOperations] = useState([]);
const [tableData, setTableData] = useState([])
const [showLoader, setShowLoader] = useState(false)
useEffect(() => { useEffect(() => {
if (selectedWellId > 0) { if (selectedWellId > 0) {
invokeWebApiWrapperAsync( invokeWebApiWrapperAsync(
async () => { async () => {
const operations = await getOperations(selectedWellId); const operations = await getOperations(selectedWellId);
setWellOperations(operations.operations) setWellOperations(operations.operations)
setTvdDataPlan(operations.plan) setTvdDataPlan(operations.plan)
setTvdDataFact(operations.fact) setTvdDataFact(operations.fact)
setTvdDataForecast(operations.predict) setTvdDataForecast(operations.predict)
}, },
null, setShowLoader,
`Не удалось загрузить операции по скважине "${selectedWellId}"`, `Не удалось загрузить операции по скважине "${selectedWellId}"`,
); );
} else {
setWellOperations([])
} }
}, [selectedWellId]); }, [selectedWellId]);
let tableData = clusterData.statsWells?.map((well) => {
useEffect(() => {
let data = statsWells?.map((well) => {
if (!filtersWellsType.some((el) => el.text === well.wellType)) if (!filtersWellsType.some((el) => el.text === well.wellType))
filtersWellsType.push({ filtersWellsType.push({ text: well.wellType, value: well.wellType,});
text: well.wellType,
value: well.wellType,
});
return { return {
key: well.caption, key: well.caption,
@ -72,14 +72,8 @@ useEffect(() => {
wellType: well.wellType, wellType: well.wellType,
factStart: well.total?.fact?.start, factStart: well.total?.fact?.start,
factEnd: well.total?.fact?.end, factEnd: well.total?.fact?.end,
periodPlan: ( periodPlan: (new Date(well.total?.plan?.end) - new Date(well.total?.plan?.start)) / DAY_IN_MS,
(new Date(well.total?.plan?.end) - new Date(well.total?.plan?.start)) / periodFact: (new Date(well.total?.fact?.end) - new Date(well.total?.fact?.start)) / DAY_IN_MS,
(1000 * 60 * 60 * 24)
),
periodFact: (
(new Date(well.total?.fact?.end) - new Date(well.total?.fact?.start)) /
(1000 * 60 * 60 * 24)
),
rateOfPenetrationPlan: well.total?.plan?.rop, rateOfPenetrationPlan: well.total?.plan?.rop,
rateOfPenetrationFact: well.total?.fact?.rop, rateOfPenetrationFact: well.total?.fact?.rop,
routeSpeedPlan: well.total?.plan?.routeSpeed, routeSpeedPlan: well.total?.plan?.routeSpeed,
@ -90,7 +84,7 @@ useEffect(() => {
}; };
}); });
calcAndUpdateStatsBySections(tableData ?? [], [ calcAndUpdateStatsBySections(data ?? [], [
"factStart", "factStart",
"factEnd", "factEnd",
"periodPlan", "periodPlan",
@ -102,63 +96,24 @@ useEffect(() => {
"notProductiveTime", "notProductiveTime",
]); ]);
setTableData(data)
}, [statsWells])
const getDate = (str) => Number.isNaN(new Date(str).getTime()) ? '-' : new Date(str).toLocaleString()
const columns = [ const columns = [
makeTextColumn("скв №", "caption", null, null, makeTextColumn("скв №", "caption", null, null,
(_, item) => (<Link to={`/well/${item.id}`}>{item.caption ?? '-'}</Link> (_, item) => (<Link to={`/well/${item.id}`}>{item.caption ?? '-'}</Link>
)), )),
makeTextColumn("Тип скв.", "wellType", filtersWellsType, null, makeTextColumn("Тип скв.", "wellType", filtersWellsType, null, (text) => text ?? '-'),
(text) => text ?? '-'
),
makeGroupColumn("Фактические сроки", [ makeGroupColumn("Фактические сроки", [
makeColumn("начало", "factStart", makeColumn("начало", "factStart", { sorter: makeDateSorter('factStart'), render: getDate }),
{ makeColumn("окончание", "factEnd", { sorter: makeDateSorter('factEnd'), render: getDate })
sorter: makeDateSorter('factStart'),
render: (dateString) => !Number.isNaN(new Date(dateString).getTime())
? new Date(dateString).toLocaleString()
: '-'
}
),
makeColumn("окончание", "factEnd",
{
sorter: makeDateSorter('factEnd'),
render: (dateString) => !Number.isNaN(new Date(dateString).getTime())
? new Date(dateString).toLocaleString()
: '-'
}
),
]), ]),
makeNumericColumnPlanFact( makeNumericColumnPlanFact("Продолжительность", "period", filtersMinMax, makeFilterMinMaxFunction, getPrecision),
"Продолжительность", makeNumericColumnPlanFact("МСП", "rateOfPenetration", filtersMinMax, makeFilterMinMaxFunction, getPrecision),
"period", makeNumericColumnPlanFact("Рейсовая скорость", "routeSpeed", filtersMinMax, makeFilterMinMaxFunction, getPrecision),
filtersMinMax, makeNumericColumnPlanFact("НПВ, сут", "notProductiveTime", filtersMinMax, makeFilterMinMaxFunction, getPrecision),
makeFilterMinMaxFunction,
(number) => (!Number.isNaN(number) && number !== undefined)
? number.toFixed(2)
: '-'),
makeNumericColumnPlanFact(
"МСП",
"rateOfPenetration",
filtersMinMax,
makeFilterMinMaxFunction,
(number) => (!Number.isNaN(number) && number !== undefined)
? number.toFixed(2)
: '-'),
makeNumericColumnPlanFact(
"Рейсовая скорость",
"routeSpeed",
filtersMinMax,
makeFilterMinMaxFunction,
(number) => (!Number.isNaN(number) && number !== undefined)
? number.toFixed(2)
: '-'),
makeNumericColumnPlanFact(
"НПВ, сут",
"notProductiveTime",
filtersMinMax,
makeFilterMinMaxFunction,
(number) => (!Number.isNaN(number) && number !== undefined)
? number.toFixed(2)
: '-'),
{ {
title: "TVD", title: "TVD",
key: "tvd", key: "tvd",
@ -181,13 +136,12 @@ useEffect(() => {
title: "Подрядчики", title: "Подрядчики",
key: "companies", key: "companies",
dataIndex: "companies", dataIndex: "companies",
render: (item) => render: (item) => item?.map((company) => <Tag key={company.caption} color="blue">{company.caption}</Tag>) ?? '-',
item?.map((company) => <Tag key={company.caption} color="blue">{company.caption}</Tag>) ?? '-',
}, },
]; ];
return ( return (
<div> <>
<Table <Table
columns={columns} columns={columns}
dataSource={tableData} dataSource={tableData}
@ -220,10 +174,10 @@ useEffect(() => {
width={1500} width={1500}
footer={null} footer={null}
> >
<WellOperationsTable <LoaderPortal show={showLoader}>
wellOperations={wellOperations} <WellOperationsTable wellOperations={wellOperations} />
/> </LoaderPortal>
</Modal> </Modal>
</div> </>
); );
} }

View File

@ -1,40 +1,19 @@
import { Table } from "antd"; import { Table } from 'antd';
import { import {
makeTextColumn, makeTextColumn,
makeNumericColumnPlanFact makeNumericColumnPlanFact
} from "../../components/Table" } from '../../components/Table'
import { getPrecision } from './functions'
export default function WellOperationsTable({wellOperations}) { export default function WellOperationsTable({wellOperations}) {
const columns = [ const columns = [
makeTextColumn("Конструкция секции","sectionType"), makeTextColumn('Конструкция секции','sectionType'),
makeTextColumn("Операция","operationName"), makeTextColumn('Операция','operationName'),
makeNumericColumnPlanFact( makeNumericColumnPlanFact('Глубина забоя', 'depth', null, null, getPrecision),
"Глубина забоя", makeNumericColumnPlanFact('Часы', 'durationHours', null, null, getPrecision),
"depth", makeNumericColumnPlanFact('Комментарий', 'comment', null, null, (text) => text ?? '-')
null,
null,
(number) => (!Number.isNaN(number) && number !== undefined)
? number.toFixed(2)
: '-'
),
makeNumericColumnPlanFact(
"Часы",
"durationHours",
null,
null,
(number) => (!Number.isNaN(number) && number !== undefined)
? number.toFixed(2)
: '-'
),
makeNumericColumnPlanFact(
"Комментарий",
"comment",
null,
null,
(text) => text ?? '-'
)
]; ];
const operations = wellOperations?.map(el => { const operations = wellOperations?.map(el => {
@ -56,7 +35,7 @@ export default function WellOperationsTable({wellOperations}) {
<Table <Table
columns={columns} columns={columns}
dataSource={operations} dataSource={operations}
size={"small"} size={'small'}
bordered bordered
pagination={{ defaultPageSize: 10 }} pagination={{ defaultPageSize: 10 }}
rowKey={(record) => record.key} rowKey={(record) => record.key}

View File

@ -3,9 +3,13 @@ import { WellOperationStatService } from '../../services/api';
const maxPrefix = "isMax" const maxPrefix = "isMax"
const minPrefix = "isMin" const minPrefix = "isMin"
export const getPrecision = (number) => Number.isNaN(number ?? NaN) ? '-' : number.toFixed(2)
export const getOperations = async (idWell) => { export const getOperations = async (idWell) => {
const ops = await WellOperationStatService.getTvd(idWell); const ops = await WellOperationStatService.getTvd(idWell);
if (!ops) return [];
const convert = wellOperationDto => const convert = wellOperationDto =>
({ ({
key: wellOperationDto?.id, key: wellOperationDto?.id,

View File

@ -1,68 +1,30 @@
import { Layout, Menu } from "antd"; import { useParams } from "react-router-dom";
import { Link, Switch, Route, Redirect, useParams } from "react-router-dom";
import { useState, useEffect } from "react"; import { useState, useEffect } from "react";
import ClusterWells from "./ClusterWells"; import ClusterWells from "./ClusterWells";
import ClusterSections from "./ClusterSections";
import LoaderPortal from "../../components/LoaderPortal"; import LoaderPortal from "../../components/LoaderPortal";
import { invokeWebApiWrapperAsync } from "../../components/factory"; import { invokeWebApiWrapperAsync } from "../../components/factory";
import { WellOperationStatService } from "../../services/api"; import { WellOperationStatService } from "../../services/api";
const { Content } = Layout;
export default function Cluster() { export default function Cluster() {
let { idClaster, tab } = useParams(); let { idClaster } = useParams();
const [data, setData] = useState([]); const [data, setData] = useState([]);
const [showLoader, setShowLoader] = useState(false); const [showLoader, setShowLoader] = useState(false);
useEffect(() => { useEffect(() => invokeWebApiWrapperAsync(
invokeWebApiWrapperAsync(
async () => { async () => {
const clusterData = await WellOperationStatService.getStatCluster( const clusterData = await WellOperationStatService.getStatCluster(idClaster);
idClaster setData(clusterData?.statsWells ?? []);
);
setData(clusterData ?? []);
}, },
setShowLoader, setShowLoader,
`Не удалось загрузить данные по кусту "${idClaster}"` `Не удалось загрузить данные по кусту "${idClaster}"`
); ), [idClaster]);
}, [idClaster]);
useEffect(() => console.log(data), [data])
return ( return (
<>
<Layout>
<Menu
mode="horizontal"
selectable={true}
selectedKeys={[tab]}
className="well_menu"
>
<Menu.Item key="wells">
<Link to={`/cluster/${idClaster}/wells`}>Скважины</Link>
</Menu.Item>
<Menu.Item key="sections">
<Link to={`/cluster/${idClaster}/sections`}>Секции</Link>
</Menu.Item>
</Menu>
</Layout>
<Layout>
<LoaderPortal show={showLoader}> <LoaderPortal show={showLoader}>
<Content className="site-layout-background"> <ClusterWells statsWells={data} />
<Switch>
<Route path="/cluster/:id/wells">
<ClusterWells clusterData={data} />
</Route>
<Route path="/cluster/:id/sections">
<ClusterSections clusterData={data} />
</Route>
<Route path="/">
<Redirect to={`/cluster/${idClaster}/wells`} />
</Route>
</Switch>
</Content>
</LoaderPortal> </LoaderPortal>
</Layout> )
</>
);
} }