This commit is contained in:
ilia 2023-02-19 10:01:08 +03:00
parent ee4b8ef4bb
commit dae66e19b4
57 changed files with 6667 additions and 107 deletions

1953
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -3,6 +3,8 @@
"version": "0.1.0",
"private": true,
"dependencies": {
"@ant-design/icons": "^5.0.1",
"@reduxjs/toolkit": "^1.9.2",
"@testing-library/jest-dom": "^5.16.5",
"@testing-library/react": "^13.4.0",
"@testing-library/user-event": "^13.5.0",
@ -10,9 +12,16 @@
"@types/node": "^16.18.12",
"@types/react": "^18.0.28",
"@types/react-dom": "^18.0.11",
"antd": "^5.2.1",
"axios": "^1.3.3",
"chart.js": "^4.2.1",
"react": "^18.2.0",
"react-chartjs-2": "^5.2.0",
"react-dom": "^18.2.0",
"react-redux": "^8.0.5",
"react-router-dom": "^6.8.1",
"react-scripts": "5.0.1",
"redux": "^4.2.1",
"typescript": "^4.9.5",
"web-vitals": "^2.1.4"
},

51
public/200.html Normal file
View File

@ -0,0 +1,51 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<meta
name="description"
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>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
<style>
body, html {
background-color: #F0F0F0;
}
*{
font-family: 'Segoe UI'!important;
}
</style>
<!--
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>

View File

@ -29,6 +29,14 @@
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
<style>
body, html {
background-color: #F0F0F0;
}
*{
font-family: 'Segoe UI'!important;
}
</style>
<!--
This HTML file is a template.
If you open it directly in the browser, you will see an empty page.

View File

@ -1,38 +0,0 @@
.App {
text-align: center;
}
.App-logo {
height: 40vmin;
pointer-events: none;
}
@media (prefers-reduced-motion: no-preference) {
.App-logo {
animation: App-logo-spin infinite 20s linear;
}
}
.App-header {
background-color: #282c34;
min-height: 100vh;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
font-size: calc(10px + 2vmin);
color: white;
}
.App-link {
color: #61dafb;
}
@keyframes App-logo-spin {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}

View File

@ -1,9 +0,0 @@
import React from 'react';
import { render, screen } from '@testing-library/react';
import App from './App';
test('renders learn react link', () => {
render(<App />);
const linkElement = screen.getByText(/learn react/i);
expect(linkElement).toBeInTheDocument();
});

View File

@ -1,25 +1,25 @@
import React from 'react';
import logo from './logo.svg';
import './App.css';
import {RouterProvider} from 'react-router-dom'
import { ConfigProvider } from 'antd';
import {Provider} from 'react-redux'
import router from './router';
import store from './store'
import 'antd/dist/reset.css';
function App() {
return (
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<p>
Edit <code>src/App.tsx</code> and save to reload.
</p>
<a
className="App-link"
href="https://reactjs.org"
target="_blank"
rel="noopener noreferrer"
>
Learn React
</a>
</header>
</div>
<Provider store={store}>
<ConfigProvider theme={{
token: {
'colorPrimary': '#FAB82E'
}
}}>
<RouterProvider router={router}/>
</ConfigProvider>
</Provider>
);
}

11
src/client/chart/post.ts Normal file
View File

@ -0,0 +1,11 @@
import axios from 'axios'
import { origin } from '../config'
export const getChartData = async (fromDate: Date, toDate: Date, interval: number, signals: string[]) => {
return await axios.post(origin + 'exgausters/approximation', {
"approximation": 10,
"time_from": "2023-01-19T00:00:42.444Z",
"time_until": "2023-02-19T00:00:42.444Z",
"signals": signals
})
}

1
src/client/config.ts Normal file
View File

@ -0,0 +1 @@
export const origin = 'https://dev2.akarpov.ru/api/'

View File

@ -0,0 +1,6 @@
import axios from 'axios'
import { origin } from '../config'
export const getFields = async () => {
return await axios.get(origin + 'exgausters/list')
}

View File

@ -0,0 +1,18 @@
import react from 'react'
export const BareTemp: react.FC = () => {
return <svg width="17" height="17" viewBox="0 0 17 17" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_1_1740)">
<path d="M10.6128 9.97029C10.5772 9.94777 10.5479 9.91662 10.5276 9.87975C10.5072 9.84287 10.4966 9.80146 10.4965 9.75935V3.02435C10.4965 2.62653 10.3385 2.245 10.0572 1.96369C9.77587 1.68239 9.39434 1.52435 8.99651 1.52435C8.59869 1.52435 8.21716 1.68239 7.93585 1.96369C7.65455 2.245 7.49651 2.62653 7.49651 3.02435V9.75935C7.49645 9.80138 7.48579 9.84271 7.46553 9.87952C7.44526 9.91633 7.41604 9.94745 7.38058 9.96998C6.93627 10.2594 6.57518 10.6598 6.33299 11.1315C6.0908 11.6032 5.9759 12.1299 5.99964 12.6597C6.0354 13.4425 6.37605 14.1803 6.94875 14.7152C7.52146 15.2501 8.28073 15.5397 9.06419 15.522C9.84765 15.5043 10.5931 15.1808 11.1411 14.6206C11.6891 14.0604 11.9961 13.308 11.9965 12.5244C11.9967 12.0171 11.8703 11.5178 11.6286 11.0718C11.387 10.6258 11.0378 10.2472 10.6128 9.97029V9.97029Z" stroke="#868686" stroke-width="1.00189" stroke-miterlimit="10" stroke-linecap="round"/>
<path d="M8.99658 4.02472V12.5247" stroke="#868686" stroke-width="1.00189" stroke-miterlimit="10" stroke-linecap="round"/>
<path d="M8.99744 14.0254C9.82648 14.0254 10.4985 13.3533 10.4985 12.5243C10.4985 11.6953 9.82648 11.0232 8.99744 11.0232C8.1684 11.0232 7.49634 11.6953 7.49634 12.5243C7.49634 13.3533 8.1684 14.0254 8.99744 14.0254Z" fill="#868686"/>
</g>
<defs>
<clipPath id="clip0_1_1740">
<rect width="16" height="16" fill="white" transform="translate(0.996826 0.523132)"/>
</clipPath>
</defs>
</svg>
}

View File

@ -0,0 +1,18 @@
import react from 'react'
export const DangerTemp: react.FC = () => {
return <svg width="17" height="17" viewBox="0 0 17 17" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_1_2255)">
<path d="M10.6128 9.97029C10.5772 9.94777 10.5479 9.91662 10.5276 9.87975C10.5072 9.84287 10.4966 9.80146 10.4965 9.75935V3.02435C10.4965 2.62653 10.3385 2.245 10.0572 1.96369C9.77587 1.68239 9.39434 1.52435 8.99651 1.52435C8.59869 1.52435 8.21716 1.68239 7.93585 1.96369C7.65455 2.245 7.49651 2.62653 7.49651 3.02435V9.75935C7.49645 9.80138 7.48579 9.84271 7.46553 9.87952C7.44526 9.91633 7.41604 9.94745 7.38058 9.96998C6.93627 10.2594 6.57518 10.6598 6.33299 11.1315C6.0908 11.6032 5.9759 12.1299 5.99964 12.6597C6.0354 13.4425 6.37605 14.1803 6.94875 14.7152C7.52146 15.2501 8.28073 15.5397 9.06419 15.522C9.84765 15.5043 10.5931 15.1808 11.1411 14.6206C11.6891 14.0604 11.9961 13.308 11.9965 12.5244C11.9967 12.0171 11.8703 11.5178 11.6286 11.0718C11.387 10.6258 11.0378 10.2472 10.6128 9.97029V9.97029Z" stroke="#E32112" stroke-width="1.00189" stroke-miterlimit="10" stroke-linecap="round"/>
<path d="M8.99658 4.02472V12.5247" stroke="#E32112" stroke-width="1.00189" stroke-miterlimit="10" stroke-linecap="round"/>
<path d="M8.99744 14.0254C9.82648 14.0254 10.4985 13.3533 10.4985 12.5243C10.4985 11.6953 9.82648 11.0232 8.99744 11.0232C8.1684 11.0232 7.49634 11.6953 7.49634 12.5243C7.49634 13.3533 8.1684 14.0254 8.99744 14.0254Z" fill="#E32112"/>
</g>
<defs>
<clipPath id="clip0_1_2255">
<rect width="16" height="16" fill="white" transform="translate(0.996826 0.523132)"/>
</clipPath>
</defs>
</svg>
}

View File

@ -0,0 +1,19 @@
import react from 'react'
export const WarningTemp: react.FC = () => {
return <svg width="16" height="17" viewBox="0 0 16 17" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_1_2072)">
<path d="M9.61594 9.97206C9.58037 9.94954 9.55106 9.91839 9.53074 9.88152C9.51041 9.84464 9.49973 9.80323 9.49969 9.76112V3.02612C9.49969 2.6283 9.34165 2.24677 9.06035 1.96546C8.77904 1.68416 8.39751 1.52612 7.99969 1.52612C7.60186 1.52612 7.22033 1.68416 6.93903 1.96546C6.65772 2.24677 6.49969 2.6283 6.49969 3.02612V9.76112C6.49962 9.80315 6.48896 9.84448 6.4687 9.88129C6.44844 9.9181 6.41922 9.94922 6.38375 9.97175C5.93944 10.2612 5.57835 10.6615 5.33616 11.1332C5.09397 11.605 4.97907 12.1317 5.00281 12.6614C5.03857 13.4443 5.37923 14.1821 5.95193 14.717C6.52463 15.2519 7.2839 15.5415 8.06736 15.5238C8.85082 15.5061 9.59626 15.1826 10.1443 14.6224C10.6922 14.0622 10.9993 13.3098 10.9997 12.5261C10.9999 12.0189 10.8735 11.5196 10.6318 11.0736C10.3902 10.6275 10.041 10.2489 9.61594 9.97206V9.97206Z" stroke="#F37E0D" stroke-width="1.00189" stroke-miterlimit="10" stroke-linecap="round"/>
<path d="M7.99976 4.02649V12.5265" stroke="#F37E0D" stroke-width="1.00189" stroke-miterlimit="10" stroke-linecap="round"/>
<path d="M8.00062 14.0272C8.82965 14.0272 9.50172 13.3551 9.50172 12.5261C9.50172 11.697 8.82965 11.025 8.00062 11.025C7.17158 11.025 6.49951 11.697 6.49951 12.5261C6.49951 13.3551 7.17158 14.0272 8.00062 14.0272Z" fill="#F37E0D"/>
</g>
<defs>
<clipPath id="clip0_1_2072">
<rect width="16" height="16" fill="white" transform="translate(0 0.524902)"/>
</clipPath>
</defs>
</svg>
}

View File

@ -0,0 +1,14 @@
import react from 'react'
export const BareVibration: react.FC = () => {
return <svg width="17" height="17" viewBox="0 0 17 17" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M7.50679 6.5322C7.0188 7.08147 6.74927 7.79068 6.74927 8.52541C6.74927 9.26015 7.0188 9.96936 7.50679 10.5186" stroke="#868686" stroke-width="1.00189" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M10.5247 10.5186C11.0126 9.96936 11.2822 9.26015 11.2822 8.52541C11.2822 7.79068 11.0126 7.08147 10.5247 6.5322" stroke="#868686" stroke-width="1.00189" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M5.91345 4.93918C5.00428 5.91184 4.49854 7.19355 4.49854 8.52496C4.49854 9.85637 5.00428 11.1381 5.91345 12.1107" stroke="#868686" stroke-width="1.00189" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M12.1167 12.1107C13.0259 11.1381 13.5316 9.85637 13.5316 8.52496C13.5316 7.19355 13.0259 5.91184 12.1167 4.93918" stroke="#868686" stroke-width="1.00189" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M13.8757 13.5253C15.1037 12.1489 15.7824 10.3688 15.7824 8.52425C15.7824 6.67968 15.1037 4.89958 13.8757 3.52316" stroke="#868686" stroke-width="1.00189" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M4.15467 3.52316C2.92669 4.89958 2.24805 6.67968 2.24805 8.52425C2.24805 10.3688 2.92669 12.1489 4.15467 13.5253" stroke="#868686" stroke-width="1.00189" stroke-linecap="round" stroke-linejoin="round"/>
</svg>
}

View File

@ -0,0 +1,14 @@
import react from 'react'
export const DangerVibration: react.FC = () => {
return <svg width="17" height="17" viewBox="0 0 17 17" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M7.50679 6.53217C7.0188 7.08144 6.74927 7.79065 6.74927 8.52538C6.74927 9.26012 7.0188 9.96933 7.50679 10.5186" stroke="#E32112" stroke-width="1.00189" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M10.5247 10.5186C11.0126 9.96933 11.2822 9.26012 11.2822 8.52538C11.2822 7.79065 11.0126 7.08144 10.5247 6.53217" stroke="#E32112" stroke-width="1.00189" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M5.91345 4.93915C5.00428 5.91181 4.49854 7.19352 4.49854 8.52493C4.49854 9.85634 5.00428 11.138 5.91345 12.1107" stroke="#E32112" stroke-width="1.00189" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M12.1167 12.1107C13.0259 11.138 13.5316 9.85634 13.5316 8.52493C13.5316 7.19352 13.0259 5.91181 12.1167 4.93915" stroke="#E32112" stroke-width="1.00189" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M13.8757 13.5253C15.1037 12.1489 15.7824 10.3688 15.7824 8.52422C15.7824 6.67965 15.1037 4.89955 13.8757 3.52313" stroke="#E32112" stroke-width="1.00189" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M4.15467 3.52313C2.92669 4.89955 2.24805 6.67965 2.24805 8.52422C2.24805 10.3688 2.92669 12.1489 4.15467 13.5253" stroke="#E32112" stroke-width="1.00189" stroke-linecap="round" stroke-linejoin="round"/>
</svg>
}

View File

@ -0,0 +1,14 @@
import react from 'react'
export const WarningVibration: react.FC = () => {
return <svg width="17" height="17" viewBox="0 0 17 17" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M7.50679 6.53217C7.0188 7.08144 6.74927 7.79065 6.74927 8.52538C6.74927 9.26012 7.0188 9.96933 7.50679 10.5186" stroke="#F37E0D" stroke-width="1.00189" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M10.5247 10.5186C11.0126 9.96933 11.2822 9.26012 11.2822 8.52538C11.2822 7.79065 11.0126 7.08144 10.5247 6.53217" stroke="#F37E0D" stroke-width="1.00189" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M5.91345 4.93915C5.00428 5.91181 4.49854 7.19352 4.49854 8.52493C4.49854 9.85634 5.00428 11.138 5.91345 12.1107" stroke="#F37E0D" stroke-width="1.00189" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M12.1167 12.1107C13.0259 11.138 13.5316 9.85634 13.5316 8.52493C13.5316 7.19352 13.0259 5.91181 12.1167 4.93915" stroke="#F37E0D" stroke-width="1.00189" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M13.8757 13.5253C15.1037 12.1489 15.7824 10.3688 15.7824 8.52422C15.7824 6.67965 15.1037 4.89955 13.8757 3.52313" stroke="#F37E0D" stroke-width="1.00189" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M4.15467 3.52313C2.92669 4.89955 2.24805 6.67965 2.24805 8.52422C2.24805 10.3688 2.92669 12.1489 4.15467 13.5253" stroke="#F37E0D" stroke-width="1.00189" stroke-linecap="round" stroke-linejoin="round"/>
</svg>
}

View File

@ -0,0 +1,29 @@
import { Typography } from 'antd'
import react from 'react'
import { Temperature, Vibration } from './status'
import './style.css'
interface IBearingCard {
name: string;
tags: {
name: "temp" | "vibration" | "oil",
type: "danger" | "bare" | "warning"
}[]
}
export const BearingCard: react.FC<IBearingCard> = (props) => {
const cardMapping = {
"temp": (type: "danger" | "bare" | "warning") => <Temperature state={type}/>,
"vibration": (type: "danger" | "bare" | "warning") => <Vibration state={type}/>
}
return <div className='b-card__container'>
<Typography.Text>{props.name}</Typography.Text>
<div className="tags">
{
props.tags.map((e) => {
return ((cardMapping as any)![e.name as any] as any)(e.type)
})
}
</div>
</div>
}

View File

@ -0,0 +1,73 @@
import { Tag, Typography } from 'antd'
import react from 'react'
import { BareTemp } from './icons/temperature/BareTemp'
import { DangerTemp } from './icons/temperature/DangerTemp'
import { WarningTemp } from './icons/temperature/WarningTemp'
import { BareVibration } from './icons/vibration/BareVibration'
import { DangerVibration } from './icons/vibration/DangerVibration'
import { WarningVibration } from './icons/vibration/WarningVibration'
import './style.css'
interface IIcon{
state: "bare" | "warning" | "danger"
}
export const Temperature: react.FC<IIcon> = (props) => {
var icons = {
"bare": <BareTemp />,
"warning": <WarningTemp />,
"danger": <DangerTemp />
}
var colors = {
"bare": "#F4F4F4",
"warning": "#FEF1DB",
"danger": "#FCDBCB"
}
var borderColors = {
"bare": "#868686",
"warning": "#F69112",
"danger": "#EB5835"
}
return <div style={{
backgroundColor: colors[props.state],
border: `1px solid ${borderColors[props.state]}`,
display: 'inline-flex',
alignItems: 'center',
justifyContent: 'center',
width: '40px',
borderRadius: '5px'
}}>
{icons[props.state]}
<Typography.Text>T</Typography.Text>
</div>
}
export const Vibration: react.FC<IIcon> = (props) => {
var icons = {
"bare": <BareVibration />,
"warning": <WarningVibration />,
"danger": <DangerVibration />
}
var colors = {
"bare": "#F4F4F4",
"warning": "#FEF1DB",
"danger": "#FCDBCB"
}
var borderColors = {
"bare": "#868686",
"warning": "#F69112",
"danger": "#EB5835"
}
return <div style={{
backgroundColor: colors[props.state],
border: `1px solid ${borderColors[props.state]}`,
display: 'inline-flex',
alignItems: 'center',
justifyContent: 'center',
width: '40px',
borderRadius: '5px'
}}>
{icons[props.state]}
<Typography.Text>V</Typography.Text>
</div>
}

View File

@ -0,0 +1,13 @@
.b-card__container{
background-color: #FAFAFA;
border-radius: 5px;
padding: 10px;
display: flex;
justify-content: space-between;
align-items: center;
}
.tags{
display: flex;
gap: 2px;
align-items: center;
}

View File

@ -0,0 +1,91 @@
import react from 'react'
export const BriefExgausterScheme: react.FC = () => {
return <svg width="260" height="139" viewBox="0 0 260 139" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect x="1" y="1.5249" width="258" height="136" rx="5" fill="#EFF2F6"/>
<rect x="170" y="18.5248" width="60" height="50" rx="3.50693" fill="#677272"/>
<path d="M167 31.5249H170V57.5249L167 53.7074V31.5249Z" fill="#3B4848"/>
<path d="M233 57.5248L230 57.5248L230 31.5248L233 35.3424L233 57.5248Z" fill="#3B4848"/>
<rect x="79" y="31.5249" width="61" height="51" rx="4.54549" fill="#677272"/>
<path d="M82.5 33.5249L83.145 33.9077L83.799 34.2749L83.79 35.0249L83.799 35.7749L83.145 36.1421L82.5 36.5249L81.855 36.1421L81.201 35.7749L81.21 35.0249L81.201 34.2749L81.855 33.9077L82.5 33.5249Z" fill="#8D9595"/>
<path d="M82.5 77.55L83.145 77.9329L83.799 78.3L83.79 79.05L83.799 79.8L83.145 80.1672L82.5 80.55L81.855 80.1672L81.201 79.8L81.21 79.05L81.201 78.3L81.855 77.9329L82.5 77.55Z" fill="#8D9595"/>
<path d="M82.5 55.0376L83.145 55.4204L83.799 55.7876L83.79 56.5376L83.799 57.2876L83.145 57.6548L82.5 58.0376L81.855 57.6548L81.201 57.2876L81.21 56.5376L81.201 55.7876L81.855 55.4204L82.5 55.0376Z" fill="#8D9595"/>
<path d="M136.5 33.5249L137.145 33.9077L137.799 34.2749L137.79 35.0249L137.799 35.7749L137.145 36.1421L136.5 36.5249L135.855 36.1421L135.201 35.7749L135.21 35.0249L135.201 34.2749L135.855 33.9077L136.5 33.5249Z" fill="#8D9595"/>
<path d="M136.5 77.55L137.145 77.9329L137.799 78.3L137.79 79.05L137.799 79.8L137.145 80.1672L136.5 80.55L135.855 80.1672L135.201 79.8L135.21 79.05L135.201 78.3L135.855 77.9329L136.5 77.55Z" fill="#8D9595"/>
<path d="M136.5 55.0376L137.145 55.4204L137.799 55.7876L137.79 56.5376L137.799 57.2876L137.145 57.6548L136.5 58.0376L135.855 57.6548L135.201 57.2876L135.21 56.5376L135.201 55.7876L135.855 55.4204L136.5 55.0376Z" fill="#8D9595"/>
<path d="M109.827 33.5249L110.472 33.9077L111.126 34.2749L111.117 35.0249L111.126 35.7749L110.472 36.1421L109.827 36.5249L109.182 36.1421L108.528 35.7749L108.537 35.0249L108.528 34.2749L109.182 33.9077L109.827 33.5249Z" fill="#8D9595"/>
<path d="M109.827 77.55L110.472 77.9329L111.126 78.3L111.117 79.05L111.126 79.8L110.472 80.1672L109.827 80.55L109.182 80.1672L108.528 79.8L108.537 79.05L108.528 78.3L109.182 77.9329L109.827 77.55Z" fill="#8D9595"/>
<mask id="path-14-inside-1_1_1636" fill="white">
<rect x="87" y="39.525" width="21" height="16" rx="0.757583"/>
</mask>
<rect x="87" y="39.525" width="21" height="16" rx="0.757583" fill="#414F4F" stroke="#8D9595" stroke-width="2" mask="url(#path-14-inside-1_1_1636)"/>
<mask id="path-15-inside-2_1_1636" fill="white">
<rect x="87" y="58.525" width="21" height="16" rx="0.757583"/>
</mask>
<rect x="87" y="58.525" width="21" height="16" rx="0.757583" fill="#414F4F" stroke="#8D9595" stroke-width="2" mask="url(#path-15-inside-2_1_1636)"/>
<mask id="path-16-inside-3_1_1636" fill="white">
<rect x="111" y="39.525" width="21" height="16" rx="0.757583"/>
</mask>
<rect x="111" y="39.525" width="21" height="16" rx="0.757583" fill="#414F4F" stroke="#8D9595" stroke-width="2" mask="url(#path-16-inside-3_1_1636)"/>
<mask id="path-17-inside-4_1_1636" fill="white">
<rect x="111" y="58.525" width="21" height="16" rx="0.757583"/>
</mask>
<rect x="111" y="58.525" width="21" height="16" rx="0.757583" fill="#414F4F" stroke="#8D9595" stroke-width="2" mask="url(#path-17-inside-4_1_1636)"/>
<rect x="10" y="56.5248" width="16" height="28" rx="2.27275" fill="#677272"/>
<path d="M12.5 57.8198L13.145 58.2026L13.799 58.5698L13.79 59.3198L13.799 60.0698L13.145 60.4369L12.5 60.8198L11.855 60.4369L11.201 60.0698L11.21 59.3198L11.201 58.5698L11.855 58.2026L12.5 57.8198Z" fill="#8D9595"/>
<path d="M12.5 80.7774L13.145 81.1602L13.799 81.5274L13.79 82.2774L13.799 83.0274L13.145 83.3946L12.5 83.7774L11.855 83.3946L11.201 83.0274L11.21 82.2774L11.201 81.5274L11.855 81.1602L12.5 80.7774Z" fill="#8D9595"/>
<path d="M23.5 57.7774L24.145 58.1602L24.799 58.5274L24.79 59.2774L24.799 60.0274L24.145 60.3946L23.5 60.7774L22.855 60.3946L22.201 60.0274L22.21 59.2774L22.201 58.5274L22.855 58.1602L23.5 57.7774Z" fill="#8D9595"/>
<path d="M23.5 80.7774L24.145 81.1602L24.799 81.5274L24.79 82.2774L24.799 83.0274L24.145 83.3946L23.5 83.7774L22.855 83.3946L22.201 83.0274L22.21 82.2774L22.201 81.5274L22.855 81.1602L23.5 80.7774Z" fill="#8D9595"/>
<path d="M14 66.5248H29V76.5248H14V66.5248Z" fill="#3B4848"/>
<mask id="path-24-inside-5_1_1636" fill="white">
<rect x="13" y="61.5248" width="10" height="18" rx="0.757583"/>
</mask>
<rect x="13" y="61.5248" width="10" height="18" rx="0.757583" fill="#414F4F" stroke="#8D9595" stroke-width="2" mask="url(#path-24-inside-5_1_1636)"/>
<rect x="55" y="56.5249" width="16" height="28" rx="2.27275" fill="#677272"/>
<path d="M57.5 57.8198L58.145 58.2027L58.799 58.5698L58.79 59.3198L58.799 60.0698L58.145 60.437L57.5 60.8198L56.855 60.437L56.201 60.0698L56.21 59.3198L56.201 58.5698L56.855 58.2027L57.5 57.8198Z" fill="#8D9595"/>
<path d="M57.5 80.7775L58.145 81.1603L58.799 81.5275L58.79 82.2775L58.799 83.0275L58.145 83.3946L57.5 83.7775L56.855 83.3946L56.201 83.0275L56.21 82.2775L56.201 81.5275L56.855 81.1603L57.5 80.7775Z" fill="#8D9595"/>
<path d="M68.5 57.7775L69.145 58.1603L69.799 58.5275L69.79 59.2775L69.799 60.0275L69.145 60.3946L68.5 60.7775L67.855 60.3946L67.201 60.0275L67.21 59.2775L67.201 58.5275L67.855 58.1603L68.5 57.7775Z" fill="#8D9595"/>
<path d="M68.5 80.7775L69.145 81.1603L69.799 81.5275L69.79 82.2775L69.799 83.0275L69.145 83.3946L68.5 83.7775L67.855 83.3946L67.201 83.0275L67.21 82.2775L67.201 81.5275L67.855 81.1603L68.5 80.7775Z" fill="#8D9595"/>
<path d="M53 66.5249H79V76.5249H53V66.5249Z" fill="#3B4848"/>
<mask id="path-31-inside-6_1_1636" fill="white">
<rect x="58" y="61.5249" width="10" height="18" rx="0.757583"/>
</mask>
<rect x="58" y="61.5249" width="10" height="18" rx="0.757583" fill="#414F4F" stroke="#8D9595" stroke-width="2" mask="url(#path-31-inside-6_1_1636)"/>
<rect x="150" y="29.5249" width="16" height="28" rx="2.27275" fill="#677272"/>
<path d="M152.5 30.8198L153.145 31.2027L153.799 31.5698L153.79 32.3198L153.799 33.0698L153.145 33.437L152.5 33.8198L151.855 33.437L151.201 33.0698L151.21 32.3198L151.201 31.5698L151.855 31.2027L152.5 30.8198Z" fill="#8D9595"/>
<path d="M152.5 53.7775L153.145 54.1603L153.799 54.5275L153.79 55.2775L153.799 56.0275L153.145 56.3946L152.5 56.7775L151.855 56.3946L151.201 56.0275L151.21 55.2775L151.201 54.5275L151.855 54.1603L152.5 53.7775Z" fill="#8D9595"/>
<path d="M163.5 30.7775L164.145 31.1603L164.799 31.5275L164.79 32.2775L164.799 33.0275L164.145 33.3946L163.5 33.7775L162.855 33.3946L162.201 33.0275L162.21 32.2775L162.201 31.5275L162.855 31.1603L163.5 30.7775Z" fill="#8D9595"/>
<path d="M163.5 53.7775L164.145 54.1603L164.799 54.5275L164.79 55.2775L164.799 56.0275L164.145 56.3946L163.5 56.7775L162.855 56.3946L162.201 56.0275L162.21 55.2775L162.201 54.5275L162.855 54.1603L163.5 53.7775Z" fill="#8D9595"/>
<path d="M140 39.5249H167V49.5249H140V39.5249Z" fill="#3B4848"/>
<mask id="path-38-inside-7_1_1636" fill="white">
<rect x="153" y="34.5249" width="10" height="18" rx="0.757583"/>
</mask>
<rect x="153" y="34.5249" width="10" height="18" rx="0.757583" fill="#414F4F" stroke="#8D9595" stroke-width="2" mask="url(#path-38-inside-7_1_1636)"/>
<rect x="234" y="29.5249" width="16" height="28" rx="2.27275" fill="#677272"/>
<path d="M236.5 30.8198L237.145 31.2027L237.799 31.5698L237.79 32.3198L237.799 33.0698L237.145 33.437L236.5 33.8198L235.855 33.437L235.201 33.0698L235.21 32.3198L235.201 31.5698L235.855 31.2027L236.5 30.8198Z" fill="#8D9595"/>
<path d="M236.5 53.7775L237.145 54.1603L237.799 54.5275L237.79 55.2775L237.799 56.0275L237.145 56.3946L236.5 56.7775L235.855 56.3946L235.201 56.0275L235.21 55.2775L235.201 54.5275L235.855 54.1603L236.5 53.7775Z" fill="#8D9595"/>
<path d="M247.5 30.7775L248.145 31.1603L248.799 31.5275L248.79 32.2775L248.799 33.0275L248.145 33.3946L247.5 33.7775L246.855 33.3946L246.201 33.0275L246.21 32.2775L246.201 31.5275L246.855 31.1603L247.5 30.7775Z" fill="#8D9595"/>
<path d="M247.5 53.7775L248.145 54.1603L248.799 54.5275L248.79 55.2775L248.799 56.0275L248.145 56.3946L247.5 56.7775L246.855 56.3946L246.201 56.0275L246.21 55.2775L246.201 54.5275L246.855 54.1603L247.5 53.7775Z" fill="#8D9595"/>
<path d="M231 39.5249H247V49.5249H231V39.5249Z" fill="#3B4848"/>
<mask id="path-45-inside-8_1_1636" fill="white">
<rect x="237" y="34.5249" width="10" height="18" rx="0.757583"/>
</mask>
<rect x="237" y="34.5249" width="10" height="18" rx="0.757583" fill="#414F4F" stroke="#8D9595" stroke-width="2" mask="url(#path-45-inside-8_1_1636)"/>
<rect x="29.526" y="42.0509" width="22.9479" height="54.9479" fill="#8D9595" stroke="#677272" stroke-width="1.05208"/>
<rect x="29.2742" y="43.9619" width="23.0458" height="1.40277" fill="#677272"/>
<rect x="29.2742" y="49.573" width="23.0458" height="1.40277" fill="#677272"/>
<rect x="29.2742" y="55.1841" width="23.0458" height="1.40277" fill="#677272"/>
<rect x="29.2742" y="60.7952" width="23.0458" height="1.40277" fill="#677272"/>
<rect x="29.2742" y="66.4064" width="23.0458" height="1.40277" fill="#677272"/>
<rect x="29.2742" y="72.0173" width="23.0458" height="1.40277" fill="#677272"/>
<rect x="29.2742" y="77.6285" width="23.0458" height="1.40277" fill="#677272"/>
<rect x="29.2742" y="83.2396" width="23.0458" height="1.40277" fill="#677272"/>
<rect x="29.2742" y="88.8508" width="23.0458" height="1.40277" fill="#677272"/>
<rect x="29.2742" y="94.4619" width="23.0458" height="1.40277" fill="#677272"/>
<path d="M11.9397 20.5644L29 41.5248H53L70.4462 20.5644V10.5248H11.9397V20.5644Z" fill="#677272"/>
<path d="M70 118.654L53 97.5248L28.9474 97.5248L12 118.654L12 128.525L70 128.525L70 118.654Z" fill="#677272"/>
<rect x="1" y="1.5249" width="258" height="136" rx="5" stroke="#CED7E7" stroke-width="2"/>
</svg>
}

View File

@ -0,0 +1,116 @@
import { Button, Collapse, Divider, Tag, Typography } from 'antd'
import react from 'react'
import {RightOutlined} from '@ant-design/icons';
import './style.css'
import { BriefExgausterScheme } from '../BriefExgausterScheme';
import { BearingCard } from '../BearingCard';
import { useNavigate } from 'react-router-dom';
import { useAppSelector } from '../../store';
import { fields } from '../../store/slices/FieldMappingSlice';
const { Panel } = Collapse;
interface IExgauster {
name: string;
}
export const ExgausterCard: react.FC<IExgauster> = (props) => {
const navigate = useNavigate();
const retrieveFields = useAppSelector(fields)
var ex_fields = Array.from(new Set(
retrieveFields.filter(
(e) => e.parent == props.name
).filter(e => {
return typeof e.entity_name == 'string'
}).map(
(e) => e.entity_name
).filter((e) => typeof e == 'string')
)
)
var fieldsMap = new Map<string, Set<string>>();
ex_fields.map((e) => {fieldsMap.set(e, new Set())})
retrieveFields.filter((e) => {
return e.parent == props.name && typeof e.entity_name == 'string'
}).filter((e) => e.entity_name.split(' ')[0] == 'Подшипник').map((e) => {
var type = "temp";
if (e.name.split(' ')[1].toLowerCase() == 'вибрация') type = 'vibration';
(fieldsMap as any).get(e.entity_name).add(type);
});
return <div className='ex-card__container'>
<div className="ex-card__heading">
<div className="status">
<div className="status-content"></div>
<Typography.Text style={{color: 'white'}} strong>{props.name}</Typography.Text>
</div>
<Button icon={<RightOutlined />} onClick={() => {
navigate(`/exgauster/${props.name}/mnemoscheme`)
}}/>
</div>
<div className="ex-card__content">
<div className="rotor-info">
<div className="rotor-name">
<Typography.Text style={{fontSize: '16px'}} strong>Имя ротора</Typography.Text>
<Tag>12.02.2022</Tag>
</div>
<Typography.Text
style={{
textDecoration: 'underline',
textDecorationStyle: 'dotted',
color: '#8E4D9B',
}}
>Изменить</Typography.Text>
</div>
<Divider></Divider>
<BriefExgausterScheme />
<Collapse style={{width: '100%', marginTop: '20px'}}>
<Panel header='Предупреждение' key='1'>
<div className="br__cont">
<BearingCard
tags={
[
{
name: "temp",
type: "bare"
}
]
}
name="Подшипник 3"
/>
<BearingCard
tags={
[
{
name: "temp",
type: "bare"
}
]
}
name="Подшипник 3"
/>
</div>
</Panel>
<Panel header='Все подшипники' key='2'>
<div className="br__cont">
{
ex_fields.map((e) => {
return <BearingCard
name={e}
tags={
Array.from(fieldsMap.get(e) as any).map((e) => {
return {
type: 'bare',
name: e as any
}
})
}
/>
})
}
</div>
</Panel>
</Collapse>
</div>
</div>
}

View File

@ -0,0 +1,50 @@
.ex-card__container{
background-color: white;
border: #E5E5E5 solid 1px;
border-radius: 5px;
display: inline-block;
}
.ex-card__heading{
padding: 10px;
background-color: #6E6E6D;
border-radius: 5px 5px 0px 0px;
display: flex;
width: 280px;
justify-content: space-between;
align-items: center;
}
.status-content{
width: 10px;
height: 10px;
border-radius: 100px;
background-color: #6EA566;
}
.status{
display: flex;
gap: 5px;
align-items: center;
}
.ex-card__content{
padding: 10px;
display: flex;
flex-direction: column;
align-items: center;
}
.rotor-info{
width: 100%;
display: flex;
justify-content: space-between;
align-items: center;
}
.rotor-name{
display: flex;
align-items: center;
gap: 10px;
}
.br__cont{
display: flex;
flex-direction: column;
gap: 10px;
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,71 @@
export default {
"У-171": {
"1": {
"T": "SM_Exgauster\\[2:27]",
"V": "SM_Exgauster\\[2:1]",
"O": "SM_Exgauster\\[2:2]",
"H": "SM_Exgauster\\[2:0]"
},
"2": {
"T": "SM_Exgauster\\[2:28]",
"V": "SM_Exgauster\\[2:4]",
"O": "SM_Exgauster\\[2:5]",
"H": "SM_Exgauster\\[2:3]"
},
"3": {
"T": "SM_Exgauster\\[2:29]"
},
"4": {
"T": "SM_Exgauster\\[2:30]"
},
"5": {
"T": "SM_Exgauster\\[2:31]"
},
"6": {
"T": "SM_Exgauster\\[2:32]"
},
"7": {
"T": "SM_Exgauster\\[2:33]",
"V": "SM_Exgauster\\[2:7]",
"O": "SM_Exgauster\\[2:8]",
"H": "SM_Exgauster\\[2:6]"
},
"8": {
"T": "SM_Exgauster\\[2:34]",
"V": "SM_Exgauster\\[2:10]",
"O": "SM_Exgauster\\[2:11]",
"H": "SM_Exgauster\\[2:9]"
},
"9": {
'T': "SM_Exgauster\\[2:35]"
},
"FREEZE": {
"oil_temperature_after": "SM_Exgauster\\[2:42]",
"oil_temperature_before": "SM_Exgauster\\[2:41]",
"water_temperature_after": "SM_Exgauster\\[2:37]",
"water_temperature_before": "SM_Exgauster\\[2:36]"
},
"GAUSE_COLLECTOR": {
"temperature_before": "SM_Exgauster\\[2:24]",
"underpressure_before": "SM_Exgauster\\[2:61]"
},
"POS_ZADV": {
"gas_valve_closed": "SM_Exgauster\\[4.1]",
"gas_valve_open": "SM_Exgauster\\[4.2]",
"gas_valve_position": "SM_Exgauster\\[4:6]"
},
"MAIN_DRIVE": {
"rotor_current": "SM_Exgauster\\[4:2]",
"rotor_voltage": "SM_Exgauster\\[4:4]",
"stator_current": "SM_Exgauster\\[4:3]",
"stator_voltage": "SM_Exgauster\\[4:5]"
},
"OIL_SYSTEM": {
"oil_level": "SM_Exgauster\\[4:0]",
"oil_pressure": "SM_Exgauster\\[4:1]",
},
"EX_WORK": {
'work': "SM_Exgauster\\[2.0]"
}
}
}

View File

@ -0,0 +1,25 @@
import { Button, Typography } from 'antd'
import react, { ReactNode, ReactChild } from 'react'
import {FileOutlined} from '@ant-design/icons'
import './style.css'
interface IMainContent{
children: ReactNode;
}
export const MainContent: react.FC<IMainContent> = (props) => {
return <div className='main-content'>
<div className="heading">
<Button
icon={<FileOutlined />}
type='primary'
/>
<Typography.Text strong>Главный экран</Typography.Text>
</div>
<div className="content">
{props.children}
</div>
</div>
}

View File

@ -0,0 +1,21 @@
.main-content{
display: flex;
flex-direction: column;
background-color: white;
border: 1px solid #EAEAEA;
margin: 20px;
border-radius: 5px;
}
.heading{
padding: 10px;
background-color: #FAFAFA;
display: flex;
gap: 10px;
align-items: center;
border-radius: 5px 5px 0px 0px;
}
.content{
padding: 10px;
}

View File

@ -0,0 +1,22 @@
import { Typography } from 'antd'
import react from 'react'
import { ExgausterCard } from '../ExgausterCard'
import './style.css'
interface IAlgo {
first_exgauster: string;
second_exgauster: string;
}
export const TheAlgoMachineCard: react.FC<IAlgo> = (props) => {
return <div className='algo-machine__container'>
<div className="algo-machine__header">
<Typography.Text strong style={{color: '#6E6E6D'}}>Алгомашина 1</Typography.Text>
</div>
<div className="exgausters">
<ExgausterCard name={props.first_exgauster}></ExgausterCard>
<ExgausterCard name={props.second_exgauster}></ExgausterCard>
</div>
</div>
}

View File

@ -0,0 +1,16 @@
.algo-machine__container{
display: inline-flex;
flex-direction: column;
gap: 10px;
}
.algo-machine__header{
padding: 10px;
background-color: #F4F4F4;
border-radius: 5px;
display: inline-block;
}
.exgausters{
display: flex;
gap: 10px;
}

View File

@ -0,0 +1,49 @@
import 'chart.js/auto';
import react, {useRef} from 'react'
import { Line } from "react-chartjs-2";
interface IEChart {
data: {
name: string;
data: number[]
}[]
}
export const TheChart: react.FC<IEChart> = (props) => {
const ref = useRef();
const data = {
labels: [...(Array((props.data[0] as any).data.length).keys() as any)],
datasets: props.data.map((e) => {
return {
'label': e.name,
'data': e.data
}
}),
options: {
scales: {
y: {
beginAtZero: true
}
},
responsive: true,
maintainAspectRatio: false,
}
};
return <Line data={data} ref={ref} style={{width: 600}} options={{
scales: {
y: {
beginAtZero: true
}
},
responsive: true,
maintainAspectRatio: false,
plugins: {
legend: {
display: false
}
}
}
}></Line>
}

View File

@ -0,0 +1,33 @@
import { Button } from 'antd'
import react from 'react'
import { useNavigate } from 'react-router-dom'
import './style.css'
interface ITHeCharMnem{
type: "mnem" | "chart";
}
export const TheChartMnemSwitch: react.FC<ITHeCharMnem> = (props) => {
const navigate = useNavigate();
return <div className='switch__container'>
<div className="switch-flex">
<Button
type={props.type == 'mnem' ? 'primary' : 'default'}
onClick={() => {
navigate('/exgauster/1/mnemoscheme')
}}
>
Мнемосхема
</Button>
<Button
type={props.type == 'chart' ? 'primary' : 'default'}
onClick={() => {
navigate('/exgauster/1/graph')
}}
>
График
</Button>
</div>
</div>
}

View File

@ -0,0 +1,13 @@
.switch__container{
margin: 20px;
display: flex;
justify-content: end;
}
.switch-flex{
padding: 10px;
background-color: white;
border-radius: 5px;
display: flex;
gap: 5px;
}

View File

@ -0,0 +1,16 @@
import react from 'react'
export const Logo: react.FC = () => {
return <svg width="112" height="19" viewBox="0 0 112 19" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M17.4127 0.524902H0V4.09575H17.4127V0.524902Z" fill="#FCB53B"/>
<path d="M17.4127 7.73901H0V11.3099H17.4127V7.73901Z" fill="#F57F29"/>
<path d="M17.4127 14.9539H0V18.5247H17.4127V14.9539Z" fill="#E32213"/>
<path d="M24.3914 0.524902V18.5249H38.7022V14.9541H27.8457V11.3103H38.7022V7.73948H27.8457V4.09575H38.7022V0.524902H24.3914Z" fill="black"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M82.4107 0.524902L75.7135 18.5249H79.7318L81.0712 14.8812H89.1783L90.5178 18.452H94.4656L87.3454 0.524902H82.4107ZM85.0895 4.09575L87.8389 11.3103H82.3402L85.0895 4.09575Z" fill="black"/>
<path d="M96.8626 18.5246V14.808H106.168C107.085 14.808 107.86 14.0064 107.86 13.059C107.86 12.1116 107.085 11.31 106.168 11.31H98.625V7.73916H106.168C107.085 7.73916 107.86 6.93754 107.86 5.99018C107.86 5.04281 107.085 4.24119 106.168 4.24119H96.8626V0.597464H106.309C109.129 0.597464 111.526 3.00232 111.526 5.9173C111.526 7.30192 111.244 8.46791 109.411 9.56103C111.032 10.4355 111.526 11.8201 111.526 13.2048C111.526 16.557 109.129 18.5246 106.309 18.5246H96.8626Z" fill="black"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M70.9193 0.524902H61.3317V18.5249H64.7861V11.3103H70.9193C73.8096 11.3103 76.136 8.90547 76.136 5.91761C76.136 2.92976 73.8096 0.524902 70.9193 0.524902ZM70.7783 7.73948H64.7861V4.16863H70.7783C71.6947 4.16863 72.4702 4.97025 72.4702 5.91761C72.4702 6.93786 71.6947 7.73948 70.7783 7.73948Z" fill="black"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M57.5958 5.84474C57.5958 7.22936 57.3138 8.39535 55.4809 9.48847C57.1023 10.4358 57.7368 11.8204 57.8073 13.2051C57.8073 16.5573 55.4104 18.5249 52.5905 18.5249H42.862V0.524902H52.379C55.1989 0.524902 57.5958 2.92976 57.5958 5.84474ZM52.1675 4.16863H46.3163V7.6666H52.1675C53.084 7.6666 53.8595 6.86498 53.8595 5.91761C53.8595 4.97025 53.084 4.16863 52.1675 4.16863ZM46.3163 14.8812H52.379C53.366 14.8812 54.1414 14.0796 54.0709 13.0593C54.0709 12.1119 53.2955 11.3103 52.379 11.3103H46.3163V14.8812Z" fill="black"/>
</svg>
}

View File

@ -0,0 +1,32 @@
import react from 'react'
import {Breadcrumb, Button, Divider, Typography} from 'antd'
import {MenuOutlined} from '@ant-design/icons'
import './style.css'
import { Logo } from './Logo'
export const TheHeader: react.FC = () => {
return <div className='header__container'>
<div className="menu-item">
<Button
icon={<MenuOutlined />}
type='primary'
size='large'
/>
<Divider type='vertical' style={{height: '36px'}} />
<Logo />
<Breadcrumb style={{paddingLeft: '30px'}}>
<Breadcrumb.Item>
<Typography.Text strong>Прогнозная аналитика эксгаустеров</Typography.Text>
</Breadcrumb.Item>
</Breadcrumb>
</div>
<div className="menu-item">
<Button type='primary'>
<Typography.Text strong>Справочник</Typography.Text>
</Button>
</div>
</div>
}

View File

@ -0,0 +1,15 @@
.header__container{
padding: 10px 20px;
background-color: white;
display: flex;
flex-direction: row;
justify-content: space-between;
}
.menu-item{
display: flex;
flex-direction: row;
gap: 10px;
align-items: center;
}

View File

@ -0,0 +1,19 @@
import react from 'react'
export const Temperature: react.FC = () => {
return <svg width="21" height="16" viewBox="0 0 21 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M6.591 3.4249V4.5429H4.264C4.09933 4.5429 3.98667 4.5299 3.926 4.5039L3.913 4.5299C3.939 4.59057 3.952 4.69457 3.952 4.8419V12.5249H2.782V4.8419C2.782 4.69457 2.795 4.59057 2.821 4.5299L2.795 4.5039C2.73433 4.5299 2.626 4.5429 2.47 4.5429H0.13V3.4249H6.591Z" fill="#2B2B2A"/>
<g clip-path="url(#clip0_1_1578)">
<path d="M15.4139 9.2912C15.3828 9.27149 15.3571 9.24424 15.3394 9.21197C15.3216 9.1797 15.3122 9.14347 15.3122 9.10663V3.2135C15.3122 2.8654 15.1739 2.53156 14.9278 2.28542C14.6816 2.03928 14.3478 1.901 13.9997 1.901C13.6516 1.901 13.3178 2.03928 13.0716 2.28542C12.8255 2.53156 12.6872 2.8654 12.6872 3.2135V9.10663C12.6871 9.1434 12.6778 9.17956 12.6601 9.21177C12.6424 9.24398 12.6168 9.27121 12.5857 9.29092C12.197 9.54417 11.881 9.89448 11.6691 10.3072C11.4572 10.72 11.3567 11.1809 11.3774 11.6444C11.4087 12.3294 11.7068 12.9749 12.2079 13.443C12.709 13.911 13.3734 14.1644 14.0589 14.149C14.7444 14.1335 15.3967 13.8504 15.8762 13.3602C16.3557 12.87 16.6243 12.2117 16.6247 11.526C16.6249 11.0821 16.5142 10.6453 16.3028 10.255C16.0914 9.86474 15.7858 9.53345 15.4139 9.2912V9.2912Z" stroke="black" stroke-width="1.00189" stroke-miterlimit="10" stroke-linecap="round"/>
<path d="M13.9996 4.08875V11.5262" stroke="black" stroke-width="1.00189" stroke-miterlimit="10" stroke-linecap="round"/>
<path d="M14.0005 12.8393C14.7259 12.8393 15.3139 12.2513 15.3139 11.5259C15.3139 10.8005 14.7259 10.2124 14.0005 10.2124C13.2751 10.2124 12.687 10.8005 12.687 11.5259C12.687 12.2513 13.2751 12.8393 14.0005 12.8393Z" fill="black"/>
</g>
<defs>
<clipPath id="clip0_1_1578">
<rect width="14" height="14" fill="white" transform="translate(7 1.0249)"/>
</clipPath>
</defs>
</svg>
}

View File

@ -0,0 +1,15 @@
import react from 'react'
export const Vibration: react.FC = () => {
return <svg width="25" height="16" viewBox="0 0 25 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M8.151 3.4249L4.16 12.6549H4.03L0.026 3.4249H1.404L3.614 8.8719C3.80467 9.34857 3.95633 9.8989 4.069 10.5229H4.121C4.20767 9.95957 4.35933 9.40924 4.576 8.8719L6.786 3.4249H8.151Z" fill="#2B2B2A"/>
<path d="M16.695 6.28162C16.2681 6.76213 16.0323 7.38255 16.0323 8.0253C16.0323 8.66806 16.2681 9.28848 16.695 9.76899" stroke="black" stroke-width="1.00189" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M19.3351 9.76899C19.762 9.28848 19.9978 8.66806 19.9978 8.0253C19.9978 7.38255 19.762 6.76213 19.3351 6.28162" stroke="black" stroke-width="1.00189" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M15.301 4.88806C14.5057 5.73896 14.0632 6.86021 14.0632 8.02494C14.0632 9.18967 14.5057 10.3109 15.301 11.1618" stroke="black" stroke-width="1.00189" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M20.7278 11.1618C21.5231 10.3109 21.9656 9.18967 21.9656 8.02494C21.9656 6.86021 21.5231 5.73896 20.7278 4.88806" stroke="black" stroke-width="1.00189" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M22.2666 12.3993C23.3408 11.1952 23.9345 9.63794 23.9345 8.02429C23.9345 6.41064 23.3408 4.85339 22.2666 3.64929" stroke="black" stroke-width="1.00189" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M13.7624 3.64929C12.6882 4.85339 12.0945 6.41064 12.0945 8.02429C12.0945 9.63794 12.6882 11.1952 13.7624 12.3993" stroke="black" stroke-width="1.00189" stroke-linecap="round" stroke-linejoin="round"/>
</svg>
}

View File

@ -0,0 +1,41 @@
import { Typography } from 'antd'
import react from 'react'
import { Temperature } from './icons/Temperature'
import { Vibration } from './icons/Vibration'
import './style.css'
interface ITheLegend{
type?: "short" | "long"
}
export const TheLegend: react.FC<ITheLegend> = (props) => {
var type = props.type;
if (!props.type) type = "long";
return <div className='legend__container'>
<div className="legend__flex">
{
type == 'long' ? <>
<div className="legend-item">
<Temperature />
<Typography.Text>Температура</Typography.Text>
</div>
<div className="legend-item">
<Vibration />
<Typography.Text>Вибрация</Typography.Text>
</div>
</> : <></>
}
<div className="legend-item">
<div className="warn"></div>
<Typography.Text>Предупреждение</Typography.Text>
</div>
<div className="legend-item">
<div className="danger"></div>
<Typography.Text>Опасность</Typography.Text>
</div>
</div>
</div>
}

View File

@ -0,0 +1,27 @@
.legend__container{
display: flex;
justify-content: end;
}
.legend__flex{
display: flex;
gap: 20px;
}
.legend-item{
display: flex;
align-items: center;
gap: 2px;
}
.warn{
width: 15px;
height: 15px;
background-color: #F9A823;
border-radius: 3px;
}
.danger{
width: 15px;
height: 15px;
background-color: #E32112;
border-radius: 3px;
}

View File

@ -0,0 +1,38 @@
import react from 'react'
import {Button, DatePicker} from 'antd';
import { useNavigate } from 'react-router-dom';
import './style.css'
const {RangePicker} = DatePicker;
interface ISwitcher{
type: "mnem" | "chart"
}
export const TheTimestampedSwitcher: react.FC<ISwitcher> = (props) => {
const navigate = useNavigate();
return <div className="time-switch__container">
<div className="timestamps">
<RangePicker></RangePicker>
</div>
<div className="switch-flex">
<Button
type={props.type == 'mnem' ? 'primary' : 'default'}
onClick={() => {
navigate('/exgauster/1/mnemoscheme')
}}
>
Мнемосхема
</Button>
<Button
type={props.type == 'chart' ? 'primary' : 'default'}
onClick={() => {
navigate('/exgauster/1/graph')
}}
>
График
</Button>
</div>
</div>
}

View File

@ -0,0 +1,23 @@
.switch__container{
margin: 20px;
display: flex;
justify-content: end;
}
.switch-flex{
padding: 10px;
background-color: white;
border-radius: 5px;
display: flex;
gap: 5px;
}
.time-switch__container{
margin: 20px;
display: flex;
justify-content: space-between;
}
.timestamps{
padding: 10px;
background-color: white;
border-radius: 5px;
}

View File

@ -1,13 +0,0 @@
body {
margin: 0;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
code {
font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
monospace;
}

View File

@ -1,8 +1,6 @@
import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
const root = ReactDOM.createRoot(
document.getElementById('root') as HTMLElement
@ -12,8 +10,3 @@ root.render(
<App />
</React.StrictMode>
);
// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();

View File

@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 841.9 595.3"><g fill="#61DAFB"><path d="M666.3 296.5c0-32.5-40.7-63.3-103.1-82.4 14.4-63.6 8-114.2-20.2-130.4-6.5-3.8-14.1-5.6-22.4-5.6v22.3c4.6 0 8.3.9 11.4 2.6 13.6 7.8 19.5 37.5 14.9 75.7-1.1 9.4-2.9 19.3-5.1 29.4-19.6-4.8-41-8.5-63.5-10.9-13.5-18.5-27.5-35.3-41.6-50 32.6-30.3 63.2-46.9 84-46.9V78c-27.5 0-63.5 19.6-99.9 53.6-36.4-33.8-72.4-53.2-99.9-53.2v22.3c20.7 0 51.4 16.5 84 46.6-14 14.7-28 31.4-41.3 49.9-22.6 2.4-44 6.1-63.6 11-2.3-10-4-19.7-5.2-29-4.7-38.2 1.1-67.9 14.6-75.8 3-1.8 6.9-2.6 11.5-2.6V78.5c-8.4 0-16 1.8-22.6 5.6-28.1 16.2-34.4 66.7-19.9 130.1-62.2 19.2-102.7 49.9-102.7 82.3 0 32.5 40.7 63.3 103.1 82.4-14.4 63.6-8 114.2 20.2 130.4 6.5 3.8 14.1 5.6 22.5 5.6 27.5 0 63.5-19.6 99.9-53.6 36.4 33.8 72.4 53.2 99.9 53.2 8.4 0 16-1.8 22.6-5.6 28.1-16.2 34.4-66.7 19.9-130.1 62-19.1 102.5-49.9 102.5-82.3zm-130.2-66.7c-3.7 12.9-8.3 26.2-13.5 39.5-4.1-8-8.4-16-13.1-24-4.6-8-9.5-15.8-14.4-23.4 14.2 2.1 27.9 4.7 41 7.9zm-45.8 106.5c-7.8 13.5-15.8 26.3-24.1 38.2-14.9 1.3-30 2-45.2 2-15.1 0-30.2-.7-45-1.9-8.3-11.9-16.4-24.6-24.2-38-7.6-13.1-14.5-26.4-20.8-39.8 6.2-13.4 13.2-26.8 20.7-39.9 7.8-13.5 15.8-26.3 24.1-38.2 14.9-1.3 30-2 45.2-2 15.1 0 30.2.7 45 1.9 8.3 11.9 16.4 24.6 24.2 38 7.6 13.1 14.5 26.4 20.8 39.8-6.3 13.4-13.2 26.8-20.7 39.9zm32.3-13c5.4 13.4 10 26.8 13.8 39.8-13.1 3.2-26.9 5.9-41.2 8 4.9-7.7 9.8-15.6 14.4-23.7 4.6-8 8.9-16.1 13-24.1zM421.2 430c-9.3-9.6-18.6-20.3-27.8-32 9 .4 18.2.7 27.5.7 9.4 0 18.7-.2 27.8-.7-9 11.7-18.3 22.4-27.5 32zm-74.4-58.9c-14.2-2.1-27.9-4.7-41-7.9 3.7-12.9 8.3-26.2 13.5-39.5 4.1 8 8.4 16 13.1 24 4.7 8 9.5 15.8 14.4 23.4zM420.7 163c9.3 9.6 18.6 20.3 27.8 32-9-.4-18.2-.7-27.5-.7-9.4 0-18.7.2-27.8.7 9-11.7 18.3-22.4 27.5-32zm-74 58.9c-4.9 7.7-9.8 15.6-14.4 23.7-4.6 8-8.9 16-13 24-5.4-13.4-10-26.8-13.8-39.8 13.1-3.1 26.9-5.8 41.2-7.9zm-90.5 125.2c-35.4-15.1-58.3-34.9-58.3-50.6 0-15.7 22.9-35.6 58.3-50.6 8.6-3.7 18-7 27.7-10.1 5.7 19.6 13.2 40 22.5 60.9-9.2 20.8-16.6 41.1-22.2 60.6-9.9-3.1-19.3-6.5-28-10.2zM310 490c-13.6-7.8-19.5-37.5-14.9-75.7 1.1-9.4 2.9-19.3 5.1-29.4 19.6 4.8 41 8.5 63.5 10.9 13.5 18.5 27.5 35.3 41.6 50-32.6 30.3-63.2 46.9-84 46.9-4.5-.1-8.3-1-11.3-2.7zm237.2-76.2c4.7 38.2-1.1 67.9-14.6 75.8-3 1.8-6.9 2.6-11.5 2.6-20.7 0-51.4-16.5-84-46.6 14-14.7 28-31.4 41.3-49.9 22.6-2.4 44-6.1 63.6-11 2.3 10.1 4.1 19.8 5.2 29.1zm38.5-66.7c-8.6 3.7-18 7-27.7 10.1-5.7-19.6-13.2-40-22.5-60.9 9.2-20.8 16.6-41.1 22.2-60.6 9.9 3.1 19.3 6.5 28.1 10.2 35.4 15.1 58.3 34.9 58.3 50.6-.1 15.7-23 35.6-58.4 50.6zM320.8 78.4z"/><circle cx="420.9" cy="296.5" r="45.7"/><path d="M520.5 78.1z"/></g></svg>

Before

Width:  |  Height:  |  Size: 2.6 KiB

312
src/mock.ts Normal file
View File

@ -0,0 +1,312 @@
export default {
"SM_Exgauster\\[0:0]": 1.655092477798462,
"SM_Exgauster\\[0:1]": 1.545138955116272,
"SM_Exgauster\\[0:1]_status": "normal",
"SM_Exgauster\\[0:2]": 1.0678209066390991,
"SM_Exgauster\\[0:2]_status": "normal",
"SM_Exgauster\\[0:3]": 2.251157522201538,
"SM_Exgauster\\[0:3]_status": "normal",
"SM_Exgauster\\[0:4]": 1.9155092239379883,
"SM_Exgauster\\[0:5]": 1.498842477798462,
"SM_Exgauster\\[0:5]_status": "normal",
"SM_Exgauster\\[0:6]": 2.0406742095947266,
"SM_Exgauster\\[0:6]_status": "normal",
"SM_Exgauster\\[0:7]": 1.9097222089767456,
"SM_Exgauster\\[0:8]": 1.9263808727264404,
"SM_Exgauster\\[0:9]": 1.5856481790542603,
"SM_Exgauster\\[0:9]_status": "normal",
"SM_Exgauster\\[0:10]": 2.2048611640930176,
"SM_Exgauster\\[0:10]_status": "normal",
"SM_Exgauster\\[0:11]": 1.1111111640930176,
"SM_Exgauster\\[0:11]_status": "normal",
"SM_Exgauster\\[0:12]": 1.9097222089767456,
"SM_Exgauster\\[0:12]_status": "normal",
"SM_Exgauster\\[0:13]": 1.7939815521240234,
"SM_Exgauster\\[0:14]": 0.5787037014961243,
"SM_Exgauster\\[0:14]_status": "normal",
"SM_Exgauster\\[0:15]": 1.672453761100769,
"SM_Exgauster\\[0:15]_status": "normal",
"SM_Exgauster\\[0:16]": 2.372685194015503,
"SM_Exgauster\\[0:16]_status": "normal",
"SM_Exgauster\\[0:17]": 1.3657407760620117,
"SM_Exgauster\\[0:17]_status": "normal",
"SM_Exgauster\\[0:18]": 1.591435194015503,
"SM_Exgauster\\[0:18]_status": "normal",
"SM_Exgauster\\[0:19]": 1.4756944179534912,
"SM_Exgauster\\[0:19]_status": "normal",
"SM_Exgauster\\[0:20]": 2.627315044403076,
"SM_Exgauster\\[0:20]_status": "normal",
"SM_Exgauster\\[0:21]": 1.2557870149612427,
"SM_Exgauster\\[0:22]": 0.8391203880310059,
"SM_Exgauster\\[0:22]_status": "normal",
"SM_Exgauster\\[0:23]": 2.2974536418914795,
"SM_Exgauster\\[0:24]": 111.99675750732422,
"SM_Exgauster\\[0:25]": 116.49676513671875,
"SM_Exgauster\\[0:27]": 45.0,
"SM_Exgauster\\[0:28]": 44.80000305175781,
"SM_Exgauster\\[0:28]_status": "normal",
"SM_Exgauster\\[0:29]": 36.5,
"SM_Exgauster\\[0:29]_status": "normal",
"SM_Exgauster\\[0:30]": 40.0,
"SM_Exgauster\\[0:30]_status": "normal",
"SM_Exgauster\\[0:31]": 35.399993896484375,
"SM_Exgauster\\[0:32]": 33.70000457763672,
"SM_Exgauster\\[0:32]_status": "normal",
"SM_Exgauster\\[0:33]": 28.699996948242188,
"SM_Exgauster\\[0:33]_status": "normal",
"SM_Exgauster\\[0:34]": 37.099998474121094,
"SM_Exgauster\\[0:34]_status": "normal",
"SM_Exgauster\\[0:35]": 35.599998474121094,
"SM_Exgauster\\[0:36]": 13.900001525878906,
"SM_Exgauster\\[0:37]": 15.5,
"SM_Exgauster\\[0:41]": 31.300003051757812,
"SM_Exgauster\\[0:42]": 27.70000457763672,
"SM_Exgauster\\[0:43]": 50.80000305175781,
"SM_Exgauster\\[0:43]_status": "normal",
"SM_Exgauster\\[0:44]": 54.0,
"SM_Exgauster\\[0:44]_status": "normal",
"SM_Exgauster\\[0:45]": 41.69999694824219,
"SM_Exgauster\\[0:45]_status": "normal",
"SM_Exgauster\\[0:47]": 46.0,
"SM_Exgauster\\[0:47]_status": "normal",
"SM_Exgauster\\[0:48]": 41.5,
"SM_Exgauster\\[0:49]": 40.0,
"SM_Exgauster\\[0:50]": 32.30000305175781,
"SM_Exgauster\\[0:50]_status": "normal",
"SM_Exgauster\\[0:51]": 44.19999694824219,
"SM_Exgauster\\[0:51]_status": "normal",
"SM_Exgauster\\[0:52]": 41.19999694824219,
"SM_Exgauster\\[0:52]_status": "normal",
"SM_Exgauster\\[0:53]": 14.400001525878906,
"SM_Exgauster\\[0:54]": 13.599998474121094,
"SM_Exgauster\\[0:59]": 32.20000457763672,
"SM_Exgauster\\[0:60]": 36.400001525878906,
"SM_Exgauster\\[0:61]": 757.3784790039062,
"SM_Exgauster\\[0:62]": 760.27197265625,
"SM_Exgauster\\[0.0]": 1.0,
"SM_Exgauster\\[0.1]": 1.0,
"SM_Exgauster\\[1:0]": 63.0,
"SM_Exgauster\\[1:1]": 0.9549999833106995,
"SM_Exgauster\\[1:2]": 1893.0,
"SM_Exgauster\\[1:3]": 1956.0,
"SM_Exgauster\\[1:4]": 0.0,
"SM_Exgauster\\[1:5]": 106.0,
"SM_Exgauster\\[1:6]": 10.0,
"SM_Exgauster\\[1:7]": 69.5999984741211,
"SM_Exgauster\\[1:8]": 0.9700000286102295,
"SM_Exgauster\\[1:9]": 1100.0,
"SM_Exgauster\\[1:10]": 1818.0,
"SM_Exgauster\\[1:11]": 2.0,
"SM_Exgauster\\[1:12]": 106.0,
"SM_Exgauster\\[1:13]": 10.0,
"SM_Exgauster\\[1.1]": 0.0,
"SM_Exgauster\\[1.2]": 1.0,
"SM_Exgauster\\[1.6]": 0.0,
"SM_Exgauster\\[1.7]": 1.0,
"SM_Exgauster\\[2:0]": 0.2430555522441864,
"SM_Exgauster\\[2:0]_status": "normal",
"SM_Exgauster\\[2:1]": 0.2604166567325592,
"SM_Exgauster\\[2:1]_status": "normal",
"SM_Exgauster\\[2:2]": 0.23726852238178253,
"SM_Exgauster\\[2:2]_status": "normal",
"SM_Exgauster\\[2:3]": 0.41090577840805054,
"SM_Exgauster\\[2:4]": 0.5324074029922485,
"SM_Exgauster\\[2:4]_status": "normal",
"SM_Exgauster\\[2:5]": 0.30092594027519226,
"SM_Exgauster\\[2:5]_status": "normal",
"SM_Exgauster\\[2:6]": 0.46296295523643494,
"SM_Exgauster\\[2:6]_status": "normal",
"SM_Exgauster\\[2:7]": 1.048760175704956,
"SM_Exgauster\\[2:7]_status": "normal",
"SM_Exgauster\\[2:8]": 1.2731481790542603,
"SM_Exgauster\\[2:9]": 0.4861111044883728,
"SM_Exgauster\\[2:9]_status": "normal",
"SM_Exgauster\\[2:10]": 0.23148147761821747,
"SM_Exgauster\\[2:10]_status": "normal",
"SM_Exgauster\\[2:11]": 0.8738425970077515,
"SM_Exgauster\\[2:11]_status": "normal",
"SM_Exgauster\\[2:12]": 1.1979166269302368,
"SM_Exgauster\\[2:12]_status": "normal",
"SM_Exgauster\\[2:13]": 1.7881944179534912,
"SM_Exgauster\\[2:14]": 2.401620388031006,
"SM_Exgauster\\[2:14]_status": "normal",
"SM_Exgauster\\[2:15]": 1.0706018209457397,
"SM_Exgauster\\[2:15]_status": "normal",
"SM_Exgauster\\[2:16]": 1.469907522201538,
"SM_Exgauster\\[2:16]_status": "normal",
"SM_Exgauster\\[2:17]": 1.8634259700775146,
"SM_Exgauster\\[2:17]_status": "normal",
"SM_Exgauster\\[2:18]": 0.5613425970077515,
"SM_Exgauster\\[2:18]_status": "normal",
"SM_Exgauster\\[2:19]": 0.7002314925193787,
"SM_Exgauster\\[2:19]_status": "normal",
"SM_Exgauster\\[2:20]": 0.4861111044883728,
"SM_Exgauster\\[2:20]_status": "normal",
"SM_Exgauster\\[2:21]": 1.3541667461395264,
"SM_Exgauster\\[2:21]_status": "normal",
"SM_Exgauster\\[2:22]": 0.694444477558136,
"SM_Exgauster\\[2:22]_status": "normal",
"SM_Exgauster\\[2:23]": 1.6145832538604736,
"SM_Exgauster\\[2:24]": 122.47338104248047,
"SM_Exgauster\\[2:25]": 124.17337799072266,
"SM_Exgauster\\[2:27]": 60.30000305175781,
"SM_Exgauster\\[2:28]": 54.99999237060547,
"SM_Exgauster\\[2:28]_status": "normal",
"SM_Exgauster\\[2:29]": 43.5,
"SM_Exgauster\\[2:29]_status": "normal",
"SM_Exgauster\\[2:30]": 45.900001525878906,
"SM_Exgauster\\[2:31]": 35.29999542236328,
"SM_Exgauster\\[2:31]_status": "normal",
"SM_Exgauster\\[2:32]": 37.900001525878906,
"SM_Exgauster\\[2:32]_status": "normal",
"SM_Exgauster\\[2:33]": 32.599998474121094,
"SM_Exgauster\\[2:33]_status": "normal",
"SM_Exgauster\\[2:34]": 36.5,
"SM_Exgauster\\[2:34]_status": "normal",
"SM_Exgauster\\[2:35]": 37.400001525878906,
"SM_Exgauster\\[2:35]_status": "warning",
"SM_Exgauster\\[2:36]": 14.300000190734863,
"SM_Exgauster\\[2:37]": 16.099998474121094,
"SM_Exgauster\\[2:41]": 28.5,
"SM_Exgauster\\[2:42]": 24.400001525878906,
"SM_Exgauster\\[2:43]": 50.899993896484375,
"SM_Exgauster\\[2:43]_status": "normal",
"SM_Exgauster\\[2:44]": 60.19999694824219,
"SM_Exgauster\\[2:44]_status": "normal",
"SM_Exgauster\\[2:45]": 42.0,
"SM_Exgauster\\[2:45]_status": "normal",
"SM_Exgauster\\[2:47]": 39.5,
"SM_Exgauster\\[2:47]_status": "normal",
"SM_Exgauster\\[2:48]": 29.599998474121094,
"SM_Exgauster\\[2:49]": 30.099998474121094,
"SM_Exgauster\\[2:49]_status": "normal",
"SM_Exgauster\\[2:50]": 29.199996948242188,
"SM_Exgauster\\[2:50]_status": "normal",
"SM_Exgauster\\[2:51]": 30.800003051757812,
"SM_Exgauster\\[2:51]_status": "normal",
"SM_Exgauster\\[2:52]": 33.70000457763672,
"SM_Exgauster\\[2:52]_status": "alarm",
"SM_Exgauster\\[2:53]": 14.0,
"SM_Exgauster\\[2:54]": 14.800003051757812,
"SM_Exgauster\\[2:59]": 24.199996948242188,
"SM_Exgauster\\[2:60]": 19.800003051757812,
"SM_Exgauster\\[2:61]": 758.8252563476562,
"SM_Exgauster\\[2:62]": 704.57177734375,
"SM_Exgauster\\[2.0]": 1.0,
"SM_Exgauster\\[2.1]": 1.0,
"SM_Exgauster\\[3:0]": 1.0532407760620117,
"SM_Exgauster\\[3:0]_status": "normal",
"SM_Exgauster\\[3:1]": 0.9953703880310059,
"SM_Exgauster\\[3:1]_status": "normal",
"SM_Exgauster\\[3:2]": 0.8043981194496155,
"SM_Exgauster\\[3:2]_status": "normal",
"SM_Exgauster\\[3:3]": 1.0532407760620117,
"SM_Exgauster\\[3:3]_status": "normal",
"SM_Exgauster\\[3:4]": 1.1863425970077515,
"SM_Exgauster\\[3:5]": 0.7754629850387573,
"SM_Exgauster\\[3:5]_status": "normal",
"SM_Exgauster\\[3:6]": 0.8911386728286743,
"SM_Exgauster\\[3:7]": 0.694444477558136,
"SM_Exgauster\\[3:7]_status": "normal",
"SM_Exgauster\\[3:8]": 2.2627315521240234,
"SM_Exgauster\\[3:8]_status": "normal",
"SM_Exgauster\\[3:9]": 0.5929374098777771,
"SM_Exgauster\\[3:9]_status": "normal",
"SM_Exgauster\\[3:10]": 0.41087961196899414,
"SM_Exgauster\\[3:10]_status": "normal",
"SM_Exgauster\\[3:11]": 2.309027671813965,
"SM_Exgauster\\[3:11]_status": "normal",
"SM_Exgauster\\[3:12]": 0.7002314925193787,
"SM_Exgauster\\[3:12]_status": "normal",
"SM_Exgauster\\[3:13]": 0.5266203880310059,
"SM_Exgauster\\[3:13]_status": "normal",
"SM_Exgauster\\[3:14]": 0.19675925374031067,
"SM_Exgauster\\[3:14]_status": "normal",
"SM_Exgauster\\[3:15]": 0.5613425970077515,
"SM_Exgauster\\[3:16]": 0.49768519401550293,
"SM_Exgauster\\[3:16]_status": "normal",
"SM_Exgauster\\[3:17]": 0.5787037014961243,
"SM_Exgauster\\[3:17]_status": "normal",
"SM_Exgauster\\[3:18]": 0.6018518805503845,
"SM_Exgauster\\[3:18]_status": "normal",
"SM_Exgauster\\[3:19]": 0.5266203880310059,
"SM_Exgauster\\[3:19]_status": "normal",
"SM_Exgauster\\[3:20]": 0.9317129850387573,
"SM_Exgauster\\[3:20]_status": "normal",
"SM_Exgauster\\[3:21]": 0.37037038803100586,
"SM_Exgauster\\[3:22]": 0.30467233061790466,
"SM_Exgauster\\[3:22]_status": "normal",
"SM_Exgauster\\[3:23]": 0.6076388955116272,
"SM_Exgauster\\[3:24]": 90.68394470214844,
"SM_Exgauster\\[3:25]": 95.78356170654297,
"SM_Exgauster\\[3:27]": 41.399993896484375,
"SM_Exgauster\\[3:28]": 52.30000305175781,
"SM_Exgauster\\[3:29]": 39.20000457763672,
"SM_Exgauster\\[3:29]_status": "normal",
"SM_Exgauster\\[3:30]": 48.69999694824219,
"SM_Exgauster\\[3:30]_status": "normal",
"SM_Exgauster\\[3:31]": 45.0,
"SM_Exgauster\\[3:32]": 42.79999542236328,
"SM_Exgauster\\[3:32]_status": "normal",
"SM_Exgauster\\[3:33]": 32.400001525878906,
"SM_Exgauster\\[3:33]_status": "normal",
"SM_Exgauster\\[3:34]": 37.19999694824219,
"SM_Exgauster\\[3:34]_status": "normal",
"SM_Exgauster\\[3:35]": 36.400001525878906,
"SM_Exgauster\\[3:35]_status": "normal",
"SM_Exgauster\\[3:36]": 13.599998474121094,
"SM_Exgauster\\[3:37]": -3276.800048828125,
"SM_Exgauster\\[3:41]": 30.29999542236328,
"SM_Exgauster\\[3:42]": 30.599998474121094,
"SM_Exgauster\\[3:43]": 52.600006103515625,
"SM_Exgauster\\[3:44]": 47.69999694824219,
"SM_Exgauster\\[3:45]": 47.79999542236328,
"SM_Exgauster\\[3:45]_status": "normal",
"SM_Exgauster\\[3:47]": 45.5,
"SM_Exgauster\\[3:47]_status": "normal",
"SM_Exgauster\\[3:48]": 50.899993896484375,
"SM_Exgauster\\[3:48]_status": "normal",
"SM_Exgauster\\[3:49]": 45.099998474121094,
"SM_Exgauster\\[3:50]": 38.099998474121094,
"SM_Exgauster\\[3:50]_status": "normal",
"SM_Exgauster\\[3:51]": 36.69999694824219,
"SM_Exgauster\\[3:51]_status": "normal",
"SM_Exgauster\\[3:52]": 35.0,
"SM_Exgauster\\[3:52]_status": "normal",
"SM_Exgauster\\[3:53]": 12.199996948242188,
"SM_Exgauster\\[3:54]": -3276.800048828125,
"SM_Exgauster\\[3:59]": 37.69999694824219,
"SM_Exgauster\\[3:60]": 34.69999694824219,
"SM_Exgauster\\[3:61]": 630.7869873046875,
"SM_Exgauster\\[3:62]": 615.5960693359375,
"SM_Exgauster\\[3.0]": 1.0,
"SM_Exgauster\\[3.1]": 1.0,
"SM_Exgauster\\[4:0]": 76.51472473144531,
"SM_Exgauster\\[4:1]": 2.2827234268188477,
"SM_Exgauster\\[4:3]": 181.38658142089844,
"SM_Exgauster\\[4:7]": 88.55415344238281,
"SM_Exgauster\\[4:8]": 2.217719078063965,
"SM_Exgauster\\[4:10]": 164.85482788085938,
"SM_Exgauster\\[4.1]": 0.0,
"SM_Exgauster\\[4.2]": 1.0,
"SM_Exgauster\\[4.6]": 0.0,
"SM_Exgauster\\[4.7]": 1.0,
"SM_Exgauster\\[5:0]": 83.9000015258789,
"SM_Exgauster\\[5:1]": 0.8799999952316284,
"SM_Exgauster\\[5:2]": 2032.0,
"SM_Exgauster\\[5:3]": 1787.0,
"SM_Exgauster\\[5:4]": 464.0,
"SM_Exgauster\\[5:5]": 107.0,
"SM_Exgauster\\[5:6]": 10.0,
"SM_Exgauster\\[5:7]": 85.4000015258789,
"SM_Exgauster\\[5:8]": 2.0899999141693115,
"SM_Exgauster\\[5:9]": 2055.0,
"SM_Exgauster\\[5:10]": 1870.0,
"SM_Exgauster\\[5:11]": 524.0,
"SM_Exgauster\\[5:12]": 106.0,
"SM_Exgauster\\[5:13]": 10.0,
"SM_Exgauster\\[5.1]": 1.0,
"SM_Exgauster\\[5.2]": 1.0,
"SM_Exgauster\\[5.6]": 1.0,
"SM_Exgauster\\[5.7]": 1.0
}

View File

@ -0,0 +1,132 @@
import react from 'react'
import { MainContent } from '../../components/MainContent'
import { TheHeader } from '../../components/TheHeader'
import { TheTimestampedSwitcher } from '../../components/TheTimestampedSwitcher'
import { Tree, Select } from 'antd';
import './style.css'
import { TheChart } from '../../components/TheChart';
import { getChartData } from '../../client/chart/post';
import { useAppDispatch, useAppSelector } from '../../store';
import { fields } from '../../store/slices/FieldMappingSlice';
import { getFieldsAction } from '../../store/slices/FieldMappingSlice/actions';
interface DataNode {
title: string;
key: string;
isLeaf?: boolean;
children?: DataNode[];
}
export const ChartPage: react.FC = () => {
const [data, setData] = react.useState([]);
const [selectedData, setSelectedData] = react.useState([]);
const retFields = useAppSelector(fields);
const dispatch = useAppDispatch();
if (retFields.length == 0) {
dispatch(getFieldsAction());
}
if (data.length == 0) {
}
var chartData = [];
for (var key in data) {
chartData.push({
name: key,
data: data[key]
})
}
var fieldsMap = new Map<string, {kafka: string, name: string}[]>();
retFields.filter((e) => {
return e.parent == 'У-171'
}).map((e) => {
if (fieldsMap.has(e.entity_name)) {
(fieldsMap.get(e.entity_name as any) as any).push({
kafka: e.kafka,
name: e.name
})
} else {
fieldsMap.set(e.entity_name, [{
kafka: e.kafka,
name: e.name
}])
}
});
var fieldsTree = [];
console.log(fieldsMap.keys())
for (var kkey of (fieldsMap.keys() as any)) {
console.log(kkey)
if (typeof kkey == 'string') {
var leaf: any[] = [];
fieldsMap.get(kkey)!.map((e) => leaf.push({
'title': e.name,
'key': e.kafka,
isLeaf: true
}))
fieldsTree.push({
'title': kkey,
'key': kkey,
'children': leaf
})
}
}
console.log(fieldsTree);
return <div>
<TheHeader></TheHeader>
<TheTimestampedSwitcher type='chart'/>
<MainContent>
<div className='chart__container'>
<Tree
treeData={Array.from(fieldsTree) as any}
checkable
style={{minWidth: '300px'}}
onSelect={(e) => {
console.log(e)
}}
onCheck={(e) => {
console.log(e)
setSelectedData(e as any);
getChartData(new Date(), new Date(), 10, e as any).then((e) => {
setData(e.data);
});
}}
></Tree>
<div className="chart__chart">
<Select
defaultValue={'1-min'}
style={{
width: 90,
transform: 'translateX(-10px)'
}}
options={[
{
value: "1",
label: "1 мин"
},
{
value: "10",
label: "10 мин"
},
{
value: "30",
label: "30 мин"
},
{
value: "60",
label: "60 мин"
}
]} />
<div className="chart-cont" style={{width: '100%', height: 500}}>
{
chartData.length ? <TheChart data={chartData}></TheChart> : <></>
}
</div>
</div>
</div>
</MainContent>
</div>
}

View File

@ -0,0 +1,10 @@
.chart__container{
display: flex;
justify-content: space-between;
}
.chart__chart{
display: flex;
flex-direction: column;
align-items: end;
width: 100%;
}

47
src/pages/Main/index.tsx Normal file
View File

@ -0,0 +1,47 @@
import react, { useState } from 'react'
import { ExgausterCard } from '../../components/ExgausterCard'
import { MainContent } from '../../components/MainContent'
import { TheAlgoMachineCard } from '../../components/TheAlgoMachineCard'
import { TheHeader } from '../../components/TheHeader'
import { TheLegend } from '../../components/TheLegend'
import { useAppDispatch, useAppSelector } from '../../store'
import { exgausters, fields } from '../../store/slices/FieldMappingSlice'
import { getFieldsAction } from '../../store/slices/FieldMappingSlice/actions'
import './style.css'
export const Main: react.FC = () => {
const dispatch = useAppDispatch();
const [fetched, setFetched] = useState(false);
const retrievedFields = useAppSelector(fields);
const retrieveExgausters = useAppSelector(exgausters)
if (retrievedFields.length == 0 && !fetched) {
dispatch(getFieldsAction())
setFetched(true);
}
return <div>
<TheHeader />
<div style={{marginTop: '40px'}}>
<MainContent>
<TheLegend></TheLegend>
{
retrieveExgausters.length ? <div className="machines">
<TheAlgoMachineCard
first_exgauster={retrieveExgausters[0] as string}
second_exgauster={retrieveExgausters[1] as string}
></TheAlgoMachineCard>
<TheAlgoMachineCard
first_exgauster={retrieveExgausters[2] as string}
second_exgauster={retrieveExgausters[3] as string}
></TheAlgoMachineCard>
<TheAlgoMachineCard
first_exgauster={retrieveExgausters[4] as string}
second_exgauster={retrieveExgausters[5] as string}
></TheAlgoMachineCard>
</div> : <></>
}
</MainContent>
</div>
</div>
}

5
src/pages/Main/style.css Normal file
View File

@ -0,0 +1,5 @@
.machines{
display: flex;
justify-content: space-between;
margin-top: 30px;
}

View File

@ -0,0 +1,36 @@
import react from 'react'
import { FullScheme } from '../../components/FullScheme'
import { MainContent } from '../../components/MainContent'
import { TheChartMnemSwitch } from '../../components/TheChartMnemSwitch'
import { TheHeader } from '../../components/TheHeader'
import { TheLegend } from '../../components/TheLegend'
import mock from '../../mock'
export const Mnemoscheme: react.FC = () => {
const [connected, setConnected] = react.useState(false);
const [data, setData] = react.useState({});
if (!connected) {
const socket = new WebSocket('wss://dev2.akarpov.ru/')
socket.addEventListener('open', (e) => {
console.log(e)
})
socket.addEventListener('message', (e) => {
console.log(e.data['SM_Exgauster\\[0:0]'])
setData(JSON.parse(e.data));
});
setConnected(true);
}
return <div>
<TheHeader></TheHeader>
<TheChartMnemSwitch type='mnem' />
<MainContent>
<div>
<TheLegend type='short'></TheLegend>
<div style={{scale: '0.95', transform: 'translateY(-50px)', display: Object.keys(data).length === 0 ? 'none' : 'block'}}>
<FullScheme name='У-171' data={Object.keys(data).length === 0 ? mock : data}></FullScheme>
</div>
</div>
</MainContent>
</div>
}

View File

@ -1 +0,0 @@
/// <reference types="react-scripts" />

View File

@ -1,15 +0,0 @@
import { ReportHandler } from 'web-vitals';
const reportWebVitals = (onPerfEntry?: ReportHandler) => {
if (onPerfEntry && onPerfEntry instanceof Function) {
import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => {
getCLS(onPerfEntry);
getFID(onPerfEntry);
getFCP(onPerfEntry);
getLCP(onPerfEntry);
getTTFB(onPerfEntry);
});
}
};
export default reportWebVitals;

22
src/router.tsx Normal file
View File

@ -0,0 +1,22 @@
import {createBrowserRouter} from 'react-router-dom'
import { ChartPage } from './pages/ChartPage'
import { Main } from './pages/Main'
import { Mnemoscheme } from './pages/Mnemoscheme'
const router = createBrowserRouter([
{
path: '/index',
element: <Main />
},
{
path: '/exgauster/:id/mnemoscheme',
element: <Mnemoscheme />
},
{
path: '/exgauster/:id/graph',
element: <ChartPage />
}
])
export default router;

View File

@ -1,5 +0,0 @@
// jest-dom adds custom jest matchers for asserting on DOM nodes.
// allows you to do things like:
// expect(element).toHaveTextContent(/react/i)
// learn more: https://github.com/testing-library/jest-dom
import '@testing-library/jest-dom';

15
src/store/index.ts Normal file
View File

@ -0,0 +1,15 @@
import { TypedUseSelectorHook, useDispatch, useSelector } from 'react-redux'
import { configureStore } from "@reduxjs/toolkit";
import fields from './slices/FieldMappingSlice'
const store = configureStore({reducer: {fields}})
export default store;
export type RootState = ReturnType<typeof store.getState>
export type AppDispatch = typeof store.dispatch
export const useAppDispatch: () => AppDispatch = useDispatch
export const useAppSelector: TypedUseSelectorHook<RootState> = useSelector

View File

@ -0,0 +1,11 @@
import {createAsyncThunk} from '@reduxjs/toolkit'
import { getFields } from '../../../client/fields';
export const getFieldsAction = createAsyncThunk(
'/fields/get',
async () => {
const data: any = await getFields();
return data.data;
}
)

View File

@ -0,0 +1,77 @@
import {createSlice, createSelector} from '@reduxjs/toolkit'
import { RootState } from '../..';
import { getFieldsAction } from './actions';
import { parseBearingFields, parseGauseCollector, parseMainDrive } from './utils';
export interface IField {
name: string;
kafka: string;
description: string;
parent: string;
entity_name: string;
}
interface ISlice{
fields: IField[];
}
const initialState: ISlice = {
fields: []
}
const fieldMappingSlice = createSlice({
name: 'fields',
initialState,
reducers: {},
extraReducers: (builder) => {
builder.addCase(getFieldsAction.fulfilled, (state, action) => {
var fields: IField[] = [];
console.log(action.payload)
for (var exgauster in action.payload) {
//console.log(action.payload[exgauster]);
for (var signal in action.payload[exgauster]['signals']) {
if (signal.split(' ')[0] == 'Подшипник') {
fields = fields.concat(
parseBearingFields(
action.payload[exgauster]['signals'][signal as any],
action.payload[exgauster].name,
signal
)
);
}
if (signal == 'Газовый коллектор') {
fields.push(parseGauseCollector(
action.payload[exgauster]['signals'][signal as any],
action.payload[exgauster].name,
signal
))
}
if (signal == 'Главный привод') {
console.log(parseMainDrive(
action.payload[exgauster]['signals'][signal as any],
action.payload[exgauster].name,
signal
));
fields = fields.concat(parseMainDrive(
action.payload[exgauster]['signals'][signal as any],
action.payload[exgauster].name,
signal
));
}
}
}
state.fields = fields;
})
}
});
export default fieldMappingSlice.reducer;
export const fields = createSelector((store: RootState) => store.fields.fields, (a) => a)
export const exgausters = createSelector((store: RootState) => {
var fields = store.fields.fields;
var ex_set = new Set();
fields.map((e) => ex_set.add(e.parent))
return Array.from(ex_set);
}, (a) => a)

View File

@ -0,0 +1,98 @@
import { IField } from ".";
export function parseBearingFields(bearing: any, exgauster_name: string, bearing_name: string): IField[] {
var fields: IField[] = [];
try {
fields.push({
name: 'Температура нагрева',
description: bearing['Температура нагрева']['Температура']['temperature']['description'],
parent: exgauster_name,
kafka: bearing['Температура нагрева']['Температура']['temperature']['name'],
entity_name: bearing_name
});
} catch {}
try {
fields.push({
name: 'Осевая вибрация',
description: bearing['Вибрация']['Осевая']['vibration_axial']['description'],
parent: exgauster_name,
kafka: bearing['Вибрация']['Осевая']['vibration_axial']['name'],
entity_name: bearing_name
});
} catch {}
try {
fields.push(
{
name: 'Вертикальная вибрация',
description: bearing['Вибрация']['Вертикальная']['vibration_vertical']['description'],
parent: exgauster_name,
kafka: bearing['Вибрация']['Вертикальная']['vibration_vertical']['name'],
entity_name: bearing_name
}
)
} catch {}
try {
fields.push(
{
name: 'Горизонтальная вибрация',
description: bearing['Вибрация']['Горизонтальная']['vibration_horizontal']['description'],
parent: exgauster_name,
kafka: bearing['Вибрация']['Горизонтальная']['vibration_horizontal']['name'],
entity_name: bearing
}
)
} catch {}
return fields;
}
export function parseGauseCollector(coll_data: any, ex_name: string, signal_name: string): IField {
return {
name: "Температура",
description: coll_data['temperature_before']['description'],
parent: ex_name,
kafka: coll_data['temperature_before']['description'],
entity_name: signal_name
} as IField
}
export function parseMainDrive(coll_data: any, ex_name: string, signal_name: string): IField[] {
var ans: IField[] = [];
try {
ans.push({
name: "Ток ротора",
description: coll_data['rotor_current']['description'],
parent: ex_name,
kafka: coll_data['rotor_current']['name'],
entity_name: signal_name
});
} catch {}
try{
ans.push({
name: "Напряжение ротора",
description: coll_data['rotor_voltage']['description'],
parent: ex_name,
kafka: coll_data['rotor_voltage']['name'],
entity_name: signal_name
})
} catch {}
try {
ans.push({
name: "Ток статора",
description: coll_data['stator_current']['description'],
parent: ex_name,
kafka: coll_data['stator_current']['name'],
entity_name: signal_name
})
} catch {}
try {
ans.push({
name: "Напряжение статора",
description: coll_data['stator_voltage']['description'],
parent: ex_name,
kafka: coll_data['stator_voltage']['name'],
entity_name: signal_name
})
} catch {}
return ans
}