forked from ddrilling/asb_cloud_front
перед выходными:)
This commit is contained in:
parent
d4d51941d7
commit
ea426b16ef
16
package-lock.json
generated
16
package-lock.json
generated
@ -4189,6 +4189,16 @@
|
||||
"resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz",
|
||||
"integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw=="
|
||||
},
|
||||
"chart.js": {
|
||||
"version": "3.0.2",
|
||||
"resolved": "https://registry.npmjs.org/chart.js/-/chart.js-3.0.2.tgz",
|
||||
"integrity": "sha512-DR0GmFSlxcFJp/w//ZmbxSduAkH/AqwxoiZxK97KHnWZf6gvsKWS3160WvNMMHYvzW9OXqGWjPjVh1Qu+xDabg=="
|
||||
},
|
||||
"chartjs-adapter-date-fns": {
|
||||
"version": "1.1.0-beta.1",
|
||||
"resolved": "https://registry.npmjs.org/chartjs-adapter-date-fns/-/chartjs-adapter-date-fns-1.1.0-beta.1.tgz",
|
||||
"integrity": "sha512-VNhuZ86kXKOwh61CyRLP7hoFqAR7+gjnrtf7KYLt/Wfh3jIQs14l1h+nagtQoFaabIYIo6UD5/jJb2/J6zOPcw=="
|
||||
},
|
||||
"check-types": {
|
||||
"version": "11.1.2",
|
||||
"resolved": "https://registry.npmjs.org/check-types/-/check-types-11.1.2.tgz",
|
||||
@ -5060,9 +5070,9 @@
|
||||
}
|
||||
},
|
||||
"date-fns": {
|
||||
"version": "2.19.0",
|
||||
"resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.19.0.tgz",
|
||||
"integrity": "sha512-X3bf2iTPgCAQp9wvjOQytnf5vO5rESYRXlPIVcgSbtT5OTScPcsf9eZU+B/YIkKAtYr5WeCii58BgATrNitlWg=="
|
||||
"version": "2.20.0",
|
||||
"resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.20.0.tgz",
|
||||
"integrity": "sha512-nmA7y6aDH5+fknfJ0G77HQzUSfTPpq4ifq+c9blP9d+X9zs3kNjxC+t3pcbBMGTp262a6PJB3RVjLlxIgoMI+Q=="
|
||||
},
|
||||
"debug": {
|
||||
"version": "4.3.1",
|
||||
|
@ -9,7 +9,10 @@
|
||||
"@testing-library/react": "^11.2.6",
|
||||
"@testing-library/user-event": "^12.8.3",
|
||||
"antd": "^4.15.0",
|
||||
"chart.js": "^3.0.2",
|
||||
"chartjs-adapter-date-fns": "^1.1.0-beta.1",
|
||||
"craco-less": "^1.17.1",
|
||||
"date-fns": "^2.20.0",
|
||||
"react": "^17.0.2",
|
||||
"react-dom": "^17.0.2",
|
||||
"react-router-dom": "^5.2.0",
|
||||
|
21
src/App.js
21
src/App.js
@ -3,30 +3,15 @@ import React /*, { useContext, createContext, useState }*/ from "react"
|
||||
import {
|
||||
BrowserRouter as Router,
|
||||
Switch,
|
||||
Route,
|
||||
Redirect
|
||||
} from "react-router-dom"
|
||||
Route} from "react-router-dom"
|
||||
import Login from './pages/Login'
|
||||
import Main from './pages/Main'
|
||||
import {OpenAPI} from './services/api'
|
||||
import { OpenAPI } from './services/api'
|
||||
import { PrivateRoute } from './components/PrivateRoute'
|
||||
|
||||
OpenAPI.BASE = 'http://localhost:3000'
|
||||
OpenAPI.TOKEN = localStorage['token']
|
||||
|
||||
function PrivateRoute({ children, ...rest }) {
|
||||
let token = localStorage['token']
|
||||
return (
|
||||
<Route
|
||||
{...rest}
|
||||
render={({ location }) =>
|
||||
token
|
||||
? (children)
|
||||
: (<Redirect to={{pathname: "/login", state: { from: location }}}/>)
|
||||
}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
export default function App() {
|
||||
return (
|
||||
<Router>
|
||||
|
16
src/components/PrivateRoute.jsx
Normal file
16
src/components/PrivateRoute.jsx
Normal file
@ -0,0 +1,16 @@
|
||||
import React /*, { useContext, createContext, useState }*/ from "react";
|
||||
import {
|
||||
Route,
|
||||
Redirect
|
||||
} from "react-router-dom";
|
||||
|
||||
export function PrivateRoute({ children, ...rest }) {
|
||||
let token = localStorage['token'];
|
||||
return (
|
||||
<Route
|
||||
{...rest}
|
||||
render={({ location }) => token
|
||||
? (children)
|
||||
: (<Redirect to={{ pathname: "/login", state: { from: location } }} />)} />
|
||||
);
|
||||
}
|
69
src/components/charts/ChartSaubDataOnline.jsx
Normal file
69
src/components/charts/ChartSaubDataOnline.jsx
Normal file
@ -0,0 +1,69 @@
|
||||
import { Chart, TimeScale, Legend, LineController, LineElement, PointElement } from 'chart.js'
|
||||
import 'chartjs-adapter-date-fns';
|
||||
import React, { useEffect, useRef} from 'react';
|
||||
|
||||
Chart.register( TimeScale, LineController, LineElement, PointElement, Legend );
|
||||
|
||||
const options = {
|
||||
//showLine :true,
|
||||
indexAxis:'y',
|
||||
//maintainAspectRatio: false,
|
||||
//responsive:false,
|
||||
scales: {
|
||||
y:{
|
||||
type: 'time',
|
||||
time: {
|
||||
unit: 'second',
|
||||
displayFormats: {
|
||||
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',
|
||||
year: 'yyyy.MM',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
const data= {
|
||||
datasets: [{
|
||||
label: 'Torque',
|
||||
data: [
|
||||
{x: 10, y: '2021-04-09T17:50:34.021679+05:00'},
|
||||
{x: 15, y: '2021-04-09T17:50:33.021679+05:00'},
|
||||
{x: 20, y: '2021-04-09T17:50:32.021679+05:00'}],
|
||||
boderColor: 'rgba(0, 99, 132, 1)',
|
||||
backgroundColor: 'rgba(0, 99, 132, 1)',
|
||||
},
|
||||
{
|
||||
label: 'Pressure',
|
||||
data: [
|
||||
{x: 11, y: '2021-04-09T17:50:34.021679+05:00'},
|
||||
{x: 14, y: '2021-04-09T17:50:33.021679+05:00'},
|
||||
{x: 21, y: '2021-04-09T17:50:32.021679+05:00'}],
|
||||
boderColor: 'rgba(255, 99, 132, 1)',
|
||||
backgroundColor: 'rgba(255, 99, 132, 1)',
|
||||
borderDash: [5, 5],
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
export function ChartSaubDataOnline(props){
|
||||
const chartRef = useRef(null)
|
||||
|
||||
useEffect(()=>{
|
||||
let chart = new Chart(chartRef.current, {
|
||||
type: 'line',
|
||||
data,
|
||||
options})
|
||||
//chart.canvas.parentNode.style.height = '128px';
|
||||
return _ => chart.destroy()
|
||||
},[])
|
||||
|
||||
return(<canvas ref={chartRef} />)
|
||||
}
|
@ -32,13 +32,14 @@ export default function Login() {
|
||||
try{
|
||||
let user = await login(formData)
|
||||
setUser(user)
|
||||
setLoader(false)
|
||||
history.push('well')
|
||||
}catch(e){
|
||||
if(e.status === 400)
|
||||
openNotificationError(e.message)
|
||||
console.error(`Error ${e}`)
|
||||
}
|
||||
setLoader(false)
|
||||
setLoader(false)
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
|
@ -1,6 +1,30 @@
|
||||
import React, { useState, useEffect} from 'react';
|
||||
import {ChartSaubDataOnline} from '../components/charts/ChartSaubDataOnline'
|
||||
|
||||
import {useParams} from 'react-router-dom'
|
||||
import {Subscribe} from '../services/signalr'
|
||||
import {DataService} from '../services/api'
|
||||
|
||||
export default function Well(props){
|
||||
let { id } = useParams();
|
||||
return(<div>Well id: {id}</div>)
|
||||
const [saubData, setSaubData] = useState([])
|
||||
|
||||
const handleReceiveDataSaub = (data)=>{
|
||||
setSaubData(pre => [...pre, ...data].slice(-1024))
|
||||
}
|
||||
|
||||
useEffect( ()=> {
|
||||
DataService.get(id)
|
||||
.then(handleReceiveDataSaub)
|
||||
.catch(error=>console.error(error))
|
||||
|
||||
return Subscribe('ReceiveDataSaub', `well_${id}`, handleReceiveDataSaub)
|
||||
},
|
||||
[id]);
|
||||
|
||||
|
||||
return(<div>
|
||||
Well id: {id}; points count: {saubData.length}
|
||||
<ChartSaubDataOnline/>
|
||||
</div>)
|
||||
}
|
@ -35,8 +35,8 @@ export default function Wells(props){
|
||||
let updateWellsList = async () => {
|
||||
setLoader(true)
|
||||
try{
|
||||
|
||||
setWells( await WellService.get())
|
||||
var newWells = (await WellService.get()).map(w =>{return {key:w.id, ...w}})
|
||||
setWells( newWells )
|
||||
}
|
||||
catch(e){
|
||||
console.error(`${e.message}`);
|
||||
|
@ -1 +1 @@
|
||||
npx openapi -i http://localhost:5000/swagger/v1/swagger.json -o src/services/openapi
|
||||
npx openapi -i http://localhost:5000/swagger/v1/swagger.json -o src/services/api
|
@ -5,8 +5,13 @@ export { ApiError } from './core/ApiError';
|
||||
export { OpenAPI } from './core/OpenAPI';
|
||||
|
||||
export type { AuthDto } from './models/AuthDto';
|
||||
export type { DataSaubBaseDto } from './models/DataSaubBaseDto';
|
||||
export type { TelemetryDataDto } from './models/TelemetryDataDto';
|
||||
export type { TelemetryInfoDto } from './models/TelemetryInfoDto';
|
||||
export type { UserTokenDto } from './models/UserTokenDto';
|
||||
export type { WellDto } from './models/WellDto';
|
||||
|
||||
export { AuthService } from './services/AuthService';
|
||||
export { DataService } from './services/DataService';
|
||||
export { TelemetryService } from './services/TelemetryService';
|
||||
export { WellService } from './services/WellService';
|
||||
|
32
src/services/api/models/DataSaubBaseDto.ts
Normal file
32
src/services/api/models/DataSaubBaseDto.ts
Normal file
@ -0,0 +1,32 @@
|
||||
/* istanbul ignore file */
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
|
||||
export type DataSaubBaseDto = {
|
||||
date?: string;
|
||||
mode?: number | null;
|
||||
wellDepth?: number | null;
|
||||
bitDepth?: number | null;
|
||||
blockHeight?: number | null;
|
||||
blockSpeed?: number | null;
|
||||
blockSpeedSp?: number | null;
|
||||
pressure?: number | null;
|
||||
pressureIdle?: number | null;
|
||||
pressureSp?: number | null;
|
||||
pressureDeltaLimitMax?: number | null;
|
||||
axialLoad?: number | null;
|
||||
axialLoadSp?: number | null;
|
||||
axialLoadLimitMax?: number | null;
|
||||
hookWeight?: number | null;
|
||||
hookWeightIdle?: number | null;
|
||||
hookWeightLimitMin?: number | null;
|
||||
hookWeightLimitMax?: number | null;
|
||||
rotorTorque?: number | null;
|
||||
rotorTorqueIdle?: number | null;
|
||||
rotorTorqueSp?: number | null;
|
||||
rotorTorqueLimitMax?: number | null;
|
||||
rotorSpeed?: number | null;
|
||||
flow?: number | null;
|
||||
flowIdle?: number | null;
|
||||
flowDeltaLimitMax?: number | null;
|
||||
}
|
12
src/services/api/models/TelemetryDataDto.ts
Normal file
12
src/services/api/models/TelemetryDataDto.ts
Normal file
@ -0,0 +1,12 @@
|
||||
/* istanbul ignore file */
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
|
||||
import type { DataSaubBaseDto } from './DataSaubBaseDto';
|
||||
|
||||
export type TelemetryDataDto = {
|
||||
date?: string;
|
||||
hmiVersion?: string | null;
|
||||
userName?: string | null;
|
||||
dataSaub?: Array<DataSaubBaseDto> | null;
|
||||
}
|
9
src/services/api/models/TelemetryInfoDto.ts
Normal file
9
src/services/api/models/TelemetryInfoDto.ts
Normal file
@ -0,0 +1,9 @@
|
||||
/* istanbul ignore file */
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
|
||||
export type TelemetryInfoDto = {
|
||||
caption?: string | null;
|
||||
cluster?: string | null;
|
||||
deposit?: string | null;
|
||||
}
|
@ -3,9 +3,9 @@
|
||||
/* eslint-disable */
|
||||
|
||||
export type WellDto = {
|
||||
id?: number;
|
||||
caption?: string | null;
|
||||
cluster?: string | null;
|
||||
deposit?: string | null;
|
||||
id?: number;
|
||||
lastData?: any;
|
||||
}
|
25
src/services/api/services/DataService.ts
Normal file
25
src/services/api/services/DataService.ts
Normal file
@ -0,0 +1,25 @@
|
||||
/* istanbul ignore file */
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
import type { DataSaubBaseDto } from '../models/DataSaubBaseDto';
|
||||
import { request as __request } from '../core/request';
|
||||
|
||||
export class DataService {
|
||||
|
||||
/**
|
||||
* Возвращает данные САУБ по скважине
|
||||
* @param wellId
|
||||
* @returns DataSaubBaseDto Success
|
||||
* @throws ApiError
|
||||
*/
|
||||
public static async get(
|
||||
wellId: number,
|
||||
): Promise<Array<DataSaubBaseDto>> {
|
||||
const result = await __request({
|
||||
method: 'GET',
|
||||
path: `/api/well/${wellId}/data`,
|
||||
});
|
||||
return result.body;
|
||||
}
|
||||
|
||||
}
|
48
src/services/api/services/TelemetryService.ts
Normal file
48
src/services/api/services/TelemetryService.ts
Normal file
@ -0,0 +1,48 @@
|
||||
/* istanbul ignore file */
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
import type { TelemetryDataDto } from '../models/TelemetryDataDto';
|
||||
import type { TelemetryInfoDto } from '../models/TelemetryInfoDto';
|
||||
import { request as __request } from '../core/request';
|
||||
|
||||
export class TelemetryService {
|
||||
|
||||
/**
|
||||
* Принимает общую информацию по скважине
|
||||
* @param uid Уникальный идентификатор отправителя
|
||||
* @param requestBody нформация об отправителе
|
||||
* @returns any Success
|
||||
* @throws ApiError
|
||||
*/
|
||||
public static async info(
|
||||
uid: string,
|
||||
requestBody?: TelemetryInfoDto,
|
||||
): Promise<any> {
|
||||
const result = await __request({
|
||||
method: 'POST',
|
||||
path: `/api/telemetry/${uid}/info`,
|
||||
body: requestBody,
|
||||
});
|
||||
return result.body;
|
||||
}
|
||||
|
||||
/**
|
||||
* Принимает данные от разных систем по скважине
|
||||
* @param uid Уникальный идентификатор отправителя
|
||||
* @param requestBody Данные
|
||||
* @returns any Success
|
||||
* @throws ApiError
|
||||
*/
|
||||
public static async data(
|
||||
uid: string,
|
||||
requestBody?: TelemetryDataDto,
|
||||
): Promise<any> {
|
||||
const result = await __request({
|
||||
method: 'POST',
|
||||
path: `/api/telemetry/${uid}/data`,
|
||||
body: requestBody,
|
||||
});
|
||||
return result.body;
|
||||
}
|
||||
|
||||
}
|
@ -13,7 +13,7 @@ export class WellService {
|
||||
public static async get(): Promise<Array<WellDto>> {
|
||||
const result = await __request({
|
||||
method: 'GET',
|
||||
path: `/api/Well`,
|
||||
path: `/api/well`,
|
||||
});
|
||||
return result.body;
|
||||
}
|
||||
|
70
src/services/signalr/index.ts
Normal file
70
src/services/signalr/index.ts
Normal file
@ -0,0 +1,70 @@
|
||||
import { HubConnectionBuilder, HubConnectionState } from '@microsoft/signalr';
|
||||
|
||||
// SignalR js api:
|
||||
//https://docs.microsoft.com/ru-ru/javascript/api/@aspnet/signalr/?view=signalr-js-latest
|
||||
|
||||
const ConnectionOptions = {
|
||||
accessTokenFactory: () => localStorage['token'],
|
||||
//transport:1,
|
||||
}
|
||||
|
||||
const Connection = new HubConnectionBuilder()
|
||||
.withUrl(`http://localhost:5000/hubs/telemetry`, ConnectionOptions)
|
||||
.withAutomaticReconnect()
|
||||
.build();
|
||||
|
||||
const GetConnectionAsync = async ()=>{
|
||||
if(Connection.state !== HubConnectionState.Connected)
|
||||
await Connection.start()
|
||||
|
||||
if(Connection.state === HubConnectionState.Connected)
|
||||
return Connection
|
||||
else
|
||||
throw new Error('Can`t connect to websocket')
|
||||
}
|
||||
|
||||
type handlerFunction = (...args: any[]) => void;
|
||||
|
||||
type cleanFunction = (...args: any[]) => void;
|
||||
|
||||
/** Subscribe on some SignalR method (topic).
|
||||
* @example useEffect(() => Subscribe('methodName', `${id}`, handleNewData), [id]);
|
||||
* @param {string} methodName name of the method
|
||||
* @param {string} groupName name of the group
|
||||
* @param {handlerFunction} handler fires when got new data by subscription
|
||||
* @return {cleanFunction} unsubscribe function for useEffect cleanup.
|
||||
*/
|
||||
const Subscribe = (
|
||||
methodName: string,
|
||||
groupName: string = '',
|
||||
handler: handlerFunction ):cleanFunction=>{
|
||||
|
||||
GetConnectionAsync().then(async connection => {
|
||||
if(groupName)
|
||||
await connection.send('AddToGroup', groupName)
|
||||
connection.on(methodName, handler)
|
||||
})
|
||||
|
||||
if(groupName)
|
||||
return () => {
|
||||
Connection.send('RemoveFromGroup', groupName)
|
||||
.finally(()=>Connection.off(methodName))
|
||||
}
|
||||
return () => Connection.off(methodName)
|
||||
}
|
||||
|
||||
/** Invokes some SignalR method.
|
||||
* @param {string} methodName name of the method
|
||||
* @param {any[]} args methods arguments
|
||||
* @return {Promise<void>} Promise
|
||||
*/
|
||||
const InvokeAsync = async (methodName:string, ...args:any[]) => {
|
||||
await GetConnectionAsync()
|
||||
await Connection.send(methodName, ...args)
|
||||
}
|
||||
|
||||
export {
|
||||
Subscribe,
|
||||
InvokeAsync,
|
||||
GetConnectionAsync,
|
||||
}
|
Loading…
Reference in New Issue
Block a user