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

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

View File

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

View File

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

View File

@ -1,68 +1,30 @@
import { Layout, Menu } from "antd";
import { Link, Switch, Route, Redirect, useParams } from "react-router-dom";
import { useParams } from "react-router-dom";
import { useState, useEffect } from "react";
import ClusterWells from "./ClusterWells";
import ClusterSections from "./ClusterSections";
import LoaderPortal from "../../components/LoaderPortal";
import { invokeWebApiWrapperAsync } from "../../components/factory";
import { WellOperationStatService } from "../../services/api";
const { Content } = Layout;
export default function Cluster() {
let { idClaster, tab } = useParams();
let { idClaster } = useParams();
const [data, setData] = useState([]);
const [showLoader, setShowLoader] = useState(false);
useEffect(() => {
invokeWebApiWrapperAsync(
useEffect(() => invokeWebApiWrapperAsync(
async () => {
const clusterData = await WellOperationStatService.getStatCluster(
idClaster
);
setData(clusterData ?? []);
const clusterData = await WellOperationStatService.getStatCluster(idClaster);
setData(clusterData?.statsWells ?? []);
},
setShowLoader,
`Не удалось загрузить данные по кусту "${idClaster}"`
);
}, [idClaster]);
), [idClaster]);
useEffect(() => console.log(data), [data])
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}>
<Content className="site-layout-background">
<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>
<ClusterWells statsWells={data} />
</LoaderPortal>
</Layout>
</>
);
)
}