Обработка данных графика перенесена в Column.jsx, зоны закончены

This commit is contained in:
goodmice 2021-10-27 11:05:50 +05:00
parent 35136f6269
commit 1ee38ca733
5 changed files with 230 additions and 211 deletions

View File

@ -1,4 +1,4 @@
import { useEffect, useRef, useState} from 'react'; import { useEffect, useRef, useState} from 'react'
import { import {
Chart, Chart,
TimeScale, TimeScale,
@ -10,11 +10,20 @@ import {
ChartData, ChartData,
ChartTypeRegistry, ChartTypeRegistry,
ChartOptions} from 'chart.js' ChartOptions} from 'chart.js'
import 'chartjs-adapter-moment'; import 'chartjs-adapter-moment'
import ChartDataLabels from 'chartjs-plugin-datalabels'; import ChartDataLabels from 'chartjs-plugin-datalabels'
import zoomPlugin from 'chartjs-plugin-zoom'; import zoomPlugin from 'chartjs-plugin-zoom'
Chart.register( TimeScale, LinearScale, LineController, LineElement, PointElement, Legend, ChartDataLabels, zoomPlugin ); Chart.register(
TimeScale,
LinearScale,
LineController,
LineElement,
PointElement,
Legend,
ChartDataLabels,
zoomPlugin
)
const defaultOptions = { const defaultOptions = {
responsive: true, responsive: true,
@ -23,9 +32,7 @@ const defaultOptions = {
tooltips: { tooltips: {
enabled: true, enabled: true,
callbacks: { callbacks: {
label(tooltipItem:any) { label: (tooltipItem:any) => tooltipItem.yLabel
return tooltipItem.yLabel;
}
} }
}, },
events: ['mousemove', 'mouseout', 'click', 'touchstart', 'touchmove'], events: ['mousemove', 'mouseout', 'click', 'touchstart', 'touchmove'],
@ -53,9 +60,9 @@ const defaultOptions = {
ticks: { ticks: {
z: 1, z: 1,
display : false, display : false,
textStrokeColor : "#ffff", textStrokeColor : '#ffff',
textStrokeWidth : 2, textStrokeWidth : 2,
color:"#000", color:'#000',
} }
}, },
@ -118,7 +125,7 @@ export type TimeParams = {
const linesPerInterval = 32 const linesPerInterval = 32
export const timeUnitByInterval = (intervalSec:number):String => { export const timeUnitByInterval = (intervalSec: number): String => {
if(intervalSec <= 60) if(intervalSec <= 60)
return 'millisecond' return 'millisecond'
@ -146,42 +153,42 @@ export const timeUnitByInterval = (intervalSec:number):String => {
return 'year' return 'year'
} }
export const timeParamsByInterval = (intervalSec:number) :TimeParams => { export const timeParamsByInterval = (intervalSec: number): TimeParams => {
let stepSize = intervalSec let stepSize = intervalSec
let unit = timeUnitByInterval(intervalSec) let unit = timeUnitByInterval(intervalSec)
switch(unit){ switch(unit){
case "millisecond": case 'millisecond':
stepSize *= 1000 stepSize *= 1000
break; break;
case "second": case 'second':
//stepSize *= 1 //stepSize *= 1
break; break;
case "minute": case 'minute':
stepSize /= 60 stepSize /= 60
break; break;
case "hour": case 'hour':
stepSize /= 60*60 stepSize /= 60*60
break; break;
case "day": case 'day':
stepSize /= 24*60*60 stepSize /= 24*60*60
break; break;
case "week": case 'week':
stepSize /= 7*24*60*60 stepSize /= 7*24*60*60
break; break;
case "month": case 'month':
stepSize /= 30*24*60*60 stepSize /= 30*24*60*60
break; break;
case "quarter": case 'quarter':
stepSize /= 91*24*60*60 stepSize /= 91*24*60*60
break; break;
case "year": case 'year':
stepSize /= 365.25*24*60*60 stepSize /= 365.25*24*60*60
break; break;
} }
stepSize = Math.round(stepSize/linesPerInterval) stepSize = Math.round(stepSize/linesPerInterval)
stepSize = stepSize > 0 ? stepSize : 1; stepSize = stepSize > 0 ? stepSize : 1
return {unit, stepSize} return {unit, stepSize}
} }
@ -204,20 +211,17 @@ export const ChartTimeBase: React.FC<ChartTimeBaseProps> = ({options, dataParams
return () => chart?.destroy() return () => chart?.destroy()
} }
}, [chart, options, dataParams])
useEffect(()=>{ if(!chart) return
if(!chart)
return
chart.data = dataParams.data chart.data = dataParams.data
chart.options.aspectRatio = options?.aspectRatio chart.options.aspectRatio = options?.aspectRatio
if(dataParams.yStart){ if(dataParams.yStart){
let interval = Number(dataParams.yInterval ?? 600) const interval = Number(dataParams.yInterval ?? 600)
let start = new Date(dataParams.yStart) const start = new Date(dataParams.yStart)
let end = new Date(dataParams.yStart) const end = new Date(dataParams.yStart)
end.setSeconds(end.getSeconds() + interval) end.setSeconds(end.getSeconds() + interval)
let {unit, stepSize} = timeParamsByInterval(interval) const { unit, stepSize } = timeParamsByInterval(interval)
if(chart.options.scales?.y){ if(chart.options.scales?.y){
chart.options.scales.y.max = end.getTime() chart.options.scales.y.max = end.getTime()

View File

@ -1,26 +1,24 @@
import { useParams } from "react-router-dom"; import { useParams } from 'react-router-dom'
import { useState, useEffect } from "react"; import { useState, useEffect } from 'react'
import ClusterWells from "./ClusterWells"; import ClusterWells from './ClusterWells'
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'
export default function Cluster() { export const Cluster = () => {
let { idClaster } = useParams(); const { idClaster } = useParams()
const [data, setData] = useState([]); const [data, setData] = useState([])
const [showLoader, setShowLoader] = useState(false); const [showLoader, setShowLoader] = useState(false)
useEffect(() => invokeWebApiWrapperAsync( useEffect(() => invokeWebApiWrapperAsync(
async () => { async () => {
const clusterData = await WellOperationStatService.getStatCluster(idClaster); const clusterData = await WellOperationStatService.getStatCluster(idClaster)
setData(clusterData?.statsWells ?? []); setData(clusterData?.statsWells ?? [])
}, },
setShowLoader, setShowLoader,
`Не удалось загрузить данные по кусту "${idClaster}"` `Не удалось загрузить данные по кусту "${idClaster}"`
), [idClaster]); ), [idClaster])
useEffect(() => console.log(data), [data])
return ( return (
<LoaderPortal show={showLoader}> <LoaderPortal show={showLoader}>
@ -28,3 +26,5 @@ export default function Cluster() {
</LoaderPortal> </LoaderPortal>
) )
} }
export default Cluster

View File

@ -1,121 +0,0 @@
import { useEffect, useState} from 'react';
import {ChartTimeBase, ChartTimeData, ChartTimeDataParams} from '../../components/charts/ChartTimeBase'
const GetRandomColor = () => "#" + Math.floor(Math.random()*16777215).toString(16)
function GetOrCreateDatasetByLineConfig (data: ChartTimeData, lineConfig: LineConfig) {
let dataset = data?.datasets.find(d=>d.label === lineConfig.label)
if(!dataset)
{
let color = lineConfig.borderColor
?? lineConfig.backgroundColor
?? lineConfig.color
?? GetRandomColor()
dataset = {
label:lineConfig.label,
data:[],
backgroundColor: lineConfig.backgroundColor ?? color,
borderColor: lineConfig.borderColor ?? color,
borderWidth: lineConfig.borderWidth ?? 1,
borderDash: lineConfig.dash ?? [],
showLine: lineConfig.showLine,
}
data.datasets.push(dataset);
}
return dataset
}
export type LineConfig = {
type?: string
label: string
units?: string
xAccessorName: string
yAccessorName: string
color?:string
borderColor?: string
backgroundColor?: string
borderWidth?: number
dash?:number[]
labels?: any[]
showLine: boolean
xConstValue?: number|null
}
export type ChartTimeProps = {
label?: string,
yDisplay: Boolean,
// linePv?: LineConfig,
// lineSp?: LineConfig,
// lineIdle?: LineConfig,
lines: LineConfig[],
data: any[],
interval: number,
}
export const ChartTimeOnline: React.FC<ChartTimeProps> = (props) => {
const [dataParams, setDataParams] = useState<ChartTimeDataParams>({data: {datasets:[]}, yStart: new Date(), })
useEffect(()=>{
if( (!props?.lines)
|| (!props?.data)
|| (props.lines.length === 0)
|| (props.data.length === 0))
return
setDataParams((preDataParams) => {
props.lines.forEach(lineCfg => {
let dataset = GetOrCreateDatasetByLineConfig(preDataParams.data, lineCfg)
let points = props.data.map(dataItem => {return{
x: lineCfg.xConstValue ?? dataItem[lineCfg.xAccessorName],
label: dataItem[lineCfg.xAccessorName],
y: new Date(dataItem[lineCfg.yAccessorName])}
})
//dataset.data = [ ...dataset.data, ...points,].slice(-1024)
let data = [ ...dataset.data, ...points,]
if(points?.length > 2)
data.sort((a,b) => a.y > b.y ? 1 : -1)
if(data.length > 1024)
data.splice(0, (1024 - data.length))
dataset.data = data;
});
preDataParams.yStart = new Date()
preDataParams.yStart.setSeconds(preDataParams.yStart.getSeconds() - props.interval)
preDataParams.yInterval = props.interval
preDataParams.displayLabels = props.yDisplay
return preDataParams
})
}, [ props.data, props.lines, props.interval, props.yDisplay])
const chartPluginsOptions = {
plugins:{
legend:{
display: false,
},
datalabels: {
backgroundColor: 'transparent',
borderRadius: 4,
color: '#000B',
display: function(context:any) {
return context.dataset.label === 'wellDepth'
? 'auto'
: false
},
formatter: function(value: any, context: any) {
return `${value.y.toLocaleTimeString()} ${value.label.toPrecision(4)}`
},
padding: 6,
align: 'left',
anchor: 'center',
clip: true
},
tooltip: {
enable: true
}
}
}
return(<ChartTimeBase dataParams = {dataParams} options = { chartPluginsOptions } />)
}

View File

@ -1,37 +1,129 @@
import {Grid, GridItem} from '../../components/Grid'; import { useState, useEffect } from 'react'
import {ChartTimeOnline} from './ChartTimeOnline'; import { Grid, GridItem } from '../../components/Grid'
import {ChartTimeOnlineFooter} from './ChartTimeOnlineFooter'; import { ChartTimeBase } from '../../components/charts/ChartTimeBase'
import { ChartTimeOnlineFooter } from './ChartTimeOnlineFooter'
const stroke = (sz='1px', c='white') => ({ textShadow: `-${sz} -${sz} 0 ${c}, ${sz} -${sz} 0 ${c}, -${sz} ${sz} 0 ${c}, ${sz} ${sz} 0 ${c}` }) const stroke = (sz = '1px', c = 'white') => ({ textShadow: `-${sz} -${sz} 0 ${c}, ${sz} -${sz} 0 ${c}, -${sz} ${sz} 0 ${c}, ${sz} ${sz} 0 ${c}` })
export const Column = ({lineGroup, data, interval, showBorder, style, headerHeight}) => { const chartPluginsOptions = {
let dataLast = data?.length > 0 ? data[data.length - 1] : null plugins: {
let pv = lineGroup.filter(line => line.showGraph).map(line => ({ datalabels: {
backgroundColor: 'transparent',
borderRadius: 4,
color: '#000B',
display: context => (context.dataset.label === 'wellDepth') && 'auto',
formatter: value => `${value.y.toLocaleTimeString()} ${value.label.toPrecision(4)}`,
padding: 6,
align: 'left',
anchor: 'center',
clip: true
},
legend:{ display: false },
tooltip: { enable: true }
}
}
const GetLimitShape = (flowChartData, points, accessor) => {
const min = [], max = []
for (let point of points) {
const program = flowChartData.find(v => v.depthStart < point.depth && point.depth < v.depthEnd)
if (!program) continue
min.push({ x: program[`${accessor}Min`], y: new Date(point.y), label: point.label })
max.push({ x: program[`${accessor}Max`], y: new Date(point.y), label: point.label })
}
return min.concat(max.reverse()) ?? []
}
const GetRandomColor = () => '#' + Math.floor(Math.random()*16777215).toString(16)
const GetOrCreateDatasetByLineConfig = (data, lineConfig) => {
let dataset = data?.datasets.find(d => d.label === lineConfig.label)
if(!dataset) {
let color = lineConfig.borderColor
?? lineConfig.backgroundColor
?? lineConfig.color
?? GetRandomColor()
dataset = {
label: lineConfig.label,
data: [],
backgroundColor: lineConfig.backgroundColor ?? color,
borderColor: lineConfig.borderColor ?? color,
borderWidth: lineConfig.borderWidth ?? 1,
borderDash: lineConfig.dash ?? [],
showLine: lineConfig.showLine ?? !lineConfig.isShape,
fill: lineConfig.fill ?? (lineConfig.isShape ? 'shape' : 'none')
}
data.datasets.push(dataset);
}
return dataset
}
export const Column = ({ lineGroup, data, flowChartData, interval, showBorder, style, headerHeight, yDisplay }) => {
const [dataParams, setDataParams] = useState({data: {datasets:[]}, yStart: new Date(), })
let dataLast = data?.[data.length - 1]
let pv = lineGroup.filter(line => line.showLabels).map(line => ({
color: line.color, color: line.color,
label: line.label, label: line.label,
unit: line.units, unit: line.units,
value: dataLast?.[line.xAccessorName] value: dataLast?.[line.xAccessorName]
})) }))
useEffect(()=>{
if((lineGroup.length === 0) || (data.length === 0)) return
setDataParams((preDataParams) => {
lineGroup.forEach(lineCfg => {
if (lineCfg.isShape) return
const dataset = GetOrCreateDatasetByLineConfig(preDataParams.data, lineCfg)
const points = data.map(dataItem => ({
x: lineCfg.xConstValue ?? dataItem[lineCfg.xAccessorName],
label: dataItem[lineCfg.xAccessorName],
y: new Date(dataItem[lineCfg.yAccessorName]),
depth: dataItem.wellDepth
})).filter(point => (point.x ?? null) !== null && (point.y ?? null) !== null)
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))
dataset.data = lineData
//Area
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()
preDataParams.yStart.setSeconds(preDataParams.yStart.getSeconds() - interval)
preDataParams.yInterval = interval
preDataParams.displayLabels = yDisplay ?? false
return {...preDataParams}
})
}, [data, lineGroup, interval, yDisplay, flowChartData])
return ( return (
<div style={style}> <div style={style}>
<Grid style={{height: headerHeight, boxShadow: showBorder ? 'inset 0px 0px 0px 3px black' : ''}}> <Grid style={{ height: headerHeight, boxShadow: showBorder ? 'inset 0px 0px 0px 3px black' : '' }}>
{pv?.map((v, idx) => ( {pv?.map((v, idx) => (
<GridItem className={'display_chart_label'} key={idx} row={idx} col={1} style={{color: v.color}}>{v.label}</GridItem> <GridItem className={'display_chart_label'} key={idx} row={idx} col={1} style={{ color: v.color }}>{v.label}</GridItem>
))} ))}
</Grid> </Grid>
<div style={{position: 'relative'}}> <div style={{ position: 'relative' }}>
<Grid className={'display_chart_values'}> <Grid className={'display_chart_values'}>
{pv?.map((v, idx) => ( {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> <GridItem key={idx} col={1} row={idx} style={{ ...stroke(), color: v.color, padding: '0 4px' }}>{v.value?.toFixed(2) ?? '--'} {v.unit}</GridItem>
))} ))}
</Grid> </Grid>
<ChartTimeOnline <ChartTimeBase dataParams = {dataParams} options = { chartPluginsOptions } />
data={data}
yDisplay={false}
lines={lineGroup}
interval={interval}
/>
</div> </div>
<ChartTimeOnlineFooter data={dataLast} lineGroup={lineGroup} /> <ChartTimeOnlineFooter data={dataLast} lineGroup={lineGroup} />
</div> </div>

View File

@ -10,7 +10,12 @@ import { UserOfWell } from './UserOfWells'
import LoaderPortal from '../../components/LoaderPortal' import LoaderPortal from '../../components/LoaderPortal'
import { Grid, GridItem, Flex } from '../../components/Grid' import { Grid, GridItem, Flex } from '../../components/Grid'
import { Subscribe } from '../../services/signalr' import { Subscribe } from '../../services/signalr'
import { TelemetryDataSaubService, TelemetryDataSpinService, WellService } from '../../services/api' import {
DrillFlowChartService,
TelemetryDataSaubService,
TelemetryDataSpinService,
WellService
} from '../../services/api'
import { invokeWebApiWrapperAsync } from '../../components/factory' import { invokeWebApiWrapperAsync } from '../../components/factory'
import MomentStabPicEnabled from '../../images/DempherOn.png' import MomentStabPicEnabled from '../../images/DempherOn.png'
@ -31,7 +36,7 @@ const blockHeightGroup = [
xAccessorName: 'blockPosition', xAccessorName: 'blockPosition',
yAccessorName: 'date', yAccessorName: 'date',
color: '#333', color: '#333',
showGraph: true showLabels: true
}, { }, {
label: 'wellDepth', label: 'wellDepth',
units: 'м', units: 'м',
@ -47,7 +52,15 @@ const blockHeightGroup = [
xAccessorName: 'flow', xAccessorName: 'flow',
yAccessorName: 'date', yAccessorName: 'date',
color: '#077', color: '#077',
showGraph: true showLabels: true,
showLine: true
}, {
label: 'flowLimits',
units: 'л/с',
xAccessorName: 'flow',
yAccessorName: 'date',
color: 'rgba(0,119,119,.1)',
isShape: true
} }
] ]
@ -58,7 +71,7 @@ const blockSpeedGroup = [
xAccessorName: 'blockSpeed', xAccessorName: 'blockSpeed',
yAccessorName: 'date', yAccessorName: 'date',
color: '#0a0', color: '#0a0',
showGraph: true showLabels: true,
}, { }, {
label: 'blockSpeedSp', label: 'blockSpeedSp',
units: 'м/ч', units: 'м/ч',
@ -77,7 +90,7 @@ const pressureGroup = [
xAccessorName: 'pressure', xAccessorName: 'pressure',
yAccessorName: 'date', yAccessorName: 'date',
color: '#c00', color: '#c00',
showGraph: true showLabels: true
}, { }, {
label: 'pressureSp', label: 'pressureSp',
units: 'атм', units: 'атм',
@ -102,6 +115,13 @@ const pressureGroup = [
color: '#c00', color: '#c00',
footer: true, footer: true,
dash dash
}, {
label: 'pressureLimits',
units: 'атм',
xAccessorName: 'pressure',
yAccessorName: 'date',
color: 'rgba(204,0,0,.1)',
isShape: true
} }
] ]
@ -112,7 +132,7 @@ const axialLoadGroup = [
xAccessorName: 'axialLoad', xAccessorName: 'axialLoad',
yAccessorName: 'date', yAccessorName: 'date',
color: '#00a', color: '#00a',
showGraph: true showLabels: true
}, { }, {
label: 'axialLoadSp', label: 'axialLoadSp',
units: 'т', units: 'т',
@ -129,7 +149,14 @@ const axialLoadGroup = [
color: '#00a', color: '#00a',
footer: true, footer: true,
dash dash
}, }, {
label: 'axialLoadLimits',
units: 'т',
xAccessorName: 'axialLoad',
yAccessorName: 'date',
color: 'rgba(0,0,170,.1)',
isShape: true
}
] ]
const hookWeightGroup = [ const hookWeightGroup = [
@ -139,7 +166,7 @@ const hookWeightGroup = [
xAccessorName: 'hookWeight', xAccessorName: 'hookWeight',
yAccessorName: 'date', yAccessorName: 'date',
color: '#0aa', color: '#0aa',
showGraph: true showLabels: true
}, { }, {
label: 'hookWeightIdle', label: 'hookWeightIdle',
units: 'т', units: 'т',
@ -164,14 +191,20 @@ const hookWeightGroup = [
color: '#0aa', color: '#0aa',
footer: true, footer: true,
dash dash
}, }, {
{
label: 'Обороты ротора', label: 'Обороты ротора',
units: 'об/мин', units: 'об/мин',
xAccessorName: 'rotorSpeed', xAccessorName: 'rotorSpeed',
yAccessorName: 'date', yAccessorName: 'date',
color: '#aa0', color: '#aa0',
showGraph: true showLabels: true
}, {
label: 'rotorSpeedLimits',
units: 'об/мин',
xAccessorName: 'rotorSpeed',
yAccessorName: 'date',
color: 'rgba(170,170,0,.1)',
isShape: true
} }
] ]
@ -182,7 +215,7 @@ const rotorTorqueGroup = [
xAccessorName: 'rotorTorque', xAccessorName: 'rotorTorque',
yAccessorName: 'date', yAccessorName: 'date',
color: '#a0a', color: '#a0a',
showGraph: true showLabels: true
}, { }, {
label: 'План. Момент на роторе', label: 'План. Момент на роторе',
units: 'кН·м', units: 'кН·м',
@ -207,7 +240,14 @@ const rotorTorqueGroup = [
color: '#a0a', color: '#a0a',
footer: true, footer: true,
dash dash
}, }, {
label: 'rotorTorqueLimits',
units: 'кН·м',
xAccessorName: 'rotorTorque',
yAccessorName: 'date',
color: 'rgba(170,0,170,.1)',
isShape: true
}
] ]
const paramsGroups = [blockHeightGroup, blockSpeedGroup, pressureGroup, axialLoadGroup, hookWeightGroup, rotorTorqueGroup] const paramsGroups = [blockHeightGroup, blockSpeedGroup, pressureGroup, axialLoadGroup, hookWeightGroup, rotorTorqueGroup]
@ -259,8 +299,9 @@ export default function TelemetryView({ idWell }) {
const [dataSaub, setDataSaub] = useState([]) const [dataSaub, setDataSaub] = useState([])
const [dataSpin, setDataSpin] = useState([]) const [dataSpin, setDataSpin] = useState([])
const [chartInterval, setChartInterval] = useState(defaultChartInterval) const [chartInterval, setChartInterval] = useState(defaultChartInterval)
const [wellData, setWellData] = useState({idState: 0}) const [wellData, setWellData] = useState({ idState: 0 })
const [showLoader, setShowLoader] = useState(false) const [showLoader, setShowLoader] = useState(false)
const [flowChartData, setFlowChartData] = useState([])
const options = timePeriodCollection.map((line) => <Option key={line.value}>{line.label}</Option>) const options = timePeriodCollection.map((line) => <Option key={line.value}>{line.label}</Option>)
@ -284,18 +325,20 @@ export default function TelemetryView({ idWell }) {
} }
useEffect(() => { useEffect(() => {
const unsubscribeSaub = Subscribe('hubs/telemetry', 'ReceiveDataSaub', `well_${idWell}`, handleDataSaub)
const unsubscribeSpin = Subscribe('hubs/telemetry', 'ReceiveDataSpin', `well_${idWell}`, handleDataSpin)
invokeWebApiWrapperAsync( invokeWebApiWrapperAsync(
async () => { async () => {
const flowChart = await DrillFlowChartService.get(idWell)
const dataSaub = await TelemetryDataSaubService.getData(idWell, null, chartInterval) const dataSaub = await TelemetryDataSaubService.getData(idWell, null, chartInterval)
const dataSpin = await TelemetryDataSpinService.getData(idWell, null, chartInterval) const dataSpin = await TelemetryDataSpinService.getData(idWell, null, chartInterval)
setFlowChartData(flowChart ?? [])
handleDataSaub(dataSaub) handleDataSaub(dataSaub)
handleDataSpin(dataSpin) handleDataSpin(dataSpin)
}, },
setShowLoader, null,
`Не удалось получить данные по скважине "${idWell}"`, `Не удалось получить данные по скважине "${idWell}"`,
) )
const unsubscribeSaub = Subscribe('hubs/telemetry', 'ReceiveDataSaub', `well_${idWell}`, handleDataSaub)
const unsubscribeSpin = Subscribe('hubs/telemetry', 'ReceiveDataSpin', `well_${idWell}`, handleDataSpin)
return () => { return () => {
unsubscribeSaub() unsubscribeSaub()
unsubscribeSpin() unsubscribeSpin()
@ -314,7 +357,7 @@ export default function TelemetryView({ idWell }) {
const onStatusChanged = (value) => { const onStatusChanged = (value) => {
invokeWebApiWrapperAsync( invokeWebApiWrapperAsync(
async () => { async () => {
const well = {...wellData, idState: value} const well = { ...wellData, idState: value }
await WellService.updateWell(idWell, well) await WellService.updateWell(idWell, well)
setWellData(well) setWellData(well)
}, },
@ -335,9 +378,9 @@ export default function TelemetryView({ idWell }) {
{options} {options}
</Select> </Select>
</div> </div>
<div style={{ marginLeft: '1rem'}}> <div style={{ marginLeft: '1rem' }}>
Статус:&nbsp; Статус:&nbsp;
<Select value={wellData.idState} onChange={onStatusChanged}> <Select value={wellData.idState ?? 0} onChange={onStatusChanged}>
<Option value={0} disabled>Неизвестно</Option> <Option value={0} disabled>Неизвестно</Option>
<Option value={1}>В работе</Option> <Option value={1}>В работе</Option>
<Option value={2}>Завершено</Option> <Option value={2}>Завершено</Option>
@ -358,6 +401,7 @@ export default function TelemetryView({ idWell }) {
<Column <Column
style={{ width: '13vw' }} style={{ width: '13vw' }}
data={dataSaub} data={dataSaub}
flowChartData={flowChartData}
lineGroup={group} lineGroup={group}
interval={chartInterval} interval={chartInterval}
headerHeight={'60px'} headerHeight={'60px'}