forked from ddrilling/asb_cloud_front
Удалены лишние компоненты, графики частично переработаны
This commit is contained in:
parent
1a832694b4
commit
7c81352638
@ -1,123 +0,0 @@
|
||||
import { useState, useEffect } from 'react';
|
||||
import { Button, Select, Tag, Popover, Row, Tooltip } from 'antd';
|
||||
import { ChartTimeArchive } from './charts/ChartTimeArchive';
|
||||
import { DeleteOutlined } from '@ant-design/icons';
|
||||
|
||||
const { Option } = Select;
|
||||
|
||||
const linesCollection = [
|
||||
{ label: "Глубина забоя", xAccessorName: "wellDepth", color: '#f00' },
|
||||
{ label: "Положение инструмента", xAccessorName: "bitDepth", color: '#ff0' },
|
||||
{ label: "Положение талевого блока", xAccessorName: "blockPosition", color: '#f0f' },
|
||||
{ label: "Талевый блок. Мин положение", xAccessorName: "blockPositionMin", color: '#0ff' },
|
||||
{ label: "Талевый блок. Макс положение", xAccessorName: "blockPositionMax", color: '#0f0' },
|
||||
{ label: "Скорость талевого блока", xAccessorName: "blockSpeed", color: '#00f' },
|
||||
|
||||
{ label: "Скорости талевого блока. Задание", xAccessorName: "blockSpeedSp", color: '#c00' },
|
||||
{ label: "Талевый блок. Задание скорости для роторного бурения", xAccessorName: "blockSpeedSpRotor", color: '#cc0' },
|
||||
{ label: "Талевый блок. Задание скорости для режима слайда", xAccessorName: "blockSpeedSpSlide", color: '#c0c' },
|
||||
{ label: "Талевый блок. Задание скорости для проработки", xAccessorName: "blockSpeedSpDevelop", color: '#0cc' },
|
||||
{ label: "Давление", xAccessorName: "pressure", color: '#0c0' },
|
||||
{ label: "Давление. Холостой ход", xAccessorName: "pressureIdle", color: '#00c' },
|
||||
|
||||
{ label: "Давление. Задание", xAccessorName: "pressureSp", color: '#900' },
|
||||
{ label: "Давление. Задание для роторного бурения", xAccessorName: "pressureSpRotor", color: '#990' },
|
||||
{ label: "Давление. Задание для режима слайда", xAccessorName: "pressureSpSlide", color: '#909' },
|
||||
{ label: "Давление. Задание для проработки", xAccessorName: "pressureSpDevelop", color: '#099' },
|
||||
{ label: "Давление дифф. Аварийное макс.", xAccessorName: "pressureDeltaLimitMax", color: '#090' },
|
||||
{ label: "Осевая нагрузка", xAccessorName: "axialLoad", color: '#009' },
|
||||
|
||||
{ label: "Осевая нагрузка. Задание", xAccessorName: "axialLoadSp", color: '#600' },
|
||||
{ label: "Осевая нагрузка. Аварийная макс.", xAccessorName: "axialLoadLimitMax", color: '#660' },
|
||||
{ label: "Вес на крюке", xAccessorName: "hookWeight", color: '#606' },
|
||||
{ label: "Вес на крюке. Холостой ход", xAccessorName: "hookWeightIdle", color: '#066' },
|
||||
{ label: "Вес на крюке. Посадка", xAccessorName: "hookWeightLimitMin", color: '#060' },
|
||||
{ label: "Вес на крюке. Затяжка", xAccessorName: "hookWeightLimitMax", color: '#006' },
|
||||
|
||||
{ label: "Момент на роторе", xAccessorName: "rotorTorque", color: '#300' },
|
||||
{ label: "Момент на роторе. Холостой ход", xAccessorName: "rotorTorqueIdle", color: '#330' },
|
||||
{ label: "Момент на роторе. Задание", xAccessorName: "rotorTorqueSp", color: '#303' },
|
||||
{ label: "Момент на роторе. Аварийный макс.", xAccessorName: "rotorTorqueLimitMax", color: '#033' },
|
||||
{ label: "Обороты ротора", xAccessorName: "rotorSpeed", color: '#030' },
|
||||
{ label: "Расход", xAccessorName: "flow", color: '#003' },
|
||||
|
||||
{ label: "Расход. Холостой ход", xAccessorName: "flowIdle", color: '#666' },
|
||||
{ label: "Расход. Аварийный макс.", xAccessorName: "flowDeltaLimitMax", color: '#ccc' },
|
||||
]
|
||||
|
||||
const tagRender = ({ label, value, closable, onClose }) =>{
|
||||
const onPreventMouseDown = event => {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
};
|
||||
|
||||
let color = linesCollection.find(l=>l.xAccessorName === value)?.color
|
||||
return (
|
||||
<Tag
|
||||
onMouseDown={onPreventMouseDown}
|
||||
closable={closable}
|
||||
onClose={onClose}
|
||||
style={{ marginRight: 3 }}>
|
||||
<span style={{backgroundColor:color}}> </span>
|
||||
<span> {label}</span>
|
||||
</Tag>
|
||||
);
|
||||
}
|
||||
|
||||
export function ArchiveColumn({ data, config, rangeDate, chartRatio, onRemoveChart, onSaveConfig }) {
|
||||
const [lines, setLines] = useState([]);
|
||||
|
||||
useEffect(() => {
|
||||
setLines(config.lines);
|
||||
},[config]);
|
||||
|
||||
const handleLinesSetChange = (linesKeys) => {
|
||||
let newLines = linesCollection.filter(line => linesKeys.includes(line.xAccessorName));
|
||||
config.lines = newLines;
|
||||
if(onSaveConfig)
|
||||
onSaveConfig()
|
||||
setLines(newLines);
|
||||
};
|
||||
|
||||
let selectedValues = lines?.map(line=>line.xAccessorName)??[]
|
||||
|
||||
const select = <Select
|
||||
mode="multiple"
|
||||
placeholder="Выберите линии"
|
||||
value={selectedValues}
|
||||
allowClear={false}
|
||||
showArrow
|
||||
bordered={false}
|
||||
tagRender={tagRender}
|
||||
onChange={handleLinesSetChange}
|
||||
style={{
|
||||
minWidth: "300px",
|
||||
maxWidth: "400px"
|
||||
}}
|
||||
>
|
||||
{linesCollection.map((line) => (<Option key={line.xAccessorName} value={line.xAccessorName} color={line.color}>{line.label}</Option>))}
|
||||
</Select>;
|
||||
|
||||
const popBar = <Row>
|
||||
{select}
|
||||
<Tooltip title="Удалить этот график">
|
||||
<Button onClick={() => onRemoveChart(config.id)}><DeleteOutlined /></Button>
|
||||
</Tooltip>
|
||||
</Row>
|
||||
|
||||
return (
|
||||
<>
|
||||
<Popover content={popBar}>
|
||||
<div>
|
||||
<ChartTimeArchive
|
||||
data={data}
|
||||
yDisplay={config.yDisplay}
|
||||
lines={lines}
|
||||
rangeDate={rangeDate}
|
||||
chartRatio={chartRatio}
|
||||
/>
|
||||
</div>
|
||||
</Popover>
|
||||
|
||||
</>);
|
||||
}
|
@ -1,16 +0,0 @@
|
||||
import ChartDataLabels from 'chartjs-plugin-datalabels'
|
||||
|
||||
const defaultOptionsDepthLabels = {
|
||||
borderWidth: 1,
|
||||
borderColor: black,
|
||||
borderRadius: 4,
|
||||
clamp: true,
|
||||
display: true,
|
||||
data: {
|
||||
datasets: [{
|
||||
datalabels: {
|
||||
color: '#0f4000'
|
||||
}
|
||||
}]
|
||||
}
|
||||
}
|
@ -108,6 +108,7 @@ export type ChartTimeData = ChartData<keyof ChartTypeRegistry, {
|
||||
export type ChartTimeDataParams = {
|
||||
data: ChartTimeData,
|
||||
yStart?: Date,
|
||||
yEnd?: Date,
|
||||
yInterval?: number,
|
||||
displayLabels?: Boolean,
|
||||
}
|
||||
@ -217,9 +218,10 @@ export const ChartTimeBase: React.FC<ChartTimeBaseProps> = ({options, dataParams
|
||||
chart.data = dataParams.data
|
||||
chart.options.aspectRatio = options?.aspectRatio
|
||||
if(dataParams.yStart){
|
||||
const interval = Number(dataParams.yInterval ?? 600)
|
||||
const start = new Date(dataParams.yStart)
|
||||
const end = new Date(dataParams.yStart)
|
||||
const end = new Date(dataParams.yEnd ?? dataParams.yStart)
|
||||
const interval = Number(dataParams.yInterval ?? (dataParams.yEnd ? end.getSeconds() - start.getSeconds() : 600))
|
||||
if (!dataParams.yEnd)
|
||||
end.setSeconds(end.getSeconds() + interval)
|
||||
const { unit, stepSize } = timeParamsByInterval(interval)
|
||||
|
||||
|
@ -1,144 +1,62 @@
|
||||
import { useRef, useLayoutEffect, useState, useEffect } from 'react'
|
||||
import {
|
||||
Button,
|
||||
DatePicker,
|
||||
Row,
|
||||
Col,
|
||||
Tooltip} from 'antd'
|
||||
import { useState, useEffect } from 'react'
|
||||
import { DatePicker } from 'antd'
|
||||
import { TelemetryDataSaubService } from '../services/api'
|
||||
import {generateUUID} from '../services/UidGenerator'
|
||||
import { ArchiveColumn } from '../components/ArchiveColumn'
|
||||
import moment from 'moment'
|
||||
import { notify } from "../components/factory"
|
||||
import { invokeWebApiWrapperAsync } from "../components/factory"
|
||||
import LoaderPortal from '../components/LoaderPortal'
|
||||
import { Grid, GridItem } from '../components/Grid'
|
||||
import { Column } from './TelemetryView/Column'
|
||||
import { paramsGroups } from './TelemetryView'
|
||||
|
||||
const { RangePicker } = DatePicker
|
||||
|
||||
const SaveObject = (key, obj) => {
|
||||
let json = JSON.stringify(obj)
|
||||
localStorage.setItem(key, json)
|
||||
}
|
||||
|
||||
const LoadObject = (key) => {
|
||||
let json = localStorage.getItem(key)
|
||||
return json ? JSON.parse(json) : null
|
||||
}
|
||||
|
||||
export default function Archive({idWell}) {
|
||||
const [saubData, setSaubData] = useState([])
|
||||
const [chartsCfgs, setChartsCfgs] = useState([])
|
||||
const [dataSaub, setDataSaub] = useState([])
|
||||
const [rangeDate, setRangeDate] = useState([moment().subtract(3,'hours'), moment()])
|
||||
const [geometry, setGeometry] = useState({ratioRest:1, ratio1st:1, wRest:.5, w1st:.5})
|
||||
const [loader, setLoader] = useState(false)
|
||||
const chartsCfgsKey = 'chartsCfgs'
|
||||
const chartsContainerRef = useRef();
|
||||
|
||||
const handleReceiveDataSaub = (data) => {
|
||||
if (data)
|
||||
setSaubData(data)
|
||||
}
|
||||
|
||||
const onAddChart = () => {
|
||||
let newChartCfgs = [...chartsCfgs, {id: generateUUID(), yDisplay: false, aspectRatio:1}]
|
||||
setChartsCfgs(newChartCfgs)
|
||||
}
|
||||
|
||||
const onRemoveChart = (id) => {
|
||||
let newChartCfgs = chartsCfgs.filter(cfg => cfg.id !== id )
|
||||
setChartsCfgs(newChartCfgs)
|
||||
}
|
||||
|
||||
const onSaveConfig = ()=>{
|
||||
SaveObject(chartsCfgsKey, chartsCfgs)
|
||||
}
|
||||
const [showLoader, setShowLoader] = useState(false)
|
||||
const [chartInterval, setChartInterval] = useState(600)
|
||||
|
||||
const onChangeRange = (range) => {
|
||||
setRangeDate(range)
|
||||
}
|
||||
|
||||
useLayoutEffect(()=>{
|
||||
if(chartsContainerRef.current && chartsCfgs?.length){
|
||||
let w = chartsContainerRef.current.offsetWidth //1792
|
||||
w = w > 0 ? w : 1792
|
||||
let ot = chartsContainerRef.current.offsetTop
|
||||
let ph = chartsContainerRef.current.offsetParent.offsetHeight
|
||||
let h = ph - ot - 32 //761
|
||||
h = h > 0 ? h : 761
|
||||
|
||||
let chartsCount = chartsCfgs.length
|
||||
|
||||
let labelLenght = 8
|
||||
let borderWidth = 8
|
||||
let wRest = Math.floor((w - labelLenght)/chartsCount) - borderWidth
|
||||
let w1st = wRest + labelLenght
|
||||
|
||||
let ratio1st = w1st/h
|
||||
let ratioRest = wRest/h
|
||||
|
||||
setGeometry({ratio1st, ratioRest, w1st, wRest})
|
||||
}
|
||||
},[chartsContainerRef, chartsCfgs])
|
||||
|
||||
useEffect(() => {
|
||||
let cfgs = LoadObject(chartsCfgsKey)
|
||||
if(cfgs)
|
||||
setChartsCfgs(cfgs)
|
||||
},[])
|
||||
|
||||
useEffect(()=>{
|
||||
SaveObject(chartsCfgsKey, chartsCfgs)
|
||||
},[chartsCfgs])
|
||||
|
||||
useEffect(() => {
|
||||
let interval = (rangeDate[1] - rangeDate[0]) / 1000
|
||||
useEffect(() => invokeWebApiWrapperAsync(
|
||||
async () => {
|
||||
const interval = (rangeDate[1] - rangeDate[0]) / 1000
|
||||
let startDate = rangeDate[0].toISOString()
|
||||
|
||||
setLoader(true)
|
||||
TelemetryDataSaubService.getData(idWell, startDate, interval, 2048)
|
||||
.then(handleReceiveDataSaub)
|
||||
.catch(error => {
|
||||
notify(`Не удалось загрузить данные по скважине (${idWell}) c ${rangeDate[0]} по ${rangeDate[1]}`, 'error')
|
||||
console.error(error)
|
||||
})
|
||||
.finally(()=>setLoader(false))
|
||||
}, [idWell, rangeDate]);
|
||||
const data = await TelemetryDataSaubService.getData(idWell, startDate, interval, 2048)
|
||||
data?.sort((a, b) => a.date > b.date ? 1 : -1)
|
||||
setDataSaub(data ?? [])
|
||||
setChartInterval(interval)
|
||||
},
|
||||
setShowLoader,
|
||||
`Не удалось загрузить данные по скважине "${idWell}" c ${rangeDate[0]} по ${rangeDate[1]}`
|
||||
), [idWell, rangeDate])
|
||||
|
||||
let charts = null
|
||||
if(chartsCfgs.length > 0){
|
||||
chartsCfgs[0].yDisplay = true
|
||||
|
||||
charts = chartsCfgs.map((cfg, i) =>
|
||||
<Col flex={`${i===0 ? geometry.w1st : geometry.wRest}px`}
|
||||
key={cfg.id}>
|
||||
<ArchiveColumn
|
||||
data={saubData}
|
||||
rangeDate={rangeDate}
|
||||
chartRatio={i===0 ? geometry.ratio1st : geometry.ratioRest}
|
||||
onRemoveChart={onRemoveChart}
|
||||
onSaveConfig={onSaveConfig}
|
||||
config={cfg}/>
|
||||
</Col>)
|
||||
}
|
||||
|
||||
return (<>
|
||||
<Tooltip title="Добавить график">
|
||||
<Button
|
||||
type="primary"
|
||||
onClick={onAddChart}
|
||||
disabled={chartsCfgs.length >= 6}>
|
||||
+
|
||||
</Button>
|
||||
</Tooltip>
|
||||
return (
|
||||
<>
|
||||
<RangePicker
|
||||
showTime
|
||||
allowClear={false}
|
||||
onChange = {onChangeRange}
|
||||
value = {rangeDate}
|
||||
/>
|
||||
<LoaderPortal show={loader}>
|
||||
<Row ref={chartsContainerRef}>
|
||||
{charts}
|
||||
</Row>
|
||||
<LoaderPortal show={showLoader}>
|
||||
<Grid onWheel={(e) => console.log(e)}>
|
||||
{paramsGroups.map((group, index) => (
|
||||
<GridItem col={index+1} row={'1'} className={'border_small'} key={`${group.label}${index}`} style={{padding:0}}>
|
||||
<Column
|
||||
style={{ width: '15vw' }}
|
||||
data={dataSaub}
|
||||
lineGroup={group}
|
||||
interval={chartInterval}
|
||||
headerHeight={'50px'}
|
||||
/>
|
||||
</GridItem>
|
||||
))}
|
||||
</Grid>
|
||||
</LoaderPortal>
|
||||
</>)
|
||||
</>
|
||||
)
|
||||
}
|
@ -61,7 +61,7 @@ const GetOrCreateDatasetByLineConfig = (data, lineConfig) => {
|
||||
return dataset
|
||||
}
|
||||
|
||||
export const Column = ({ lineGroup, data, flowChartData, interval, showBorder, style, headerHeight, yDisplay }) => {
|
||||
export const Column = ({ lineGroup, data, flowChartData, interval, showBorder, style, headerHeight, yDisplay, yStart, showLastValues, pointCount }) => {
|
||||
const [dataParams, setDataParams] = useState({data: {datasets:[]}, yStart: new Date(), })
|
||||
|
||||
let dataLast = data?.[data.length - 1]
|
||||
@ -89,26 +89,29 @@ export const Column = ({ lineGroup, data, flowChartData, interval, showBorder, s
|
||||
const lineData = [ ...dataset.data, ...points,]
|
||||
if(points?.length > 2)
|
||||
lineData.sort((a,b) => a.y > b.y ? 1 : -1)
|
||||
if(lineData.length > 1024)
|
||||
lineData.splice(0, (1024 - lineData.length))
|
||||
if(lineData.length > pointCount)
|
||||
lineData.splice(0, (pointCount - lineData.length))
|
||||
|
||||
dataset.data = lineData
|
||||
|
||||
//Area
|
||||
if (flowChartData) {
|
||||
lineGroup.filter(cfg => cfg.isShape && cfg.xAccessorName === lineCfg.xAccessorName).forEach(areaCfg => {
|
||||
const dataset = GetOrCreateDatasetByLineConfig(preDataParams.data, areaCfg)
|
||||
dataset.data = GetLimitShape(flowChartData, lineData, areaCfg.xAccessorName)
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
preDataParams.yStart = new Date(Math.max(new Date(dataLast.date), preDataParams.yStart ?? new Date(0)))
|
||||
preDataParams.yStart = yStart ?? new Date(Math.max(new Date(dataLast.date), preDataParams.yStart ?? new Date(0)))
|
||||
if (!yStart)
|
||||
preDataParams.yStart.setSeconds(preDataParams.yStart.getSeconds() - interval * 0.97)
|
||||
preDataParams.yInterval = interval
|
||||
preDataParams.displayLabels = yDisplay ?? false
|
||||
return {...preDataParams}
|
||||
})
|
||||
|
||||
}, [data, lineGroup, interval, yDisplay, flowChartData, dataLast])
|
||||
}, [data, lineGroup, interval, yDisplay, yStart, flowChartData, dataLast, pointCount])
|
||||
|
||||
return (
|
||||
<div style={style}>
|
||||
@ -118,14 +121,22 @@ export const Column = ({ lineGroup, data, flowChartData, interval, showBorder, s
|
||||
))}
|
||||
</Grid>
|
||||
<div style={{ position: 'relative' }}>
|
||||
{showLastValues && (
|
||||
<Grid className={'display_chart_values'}>
|
||||
{pv?.map((v, idx) => (
|
||||
<GridItem key={idx} col={1} row={idx} style={{ ...stroke(), color: v.color, padding: '0 4px' }}>{v.value?.toFixed(2) ?? '--'} {v.unit}</GridItem>
|
||||
))}
|
||||
</Grid>
|
||||
)}
|
||||
<ChartTimeBase dataParams = {dataParams} options = { chartPluginsOptions } />
|
||||
</div>
|
||||
{showLastValues && (
|
||||
<ChartTimeOnlineFooter data={dataLast} lineGroup={lineGroup} />
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
Column.defaultProps = {
|
||||
pointCount: 2048
|
||||
}
|
||||
|
@ -250,7 +250,14 @@ const rotorTorqueGroup = [
|
||||
}
|
||||
]
|
||||
|
||||
const paramsGroups = [blockHeightGroup, blockSpeedGroup, pressureGroup, axialLoadGroup, hookWeightGroup, rotorTorqueGroup]
|
||||
export const paramsGroups = [
|
||||
blockHeightGroup,
|
||||
blockSpeedGroup,
|
||||
pressureGroup,
|
||||
axialLoadGroup,
|
||||
hookWeightGroup,
|
||||
rotorTorqueGroup
|
||||
]
|
||||
|
||||
const timePeriodCollection = [
|
||||
{ value: '60', label: '1 минута' },
|
||||
@ -400,6 +407,7 @@ export default function TelemetryView({ idWell }) {
|
||||
{paramsGroups.map((group, index) =>
|
||||
<GridItem col={2 + index} row={'2'} className={'border_small'} key={`${group.label}${index}`} style={{padding:0}}>
|
||||
<Column
|
||||
showLastValues
|
||||
style={{ width: '13vw' }}
|
||||
data={dataSaub}
|
||||
flowChartData={flowChartData}
|
||||
|
Loading…
Reference in New Issue
Block a user