forked from ddrilling/asb_cloud_front
Add archive page
This commit is contained in:
parent
f221ae5290
commit
5131259b3f
123
src/components/ArchiveColumn.jsx
Normal file
123
src/components/ArchiveColumn.jsx
Normal file
@ -0,0 +1,123 @@
|
||||
import { useState, useEffect } from 'react';
|
||||
import { Button, Select, Tag, Popover, Row, Tooltip } from 'antd';
|
||||
import { ChartTimeArchive } from './charts/ChartTimeArchive';
|
||||
//import { SlidersOutlined } 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
|
||||
//color={color}
|
||||
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}
|
||||
//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)}>X</Button>
|
||||
</Tooltip>
|
||||
</Row>
|
||||
|
||||
return (
|
||||
<>
|
||||
<Popover content={popBar}>
|
||||
<div>
|
||||
<ChartTimeArchive
|
||||
data={data}
|
||||
yDisplay={config.yDisplay}
|
||||
lines={lines}
|
||||
rangeDate={rangeDate}
|
||||
chartRatio={chartRatio}
|
||||
/>
|
||||
</div>
|
||||
</Popover>
|
||||
|
||||
</>);
|
||||
}
|
@ -1,4 +1,5 @@
|
||||
import { useState, useEffect } from 'react'
|
||||
import { useParams } from 'react-router-dom'
|
||||
import { WellService } from '../services/api'
|
||||
import Loader from '../components/Loader'
|
||||
import { TreeSelect } from 'antd'
|
||||
@ -38,6 +39,7 @@ export default function WellTreeSelector(props) {
|
||||
const [wellsTree, setWellsTree] = useState([])
|
||||
const [loader, setLoader] = useState(false)
|
||||
const history = useHistory()
|
||||
let { id } = useParams();
|
||||
|
||||
let updateWellsList = async () => {
|
||||
setLoader(true)
|
||||
@ -72,6 +74,7 @@ export default function WellTreeSelector(props) {
|
||||
treeData={wellsTree}
|
||||
treeDefaultExpandAll
|
||||
onSelect={onSelect}
|
||||
value = {id}
|
||||
/>
|
||||
{loader && <Loader />}
|
||||
</>
|
||||
|
73
src/components/charts/ChartTimeArchive.jsx
Normal file
73
src/components/charts/ChartTimeArchive.jsx
Normal file
@ -0,0 +1,73 @@
|
||||
import moment from 'moment';
|
||||
import { useEffect, useState} from 'react';
|
||||
import {ChartTimeBase} from './ChartTimeBase'
|
||||
|
||||
const GetRandomColor = () => "#" + Math.floor(Math.random()*16777215).toString(16)
|
||||
|
||||
const CreateDataset = (lineConfig) => {
|
||||
let color = lineConfig.borderColor
|
||||
?? lineConfig.backgroundColor
|
||||
?? lineConfig.color
|
||||
?? GetRandomColor()
|
||||
|
||||
let dataset = {
|
||||
label: lineConfig.label,
|
||||
data: [],
|
||||
backgroundColor: lineConfig.backgroundColor ?? color,
|
||||
borderColor: lineConfig.borderColor ?? color,
|
||||
borderWidth: lineConfig.borderWidth ?? 1,
|
||||
borderDash: lineConfig.dash ?? [],
|
||||
}
|
||||
return dataset
|
||||
}
|
||||
|
||||
const ChartOptions = {
|
||||
responsive: true,
|
||||
// plugins:{
|
||||
// legend:{
|
||||
// maxHeight: 64,
|
||||
// fullSize: true,
|
||||
// display: true,
|
||||
// posision:'chartArea',
|
||||
// align: 'start',
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
export const ChartTimeArchive = ({lines, data, yDisplay, rangeDate, chartRatio}) => {
|
||||
const [dataParams, setDataParams] = useState({data:{datasets:[]}})
|
||||
|
||||
useEffect(() => {
|
||||
if ((!lines)
|
||||
|| (!data))
|
||||
return
|
||||
|
||||
let newDatasets = lines.map(lineCfg => {
|
||||
let dataset = CreateDataset(lineCfg)
|
||||
dataset.data = data.map(dataItem => {
|
||||
return {
|
||||
x: dataItem[lineCfg.xAccessorName],
|
||||
y: new Date(dataItem[lineCfg.yAccessorName??'date'])
|
||||
}
|
||||
})
|
||||
return dataset
|
||||
})
|
||||
|
||||
let interval = rangeDate ? (rangeDate[1] - rangeDate[0]) / 1000 : null
|
||||
let startDate = rangeDate ? rangeDate[0] : moment()
|
||||
let newParams = {
|
||||
yInterval: interval,
|
||||
yStart: startDate,
|
||||
displayLabels: yDisplay??false,
|
||||
data: {
|
||||
datasets: newDatasets
|
||||
}
|
||||
}
|
||||
setDataParams(newParams)
|
||||
}, [data, lines, yDisplay, rangeDate, chartRatio])
|
||||
|
||||
const opt = ChartOptions
|
||||
opt.aspectRatio = chartRatio
|
||||
|
||||
return (<ChartTimeBase dataParams={dataParams} options={opt}/>)
|
||||
}
|
@ -1,82 +0,0 @@
|
||||
import { useEffect, useState} from 'react';
|
||||
import {ChartTimeBase, ChartTimeData, ChartTimeDataParams} from './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 ?? [],
|
||||
}
|
||||
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[]
|
||||
}
|
||||
|
||||
export type ChartTimeProps = {
|
||||
label?: string,
|
||||
yDisplay: Boolean,
|
||||
lines: LineConfig[],
|
||||
data: any[],
|
||||
interval: number,
|
||||
}
|
||||
|
||||
export const ChartTimeArchive: 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: dataItem[lineCfg.xAccessorName],
|
||||
y: new Date(dataItem[lineCfg.yAccessorName])
|
||||
}
|
||||
})
|
||||
dataset.data = points;
|
||||
});
|
||||
|
||||
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])
|
||||
|
||||
return (<ChartTimeBase dataParams={dataParams} />)
|
||||
}
|
@ -16,8 +16,9 @@ Chart.register( TimeScale, LinearScale, LineController, LineElement, PointElemen
|
||||
|
||||
const defaultOptions = {
|
||||
//maintainAspectRatio: false,
|
||||
aspectRatio:0.45,
|
||||
aspectRatio: 0.45,
|
||||
animation: false,
|
||||
events: ['mousemove', 'mouseout', 'click', 'touchstart', 'touchmove'],
|
||||
scales: {
|
||||
y:{
|
||||
type: 'time',
|
||||
@ -38,12 +39,13 @@ const defaultOptions = {
|
||||
year: 'yyyy.MM',
|
||||
},
|
||||
},
|
||||
position:{ x: 20 },
|
||||
//position:'center',
|
||||
grid:{
|
||||
drawTicks: false,
|
||||
},
|
||||
ticks: {
|
||||
z: 1,
|
||||
display : false,
|
||||
textStrokeColor : "#ffff",
|
||||
textStrokeWidth : 2,
|
||||
color:"#000",
|
||||
@ -98,49 +100,49 @@ const timeUnitByInterval = (intervalSec:number):String =>{
|
||||
return 'year'
|
||||
}
|
||||
|
||||
export const ChartTimeBase: React.FC<ChartTimeBaseProps> = (props) => {
|
||||
export const ChartTimeBase: React.FC<ChartTimeBaseProps> = ({options, dataParams}) => {
|
||||
const chartRef = useRef<HTMLCanvasElement>(null)
|
||||
|
||||
const [chart, setChart] = useState<any>()
|
||||
|
||||
useEffect(()=>{
|
||||
if(chartRef.current && (!chart)){
|
||||
if((chartRef.current)&&(!chart)){
|
||||
let thisOptions = {}
|
||||
Object.assign(thisOptions, defaultOptions, props.options)
|
||||
Object.assign(thisOptions, defaultOptions, options)
|
||||
|
||||
let newChart = new Chart(chartRef.current, {
|
||||
type: 'line',
|
||||
options: thisOptions,
|
||||
data: props.dataParams.data
|
||||
data: dataParams.data
|
||||
})
|
||||
setChart(newChart)
|
||||
|
||||
return () => chart?.destroy()
|
||||
}
|
||||
}, [chart, props.options, props.dataParams])
|
||||
}, [chart, options, dataParams])
|
||||
|
||||
useEffect(()=>{
|
||||
if(!chart)
|
||||
return
|
||||
|
||||
chart.data = props.dataParams.data
|
||||
chart.data = dataParams.data
|
||||
chart.options.aspectRatio = options?.aspectRatio
|
||||
|
||||
if(props.dataParams.yStart){
|
||||
let interval = Number(props.dataParams.yInterval ?? 600)
|
||||
let start = new Date(props.dataParams.yStart)
|
||||
let end = new Date(props.dataParams.yStart)
|
||||
if(dataParams.yStart){
|
||||
let interval = Number(dataParams.yInterval ?? 600)
|
||||
let start = new Date(dataParams.yStart)
|
||||
let end = new Date(dataParams.yStart)
|
||||
end.setSeconds(end.getSeconds() + interval)
|
||||
|
||||
if(chart.options.scales?.y){
|
||||
chart.options.scales.y.max = end.getTime()
|
||||
chart.options.scales.y.min = start.getTime()
|
||||
chart.options.scales.y.ticks.display = props.dataParams.displayLabels ?? true
|
||||
chart.options.scales.y.ticks.display = dataParams.displayLabels ?? true
|
||||
chart.options.scales.y.time.unit = timeUnitByInterval(interval)
|
||||
chart.options.scales.y.time.stepSize = Math.round(interval/24)
|
||||
chart.options.scales.y.time.stepSize = Math.round(interval/32)
|
||||
}
|
||||
}
|
||||
|
||||
chart.update()
|
||||
}, [chart, props])
|
||||
}, [chart, dataParams, options])
|
||||
|
||||
return(<canvas ref={chartRef} />)
|
||||
}
|
@ -1,188 +1,139 @@
|
||||
import { useState, useEffect } from 'react'
|
||||
import { useRef, useLayoutEffect, useState, useEffect } from 'react'
|
||||
import {
|
||||
Button,
|
||||
DatePicker,
|
||||
ConfigProvider,
|
||||
Select,
|
||||
Row,
|
||||
Col,
|
||||
} from 'antd'
|
||||
Tooltip} from 'antd'
|
||||
import { useParams } from 'react-router-dom'
|
||||
import { Subscribe } from '../services/signalr'
|
||||
import { DataService } from '../services/api'
|
||||
import 'moment/locale/ru'
|
||||
import locale from 'antd/lib/locale/ru_RU'
|
||||
import { ChartTimeArchive } from '../components/charts/ChartTimeArchive'
|
||||
import { Display } from '../components/Display'
|
||||
import { ChartTimeOnlineFooter } from '../components/ChartTimeOnlineFooter'
|
||||
import { UserOfWells } from '../components/UserOfWells'
|
||||
|
||||
import {generateUUID} from '../services/UidGenerator'
|
||||
import { ArchiveColumn } from '../components/ArchiveColumn'
|
||||
import moment from 'moment'
|
||||
|
||||
const { RangePicker } = DatePicker;
|
||||
const { Option } = Select;
|
||||
|
||||
// Выбор периода времени
|
||||
const RangePickerLocalized = ({locale, ...other}) => {
|
||||
return (
|
||||
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() {
|
||||
let { id } = useParams();
|
||||
const [saubData, setSaubData] = useState([])
|
||||
const [chartsCfgs, setChartsCfgs] = useState([])
|
||||
const [rangeDate, setRangeDate] = useState([moment().subtract(3,'hours'), moment()])
|
||||
const [geometry, setGeometry] = useState({ratioRest:1, ratio1st:1, wRest:.5, w1st:.5})
|
||||
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 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
|
||||
let startDate = rangeDate[0].toISOString()
|
||||
|
||||
DataService.getData(id, startDate, interval, 2048)
|
||||
.then(handleReceiveDataSaub)
|
||||
.catch(error => console.error(error))
|
||||
}, [id, 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>
|
||||
<ConfigProvider locale={locale}>
|
||||
<RangePicker
|
||||
showTime
|
||||
style={{ margin: '5px 5px', }}
|
||||
{...other}
|
||||
onChange = {onChangeRange}
|
||||
value = {rangeDate}
|
||||
/>
|
||||
</ConfigProvider>
|
||||
)
|
||||
}
|
||||
|
||||
// Выбор "перьев" для графиков - перенести в шапку графика
|
||||
const SelectDataCharts = () => {
|
||||
const linesCollection = [
|
||||
{ label: "Глубина забоя", xAccessorName: "wellDepth", color: '#a0a' },
|
||||
{ label: "Положение инструмента", xAccessorName: "bitDepth", color: '#a0a' },
|
||||
{ label: "Высота талевого блока", xAccessorName: "blockPosition", color: '#a0a' },
|
||||
{ label: "Талевый блок. Мин положение", xAccessorName: "blockPositionMin", color: '#a0a' },
|
||||
{ label: "Талевый блок. Макс положение", xAccessorName: "blockPositionMax", color: '#a0a' },
|
||||
{ label: "Скорость талевого блока", xAccessorName: "blockSpeed", color: '#a0a' },
|
||||
{ label: "Скорости талевого блока. Задание", xAccessorName: "blockSpeedSp", color: '#a0a' },
|
||||
{ label: "Талевый блок. Задание скорости для роторного бурения", xAccessorName: "blockSpeedSpRotor", color: '#a0a' },
|
||||
{ label: "Талевый блок. Задание скорости для режима слайда", xAccessorName: "blockSpeedSpSlide", color: '#a0a' },
|
||||
{ label: "Талевый блок. Задание скорости для проработки", xAccessorName: "blockSpeedSpDevelop", color: '#a0a' },
|
||||
{ label: "Давление", xAccessorName: "pressure", color: '#a0a' },
|
||||
{ label: "Давление. Холостой ход", xAccessorName: "pressureIdle", color: '#a0a' },
|
||||
{ label: "Давление. Задание", xAccessorName: "pressureSp", color: '#a0a' },
|
||||
{ label: "Давление. Задание для роторного бурения", xAccessorName: "pressureSpRotor", color: '#a0a' },
|
||||
{ label: "Давление. Задание для режима слайда", xAccessorName: "pressureSpSlide", color: '#a0a' },
|
||||
{ label: "Давление. Задание для проработки", xAccessorName: "pressureSpDevelop", color: '#a0a' },
|
||||
{ label: "Давление дифф. Аварийное макс.", xAccessorName: "pressureDeltaLimitMax", color: '#a0a' },
|
||||
{ label: "Осевая нагрузка", xAccessorName: "axialLoad", color: '#a0a' },
|
||||
{ label: "Осевая нагрузка. Задание", xAccessorName: "axialLoadSp", color: '#a0a' },
|
||||
{ label: "Осевая нагрузка. Аварийная макс.", xAccessorName: "axialLoadLimitMax", color: '#a0a' },
|
||||
{ label: "Вес на крюке", xAccessorName: "hookWeight", color: '#a0a' },
|
||||
{ label: "Вес на крюке. Холостой ход", xAccessorName: "hookWeightIdle", color: '#a0a' },
|
||||
{ label: "Вес на крюке. Посадка", xAccessorName: "hookWeightLimitMin", color: '#a0a' },
|
||||
{ label: "Вес на крюке. Затяжка", xAccessorName: "hookWeightLimitMax", color: '#a0a' },
|
||||
{ label: "Момент на роторе", xAccessorName: "rotorTorque", color: '#a0a' },
|
||||
{ label: "Момент на роторе. Холостой ход", xAccessorName: "rotorTorqueIdle", color: '#a0a' },
|
||||
{ label: "Момент на роторе. Задание", xAccessorName: "rotorTorqueSp", color: '#a0a' },
|
||||
{ label: "Момент на роторе. Аварийный макс.", xAccessorName: "rotorTorqueLimitMax", color: '#a0a' },
|
||||
{ label: "Обороты ротора", xAccessorName: "rotorSpeed", color: '#a0a' },
|
||||
{ label: "Расход", xAccessorName: "flow", color: '#a0a' },
|
||||
{ label: "Расход. Холостой ход", xAccessorName: "flowIdle", color: '#a0a' },
|
||||
{ label: "Расход. Аварийный макс.", xAccessorName: "flowDeltaLimitMax", color: '#a0a' },
|
||||
]
|
||||
|
||||
const children = linesCollection.map((line) => (<Option key={line.xAccessorName}>{line.label}</Option>))
|
||||
|
||||
function handleChange(value) {
|
||||
console.log(`selected ${value}`);
|
||||
}
|
||||
|
||||
return (
|
||||
<Select
|
||||
mode="multiple"
|
||||
allowClear
|
||||
style={{ width: '50%' }}
|
||||
placeholder="Выберите значения"
|
||||
defaultValue={["wellDepth"]}
|
||||
onChange={handleChange}
|
||||
>
|
||||
{children}
|
||||
</Select>
|
||||
)
|
||||
}
|
||||
|
||||
const Column = ({ lineGroup, data, interval }) => {
|
||||
let lines = [lineGroup.linePv]
|
||||
|
||||
if (lineGroup.lineSp)
|
||||
lines.push(lineGroup.lineSp)
|
||||
|
||||
let dataLast = null
|
||||
let pv = null
|
||||
if (data?.length > 0) {
|
||||
dataLast = data[data.length - 1];
|
||||
if (lineGroup.linePv)
|
||||
pv = dataLast[lineGroup.linePv?.xAccessorName]
|
||||
}
|
||||
return (
|
||||
<>
|
||||
<Display
|
||||
label={lineGroup.label}
|
||||
value={pv}
|
||||
suffix={lineGroup.linePv?.units} />
|
||||
<ChartTimeArchive
|
||||
data={data}
|
||||
yDisplay={lineGroup.yDisplay}
|
||||
lines={lines}
|
||||
interval={interval} />
|
||||
<ChartTimeOnlineFooter
|
||||
data={dataLast}
|
||||
{...lineGroup} />
|
||||
</>)
|
||||
}
|
||||
|
||||
const paramsGroups = []
|
||||
|
||||
export default function Archive(props) {
|
||||
let { id } = useParams();
|
||||
const [saubData, setSaubData] = useState([])
|
||||
const [chartInterval, setChartInterval] = useState(600)
|
||||
|
||||
const handleReceiveDataSaub = (data) => {
|
||||
if (data) {
|
||||
setSaubData(data)
|
||||
}
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
DataService.getData(id)
|
||||
.then(handleReceiveDataSaub)
|
||||
.catch(error => console.error(error))
|
||||
|
||||
let unSubscribeMessages = Subscribe('ReceiveDataSaub', `well_${id}`, handleReceiveDataSaub)
|
||||
return () => {
|
||||
unSubscribeMessages()
|
||||
}
|
||||
}, [id]);
|
||||
|
||||
const colSpan = 24 / (paramsGroups.length)
|
||||
|
||||
return (<>
|
||||
<div style={{ display: 'flex' }}>
|
||||
<h2>Архив</h2>
|
||||
<span style={{ flexGrow: 10 }}></span>
|
||||
<UserOfWells data={saubData} />
|
||||
</div>
|
||||
<hr />
|
||||
<Button type="primary" style={{
|
||||
borderRadius: '5px',
|
||||
font: 'bold',
|
||||
textAlign: 'center',
|
||||
margin: '5px 5px',
|
||||
}}>Добавить график</Button>
|
||||
<RangePickerLocalized />
|
||||
<SelectDataCharts />
|
||||
<Row style={{ marginBottom: '1rem' }}>
|
||||
<Col>
|
||||
Интервал:
|
||||
<Select defaultValue="600" onChange={setChartInterval}>
|
||||
<Option value='600'>10 минут</Option>
|
||||
<Option value='1800'>30 минут</Option>
|
||||
<Option value='3600'>1 час</Option>
|
||||
<Option value='21600'>6 час</Option>
|
||||
<Option value='86400'>1 день</Option>
|
||||
</Select>
|
||||
</Col>
|
||||
</Row>
|
||||
<Row>
|
||||
<Col span={24 - 2}>
|
||||
<Row>
|
||||
{paramsGroups.map(group =>
|
||||
<Col span={colSpan} className='border_small' key={group.label}>
|
||||
<Column data={saubData} lineGroup={group} interval={chartInterval} />
|
||||
</Col>)}
|
||||
</Row>
|
||||
</Col>
|
||||
<Row ref={chartsContainerRef}>
|
||||
{charts}
|
||||
</Row>
|
||||
</>)
|
||||
}
|
13
src/services/UidGenerator.ts
Normal file
13
src/services/UidGenerator.ts
Normal file
@ -0,0 +1,13 @@
|
||||
export function generateUUID():string {
|
||||
let seed = (25869874412483
|
||||
* new Date().getTime()
|
||||
* (performance && performance.now && (performance.now()))) % 173395562924509
|
||||
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
|
||||
let random = Math.random()
|
||||
seed = seed > 272
|
||||
? seed = seed / 17
|
||||
: seed = (seed * random * random * 557833831325167) % 173395562924509
|
||||
random = Math.floor((random * seed) % 16)
|
||||
return (c === 'x' ? random : (random & 0xB)).toString(16)
|
||||
})
|
||||
}
|
Loading…
Reference in New Issue
Block a user