forked from ddrilling/asb_cloud_front
разрешение конфликта и merge filter-message
This commit is contained in:
commit
2184ae71a1
Binary file not shown.
Before Width: | Height: | Size: 3.8 KiB After Width: | Height: | Size: 354 KiB |
@ -10,34 +10,11 @@
|
||||
content="Web site created using create-react-app"
|
||||
/>
|
||||
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
|
||||
<!--
|
||||
manifest.json provides metadata used when your web app is installed on a
|
||||
user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
|
||||
-->
|
||||
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
|
||||
<!--
|
||||
Notice the use of %PUBLIC_URL% in the tags above.
|
||||
It will be replaced with the URL of the `public` folder during the build.
|
||||
Only files inside the `public` folder can be referenced from the HTML.
|
||||
|
||||
Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
|
||||
work correctly both with client-side routing and a non-root public URL.
|
||||
Learn how to configure a non-root public URL by running `npm run build`.
|
||||
-->
|
||||
<title>React App</title>
|
||||
<title>АСБ Vision</title>
|
||||
</head>
|
||||
<body>
|
||||
<noscript>You need to enable JavaScript to run this app.</noscript>
|
||||
<div id="root"></div>
|
||||
<!--
|
||||
This HTML file is a template.
|
||||
If you open it directly in the browser, you will see an empty page.
|
||||
|
||||
You can add webfonts, meta tags, or analytics to this file.
|
||||
The build step will place the bundled scripts into the <body> tag.
|
||||
|
||||
To begin the development, run `npm start` or `yarn start`.
|
||||
To create a production bundle, use `npm run build` or `yarn build`.
|
||||
-->
|
||||
</body>
|
||||
</html>
|
||||
|
Binary file not shown.
Before Width: | Height: | Size: 5.2 KiB |
Binary file not shown.
Before Width: | Height: | Size: 9.4 KiB |
@ -1,14 +1,14 @@
|
||||
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';
|
||||
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: "blockPosition", color: '#f0f' },
|
||||
{ label: "Талевый блок. Мин положение", xAccessorName: "blockPositionMin", color: '#0ff' },
|
||||
{ label: "Талевый блок. Макс положение", xAccessorName: "blockPositionMax", color: '#0f0' },
|
||||
{ label: "Скорость талевого блока", xAccessorName: "blockSpeed", color: '#00f' },
|
||||
@ -54,7 +54,6 @@ const tagRender = ({ label, value, closable, onClose }) =>{
|
||||
let color = linesCollection.find(l=>l.xAccessorName === value)?.color
|
||||
return (
|
||||
<Tag
|
||||
//color={color}
|
||||
onMouseDown={onPreventMouseDown}
|
||||
closable={closable}
|
||||
onClose={onClose}
|
||||
@ -86,7 +85,8 @@ export function ArchiveColumn({ data, config, rangeDate, chartRatio, onRemoveCha
|
||||
mode="multiple"
|
||||
placeholder="Выберите линии"
|
||||
value={selectedValues}
|
||||
//showArrow
|
||||
allowClear={false}
|
||||
showArrow
|
||||
bordered={false}
|
||||
tagRender={tagRender}
|
||||
onChange={handleLinesSetChange}
|
||||
@ -101,7 +101,7 @@ export function ArchiveColumn({ data, config, rangeDate, chartRatio, onRemoveCha
|
||||
const popBar = <Row>
|
||||
{select}
|
||||
<Tooltip title="Удалить этот график">
|
||||
<Button onClick={() => onRemoveChart(config.id)}>X</Button>
|
||||
<Button onClick={() => onRemoveChart(config.id)}><DeleteOutlined /></Button>
|
||||
</Tooltip>
|
||||
</Row>
|
||||
|
||||
|
@ -4,6 +4,7 @@ import { WellService } from '../services/api'
|
||||
import Loader from '../components/Loader'
|
||||
import { TreeSelect } from 'antd'
|
||||
import { useHistory } from 'react-router-dom'
|
||||
import notify from './notify'
|
||||
|
||||
const groupBy = (table, ...keys) => {
|
||||
let key = keys[0]
|
||||
@ -49,6 +50,7 @@ export default function WellTreeSelector(props) {
|
||||
setWellsTree(wellsTree)
|
||||
}
|
||||
catch (e) {
|
||||
notify('Не удалось загрузить список скважин', 'error')
|
||||
console.error(`${e.message}`);
|
||||
}
|
||||
setLoader(false)
|
||||
@ -65,11 +67,10 @@ export default function WellTreeSelector(props) {
|
||||
return (
|
||||
<>
|
||||
<TreeSelect
|
||||
style={{
|
||||
width: '25%',
|
||||
alignItems: 'center'
|
||||
}}
|
||||
placeholder="Выберите месторождение"
|
||||
className='header-tree-select'
|
||||
bordered={false}
|
||||
dropdownMatchSelectWidth={false}
|
||||
placeholder='Выберите месторождение'
|
||||
treeData={wellsTree}
|
||||
treeDefaultExpandAll
|
||||
onSelect={onSelect}
|
||||
|
@ -30,11 +30,11 @@ const defaultOptions = {
|
||||
millisecond: 'HH:mm:ss.SSS',
|
||||
second: 'HH:mm:ss',
|
||||
minute: 'HH:mm:ss',
|
||||
hour: 'dd HH:mm:ss',
|
||||
day: 'MM.dd HH:mm',
|
||||
week: 'yy.MM.dd HH:mm',
|
||||
month: 'yyyy.MM.dd',
|
||||
quarter: 'yyyy.MM.dd',
|
||||
hour: 'DD HH:mm:ss',
|
||||
day: 'MM.DD HH:mm',
|
||||
week: 'yy.MM.DD HH:mm',
|
||||
month: 'yyyy.MM.DD',
|
||||
quarter: 'yyyy.MM.DD',
|
||||
year: 'yyyy.MM',
|
||||
},
|
||||
},
|
||||
@ -90,19 +90,80 @@ export type ChartTimeBaseProps = {
|
||||
options?: ChartOptions<keyof ChartTypeRegistry> | any,
|
||||
}
|
||||
|
||||
const timeUnitByInterval = (intervalSec:number):String =>{
|
||||
if(intervalSec < 24*60*60)
|
||||
export type TimeParams = {
|
||||
unit: String
|
||||
stepSize: number
|
||||
}
|
||||
|
||||
const linesPerInterval = 32
|
||||
|
||||
const timeUnitByInterval = (intervalSec:number):String => {
|
||||
if(intervalSec <= 60)
|
||||
return 'millisecond'
|
||||
|
||||
if(intervalSec <= 32*60)
|
||||
return 'second'
|
||||
|
||||
if(intervalSec < 30*24*60*60)
|
||||
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 < 365*24*60*60)
|
||||
if(intervalSec <= 32*7*24*60*60)
|
||||
return 'week'
|
||||
|
||||
if(intervalSec <= 32*30.4375*24*60*60)
|
||||
return 'month'
|
||||
|
||||
if(intervalSec <= 32*121.75*24*60*60)
|
||||
return 'quarter'
|
||||
else
|
||||
return 'year'
|
||||
}
|
||||
|
||||
const timeParamsByInterval = (intervalSec:number) :TimeParams => {
|
||||
let stepSize = intervalSec
|
||||
let unit = timeUnitByInterval(intervalSec)
|
||||
|
||||
switch(unit){
|
||||
case "millisecond":
|
||||
stepSize *= 1000
|
||||
break;
|
||||
case "second":
|
||||
//stepSize *= 1
|
||||
break;
|
||||
case "minute":
|
||||
stepSize /= 60
|
||||
break;
|
||||
case "hour":
|
||||
stepSize /= 60*60
|
||||
break;
|
||||
case "day":
|
||||
stepSize /= 24*60*60
|
||||
break;
|
||||
case "week":
|
||||
stepSize /= 7*24*60*60
|
||||
break;
|
||||
case "month":
|
||||
stepSize /= 30*24*60*60
|
||||
break;
|
||||
case "quarter":
|
||||
stepSize /= 91*24*60*60
|
||||
break;
|
||||
case "year":
|
||||
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<ChartTimeBaseProps> = ({options, dataParams}) => {
|
||||
const chartRef = useRef<HTMLCanvasElement>(null)
|
||||
const [chart, setChart] = useState<any>()
|
||||
@ -130,18 +191,19 @@ export const ChartTimeBase: React.FC<ChartTimeBaseProps> = ({options, dataParams
|
||||
|
||||
chart.data = dataParams.data
|
||||
chart.options.aspectRatio = options?.aspectRatio
|
||||
|
||||
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)
|
||||
let {unit, stepSize} = timeParamsByInterval(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 = dataParams.displayLabels ?? true
|
||||
chart.options.scales.y.time.unit = timeUnitByInterval(interval)
|
||||
chart.options.scales.y.time.stepSize = Math.round(interval/32)
|
||||
chart.options.scales.y.time.unit = unit
|
||||
chart.options.scales.y.time.stepSize = stepSize
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -11,9 +11,9 @@ const typeDictionary = {
|
||||
* @param body string или ReactNode
|
||||
* @param type для параметра типа. Допустимые значение 'error', 'warning', 'info'
|
||||
*/
|
||||
export default function Notification(body, type='info'){
|
||||
export default function notify(body, type='info'){
|
||||
|
||||
notification.info({
|
||||
notification[type]({
|
||||
description: body,
|
||||
message: typeDictionary[type],
|
||||
type,
|
@ -12,6 +12,7 @@ import locale from 'antd/lib/locale/ru_RU'
|
||||
import {generateUUID} from '../services/UidGenerator'
|
||||
import { ArchiveColumn } from '../components/ArchiveColumn'
|
||||
import moment from 'moment'
|
||||
import notify from '../components/notify'
|
||||
|
||||
const { RangePicker } = DatePicker;
|
||||
|
||||
@ -96,7 +97,10 @@ export default function Archive() {
|
||||
|
||||
DataService.getData(id, startDate, interval, 2048)
|
||||
.then(handleReceiveDataSaub)
|
||||
.catch(error => console.error(error))
|
||||
.catch(error => {
|
||||
notify(`Не удалось загрузить данные по скважине (${id}) c ${rangeDate[0]} по ${rangeDate[1]}`, 'error')
|
||||
console.error(error)
|
||||
})
|
||||
}, [id, rangeDate]);
|
||||
|
||||
let charts = null
|
||||
@ -128,6 +132,7 @@ export default function Archive() {
|
||||
<ConfigProvider locale={locale}>
|
||||
<RangePicker
|
||||
showTime
|
||||
allowClear={false}
|
||||
onChange = {onChangeRange}
|
||||
value = {rangeDate}
|
||||
/>
|
||||
|
@ -6,7 +6,7 @@ import WellTreeSelector from '../components/WellTreeSelector'
|
||||
|
||||
const { Header } = Layout
|
||||
|
||||
export default function PageHeader(props){
|
||||
export default function PageHeader({title='Мониторинг', wellsList}){
|
||||
const login = localStorage['login']
|
||||
|
||||
let handleLogout = () => {
|
||||
@ -14,19 +14,18 @@ export default function PageHeader(props){
|
||||
localStorage.removeItem('token')
|
||||
}
|
||||
|
||||
return(
|
||||
<Layout>
|
||||
<Header className="header">
|
||||
<img src={logo} alt="АСБ" className="logo"/>
|
||||
<WellTreeSelector />
|
||||
<h1 className="title">Мониторинг</h1>
|
||||
|
||||
<Link to="/login" onClick={handleLogout}>
|
||||
<Button icon={<UserOutlined/>}>
|
||||
({login}) Выход
|
||||
</Button>
|
||||
</Link>
|
||||
</Header>
|
||||
</Layout>
|
||||
)
|
||||
};
|
||||
return(
|
||||
<Layout>
|
||||
<Header className="header">
|
||||
<img src={logo} alt="АСБ" className="logo"/>
|
||||
<WellTreeSelector wellsList={wellsList}/>
|
||||
<h1 className="title">{title}</h1>
|
||||
<Link to="/login" onClick={handleLogout}>
|
||||
<Button icon={<UserOutlined/>}>
|
||||
({login}) Выход
|
||||
</Button>
|
||||
</Link>
|
||||
</Header>
|
||||
</Layout>
|
||||
)
|
||||
};
|
39
src/pages/LayoutPortal.jsx
Normal file
39
src/pages/LayoutPortal.jsx
Normal file
@ -0,0 +1,39 @@
|
||||
import {Layout} from 'antd'
|
||||
import PageHeader from './Header'
|
||||
// import { useState, useEffect, createContext} from 'react'
|
||||
// import { useParams } from 'react-router-dom'
|
||||
|
||||
const {Content} = Layout
|
||||
|
||||
export default function LayoutPortal({title, children}) {
|
||||
// const [wells, setWells] = useState([])
|
||||
// let { id } = useParams();
|
||||
|
||||
// let updateWellsList = async () => {
|
||||
// setLoader(true)
|
||||
// try {
|
||||
// let newWells = (await WellService.getWells()).map(w => { return { key: w.id, ...w } })
|
||||
// setWells(newWells)
|
||||
// }
|
||||
// catch (e) {
|
||||
// console.error(`${e.message}`);
|
||||
// }
|
||||
// setLoader(false)
|
||||
// }
|
||||
|
||||
// useEffect(() => {
|
||||
// updateWellsList()
|
||||
// }, [])
|
||||
|
||||
// const WellsContext = createContext({wells});
|
||||
|
||||
return (
|
||||
<Content>
|
||||
<PageHeader title={title}/>
|
||||
<Layout>
|
||||
<Content className="site-layout-background sheet">
|
||||
{children}
|
||||
</Content>
|
||||
</Layout>
|
||||
</Content>)
|
||||
}
|
@ -1,31 +1,25 @@
|
||||
import {Layout} from 'antd'
|
||||
import Wells from './Wells'
|
||||
import PageHeader from './Header'
|
||||
import Well from "../components/Well";
|
||||
import LayoutPortal from './LayoutPortal'
|
||||
import {Redirect, Route, Switch} from "react-router-dom";
|
||||
|
||||
const {Content} = Layout
|
||||
|
||||
export default function Main() {
|
||||
|
||||
return (
|
||||
<Content>
|
||||
<PageHeader/>
|
||||
<Layout>
|
||||
<Content className="site-layout-background sheet">
|
||||
<Switch>
|
||||
<Route path="/well/:id/">
|
||||
<Well/>
|
||||
</Route>
|
||||
<Route path="/well">
|
||||
<Wells/>
|
||||
</Route>
|
||||
<Route path="/">
|
||||
<Redirect to={{pathname: `/well`}}/>
|
||||
</Route>
|
||||
</Switch>
|
||||
</Content>
|
||||
</Layout>
|
||||
</Content>
|
||||
<Switch>
|
||||
<Route path="/well/:id/">
|
||||
<LayoutPortal>
|
||||
<Well/>
|
||||
</LayoutPortal>
|
||||
</Route>
|
||||
<Route path="/well">
|
||||
<LayoutPortal>
|
||||
<Wells/>
|
||||
</LayoutPortal>
|
||||
</Route>
|
||||
<Route path="/">
|
||||
<Redirect to={{pathname: `/well`}}/>
|
||||
</Route>
|
||||
</Switch>
|
||||
)
|
||||
}
|
||||
|
@ -12,7 +12,7 @@ import moment from 'moment'
|
||||
import {Subscribe} from '../services/signalr'
|
||||
import {DataService, MessageService} from '../services/api'
|
||||
import '../styles/message.css'
|
||||
import Notification from "../components/Notification";
|
||||
import notify from "../components/notify";
|
||||
|
||||
const {Option} = Select
|
||||
|
||||
@ -207,14 +207,14 @@ export default function TelemetryView(props) {
|
||||
DataService.getData(id)
|
||||
.then(handleReceiveDataSaub)
|
||||
.catch((ex) => {
|
||||
Notification(`Не удалось загрузить данные по скважине "${id}"`, 'error')
|
||||
notify(`Не удалось загрузить данные по скважине "${id}"`, 'error')
|
||||
console.log(ex)
|
||||
})
|
||||
|
||||
MessageService.getMessage(id)
|
||||
.then(handleReceiveMessages)
|
||||
.catch((ex) => {
|
||||
Notification(`Не удалось загрузить сообщения по скважине "${id}"`, 'error')
|
||||
notify(`Не удалось загрузить сообщения по скважине "${id}"`, 'error')
|
||||
console.log(ex)
|
||||
})
|
||||
|
||||
|
@ -3,6 +3,7 @@ import { WellService } from '../services/api'
|
||||
import Loader from '../components/Loader'
|
||||
import { Table } from 'antd' // TreeSelect
|
||||
import { useHistory } from 'react-router-dom'
|
||||
import notify from '../components/notify'
|
||||
|
||||
const columns = [
|
||||
{
|
||||
@ -36,16 +37,17 @@ export default function Wells(props){
|
||||
setLoader(true)
|
||||
try{
|
||||
let newWells = (await WellService.getWells()).map(w =>{return {key:w.id, ...w}})
|
||||
console.log(Wells.wellsTree)
|
||||
console.log(newWells)
|
||||
setWells( newWells )
|
||||
}
|
||||
catch(e){
|
||||
console.error(`${e.message}`);
|
||||
notify('Не удалось загрузить список скважин', 'error')
|
||||
console.error(`${e}`);
|
||||
}
|
||||
setLoader(false)
|
||||
}
|
||||
|
||||
useEffect(()=>updateWellsList())
|
||||
useEffect(()=>updateWellsList(), [])
|
||||
|
||||
return(<>
|
||||
<h2>Скважины</h2>
|
||||
|
@ -61,7 +61,7 @@ html {
|
||||
.sheet{
|
||||
padding: 5px 24px;
|
||||
min-height: 280px;
|
||||
margin: 0 15px;
|
||||
margin: 0 15px 15px 15px;
|
||||
}
|
||||
|
||||
.site-layout-background {
|
||||
@ -145,3 +145,18 @@ tr.table_row_size {
|
||||
width: 50%;
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
.header-tree-select *{
|
||||
color: #fff;
|
||||
font-size: '1.5rem';
|
||||
}
|
||||
|
||||
.header-tree-select{
|
||||
border: 1px solid rgba(255, 255, 255, 0.2);
|
||||
background-color: rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
|
||||
.header-tree-select:hover{
|
||||
border: 1px solid rgba(255, 255, 255, 0.8);
|
||||
background-color: rgba(0, 0, 0, 0.5);
|
||||
}
|
@ -1,3 +0,0 @@
|
||||
.content-sheet {
|
||||
display: inline-flex;
|
||||
}
|
Loading…
Reference in New Issue
Block a user