diff --git a/src/components/ArchiveColumn.jsx b/src/components/ArchiveColumn.jsx deleted file mode 100644 index 60c5858..0000000 --- a/src/components/ArchiveColumn.jsx +++ /dev/null @@ -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 ( - -       -  {label} - - ); -} - -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 = ; - - const popBar = - {select} - - - - - - return ( - <> - -
- -
-
- - ); -} diff --git a/src/components/charts/ChartDepth.jsx b/src/components/charts/ChartDepth.jsx deleted file mode 100644 index 0af149e..0000000 --- a/src/components/charts/ChartDepth.jsx +++ /dev/null @@ -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' - } - }] - } -} \ No newline at end of file diff --git a/src/components/charts/ChartTimeBase.tsx b/src/components/charts/ChartTimeBase.tsx index b3a8621..5c7ff02 100644 --- a/src/components/charts/ChartTimeBase.tsx +++ b/src/components/charts/ChartTimeBase.tsx @@ -1,14 +1,14 @@ import { useEffect, useRef, useState} from 'react' -import { - Chart, - TimeScale, - LinearScale, - Legend, - LineController, - PointElement, - LineElement, - ChartData, - ChartTypeRegistry, +import { + Chart, + TimeScale, + LinearScale, + Legend, + LineController, + PointElement, + LineElement, + ChartData, + ChartTypeRegistry, ChartOptions} from 'chart.js' import 'chartjs-adapter-moment' import ChartDataLabels from 'chartjs-plugin-datalabels' @@ -65,7 +65,7 @@ const defaultOptions = { color:'#000', } }, - + x:{ type:'linear', position:'top' @@ -108,6 +108,7 @@ export type ChartTimeData = ChartData { if(intervalSec <= 32*60*60) return 'minute' - + if(intervalSec <= 32*12*60*60) return 'hour' - + if(intervalSec <= 32*24*60*60) return 'day' if(intervalSec <= 32*7*24*60*60) return 'week' - + if(intervalSec <= 32*30.4375*24*60*60) return 'month' @@ -186,13 +187,13 @@ export const timeParamsByInterval = (intervalSec: number): TimeParams => { stepSize /= 365.25*24*60*60 break; } - + stepSize = Math.round(stepSize/linesPerInterval) stepSize = stepSize > 0 ? stepSize : 1 return {unit, stepSize} } -export const ChartTimeBase: React.FC = ({options, dataParams}) => { +export const ChartTimeBase: React.FC = ({options, dataParams}) => { const chartRef = useRef(null) const [chart, setChart] = useState() @@ -202,7 +203,7 @@ export const ChartTimeBase: React.FC = ({options, dataParams Object.assign(thisOptions, defaultOptions, options) let newChart = new Chart(chartRef.current, { - type: 'line', + type: 'line', plugins: [ChartDataLabels], options: thisOptions, data: dataParams.data @@ -217,10 +218,11 @@ export const ChartTimeBase: React.FC = ({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) - end.setSeconds(end.getSeconds() + interval) + 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) if(chart.options.scales?.y){ @@ -236,4 +238,4 @@ export const ChartTimeBase: React.FC = ({options, dataParams }, [chart, dataParams, options]) return() -} \ No newline at end of file +} diff --git a/src/pages/Archive.jsx b/src/pages/Archive.jsx index cb75ad5..8abd9de 100644 --- a/src/pages/Archive.jsx +++ b/src/pages/Archive.jsx @@ -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([]) +export default function Archive({idWell}) { + 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 + useEffect(() => invokeWebApiWrapperAsync( + async () => { + const interval = (rangeDate[1] - rangeDate[0]) / 1000 + let startDate = rangeDate[0].toISOString() - let labelLenght = 8 - let borderWidth = 8 - let wRest = Math.floor((w - labelLenght)/chartsCount) - borderWidth - let w1st = wRest + labelLenght + 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 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 - 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]); - - let charts = null - if(chartsCfgs.length > 0){ - chartsCfgs[0].yDisplay = true - - charts = chartsCfgs.map((cfg, i) => - - - ) - } - - return (<> - - - - - - - {charts} - - - ) -} \ No newline at end of file + return ( + <> + + + console.log(e)}> + {paramsGroups.map((group, index) => ( + + + + ))} + + + + ) +} diff --git a/src/pages/TelemetryView/Column.jsx b/src/pages/TelemetryView/Column.jsx index 621d541..d67194e 100644 --- a/src/pages/TelemetryView/Column.jsx +++ b/src/pages/TelemetryView/Column.jsx @@ -18,7 +18,7 @@ const chartPluginsOptions = { anchor: 'center', clip: true }, - legend:{ display: false }, + legend: { display: false }, tooltip: { enable: true } } } @@ -41,9 +41,9 @@ const GetRandomColor = () => '#' + Math.floor(Math.random()*16777215).toString(1 const GetOrCreateDatasetByLineConfig = (data, lineConfig) => { let dataset = data?.datasets.find(d => d.label === lineConfig.label) if(!dataset) { - let color = lineConfig.borderColor - ?? lineConfig.backgroundColor - ?? lineConfig.color + let color = lineConfig.borderColor + ?? lineConfig.backgroundColor + ?? lineConfig.color ?? GetRandomColor() dataset = { @@ -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 - lineGroup.filter(cfg => cfg.isShape && cfg.xAccessorName === lineCfg.xAccessorName).forEach(areaCfg => { - const dataset = GetOrCreateDatasetByLineConfig(preDataParams.data, areaCfg) - dataset.data = GetLimitShape(flowChartData, lineData, areaCfg.xAccessorName) - }) + 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.setSeconds(preDataParams.yStart.getSeconds() - interval * 0.97) + 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 (
@@ -118,14 +121,22 @@ export const Column = ({ lineGroup, data, flowChartData, interval, showBorder, s ))}
- - {pv?.map((v, idx) => ( - {v.value?.toFixed(2) ?? '--'} {v.unit} - ))} - + {showLastValues && ( + + {pv?.map((v, idx) => ( + {v.value?.toFixed(2) ?? '--'} {v.unit} + ))} + + )}
- + {showLastValues && ( + + )}
) } + +Column.defaultProps = { + pointCount: 2048 +} diff --git a/src/pages/TelemetryView/index.jsx b/src/pages/TelemetryView/index.jsx index f3056c8..80cb9e7 100644 --- a/src/pages/TelemetryView/index.jsx +++ b/src/pages/TelemetryView/index.jsx @@ -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) =>