merge with branch master before merge

This commit is contained in:
Alexey 2021-07-27 11:33:06 +05:00
commit 6f589489e0
64 changed files with 2520 additions and 535 deletions

241
package-lock.json generated
View File

@ -22622,15 +22622,6 @@
"@hapi/hoek": "^8.3.0"
}
},
"@hypnosphi/create-react-context": {
"version": "0.3.1",
"resolved": "https://registry.npmjs.org/@hypnosphi/create-react-context/-/create-react-context-0.3.1.tgz",
"integrity": "sha512-V1klUed202XahrWJLLOT3EXNeCpFHCcJntdFGI15ntCwau+jfT386w7OFTMaCqOgXUH1fa0w/I1oZs+i/Rfr0A==",
"requires": {
"gud": "^1.0.0",
"warning": "^4.0.3"
}
},
"@istanbuljs/load-nyc-config": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz",
@ -23188,9 +23179,9 @@
},
"dependencies": {
"ws": {
"version": "6.2.1",
"resolved": "https://registry.npmjs.org/ws/-/ws-6.2.1.tgz",
"integrity": "sha512-GIyAXC2cB7LjvpgMt9EKS2ldqr0MTrORaleiOno6TweZ6r3TKtoFQWay/2PceJ3RuBasOHzXNn5Lrw1X0bEjqA==",
"version": "6.2.2",
"resolved": "https://registry.npmjs.org/ws/-/ws-6.2.2.tgz",
"integrity": "sha512-zmhltoSR8u1cnDsD43TX59mzoMZsLKqUweyYBAIvTngR3shc0W6aOZylZmq/7hqyVxPdi+5Ud2QInblgyE72fw==",
"requires": {
"async-limiter": "~1.0.0"
}
@ -28261,9 +28252,9 @@
}
},
"follow-redirects": {
"version": "1.13.3",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.13.3.tgz",
"integrity": "sha512-DUgl6+HDzB0iEptNQEXLx/KhTmDb8tZUHSeLqpnjpknR70H0nC2t9N73BK6fN4hOvJ84pKlIQVQ4k5FFlBedKA=="
"version": "1.14.1",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.1.tgz",
"integrity": "sha512-HWqDgT7ZEkqRzBvc2s64vSZ/hfOceEol3ac/7tKwzuvEyWx3/4UegXh5oBOIotkGsObyk3xznnSRVADBgWSQVg=="
},
"for-in": {
"version": "1.0.2",
@ -28646,11 +28637,6 @@
"integrity": "sha1-8QdIy+dq+WS3yWyTxrzCivEgwIE=",
"optional": true
},
"gud": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/gud/-/gud-1.0.0.tgz",
"integrity": "sha512-zGEOVKFM5sVPPrYs7J5/hYEw2Pof8KCyOwyhG8sAF26mCAeUFAcYPu1mwB7hhpIP29zOIBaDqwuHdLp0jvZXjw=="
},
"gzip-size": {
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/gzip-size/-/gzip-size-5.1.1.tgz",
@ -29049,114 +29035,6 @@
"requires-port": "^1.0.0"
}
},
"http-proxy-middleware": {
"version": "0.19.1",
"resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-0.19.1.tgz",
"integrity": "sha512-yHYTgWMQO8VvwNS22eLLloAkvungsKdKTLO8AJlftYIKNfJr3GK3zK0ZCfzDDGUBttdGc8xFy1mCitvNKQtC3Q==",
"requires": {
"http-proxy": "^1.17.0",
"is-glob": "^4.0.0",
"lodash": "^4.17.11",
"micromatch": "^3.1.10"
},
"dependencies": {
"braces": {
"version": "2.3.2",
"resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz",
"integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==",
"requires": {
"arr-flatten": "^1.1.0",
"array-unique": "^0.3.2",
"extend-shallow": "^2.0.1",
"fill-range": "^4.0.0",
"isobject": "^3.0.1",
"repeat-element": "^1.1.2",
"snapdragon": "^0.8.1",
"snapdragon-node": "^2.0.1",
"split-string": "^3.0.2",
"to-regex": "^3.0.1"
},
"dependencies": {
"extend-shallow": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
"integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
"requires": {
"is-extendable": "^0.1.0"
}
}
}
},
"fill-range": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz",
"integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=",
"requires": {
"extend-shallow": "^2.0.1",
"is-number": "^3.0.0",
"repeat-string": "^1.6.1",
"to-regex-range": "^2.1.0"
},
"dependencies": {
"extend-shallow": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
"integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
"requires": {
"is-extendable": "^0.1.0"
}
}
}
},
"is-number": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz",
"integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=",
"requires": {
"kind-of": "^3.0.2"
},
"dependencies": {
"kind-of": {
"version": "3.2.2",
"resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
"integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
"requires": {
"is-buffer": "^1.1.5"
}
}
}
},
"micromatch": {
"version": "3.1.10",
"resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz",
"integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==",
"requires": {
"arr-diff": "^4.0.0",
"array-unique": "^0.3.2",
"braces": "^2.3.1",
"define-property": "^2.0.2",
"extend-shallow": "^3.0.2",
"extglob": "^2.0.4",
"fragment-cache": "^0.2.1",
"kind-of": "^6.0.2",
"nanomatch": "^1.2.9",
"object.pick": "^1.3.0",
"regex-not": "^1.0.0",
"snapdragon": "^0.8.1",
"to-regex": "^3.0.2"
}
},
"to-regex-range": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz",
"integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=",
"requires": {
"is-number": "^3.0.0",
"repeat-string": "^1.6.1"
}
}
}
},
"http-signature": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz",
@ -32963,6 +32841,11 @@
"resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz",
"integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g=="
},
"pigeon-maps": {
"version": "0.19.7",
"resolved": "https://registry.npmjs.org/pigeon-maps/-/pigeon-maps-0.19.7.tgz",
"integrity": "sha512-8yS5o7lr3mr5674Cfkxrk3EqPiV6WjGBrpVKNn6/40bTdH5qq2NNXK2Iu0fQcDRRZ6mTtXHX0tJAO1tp8ZKBNg=="
},
"pinkie": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz",
@ -33072,11 +32955,6 @@
"ts-pnp": "^1.1.6"
}
},
"popper.js": {
"version": "1.16.1",
"resolved": "https://registry.npmjs.org/popper.js/-/popper.js-1.16.1.tgz",
"integrity": "sha512-Wb4p1J4zyFTbM+u6WuO4XstYx4Ky9Cewe4DWrel7B0w6VVICvPwdOpotjzcf6eD8TsckVnIMNONQyPIUFOUbCQ=="
},
"portfinder": {
"version": "1.0.28",
"resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.28.tgz",
@ -33103,9 +32981,9 @@
"integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs="
},
"postcss": {
"version": "7.0.35",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz",
"integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==",
"version": "7.0.36",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz",
"integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==",
"requires": {
"chalk": "^2.4.2",
"source-map": "^0.6.1",
@ -34783,18 +34661,6 @@
"whatwg-fetch": "^3.4.1"
}
},
"react-datepicker": {
"version": "3.8.0",
"resolved": "https://registry.npmjs.org/react-datepicker/-/react-datepicker-3.8.0.tgz",
"integrity": "sha512-iFVNEp8DJoX5yEvEiciM7sJKmLGrvE70U38KhpG13XrulNSijeHw1RZkhd/0UmuXR71dcZB/kdfjiidifstZjw==",
"requires": {
"classnames": "^2.2.6",
"date-fns": "^2.0.1",
"prop-types": "^15.7.2",
"react-onclickoutside": "^6.10.0",
"react-popper": "^1.3.8"
}
},
"react-dev-utils": {
"version": "11.0.4",
"resolved": "https://registry.npmjs.org/react-dev-utils/-/react-dev-utils-11.0.4.tgz",
@ -34921,25 +34787,6 @@
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="
},
"react-onclickoutside": {
"version": "6.10.0",
"resolved": "https://registry.npmjs.org/react-onclickoutside/-/react-onclickoutside-6.10.0.tgz",
"integrity": "sha512-7i2L3ef+0ILXpL6P+Hg304eCQswh4jl3ynwR71BSlMU49PE2uk31k8B2GkP6yE9s2D4jTGKnzuSpzWxu4YxfQQ=="
},
"react-popper": {
"version": "1.3.11",
"resolved": "https://registry.npmjs.org/react-popper/-/react-popper-1.3.11.tgz",
"integrity": "sha512-VSA/bS+pSndSF2fiasHK/PTEEAyOpX60+H5EPAjoArr8JGm+oihu4UbrqcEBpQibJxBVCpYyjAX7abJ+7DoYVg==",
"requires": {
"@babel/runtime": "^7.1.2",
"@hypnosphi/create-react-context": "^0.3.1",
"deep-equal": "^1.1.1",
"popper.js": "^1.14.4",
"prop-types": "^15.6.1",
"typed-styles": "^0.0.7",
"warning": "^4.0.2"
}
},
"react-refresh": {
"version": "0.8.3",
"resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.8.3.tgz",
@ -35443,9 +35290,9 @@
"integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo="
},
"resolve-url-loader": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/resolve-url-loader/-/resolve-url-loader-3.1.2.tgz",
"integrity": "sha512-QEb4A76c8Mi7I3xNKXlRKQSlLBwjUV/ULFMP+G7n3/7tJZ8MG5wsZ3ucxP1Jz8Vevn6fnJsxDx9cIls+utGzPQ==",
"version": "3.1.4",
"resolved": "https://registry.npmjs.org/resolve-url-loader/-/resolve-url-loader-3.1.4.tgz",
"integrity": "sha512-D3sQ04o0eeQEySLrcz4DsX3saHfsr8/N6tfhblxgZKXxMT2Louargg12oGNfoTRLV09GXhVUe5/qgA5vdgNigg==",
"requires": {
"adjust-sourcemap-loader": "3.0.0",
"camelcase": "5.3.1",
@ -35453,7 +35300,7 @@
"convert-source-map": "1.7.0",
"es6-iterator": "2.0.3",
"loader-utils": "1.2.3",
"postcss": "7.0.21",
"postcss": "7.0.36",
"rework": "1.0.1",
"rework-visit": "1.0.0",
"source-map": "0.6.1"
@ -35487,28 +35334,10 @@
"json5": "^1.0.1"
}
},
"postcss": {
"version": "7.0.21",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.21.tgz",
"integrity": "sha512-uIFtJElxJo29QC753JzhidoAhvp/e/Exezkdhfmt8AymWT6/5B7W1WmponYWkHk2eg6sONyTch0A3nkMPun3SQ==",
"requires": {
"chalk": "^2.4.2",
"source-map": "^0.6.1",
"supports-color": "^6.1.0"
}
},
"source-map": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="
},
"supports-color": {
"version": "6.1.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz",
"integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==",
"requires": {
"has-flag": "^3.0.0"
}
}
}
},
@ -37211,9 +37040,9 @@
}
},
"trim-newlines": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-3.0.0.tgz",
"integrity": "sha512-C4+gOpvmxaSMKuEf9Qc134F1ZuOHVXKRbtEflf4NTtuuJDEIJ9p5PXsalL8SkeRw+qit1Mo+yuvMPAKwWg/1hA==",
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-3.0.1.tgz",
"integrity": "sha512-c1PTsA3tYrIsLGkJkzHF+w9F2EyxfXGo4UyJc4pFL++FMjnq0HJS69T3M7d//gKrFKwy429bouPescbjecU+Zw==",
"dev": true
},
"tryer": {
@ -37310,11 +37139,6 @@
"mime-types": "~2.1.24"
}
},
"typed-styles": {
"version": "0.0.7",
"resolved": "https://registry.npmjs.org/typed-styles/-/typed-styles-0.0.7.tgz",
"integrity": "sha512-pzP0PWoZUhsECYjABgCGQlRGL1n7tOHsgwYv3oIiEpJwGhFTuty/YNeduxQYzXXa3Ge5BdT6sHYIQYpl4uJ+5Q=="
},
"typedarray": {
"version": "0.0.6",
"resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz",
@ -38429,6 +38253,17 @@
}
}
},
"http-proxy-middleware": {
"version": "0.19.1",
"resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-0.19.1.tgz",
"integrity": "sha512-yHYTgWMQO8VvwNS22eLLloAkvungsKdKTLO8AJlftYIKNfJr3GK3zK0ZCfzDDGUBttdGc8xFy1mCitvNKQtC3Q==",
"requires": {
"http-proxy": "^1.17.0",
"is-glob": "^4.0.0",
"lodash": "^4.17.11",
"micromatch": "^3.1.10"
}
},
"import-local": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/import-local/-/import-local-2.0.0.tgz",
@ -38652,9 +38487,9 @@
}
},
"ws": {
"version": "6.2.1",
"resolved": "https://registry.npmjs.org/ws/-/ws-6.2.1.tgz",
"integrity": "sha512-GIyAXC2cB7LjvpgMt9EKS2ldqr0MTrORaleiOno6TweZ6r3TKtoFQWay/2PceJ3RuBasOHzXNn5Lrw1X0bEjqA==",
"version": "6.2.2",
"resolved": "https://registry.npmjs.org/ws/-/ws-6.2.2.tgz",
"integrity": "sha512-zmhltoSR8u1cnDsD43TX59mzoMZsLKqUweyYBAIvTngR3shc0W6aOZylZmq/7hqyVxPdi+5Ud2QInblgyE72fw==",
"requires": {
"async-limiter": "~1.0.0"
}
@ -39110,9 +38945,9 @@
}
},
"ws": {
"version": "7.4.4",
"resolved": "https://registry.npmjs.org/ws/-/ws-7.4.4.tgz",
"integrity": "sha512-Qm8k8ojNQIMx7S+Zp8u/uHOx7Qazv3Yv4q68MiWWWOJhiwG5W3x7iqmRtJo8xxrciZUY4vRxUTJCKuRnF28ZZw=="
"version": "7.5.3",
"resolved": "https://registry.npmjs.org/ws/-/ws-7.5.3.tgz",
"integrity": "sha512-kQ/dHIzuLrS6Je9+uv81ueZomEwH0qVYstcAQ4/Z93K8zeko9gtAbttJWzoC5ukqXY1PpoouV3+VSOqEAFt5wg=="
},
"xml-name-validator": {
"version": "3.0.0",

View File

@ -14,10 +14,9 @@
"chartjs-plugin-datalabels": "^2.0.0-rc.1",
"chartjs-plugin-zoom": "^1.1.1",
"craco-less": "^1.17.1",
"date-fns": "^2.20.0",
"moment": "^2.29.1",
"pigeon-maps": "^0.19.7",
"react": "^17.0.2",
"react-datepicker": "^3.8.0",
"react-dom": "^17.0.2",
"react-router-dom": "^5.2.0",
"react-scripts": "4.0.3",

View File

@ -6,16 +6,6 @@
"src": "favicon.ico",
"sizes": "64x64 32x32 24x24 16x16",
"type": "image/x-icon"
},
{
"src": "logo192.png",
"type": "image/png",
"sizes": "192x192"
},
{
"src": "logo512.png",
"type": "image/png",
"sizes": "512x512"
}
],
"start_url": ".",

View File

@ -8,7 +8,7 @@ import Main from './pages/Main'
import { OpenAPI } from './services/api'
import { PrivateRoute } from './components/PrivateRoute'
OpenAPI.BASE = 'http://localhost:3000'
//OpenAPI.BASE = 'http://localhost:3000'
OpenAPI.TOKEN = localStorage['token']
export default function App() {

View File

@ -0,0 +1,106 @@
let date = new Date().toLocaleString()
export function CementFluid() {
return (<>
<table>
<thead style={{borderTop:"2px solid", borderLeft: "2px solid", borderRight: "2px solid", borderBottom: "2px solid", width: "800px", fontWeight: "800", textAlign: "center"}}>
<tr>
<td style={{borderTop:"2px solid", borderLeft: "2px solid", borderRight: "2px solid", borderBottom: "2px solid", width: "66px", fontWeight: "800", textAlign: "center"}}>
<b>Наименование</b></td>
<td style={{borderTop:"2px solid", borderLeft: "2px solid", borderRight: "2px solid", borderBottom: "2px solid", width: "66px", fontWeight: "800", textAlign: "center"}}>Температура, °C</td>
<td style={{borderTop:"2px solid", borderLeft: "2px solid", borderRight: "2px solid", borderBottom: "2px solid", width: "66px", fontWeight: "800", textAlign: "center"}}>Плотность, г/см³</td>
<td style={{borderTop:"2px solid", borderLeft: "2px solid", borderRight: "2px solid", borderBottom: "2px solid", width: "66px", fontWeight: "800", textAlign: "center"}}>Усл. вязкость, сек</td>
<td style={{borderTop:"2px solid", borderLeft: "2px solid", borderRight: "2px solid", borderBottom: "2px solid", width: "66px", fontWeight: "800", textAlign: "center"}}>R300</td>
<td style={{borderTop:"2px solid", borderLeft: "2px solid", borderRight: "2px solid", borderBottom: "2px solid", width: "66px", fontWeight: "800", textAlign: "center"}}>R600</td>
<td style={{borderTop:"2px solid", borderLeft: "2px solid", borderRight: "2px solid", borderBottom: "2px solid", width: "66px", fontWeight: "800", textAlign: "center"}}>R3/R6</td>
<td style={{borderTop:"2px solid", borderLeft: "2px solid", borderRight: "2px solid", borderBottom: "2px solid", width: "66px", fontWeight: "800", textAlign: "center"}}>ДНС, дПа</td>
<td style={{borderTop:"2px solid", borderLeft: "2px solid", borderRight: "2px solid", borderBottom: "2px solid", width: "66px", fontWeight: "800", textAlign: "center"}}>Пластич. вязкость, сПз</td>
<td style={{borderTop:"2px solid", borderLeft: "2px solid", borderRight: "2px solid", borderBottom: "2px solid", width: "66px", fontWeight: "800", textAlign: "center"}}>СНС, дПа</td>
<td style={{borderTop:"2px solid", borderLeft: "2px solid", borderRight: "2px solid", borderBottom: "2px solid", width: "66px", fontWeight: "800", textAlign: "center"}}>R3/R6 49С</td>
<td style={{borderTop:"2px solid", borderLeft: "2px solid", borderRight: "2px solid", borderBottom: "2px solid", width: "66px", fontWeight: "800", textAlign: "center"}}>ДНС 49С, дПа</td>
<td style={{borderTop:"2px solid", borderLeft: "2px solid", borderRight: "2px solid", borderBottom: "2px solid", width: "66px", fontWeight: "800", textAlign: "center"}}>Пластич. вязкость 49С, сПз</td>
<td style={{borderTop:"2px solid", borderLeft: "2px solid", borderRight: "2px solid", borderBottom: "2px solid", width: "66px", fontWeight: "800", textAlign: "center"}}>СНС 49С, дПа</td>
<td style={{borderTop:"2px solid", borderLeft: "2px solid", borderRight: "2px solid", borderBottom: "2px solid", width: "66px", fontWeight: "800", textAlign: "center"}}>МВТ, кг/м³</td>
<td style={{borderTop:"2px solid", borderLeft: "2px solid", borderRight: "2px solid", borderBottom: "2px solid", width: "66px", fontWeight: "800", textAlign: "center"}}>Песок, %</td>
<td style={{borderTop:"2px solid", borderLeft: "2px solid", borderRight: "2px solid", borderBottom: "2px solid", width: "66px", fontWeight: "800", textAlign: "center"}}>Фильтрация, см³/30мин</td>
<td style={{borderTop:"2px solid", borderLeft: "2px solid", borderRight: "2px solid", borderBottom: "2px solid", width: "66px", fontWeight: "800", textAlign: "center"}}>Корка, мм</td>
<td style={{borderTop:"2px solid", borderLeft: "2px solid", borderRight: "2px solid", borderBottom: "2px solid", width: "66px", fontWeight: "800", textAlign: "center"}}>КТК</td>
<td style={{borderTop:"2px solid", borderLeft: "2px solid", borderRight: "2px solid", borderBottom: "2px solid", width: "66px", fontWeight: "800", textAlign: "center"}}>рН</td>
<td style={{borderTop:"2px solid", borderLeft: "2px solid", borderRight: "2px solid", borderBottom: "2px solid", width: "66px", fontWeight: "800", textAlign: "center"}}>Жесткость, мг/л</td>
<td style={{borderTop:"2px solid", borderLeft: "2px solid", borderRight: "2px solid", borderBottom: "2px solid", width: "66px", fontWeight: "800", textAlign: "center"}}>Хлориды, мг/л</td>
<td style={{borderTop:"2px solid", borderLeft: "2px solid", borderRight: "2px solid", borderBottom: "2px solid", width: "66px", fontWeight: "800", textAlign: "center"}}>Pf</td>
<td style={{borderTop:"2px solid", borderLeft: "2px solid", borderRight: "2px solid", borderBottom: "2px solid", width: "66px", fontWeight: "800", textAlign: "center"}}>Mf</td>
<td style={{borderTop:"2px solid", borderLeft: "2px solid", borderRight: "2px solid", borderBottom: "2px solid", width: "66px", fontWeight: "800", textAlign: "center"}}>Pm</td>
<td style={{borderTop:"2px solid", borderLeft: "2px solid", borderRight: "2px solid", borderBottom: "2px solid", width: "66px", fontWeight: "800", textAlign: "center"}}>Твердая фаза раствора, %</td>
<td style={{borderTop:"2px solid", borderLeft: "2px solid", borderRight: "2px solid", borderBottom: "2px solid", width: "66px", fontWeight: "800", textAlign: "center"}}>Смазка, %</td>
<td style={{borderTop:"2px solid", borderLeft: "2px solid", borderRight: "2px solid", borderBottom: "2px solid", width: "66px", fontWeight: "800", textAlign: "center"}}>Карбонат кальция, кг/м³</td>
</tr>
</thead>
<tbody style={{borderTop:"2px solid", borderLeft: "2px solid", borderRight: "2px solid", borderBottom: "2px solid", width: "66px", fontWeight: "400", textAlign: "center"}}>
<tr>
<td style={{borderTop:"2px solid", borderLeft: "2px solid", borderRight: "2px solid", borderBottom: "2px solid", width: "66px", fontWeight: "800", textAlign: "center"}}><b>План</b></td>
<td style={{borderTop:"1px solid", borderLeft: "1px solid", borderRight: "1px solid", borderBottom: "1px solid", width: "66px", fontWeight: "400", textAlign: "center"}}>&nbsp;</td>
<td style={{borderTop:"1px solid", borderLeft: "1px solid", borderRight: "1px solid", borderBottom: "1px solid", width: "66px", fontWeight: "400", textAlign: "center"}}>&nbsp;</td>
<td style={{borderTop:"1px solid", borderLeft: "1px solid", borderRight: "1px solid", borderBottom: "1px solid", width: "66px", fontWeight: "400", textAlign: "center"}}>&nbsp;</td>
<td style={{borderTop:"1px solid", borderLeft: "1px solid", borderRight: "1px solid", borderBottom: "1px solid", width: "66px", fontWeight: "400", textAlign: "center"}}>&nbsp;</td>
<td style={{borderTop:"1px solid", borderLeft: "1px solid", borderRight: "1px solid", borderBottom: "1px solid", width: "66px", fontWeight: "400", textAlign: "center"}}>&nbsp;</td>
<td style={{borderTop:"1px solid", borderLeft: "1px solid", borderRight: "1px solid", borderBottom: "1px solid", width: "66px", fontWeight: "400", textAlign: "center"}}>&nbsp;</td>
<td style={{borderTop:"1px solid", borderLeft: "1px solid", borderRight: "1px solid", borderBottom: "1px solid", width: "66px", fontWeight: "400", textAlign: "center"}}>&nbsp;</td>
<td style={{borderTop:"1px solid", borderLeft: "1px solid", borderRight: "1px solid", borderBottom: "1px solid", width: "66px", fontWeight: "400", textAlign: "center"}}>&nbsp;</td>
<td style={{borderTop:"1px solid", borderLeft: "1px solid", borderRight: "1px solid", borderBottom: "1px solid", width: "66px", fontWeight: "400", textAlign: "center"}}>&nbsp;</td>
<td style={{borderTop:"1px solid", borderLeft: "1px solid", borderRight: "1px solid", borderBottom: "1px solid", width: "66px", fontWeight: "400", textAlign: "center"}}>&nbsp;</td>
<td style={{borderTop:"1px solid", borderLeft: "1px solid", borderRight: "1px solid", borderBottom: "1px solid", width: "66px", fontWeight: "400", textAlign: "center"}}>&nbsp;</td>
<td style={{borderTop:"1px solid", borderLeft: "1px solid", borderRight: "1px solid", borderBottom: "1px solid", width: "66px", fontWeight: "400", textAlign: "center"}}>&nbsp;</td>
<td style={{borderTop:"1px solid", borderLeft: "1px solid", borderRight: "1px solid", borderBottom: "1px solid", width: "66px", fontWeight: "400", textAlign: "center"}}>&nbsp;</td>
<td style={{borderTop:"1px solid", borderLeft: "1px solid", borderRight: "1px solid", borderBottom: "1px solid", width: "66px", fontWeight: "400", textAlign: "center"}}>&nbsp;</td>
<td style={{borderTop:"1px solid", borderLeft: "1px solid", borderRight: "1px solid", borderBottom: "1px solid", width: "66px", fontWeight: "400", textAlign: "center"}}>&nbsp;</td>
<td style={{borderTop:"1px solid", borderLeft: "1px solid", borderRight: "1px solid", borderBottom: "1px solid", width: "66px", fontWeight: "400", textAlign: "center"}}>&nbsp;</td>
<td style={{borderTop:"1px solid", borderLeft: "1px solid", borderRight: "1px solid", borderBottom: "1px solid", width: "66px", fontWeight: "400", textAlign: "center"}}>&nbsp;</td>
<td style={{borderTop:"1px solid", borderLeft: "1px solid", borderRight: "1px solid", borderBottom: "1px solid", width: "66px", fontWeight: "400", textAlign: "center"}}>&nbsp;</td>
<td style={{borderTop:"1px solid", borderLeft: "1px solid", borderRight: "1px solid", borderBottom: "1px solid", width: "66px", fontWeight: "400", textAlign: "center"}}>&nbsp;</td>
<td style={{borderTop:"1px solid", borderLeft: "1px solid", borderRight: "1px solid", borderBottom: "1px solid", width: "66px", fontWeight: "400", textAlign: "center"}}>&nbsp;</td>
<td style={{borderTop:"1px solid", borderLeft: "1px solid", borderRight: "1px solid", borderBottom: "1px solid", width: "66px", fontWeight: "400", textAlign: "center"}}>&nbsp;</td>
<td style={{borderTop:"1px solid", borderLeft: "1px solid", borderRight: "1px solid", borderBottom: "1px solid", width: "66px", fontWeight: "400", textAlign: "center"}}>&nbsp;</td>
<td style={{borderTop:"1px solid", borderLeft: "1px solid", borderRight: "1px solid", borderBottom: "1px solid", width: "66px", fontWeight: "400", textAlign: "center"}}>&nbsp;</td>
<td style={{borderTop:"1px solid", borderLeft: "1px solid", borderRight: "1px solid", borderBottom: "1px solid", width: "66px", fontWeight: "400", textAlign: "center"}}>&nbsp;</td>
<td style={{borderTop:"1px solid", borderLeft: "1px solid", borderRight: "1px solid", borderBottom: "1px solid", width: "66px", fontWeight: "400", textAlign: "center"}}>&nbsp;</td>
<td style={{borderTop:"1px solid", borderLeft: "1px solid", borderRight: "1px solid", borderBottom: "1px solid", width: "66px", fontWeight: "400", textAlign: "center"}}>&nbsp;</td>
<td style={{borderTop:"1px solid", borderLeft: "1px solid", borderRight: "1px solid", borderBottom: "1px solid", width: "66px", fontWeight: "400", textAlign: "center"}}>&nbsp;</td>
</tr>
<tr>
<td style={{borderTop:"2px solid", borderLeft: "2px solid", borderRight: "2px solid", borderBottom: "2px solid", width: "66px", fontWeight: "800"}}><b>Факт</b></td>
<td style={{borderTop:"1px solid", borderLeft: "1px solid", borderRight: "1px solid", borderBottom: "1px solid", width: "66px", fontWeight: "400", textAlign: "center"}}>&nbsp;</td>
<td style={{borderTop:"1px solid", borderLeft: "1px solid", borderRight: "1px solid", borderBottom: "1px solid", width: "66px", fontWeight: "400", textAlign: "center"}}>&nbsp;</td>
<td style={{borderTop:"1px solid", borderLeft: "1px solid", borderRight: "1px solid", borderBottom: "1px solid", width: "66px", fontWeight: "400", textAlign: "center"}}>&nbsp;</td>
<td style={{borderTop:"1px solid", borderLeft: "1px solid", borderRight: "1px solid", borderBottom: "1px solid", width: "66px", fontWeight: "400", textAlign: "center"}}>&nbsp;</td>
<td style={{borderTop:"1px solid", borderLeft: "1px solid", borderRight: "1px solid", borderBottom: "1px solid", width: "66px", fontWeight: "400", textAlign: "center"}}>&nbsp;</td>
<td style={{borderTop:"1px solid", borderLeft: "1px solid", borderRight: "1px solid", borderBottom: "1px solid", width: "66px", fontWeight: "400", textAlign: "center"}}>&nbsp;</td>
<td style={{borderTop:"1px solid", borderLeft: "1px solid", borderRight: "1px solid", borderBottom: "1px solid", width: "66px", fontWeight: "400", textAlign: "center"}}>&nbsp;</td>
<td style={{borderTop:"1px solid", borderLeft: "1px solid", borderRight: "1px solid", borderBottom: "1px solid", width: "66px", fontWeight: "400", textAlign: "center"}}>&nbsp;</td>
<td style={{borderTop:"1px solid", borderLeft: "1px solid", borderRight: "1px solid", borderBottom: "1px solid", width: "66px", fontWeight: "400", textAlign: "center"}}>&nbsp;</td>
<td style={{borderTop:"1px solid", borderLeft: "1px solid", borderRight: "1px solid", borderBottom: "1px solid", width: "66px", fontWeight: "400", textAlign: "center"}}>&nbsp;</td>
<td style={{borderTop:"1px solid", borderLeft: "1px solid", borderRight: "1px solid", borderBottom: "1px solid", width: "66px", fontWeight: "400", textAlign: "center"}}>&nbsp;</td>
<td style={{borderTop:"1px solid", borderLeft: "1px solid", borderRight: "1px solid", borderBottom: "1px solid", width: "66px", fontWeight: "400", textAlign: "center"}}>&nbsp;</td>
<td style={{borderTop:"1px solid", borderLeft: "1px solid", borderRight: "1px solid", borderBottom: "1px solid", width: "66px", fontWeight: "400", textAlign: "center"}}>&nbsp;</td>
<td style={{borderTop:"1px solid", borderLeft: "1px solid", borderRight: "1px solid", borderBottom: "1px solid", width: "66px", fontWeight: "400", textAlign: "center"}}>&nbsp;</td>
<td style={{borderTop:"1px solid", borderLeft: "1px solid", borderRight: "1px solid", borderBottom: "1px solid", width: "66px", fontWeight: "400", textAlign: "center"}}>&nbsp;</td>
<td style={{borderTop:"1px solid", borderLeft: "1px solid", borderRight: "1px solid", borderBottom: "1px solid", width: "66px", fontWeight: "400", textAlign: "center"}}>&nbsp;</td>
<td style={{borderTop:"1px solid", borderLeft: "1px solid", borderRight: "1px solid", borderBottom: "1px solid", width: "66px", fontWeight: "400", textAlign: "center"}}>&nbsp;</td>
<td style={{borderTop:"1px solid", borderLeft: "1px solid", borderRight: "1px solid", borderBottom: "1px solid", width: "66px", fontWeight: "400", textAlign: "center"}}>&nbsp;</td>
<td style={{borderTop:"1px solid", borderLeft: "1px solid", borderRight: "1px solid", borderBottom: "1px solid", width: "66px", fontWeight: "400", textAlign: "center"}}>&nbsp;</td>
<td style={{borderTop:"1px solid", borderLeft: "1px solid", borderRight: "1px solid", borderBottom: "1px solid", width: "66px", fontWeight: "400", textAlign: "center"}}>&nbsp;</td>
<td style={{borderTop:"1px solid", borderLeft: "1px solid", borderRight: "1px solid", borderBottom: "1px solid", width: "66px", fontWeight: "400", textAlign: "center"}}>&nbsp;</td>
<td style={{borderTop:"1px solid", borderLeft: "1px solid", borderRight: "1px solid", borderBottom: "1px solid", width: "66px", fontWeight: "400", textAlign: "center"}}>&nbsp;</td>
<td style={{borderTop:"1px solid", borderLeft: "1px solid", borderRight: "1px solid", borderBottom: "1px solid", width: "66px", fontWeight: "400", textAlign: "center"}}>&nbsp;</td>
<td style={{borderTop:"1px solid", borderLeft: "1px solid", borderRight: "1px solid", borderBottom: "1px solid", width: "66px", fontWeight: "400", textAlign: "center"}}>&nbsp;</td>
<td style={{borderTop:"1px solid", borderLeft: "1px solid", borderRight: "1px solid", borderBottom: "1px solid", width: "66px", fontWeight: "400", textAlign: "center"}}>&nbsp;</td>
<td style={{borderTop:"1px solid", borderLeft: "1px solid", borderRight: "1px solid", borderBottom: "1px solid", width: "66px", fontWeight: "400", textAlign: "center"}}>&nbsp;</td>
<td style={{borderTop:"1px solid", borderLeft: "1px solid", borderRight: "1px solid", borderBottom: "1px solid", width: "66px", fontWeight: "400", textAlign: "center"}}>&nbsp;</td>
</tr>
</tbody>
</table>
<div>&nbsp;</div>
<p style={{textAlign: "right"}}><b>{date}</b></p>
</>
)
}

View File

@ -1,26 +1,34 @@
import {Display} from './Display'
import RigMnemo from '../components/RigMnemo'
const params = [
{label:'Рот., об/мин', accessorName:'rotorSpeed', isArrowVisible:true},
{label:'Долото, м', accessorName:'bitDepth', isArrowVisible:true, format:2},
{label:'Забой, м', accessorName:'wellDepth', isArrowVisible:true, format:2},
{label:'Расход, м³/ч', accessorName:'flow', isArrowVisible:true},
{label:'Расход х.х., м³/ч', accessorName:'flowIdle', isArrowVisible:true},
{label: 'Время', accessorName: 'date', format:'HH:mm:ss'},
]
export const CustomColumn = ({data}) => {
const dataLast = data[data.length -1]
const lines = [
{label:'Рот., об/мин', accessorName:'rotorSpeed'},
{label:'Долото, м', accessorName:'bitDepth'},
{label:'Забой, м', accessorName:'wellDepth'},
{label:'Расход, м³/ч', accessorName:'flow'},
{label:'Расход х.х., м³/ч', accessorName:'flowIdle'},
]
if(dataLast)
lines.forEach(line => line.value = dataLast[line.accessorName]?.toPrecision(4)??'-' )
params.forEach(param => param.value = dataLast[param.accessorName])
else
lines.forEach(line => line.value = '-' )
params.forEach(param => param.value = '-' )
return (<>
{lines.map(line => <Display className='border_small display_flex_container'
key={line.label}
label={line.label}
value={line.value}
suffix={line.units}/>)}
{params.map(param => <Display className='border_small display_flex_container'
key={param.label}
label={param.label}
value={param.value}
suffix={param.units}
isArrowVisible = {param.isArrowVisible}
format = {param.format}
/>)}
<RigMnemo
blockPosition={dataLast?.blockPosition??0}
bitPosition={dataLast?.bitDepth??3200}/>
</>)
}

View File

@ -1,43 +1,70 @@
import { useState, useEffect } from 'react';
import {CaretUpOutlined, CaretDownOutlined} from '@ant-design/icons'
import {CaretUpOutlined, CaretDownOutlined, CaretRightOutlined} from '@ant-design/icons'
import moment from 'moment';
export const ValueDisplay = ({prefix, value, suffix, isArrowVisible}) =>{
const [oldVal, setOldVal] = useState(NaN)
export const formatNumber = (value, format) =>
Number.isInteger(format) && Number.isFinite(value)
? (+value).toFixed(format)
: (+value).toPrecision(4)
export const ValueDisplay = ({prefix, value, suffix, isArrowVisible, format}) =>{
const [val, setVal] = useState('---')
const [arrowState, setArrowState] = useState(0)
const [arrowState, setArrowState] = useState({
preVal: NaN,
preTimestamp: Date.now(),
direction: 0,
})
useEffect(()=>{
if(value){
if(Number.isFinite(+value)){
if (isArrowVisible)
{
let newArrowState = 0
if (value > oldVal)
newArrowState = 1
if (value < oldVal)
newArrowState = -1
setArrowState(newArrowState)
setOldVal(value)
}
setVal((+value).toPrecision(4)??'---')
}
else
setVal(value)
if(value === undefined || value === null){
setVal('---')
return
}
},[value, isArrowVisible, oldVal])
if(Number.isFinite(+value)){
if ((isArrowVisible) && (arrowState.preTimestamp + 1000 < Date.now()))
{
let direction = 0
if (value > arrowState.preVal)
direction = 1
if (value < arrowState.preVal)
direction = -1
setArrowState({
preVal: value,
preTimestamp: Date.now(),
direction: direction,
})
}
setVal(formatNumber(value, format))
return
}
let valueDate = moment(value)
if(valueDate.isValid()){
setVal(valueDate.format(format))
return
}
setVal(value)
},[value, isArrowVisible, arrowState, format])
let arrow = null
switch (arrowState){
case 1:
arrow = <CaretUpOutlined style={{color:"red"}}/>
break
case -1:
arrow = <CaretDownOutlined style={{color:"red"}}/>
break
default:
break
}
if(isArrowVisible)
switch (arrowState.direction){
case 0:
arrow = <CaretRightOutlined style={{color:"#0008"}}/>
break
case 1:
arrow = <CaretUpOutlined style={{color:"#0008"}}/>
break
case -1:
arrow = <CaretDownOutlined style={{color:"#0008"}}/>
break
default:
break
}
return(<span className='display_value'>{prefix} {val} {suffix}{arrow}</span>)
}

View File

@ -0,0 +1,19 @@
let date = new Date().toLocaleString()
export default function Disposition() {
return (
<>
<h1 style={{textAlign: "center"}}>Распоряжение</h1>
<p style={{textAlign: "justify"}}>
Текст
</p>
<p style={{textAlign: "right"}}><i>Ф.И.О.</i></p>
<p style={{textAlign: "right"}}><i>Должность</i></p>
<p style={{textAlign: "right"}}><i>Компания</i></p>
<p style={{textAlign: "right"}}><b>{date}</b></p>
</>
)
}

View File

@ -0,0 +1,230 @@
import {Table, DatePicker, Form, Button, Upload, ConfigProvider} from 'antd'
import { UploadOutlined } from '@ant-design/icons'
import MenuDocuments from "./MenuDocuments"
import { FileService } from '../services/api'
import {useState, useEffect} from "react"
import {useParams} from 'react-router-dom'
import notify from './notify'
import LoaderPortal from './LoaderPortal'
import locale from "antd/lib/locale/ru_RU"
import moment from 'moment'
const pageSize = 12
const {RangePicker} = DatePicker;
export default function Documents({selectedFileCategory}) {
let {id} = useParams()
const [page, setPage] = useState(1)
const [range, setRange] = useState([])
const [pagination, setPagination] = useState(null)
const [files, setFiles] = useState([])
const [selectedFiles, setSelectedFiles] = useState([])
const [isTableUpdating, setTableUpdating] = useState(false)
const [loader, setLoader] = useState(false)
const [form] = Form.useForm();
const handleFileNameCLick = async (event, row) => {
const element = event.target
if(!element.href.length) {
try {
setLoader(true)
await fetch(`/api/files/${id}/${row.id}`, {
headers: {
Authorization: 'Bearer ' + localStorage['token']
}
})
.then(async (response) => {
const blob = await response.blob();
let reader = new FileReader();
reader.readAsDataURL(blob);
reader.onload = function (e) {
element.href = e.target.result
element.click()
};
setLoader(false)
});
} catch (error) {
notify(`Не удалось скачать файл ${row}`, 'error')
console.log(error)
}
}
}
const columns = [
{
title: 'Документ',
key: 'document',
dataIndex: 'name',
render: (name, row) =>
<a onClick={ev => handleFileNameCLick(ev, row)} download={name}>{name}</a>
},
{
title: 'Дата загрузки',
key: 'uploadDate',
dataIndex: 'uploadDate',
render: (item) => moment.utc(item).local().format('DD MMM YYYY, HH:mm:ss')
},
{
title: 'Ф.И.О.',
key: 'userName',
dataIndex: 'userName',
}
];
const submitFileFormProps = {
progress: {
strokeColor: {
'0%': '#108ee9',
'100%': '#87d068',
},
strokeWidth: 3,
format: percent => `${parseFloat(percent.toFixed(2))}%`,
},
onChange({ file, fileList }) {
if (file.status !== 'uploading') {
setSelectedFiles(fileList)
}
}
}
const onChangeRange = (range) => {
setRange(range)
}
const onFinish = (values, form) => {
var fileList = values.fileInput.fileList
if (fileList.length > 0)
{
setLoader(true)
const formData = new FormData();
fileList.forEach(val => {
formData.append('files', val.originFileObj)
})
fetch(`/api/files/${id}/files?idCategory=${selectedFileCategory}&idUser=${localStorage['userId']}`, {
headers: {
Authorization: 'Bearer ' + localStorage['token']
},
method: 'POST',
body: formData
})
.then(async (response) => {
setLoader(false)
form.resetFields()
setTableUpdating(true)
});
}
}
const onFinishFailed = (errorInfo) => {
notify(`Не удалось отправить файлы по скважине "${id}".`, 'error')
}
useEffect(() => {
const GetDocuments = async () => {
setLoader(true)
try {
let begin = null
let end = null
if (range?.length > 1) {
begin = range[0].toISOString()
end = range[1].toISOString()
}
await FileService.getFilesInfo(
`${id}`,
(page - 1) * pageSize,
pageSize,
selectedFileCategory,
begin,
end
).then((paginatedFiles) => {
setFiles(paginatedFiles?.items.map(f => {
return {
key: f.id,
begin: f.date,
...f
}
}))
setPagination({
total: paginatedFiles?.count,
current: Math.floor(paginatedFiles?.skip / pageSize),
})
setTableUpdating(false)
setLoader(false)
}
)
} catch (ex) {
notify(`Не удалось загрузить файлы по скважине "${id}"`, 'error')
console.log(ex)
}
}
GetDocuments()
}, [id, range,page, selectedFileCategory, isTableUpdating])
return (
<div>
<MenuDocuments/>
<div className='filter-group'>
<h3 className='filter-group-heading'>Фильтр документов:</h3>
<ConfigProvider locale={locale}>
<RangePicker
showTime
onChange={onChangeRange}
/>
</ConfigProvider>
</div>
<LoaderPortal show={loader}></LoaderPortal>
<div>&nbsp;</div>
<Form
form={form}
name="DocumentsUploadForm"
onFinish={(values) => onFinish(values, form)}
onFinishFailed={onFinishFailed}
style={{width: '300px'}}
>
<Form.Item
name="fileInput"
rules={[{ required: true, message: 'Выберите файл' }]}
>
<Upload {...submitFileFormProps}>
<Button icon={<UploadOutlined />}>Загрузить файл</Button>
</Upload>
</Form.Item>
<Form.Item>
<Button
type="primary"
htmlType="submit"
disabled={selectedFiles.length === 0}
>
Отправить
</Button>
</Form.Item>
</Form>
<div>&nbsp;</div>
<Table
columns={columns}
dataSource={files}
size={'small'}
pagination={{
pageSize: pageSize,
showSizeChanger: false,
total: pagination?.total,
current: page,
onChange: (page) => setPage(page)
}}
rowKey={(record) => record.id}
/>
</div>);
}

View File

@ -0,0 +1,20 @@
import {Layout} from 'antd'
import PageHeader from './PageHeader'
const {Content} = Layout
export default function LayoutPortal({title, noSheet, children}) {
const content = noSheet
? <Layout>{children}</Layout>
: <Layout>
<Content className="site-layout-background sheet">
{children}
</Content>
</Layout>
return (
<Content>
<PageHeader title={title}/>
{content}
</Content>)
}

View File

@ -0,0 +1,50 @@
import {Menu} from "antd";
import {FolderOutlined} from "@ant-design/icons";
import {Link} from "react-router-dom";
import {useState} from "react"
export default function MenuDocuments() {
const [selectedItem, setSelectedItem] = useState(1)
const handleClick = e => {
setSelectedItem({ current: e.key });
};
return(
<>
<Menu
mode="horizontal"
selectable={true}
className="well_menu"
onClick={handleClick}
selectedKeys={[selectedItem]}
>
<Menu.Item key="1" icon={<FolderOutlined/>}>
<Link to='fluidService'>Растворный сервис</Link>
</Menu.Item>
<Menu.Item key="2" icon={<FolderOutlined/>}>
<Link to='cementing'>Цементирование</Link>
</Menu.Item>
<Menu.Item key="3" icon={<FolderOutlined/>}>
<Link to='nnb'>ННБ</Link>
</Menu.Item>
<Menu.Item key="4" icon={<FolderOutlined/>}>
<Link to='gti'>ГТИ</Link>
</Menu.Item>
<Menu.Item key="5" icon={<FolderOutlined/>}>
<Link to='documentsForWell'>Документы по скважине</Link>
</Menu.Item>
<Menu.Item key="6" icon={<FolderOutlined/>}>
<Link to='supervisor'>Супервайзер</Link>
</Menu.Item>
<Menu.Item key="7" icon={<FolderOutlined/>}>
<Link to='master'>Мастер</Link>
</Menu.Item>
<Menu.Item key="8" icon={<FolderOutlined/>}>
<Link to='lastData'>Последние данные</Link>
</Menu.Item>
</Menu>
</>)
}

250
src/components/NnbTable.jsx Normal file
View File

@ -0,0 +1,250 @@
let date = new Date().toLocaleString()
export function NnbTable() {
return (<>
<table cellspacing="0" border="0">
<colGroup span="18" width="79"></colGroup>
<tr>
<td style={{
borderTop: "2px solid #000000",
borderBottom: "2px solid #000000",
borderLeft: "2px solid #000000",
borderRight: "1px solid #000000"
}} height="91" align="center" valign="middle" bgcolor="#E2F0D9" sdnum="1049;0;0,00"><font face="Tahoma"
size="2">Глубина по
стволу, м</font></td>
<td style={{
borderTop: "2px solid #000000",
borderBottom: "2px solid #000000",
borderLeft: "1px solid #000000",
borderRight: "1px solid #000000"
}} align="center" valign="middle" bgcolor="#E2F0D9" sdnum="1049;0;0,00"><font face="Tahoma" size="2">Зенитный
угол, град</font></td>
<td style={{
borderTop: "2px solid #000000",
borderBottom: "2px solid #000000",
borderLeft: "1px solid #000000",
borderRight: "1px solid #000000"
}} align="center" valign="middle" bgcolor="#E2F0D9" sdnum="1049;0;0,00"><font face="Tahoma" size="2">Азимут
магнитный, град</font></td>
<td style={{
borderTop: "2px solid #000000",
borderBottom: "2px solid #000000",
borderLeft: "1px solid #000000",
borderRight: "1px solid #000000"
}} align="center" valign="middle" bgcolor="#E2F0D9" sdnum="1049;0;0,00"><font face="Tahoma" size="2">Азимут
истинный, град</font></td>
<td style={{
borderTop: "2px solid #000000",
borderBottom: "2px solid #000000",
borderLeft: "1px solid #000000",
borderRight: "1px solid #000000"
}} align="center" valign="middle" bgcolor="#E2F0D9" sdnum="1049;0;0,00"><font face="Tahoma" size="2">Азимут
дирекц., град</font></td>
<td style={{
borderTop: "2px solid #000000",
borderBottom: "2px solid #000000",
borderLeft: "1px solid #000000",
borderRight: "1px solid #000000"
}} align="center" valign="middle" bgcolor="#E2F0D9" sdnum="1049;0;0,00"><font face="Tahoma" size="2">Глубина по
вертикали, м</font></td>
<td style={{
borderTop: "2px solid #000000",
borderBottom: "2px solid #000000",
borderLeft: "1px solid #000000",
borderRight: "1px solid #000000"
}} align="center" valign="middle" bgcolor="#E2F0D9" sdnum="1049;0;0,00"><font face="Tahoma" size="2">Абсолютная
отметка, м</font></td>
<td style={{
borderTop: "2px solid #000000",
borderBottom: "2px solid #000000",
borderLeft: "1px solid #000000",
borderRight: "1px solid #000000"
}} align="center" valign="middle" bgcolor="#E2F0D9" sdnum="1049;0;0,00"><font face="Tahoma" size="2">Лок.
смещение к северу, м</font></td>
<td style={{
borderTop: "2px solid #000000",
borderBottom: "2px solid #000000",
borderLeft: "1px solid #000000",
borderRight: "1px solid #000000"
}} align="center" valign="middle" bgcolor="#E2F0D9" sdnum="1049;0;0,00"><font face="Tahoma" size="2">Лок.
смещение к востоку, м</font></td>
<td style={{
borderTop: "2px solid #000000",
borderBottom: "2px solid #000000",
borderLeft: "1px solid #000000",
borderRight: "1px solid #000000"
}} align="center" valign="middle" bgcolor="#E2F0D9" sdnum="1049;0;0,00"><font face="Tahoma" size="2">Отклонение
от устья, м</font></td>
<td style={{
borderTop: "2px solid #000000",
borderBottom: "2px solid #000000",
borderLeft: "1px solid #000000",
borderRight: "1px solid #000000"
}} align="center" valign="middle" bgcolor="#E2F0D9" sdnum="1049;0;0,00"><font face="Tahoma" size="2">Азимут
смещения, град</font></td>
<td style={{
borderTop: "2px solid #000000",
borderBottom: "2px solid #000000",
borderLeft: "1px solid #000000",
borderRight: "1px solid #000000"
}} align="center" valign="middle" bgcolor="#E2F0D9" sdnum="1049;0;0,00"><font face="Tahoma" size="2">Отклонение
от устья, м</font></td>
<td style={{
borderTop: "2px solid #000000",
borderBottom: "2px solid #000000",
borderLeft: "1px solid #000000",
borderRight: "1px solid #000000"
}} align="center" valign="middle" bgcolor="#E2F0D9" sdnum="1049;0;0,000"><font face="Tahoma" size="2">Пространст.
интенсивность, град/10 м</font></td>
<td style={{
borderTop: "2px solid #000000",
borderBottom: "2px solid #000000",
borderLeft: "1px solid #000000",
borderRight: "1px solid #000000"
}} align="center" valign="middle" bgcolor="#E2F0D9" sdnum="1049;0;0,00"><font face="Tahoma" size="2">Угол
установки отклон., град</font></td>
<td style={{
borderTop: "2px solid #000000",
borderBottom: "2px solid #000000",
borderLeft: "1px solid #000000",
borderRight: "1px solid #000000"
}} align="center" valign="middle" bgcolor="#E2F0D9" sdnum="1049;0;0,00"><font face="Tahoma" size="2">Интенсив.
по зениту, град/10 м</font></td>
<td style={{
borderTop: "2px solid #000000",
borderBottom: "2px solid #000000",
borderLeft: "1px solid #000000",
borderRight: "1px solid #000000"
}} align="center" valign="middle" bgcolor="#E2F0D9" sdnum="1049;0;@"><font face="Tahoma"
size="2">Комментарий</font></td>
<td style={{
borderTop: "2px solid #000000",
borderBottom: "2px solid #000000",
borderLeft: "1px solid #000000",
borderRight: "1px solid #000000"
}} align="center" valign="middle" bgcolor="#E2F0D9"><font face="Tahoma" size="2">Разница вертикальных глубин
между ХХХ (план) и ХХХ (факт)</font></td>
<td style={{
borderTop: "2px solid #000000",
borderBottom: "2px solid #000000",
borderLeft: "1px solid #000000",
borderRight: "2px solid #000000"
}} align="center" valign="middle" bgcolor="#E2F0D9"><font face="Tahoma" size="2">Расстояние в пространстве между
ХХХ (план) и ХХХ (факт)</font></td>
</tr>
<tr>
<td style={{
borderTop: "1px solid #000000",
borderBottom: "1px solid #000000",
borderLeft: "1px solid #000000",
borderRight: "1px solid #000000"
}} height="25" align="center" valign="middle" sdnum="1049;0;0,00"><font face="Tahoma" size="2"><br/></font></td>
<td style={{
borderTop: "1px solid #000000",
borderBottom: "1px solid #000000",
borderLeft: "1px solid #000000",
borderRight: "1px solid #000000"
}} align="center" valign="middle" sdnum="1049;0;0,00"><font face="Tahoma" size="2"><br/></font></td>
<td style={{
borderTop: "1px solid #000000",
borderBottom: "1px solid #000000",
borderLeft: "1px solid #000000",
borderRight: "1px solid #000000"
}} align="center" valign="middle" sdnum="1049;0;0,00"><font face="Tahoma" size="2"><br/></font></td>
<td style={{
borderTop: "1px solid #000000",
borderBottom: "1px solid #000000",
borderLeft: "1px solid #000000",
borderRight: "1px solid #000000"
}} align="center" valign="middle" sdnum="1049;0;0,00"><font face="Tahoma" size="2"><br/></font></td>
<td style={{
borderTop: "1px solid #000000",
borderBottom: "1px solid #000000",
borderLeft: "1px solid #000000",
borderRight: "1px solid #000000"
}} align="center" valign="middle" sdnum="1049;0;0,00"><font face="Tahoma" size="2"><br/></font></td>
<td style={{
borderTop: "1px solid #000000",
borderBottom: "1px solid #000000",
borderLeft: "1px solid #000000",
borderRight: "1px solid #000000"
}} align="center" valign="middle" sdnum="1049;0;0,00"><font face="Tahoma" size="2"><br/></font></td>
<td style={{
borderTop: "1px solid #000000",
borderBottom: "1px solid #000000",
borderLeft: "1px solid #000000",
borderRight: "1px solid #000000"
}} align="center" valign="middle" sdnum="1049;0;0,00"><font face="Tahoma" size="2"><br/></font></td>
<td style={{
borderTop: "1px solid #000000",
borderBottom: "1px solid #000000",
borderLeft: "1px solid #000000",
borderRight: "1px solid #000000"
}} align="center" valign="middle" sdnum="1049;0;0,00"><font face="Tahoma" size="2"><br/></font></td>
<td style={{
borderTop: "1px solid #000000",
borderBottom: "1px solid #000000",
borderLeft: "1px solid #000000",
borderRight: "1px solid #000000"
}} align="center" valign="middle" sdnum="1049;0;0,00"><font face="Tahoma" size="2"><br/></font></td>
<td style={{
borderTop: "1px solid #000000",
borderBottom: "1px solid #000000",
borderLeft: "1px solid #000000",
borderRight: "1px solid #000000"
}} align="center" valign="middle" sdnum="1049;0;0,00"><font face="Tahoma" size="2"><br/></font></td>
<td style={{
borderTop: "1px solid #000000",
borderBottom: "1px solid #000000",
borderLeft: "1px solid #000000",
borderRight: "1px solid #000000"
}} align="center" valign="middle" sdnum="1049;0;0,00"><font face="Tahoma" size="2"><br/></font></td>
<td style={{
borderTop: "1px solid #000000",
borderBottom: "1px solid #000000",
borderLeft: "1px solid #000000",
borderRight: "1px solid #000000"
}} align="center" valign="bottom"><font face="Arial Cyr"><br/></font></td>
<td style={{
borderTop: "1px solid #000000",
borderBottom: "1px solid #000000",
borderLeft: "1px solid #000000",
borderRight: "1px solid #000000"
}} align="center" valign="middle" sdnum="1049;0;0,00"><font face="Tahoma" size="2"><br/></font></td>
<td style={{
borderTop: "1px solid #000000",
borderBottom: "1px solid #000000",
borderLeft: "1px solid #000000",
borderRight: "1px solid #000000"
}} align="center" valign="middle" sdnum="1049;0;0,00"><font face="Tahoma" size="2"><br/></font></td>
<td style={{
borderTop: "1px solid #000000",
borderBottom: "1px solid #000000",
borderLeft: "1px solid #000000",
borderRight: "1px solid #000000"
}} align="center" valign="middle" sdnum="1049;0;0,00"><font face="Tahoma" size="2"><br/></font></td>
<td style={{
borderTop: "2px solid #000000",
borderBottom: "1px solid #000000",
borderLeft: "1px solid #000000",
borderRight: "1px solid #000000"
}} align="center" valign="middle"><font size="2" color="#000000"><br/></font></td>
<td style={{
borderTop: "1px solid #000000",
borderBottom: "1px solid #000000",
borderLeft: "1px solid #000000",
borderRight: "1px solid #000000"
}} align="center" valign="bottom"><font face="Tahoma" size="2"><br/></font></td>
<td style={{
borderTop: "1px solid #000000",
borderBottom: "1px solid #000000",
borderLeft: "1px solid #000000",
borderRight: "1px solid #000000"
}} align="center" valign="bottom"><font face="Tahoma" size="2"><br/></font></td>
</tr>
</table>
<div>&nbsp;</div>
<p style={{textAlign: "right"}}><b>{date}</b></p>
</>)
}

View File

@ -2,7 +2,7 @@ import { Layout, Button } from 'antd'
import { UserOutlined } from '@ant-design/icons'
import logo from '../images/logo_32.png'
import { Link } from "react-router-dom"
import WellTreeSelector from '../components/WellTreeSelector'
import WellTreeSelector from './WellTreeSelector'
const { Header } = Layout
@ -17,10 +17,11 @@ export default function PageHeader({title='Мониторинг', wellsList}){
return(
<Layout>
<Header className="header">
<img src={logo} alt="АСБ" className="logo"/>
<Link to="/" >
<img src={logo} alt="АСБ" className="logo"/>
</Link>
<WellTreeSelector wellsList={wellsList}/>
<h1 className="title">{title}</h1>
<div>&nbsp;</div>
<Link to="/login" onClick={handleLogout}>
<Button icon={<UserOutlined/>}>
({login}) Выход

184
src/components/RigMnemo.jsx Normal file
View File

@ -0,0 +1,184 @@
const styleBase = {
stroke: "none",
strokeLinecap: "butt",
strokeLinejoin: "miter",
}
const styleCasing = {
...styleBase,
fill: "#808080",
};
const styleGround = {
...styleBase,
fill: "#deaa87",
};
const styleTower = {
...styleBase,
fill: "#999999",
};
const styleWell = {
...styleBase,
fill: "#37abc8",
};
const styleBitDrive = {
...styleBase,
fill: "#ff8080",
};
const styleBitTool = {
...styleBase,
fill: "#f9f9f9",
};
const styleBlock = {
...styleBase,
fill: "#ffdd55",
};
const stylePump1 = {
...styleBase,
fill: "#5fd35f",
};
const stylePump2 = {
...styleBase,
fill: "#b3b3b3",
};
export default function RigMnemo({
blockPosition,
bitPosition,
}) {
let blockPositionLocal = +blockPosition
blockPositionLocal = blockPositionLocal ? blockPositionLocal : 0
const blockTranslate = `translate(-75, ${-35 + (50 * (30 - blockPositionLocal) / 30)})`
//let bitPositionLocal = +bitPosition
//bitPositionLocal = bitPositionLocal ? bitPositionLocal : 0
//const bitTranslate = `translate(0, ${-41 + 41 * (3426 - bitPosition)/(3426 - 3200)})`
const bitTranslate = `translate(0, 0)`
return (
<svg
width="400"
height="540"
viewBox="20 0 105.83333 145.52084"
version="1.1"
id="svg8"
>
<g id="Casing" style={styleCasing}>
<path d="m 29.897917,67.46875 v -1.322917 l 4.497916,-10e-7 v -1.322916 h 3.96875 v 1.322916 l 4.497917,10e-7 v 1.322917 z" />
<path d="M 31.75,97.895832 V 67.468749 h 9.260416 v 30.427083 z" />
<path d="m 30.95625,83.34375 0,1.058333 h 10.847917 l -10e-7,-1.058333 z" />
<path d="m 30.95625,85.195833 v 1.058333 h 10.847917 v -1.058333 z" />
<path d="m 30.95625,70.114583 v 1.058333 h 10.847918 l -10e-7,-1.058333 z" />
<path d="m 30.95625,71.966666 v 1.058333 h 10.847918 v -1.058333 z" />
</g>
<g id="Ground">
<path
style={styleGround}
d="m 62.177083,83.34375 -19.84375,0 V 97.895833 H 39.6875 V 142.875 H 33.072917 V 97.895833 H 30.427083 V 83.34375 l -10.583333,0 v 62.17708 h 42.333333 z"
id="path849"
/>
</g>
<g id="Tower" style={styleTower}>
<path d="m 29.104166,83.343749 v -2.645833 h -3.96875 v 2.645833 z" />
<path d="m 43.656249,83.343749 v -2.645833 h 3.96875 v 2.645833 z" />
<path d="m 26.458333,80.697916 v -11.90625 h 1.322917 v 11.90625 z" />
<path d="m 44.979166,80.697917 v -11.90625 h 1.322917 v 11.90625 z" />
<path d="m 22.489583,68.791666 h 27.78125 v -1.322917 h -27.78125 z" />
<path d="M 22.357422 66.013672 L 22.357422 67.601562 L 22.490234 67.601562 L 50.402344 67.601562 L 50.402344 66.013672 L 50.271484 66.013672 C 47.662479 66.013673 45.393545 66.029632 41.142578 66.013672 L 40.878906 66.013672 L 31.882812 66.013672 L 31.75 66.013672 C 31.693076 66.013672 31.673038 66.013672 31.617188 66.013672 C 27.779098 66.013674 26.402061 66.013673 22.490234 66.013672 L 22.357422 66.013672 z M 22.621094 66.277344 C 26.405208 66.277345 27.834127 66.277346 31.617188 66.277344 L 31.617188 67.335938 L 22.621094 67.335938 L 22.621094 66.277344 z M 31.882812 66.277344 L 40.878906 66.277344 L 40.878906 67.335938 L 31.882812 67.335938 L 31.882812 66.277344 z M 41.142578 66.277344 C 45.330989 66.293059 47.579975 66.277812 50.138672 66.277344 L 50.138672 67.335938 L 41.142578 67.335938 L 41.142578 66.277344 z " />
<path d="M 34.263672 2.5136719 L 34.263672 2.6464844 L 34.263672 6.7460938 L 38.496094 6.7460938 L 38.496094 2.5136719 L 34.263672 2.5136719 z M 34.527344 2.7773438 L 38.232422 2.7773438 L 38.232422 6.4824219 L 34.527344 6.4824219 L 34.527344 2.7773438 z " />
<path d="m 34.395833,4.4979166 h 3.96875 v 0.2645833 h -3.96875 z" />
<path d="M 36.247916,2.6458333 V 6.6145832 H 36.5125 V 2.6458333 Z" />
<path d="M 34.395833,6.6145833 V 7.9375 h 3.96875 V 6.6145833 Z" />
<path d="m 26.458333,68.791666 7.9375,-60.8541661 h 1.322917 l -7.9375,60.8541661 z" />
<path d="m 44.979166,68.791666 -7.9375,-60.8541661 h 1.322917 l 7.9375,60.8541661 z" />
<path d="M 42.333333,26.458333 H 30.427083 L 27.78125,25.135416 h 17.197916 z" />
<path d="M 34.396484 18.388672 L 34.396484 18.652344 L 38.365234 18.652344 L 38.365234 18.388672 L 34.396484 18.388672 z " />
<path d="M 34.925781 13.097656 L 34.925781 13.361328 L 37.835938 13.361328 L 37.835938 13.097656 L 34.925781 13.097656 z " />
<path d="M 37.724609 13.15625 L 34.285156 18.449219 L 34.505859 18.59375 L 37.947266 13.300781 L 37.724609 13.15625 z " />
<path d="M 35.841797 7.8886719 L 35.595703 7.9863281 L 37.712891 13.277344 L 37.958984 13.179688 L 35.841797 7.8886719 z " />
<path d="M 34.501953 18.441406 L 34.291016 18.601562 L 39.318359 25.214844 L 39.527344 25.054688 L 34.501953 18.441406 z " />
<path d="M 28.574219 62.044922 L 28.574219 62.308594 L 44.185547 62.308594 L 44.185547 62.044922 L 28.574219 62.044922 z " />
<path d="M 29.369141 55.429688 L 29.369141 55.695312 L 43.392578 55.695312 L 43.392578 55.429688 L 29.369141 55.429688 z " />
<g id="g985">
<path d="m 42.333333,48.947917 -11.90625,-10e-7" />
<path d="M 30.427734 48.816406 L 30.427734 49.080078 L 42.333984 49.080078 L 42.333984 48.816406 L 30.427734 48.816406 z " />
</g>
<g>
<path d="M 41.539583,42.333333 H 31.220833" />
<path d="M 31.220703 42.201172 L 31.220703 42.464844 L 41.539062 42.464844 L 41.539062 42.201172 L 31.220703 42.201172 z " />
</g>
<path d="M 31.326172 42.253906 L 31.115234 42.414062 L 36.142578 49.027344 L 36.248047 49.080078 L 36.511719 49.080078 L 36.617188 49.027344 L 41.644531 42.414062 L 41.433594 42.253906 L 36.447266 48.816406 L 36.314453 48.816406 L 31.326172 42.253906 z " />
<path d="M 33.460938 26.412109 L 33.212891 26.503906 L 36.15625 34.527344 L 36.605469 34.527344 L 39.546875 26.503906 L 39.298828 26.412109 L 36.419922 34.263672 L 36.339844 34.263672 L 33.460938 26.412109 z " />
<path d="M 32.398438 34.335938 L 32.160156 34.455078 L 36.166016 42.464844 L 36.59375 42.464844 L 40.599609 34.455078 L 40.363281 34.335938 L 36.431641 42.201172 L 36.330078 42.201172 L 32.398438 34.335938 z " />
<path d="M 30.527344 48.861328 L 30.328125 49.035156 L 36.1875 55.695312 L 36.572266 55.695312 L 42.433594 49.035156 L 42.234375 48.861328 L 36.453125 55.429688 L 36.308594 55.429688 L 30.527344 48.861328 z " />
<path d="M 36.199219 55.429688 L 28.488281 62.076172 L 28.662109 62.277344 L 36.296875 55.695312 L 36.462891 55.695312 L 44.099609 62.277344 L 44.271484 62.076172 L 36.5625 55.429688 L 36.199219 55.429688 z " />
<path d="M 32.279297 34.263672 L 32.279297 34.527344 L 40.480469 34.527344 L 40.480469 34.263672 L 32.279297 34.263672 z " />
</g>
<g id="Well" style={styleWell}>
<path d="M 33.072916,97.895832 H 39.6875 V 142.875 h -6.614584 z" />
</g>
<g id="Bit"
transform={bitTranslate}>
<path
style={styleBitDrive}
d="m 33.072916,142.875 1.322917,-3.96875 h 3.96875 L 39.6875,142.875 h -6.614584"
/>
<path
style={styleBitTool}
d="m 34.395833,138.90625 v -3.96875 h 3.96875 v 3.96875 z"
/>
</g>
<g id="Block"
transform={blockTranslate}
style={styleBlock}
>
<path d="m 111.125,45.772916 c 0,0 -0.79375,-1.102431 -0.79375,-1.322917 0,-0.220486 -0.0952,-0.338724 0,-0.529166 0.0952,-0.190442 0.29053,-0.433713 0.52917,-0.529167 0.23864,-0.09545 0.55512,-0.09545 0.79375,0 0.23863,0.09545 0.43394,0.338726 0.52916,0.529167 0.0952,0.190441 0,0.440972 0,0.529166 0,0.08819 -0.79375,1.322917 -0.79375,1.322917 z" />
<path d="m 111.38958,45.772916 c 0,0 0.17047,0.398584 0.26459,0.529167 0.0941,0.130583 0.22384,0.166227 0.26458,0.264583 0.0407,0.09836 0.0328,0.390283 0,0.529167 -0.0328,0.138884 -0.10568,0.166378 -0.26458,0.264584 -0.1589,0.09821 -0.37027,0.09821 -0.52917,0 -0.1589,-0.09821 -0.23179,-0.1257 -0.26458,-0.264584 -0.0328,-0.138884 0,-0.529167 0,-0.529167 0,0 0.10568,0.430961 0.26458,0.529167 0.1589,0.09821 0.40444,0.124726 0.52917,0 0.12472,-0.124725 0.0576,-0.39007 0,-0.529167 -0.0576,-0.139097 -0.17047,-0.133999 -0.26459,-0.264583 -0.0941,-0.130584 -0.26458,-0.529167 -0.26458,-0.529167 z" />
<path d="m 110.33125,47.360416 v 2.38125 l 0.79375,10e-7 v 0.529166 h -0.26458 V 50.8 l 1.32291,-10e-7 v -0.529166 h -0.26458 v -0.529167 l 0.79375,10e-7 v -2.38125 z" />
</g>
<g id="Pump1" transform="translate(-0.79375,2.6066667e-4)">
<circle
style={stylePump1}
id="PumpCircle"
cx="51.59375"
cy="80.698891"
r="1.984375"
/>
<path
d="m 51.064583,81.492642 1e-6,-1.587499 1.322916,0.79375 v -10e-7 z"
id="PumpTriangle"
/>
<path
style={stylePump1}
d="m 48.948828,78.052995 v 5.292056 h 0.13086 l 5.158984,-2.6e-4 v -5.292057 z m 0.263672,0.263672 4.7625,-2.61e-4 v 4.762761 l -4.7625,2.6e-4 z"
id="PumpSquare"
/>
</g>
<g id="Pump2" transform="translate(4.7625,-5.205e-4)">
<circle
style={stylePump2}
id="PumpCircle"
cx="51.59375"
cy="80.698891"
r="1.984375"
/>
<path
d="m 51.064583,81.492642 1e-6,-1.587499 1.322916,0.79375 v -10e-7 z"
id="PumpTriangle"
/>
<path
style={stylePump2}
d="m 48.948828,78.052995 v 5.292056 h 0.13086 l 5.158984,-2.6e-4 v -5.292057 z m 0.263672,0.263672 4.7625,-2.61e-4 v 4.762761 l -4.7625,2.6e-4 z"
id="PumpSquare"
/>
</g>
</svg>
);
}

383
src/components/Sludge.jsx Normal file
View File

@ -0,0 +1,383 @@
let date = new Date().toLocaleString()
export function Sludge() {
return (<>
<table cellspacing="0" border="0">
<colGroup span="22" width="85"></colGroup>
<tr>
<td style={{
borderTop: "2px solid #000000",
borderBottom: "1px solid #000000",
borderLeft: "2px solid #000000",
borderRight: "2px double #000000",
fontSize: "14",
fontFamily: "Tahoma, sans-serif"
}} rowSpan="3" height="130" align="center" valign="middle" bgcolor="#FFFF99"><b><font face="Tahoma"
size="2">N пробы</font></b>
</td>
<td style={{
borderTop: "2px solid #000000",
borderLeft: "2px solid #000000",
borderRight: "2px double #000000",
fontSize: "14",
fontFamily: "Tahoma, sans-serif"
}} rowSpan="3" align="center" valign="middle" bgcolor="#FFFF99"><b><font face="Tahoma" size="2">Глубина
отбора пробы</font></b></td>
<td style={{
borderTop: "2px solid #000000",
borderLeft: "2px solid #000000",
borderRight: "2px double #000000",
fontSize: "14",
fontFamily: "Tahoma, sans-serif"
}} colSpan="9" align="center" valign="middle" bgcolor="#FFFF99"><b><font face="Tahoma"
size="2">Литология</font></b></td>
<td style={{
borderTop: "2px solid #000000",
borderLeft: "2px solid #000000",
borderRight: "2px double #000000",
fontSize: "14",
fontFamily: "Tahoma, sans-serif"
}} rowSpan="3" align="center" valign="middle" bgcolor="#FFFF99"><b><font face="Tahoma" size="2">Краткое
описание</font></b></td>
<td style={{
borderTop: "2px solid #000000",
borderBottom: "1px solid #000000",
borderLeft: "2px solid #000000",
borderRight: "2px double #000000",
fontSize: "14",
fontFamily: "Tahoma, sans-serif"
}} rowSpan="3" align="center" valign="middle" bgcolor="#AFABAB"><b><font face="Tahoma" size="2">ЛБА
бурового раствора </font></b></td>
<td style={{
borderTop: "2px solid #000000",
borderLeft: "2px double #000000",
fontSize: "14",
fontFamily: "Tahoma, sans-serif"
}} rowSpan="3" align="center" valign="middle" bgcolor="#FFCC99"><b><font face="Tahoma" size="2">ЛБА
(шлама)</font></b></td>
<td style={{
borderTop: "2px solid #000000",
borderBottom: "2px solid #000000",
borderLeft: "2px solid #000000",
borderRight: "2px solid #000000",
fontSize: "14",
fontFamily: "Tahoma, sans-serif"
}} colSpan="6" align="center" valign="bottom" bgcolor="#FFFF99" sdnum="1049;0;0,000"><b><font face="Tahoma"
size="2">Газопоказания</font></b>
</td>
<td style={{
borderTop: "2px solid #000000",
borderLeft: "2px solid #000000",
borderRight: "2px solid #000000",
fontSize: "14",
fontFamily: "Tahoma, sans-serif"
}} rowSpan="3" align="center" valign="middle" bgcolor="#FFFF99" sdnum="1049;0;0,000"><b><font face="Tahoma"
size="2">Мех.
скорость</font></b></td>
<td style={{
borderTop: "2px solid #000000",
borderLeft: "1px solid #000000",
borderRight: "2px solid #000000",
fontSize: "14",
fontFamily: "Tahoma, sans-serif"
}} rowSpan="3" align="center" valign="middle" bgcolor="#FFCC99" sdnum="1049;0;0,00"><b><font
face="Tahoma" size="2">Предварительное заключение о насыщении по ГК</font></b></td>
</tr>
<tr>
<td style={{
borderTop: "2px solid #000000",
borderLeft: "2px solid #000000",
borderRight: "1px solid #000000",
fontSize: "14",
fontFamily: "Tahoma, sans-serif"
}} rowSpan="2" align="center" valign="middle" bgcolor="#CCCCFF"><b><font face="Tahoma" size="2">Песчаник
(%) </font></b></td>
<td style={{
borderTop: "2px solid #000000",
borderLeft: "1px solid #000000",
borderRight: "1px solid #000000",
fontSize: "14",
fontFamily: "Tahoma, sans-serif"
}} rowSpan="2" align="center" valign="middle" bgcolor="#CCCCFF"><b><font face="Tahoma" size="2">Алевролит
(%)</font></b></td>
<td style={{
borderTop: "2px solid #000000",
borderLeft: "1px solid #000000",
borderRight: "1px solid #000000",
fontSize: "14",
fontFamily: "Tahoma, sans-serif"
}} rowSpan="2" align="center" valign="middle" bgcolor="#CCCCFF"><b><font face="Tahoma" size="2">Аргиллит
(%)</font></b></td>
<td style={{
borderTop: "2px solid #000000",
borderLeft: "1px solid #000000",
borderRight: "1px solid #000000",
fontSize: "14",
fontFamily: "Tahoma, sans-serif"
}} rowSpan="2" align="center" valign="middle" bgcolor="#CCCCFF"><b><font face="Tahoma" size="2">Аргиллит
бит. (%)</font></b></td>
<td style={{
borderTop: "2px solid #000000",
borderLeft: "1px solid #000000",
borderRight: "1px solid #000000",
fontSize: "14",
fontFamily: "Tahoma, sans-serif"
}} rowSpan="2" align="center" valign="middle" bgcolor="#CCCCFF"><b><font face="Tahoma" size="2">Уголь
(%)</font></b></td>
<td style={{
borderTop: "2px solid #000000",
borderLeft: "1px solid #000000",
borderRight: "1px solid #000000",
fontSize: "14",
fontFamily: "Tahoma, sans-serif"
}} rowSpan="2" align="center" valign="middle" bgcolor="#CCCCFF"><b><font face="Tahoma" size="2">Песок
(%)</font></b></td>
<td style={{
borderTop: "2px solid #000000",
borderLeft: "1px solid #000000",
borderRight: "1px solid #000000",
fontSize: "14",
fontFamily: "Tahoma, sans-serif"
}} rowSpan="2" align="center" valign="middle" bgcolor="#CCCCFF"><b><font face="Tahoma" size="2">Глина
(%)</font></b></td>
<td style={{
borderTop: "2px solid #000000",
borderLeft: "1px solid #000000",
borderRight: "1px solid #000000",
fontSize: "14",
fontFamily: "Tahoma, sans-serif"
}} rowSpan="2" align="center" valign="middle" bgcolor="#CCCCFF"><b><font face="Tahoma" size="2">Известняк
(%)</font></b></td>
<td style={{
borderTop: "2px solid #000000",
borderLeft: "1px solid #000000",
borderRight: "2px solid #000000",
fontSize: "14",
fontFamily: "Tahoma, sans-serif"
}} rowSpan="2" align="center" valign="middle" bgcolor="#CCCCFF"><b><font face="Tahoma" size="2">Цемент
(%)</font></b></td>
<td style={{
borderLeft: "2px solid #000000",
borderRight: "1px solid #000000",
fontSize: "14",
fontFamily: "Tahoma, sans-serif"
}} rowSpan="2" align="center" valign="middle" bgcolor="#CCCCFF" sdnum="1049;0;0,000"><b><font face="Tahoma"
size="2">Сумма
УВ мах. (абс%) </font></b></td>
<td style={{
borderLeft: "1px solid #000000",
borderRight: "1px solid #000000",
fontSize: "14",
fontFamily: "Tahoma, sans-serif"
}} rowSpan="2" align="center" valign="middle" bgcolor="#CCCCFF" sdnum="1049;0;0,000"><b><font face="Tahoma"
size="2">С1
метан (отн%)</font></b></td>
<td style={{
borderLeft: "1px solid #000000",
borderRight: "1px solid #000000",
fontSize: "14",
fontFamily: "Tahoma, sans-serif"
}} rowSpan="2" align="center" valign="middle" bgcolor="#CCCCFF" sdnum="1049;0;0,000"><b><font face="Tahoma"
size="2">С2 этан
(отн%)</font></b></td>
<td style={{borderRight: "1px solid #000000", fontSize: "14", fontFamily: "Tahoma, sans-serif"}} rowSpan="2"
align="center" valign="middle" bgcolor="#CCCCFF" sdnum="1049;0;0,000"><b><font face="Tahoma" size="2">С3
пропан (отн%)</font></b></td>
<td style={{
borderLeft: "1px solid #000000",
borderRight: "1px solid #000000",
fontSize: "14",
fontFamily: "Tahoma, sans-serif"
}} rowSpan="2" align="center" valign="middle" bgcolor="#CCCCFF" sdnum="1049;0;0,000"><b><font face="Tahoma"
size="2">С4
бутан (отн%)</font></b></td>
<td style={{borderLeft: "1px solid #000000", fontSize: "14", fontFamily: "Tahoma, sans-serif"}} rowSpan="2"
align="center" valign="middle" bgcolor="#CCCCFF" sdnum="1049;0;0,000"><b><font face="Tahoma" size="2">С5
пентан (отн%)</font></b></td>
</tr>
<tr>
</tr>
<tr>
<td style={{
borderTop: "1px solid #000000",
borderBottom: "1px solid #000000",
borderLeft: "1px solid #000000",
borderRight: "1px solid #000000",
fontSize: "14",
fontFamily: "Tahoma, sans-serif"
}} height="40" align="left" valign="bottom"><font size="2" color="#000000"><br/></font></td>
<td style={{
borderTop: "1px solid #000000",
borderBottom: "1px solid #000000",
borderLeft: "1px solid #000000",
borderRight: "1px solid #000000",
fontSize: "14",
fontFamily: "Tahoma, sans-serif"
}} align="left" valign="bottom"><font size="2" color="#000000"><br/></font></td>
<td style={{
borderTop: "1px solid #000000",
borderBottom: "1px solid #000000",
borderLeft: "1px solid #000000",
borderRight: "1px solid #000000",
fontSize: "14",
fontFamily: "Tahoma, sans-serif"
}} align="left" valign="bottom"><font size="2" color="#000000"><br/></font></td>
<td style={{
borderTop: "1px solid #000000",
borderBottom: "1px solid #000000",
borderLeft: "1px solid #000000",
borderRight: "1px solid #000000",
fontSize: "14",
fontFamily: "Tahoma, sans-serif"
}} align="left" valign="bottom"><font size="2" color="#000000"><br/></font></td>
<td style={{
borderTop: "1px solid #000000",
borderBottom: "1px solid #000000",
borderLeft: "1px solid #000000",
borderRight: "1px solid #000000",
fontSize: "14",
fontFamily: "Tahoma, sans-serif"
}} align="left" valign="bottom"><font size="2" color="#000000"><br/></font></td>
<td style={{
borderTop: "1px solid #000000",
borderBottom: "1px solid #000000",
borderLeft: "1px solid #000000",
borderRight: "1px solid #000000",
fontSize: "14",
fontFamily: "Tahoma, sans-serif"
}} align="left" valign="bottom"><font size="2" color="#000000"><br/></font></td>
<td style={{
borderTop: "1px solid #000000",
borderBottom: "1px solid #000000",
borderLeft: "1px solid #000000",
borderRight: "1px solid #000000",
fontSize: "14",
fontFamily: "Tahoma, sans-serif"
}} align="left" valign="bottom"><font size="2" color="#000000"><br/></font></td>
<td style={{
borderTop: "1px solid #000000",
borderBottom: "1px solid #000000",
borderLeft: "1px solid #000000",
borderRight: "1px solid #000000",
fontSize: "14",
fontFamily: "Tahoma, sans-serif"
}} align="left" valign="bottom"><font size="2" color="#000000"><br/></font></td>
<td style={{
borderTop: "1px solid #000000",
borderBottom: "1px solid #000000",
borderLeft: "1px solid #000000",
borderRight: "1px solid #000000",
fontSize: "14",
fontFamily: "Tahoma, sans-serif"
}} align="left" valign="bottom"><font size="2" color="#000000"><br/></font></td>
<td style={{
borderTop: "1px solid #000000",
borderBottom: "1px solid #000000",
borderLeft: "1px solid #000000",
borderRight: "1px solid #000000",
fontSize: "14",
fontFamily: "Tahoma, sans-serif"
}} align="left" valign="bottom"><font size="2" color="#000000"><br/></font></td>
<td style={{
borderTop: "1px solid #000000",
borderBottom: "1px solid #000000",
borderLeft: "1px solid #000000",
borderRight: "1px solid #000000",
fontSize: "14",
fontFamily: "Tahoma, sans-serif"
}} align="left" valign="bottom"><font size="2" color="#000000"><br/></font></td>
<td style={{
borderTop: "1px solid #000000",
borderBottom: "1px solid #000000",
borderLeft: "1px solid #000000",
borderRight: "1px solid #000000",
fontSize: "14",
fontFamily: "Tahoma, sans-serif"
}} align="left" valign="bottom"><font size="2" color="#000000"><br/></font></td>
<td style={{
borderTop: "1px solid #000000",
borderBottom: "1px solid #000000",
borderLeft: "1px solid #000000",
borderRight: "1px solid #000000",
fontSize: "14",
fontFamily: "Tahoma, sans-serif"
}} align="left" valign="bottom"><font size="2" color="#000000"><br/></font></td>
<td style={{
borderTop: "1px solid #000000",
borderBottom: "1px solid #000000",
borderLeft: "1px solid #000000",
borderRight: "1px solid #000000",
fontSize: "14",
fontFamily: "Tahoma, sans-serif"
}} align="left" valign="bottom"><font size="2" color="#000000"><br/></font></td>
<td style={{
borderTop: "1px solid #000000",
borderBottom: "1px solid #000000",
borderLeft: "1px solid #000000",
borderRight: "1px solid #000000",
fontSize: "14",
fontFamily: "Tahoma, sans-serif"
}} align="left" valign="bottom"><font size="2" color="#000000"><br/></font></td>
<td style={{
borderTop: "1px solid #000000",
borderBottom: "1px solid #000000",
borderLeft: "1px solid #000000",
borderRight: "1px solid #000000",
fontSize: "14",
fontFamily: "Tahoma, sans-serif"
}} align="left" valign="bottom"><font size="2" color="#000000"><br/></font></td>
<td style={{
borderTop: "1px solid #000000",
borderBottom: "1px solid #000000",
borderLeft: "1px solid #000000",
borderRight: "1px solid #000000",
fontSize: "14",
fontFamily: "Tahoma, sans-serif"
}} align="left" valign="bottom"><font size="2" color="#000000"><br/></font></td>
<td style={{
borderTop: "1px solid #000000",
borderBottom: "1px solid #000000",
borderLeft: "1px solid #000000",
borderRight: "1px solid #000000",
fontSize: "14",
fontFamily: "Tahoma, sans-serif"
}} align="left" valign="bottom"><font size="2" color="#000000"><br/></font></td>
<td style={{
borderTop: "1px solid #000000",
borderBottom: "1px solid #000000",
borderLeft: "1px solid #000000",
borderRight: "1px solid #000000",
fontSize: "14",
fontFamily: "Tahoma, sans-serif"
}} align="left" valign="bottom"><font size="2" color="#000000"><br/></font></td>
<td style={{
borderTop: "1px solid #000000",
borderBottom: "1px solid #000000",
borderLeft: "1px solid #000000",
borderRight: "1px solid #000000",
fontSize: "14",
fontFamily: "Tahoma, sans-serif"
}} align="left" valign="bottom"><font size="2" color="#000000"><br/></font></td>
<td style={{
borderTop: "1px solid #000000",
borderBottom: "1px solid #000000",
borderLeft: "1px solid #000000",
borderRight: "1px solid #000000",
fontSize: "14",
fontFamily: "Tahoma, sans-serif"
}} align="left" valign="bottom"><font size="2" color="#000000"><br/></font></td>
<td style={{
borderTop: "1px solid #000000",
borderBottom: "1px solid #000000",
borderLeft: "1px solid #000000",
borderRight: "1px solid #000000",
fontSize: "14",
fontFamily: "Tahoma, sans-serif"
}} align="left" valign="bottom"><font size="2" color="#000000"><br/></font></td>
</tr>
</table>
<div>&nbsp;</div>
<p style={{textAlign: "right"}}><b>{date}</b></p>
</>
)
}

View File

@ -1,72 +0,0 @@
import {Layout, Menu} from "antd";
import {FolderOutlined, FundViewOutlined} from "@ant-design/icons";
import {Link, Redirect, Route, Switch, useParams} from "react-router-dom";
import Files from "../pages/Files";
import Archive from "../pages/Archive";
import Messages from "../pages/Messages";
import Report from "../pages/Report";
import Analysis from "../pages/Analysis";
import TelemetryView from "../pages/TelemetryView";
const { Content } = Layout
export default function Well() {
let { id } = useParams()
return (<>
<Layout>
<Menu
mode="horizontal"
selectable={true}
className="well_menu"
>
<Menu.Item key="1" icon={<FundViewOutlined/>}>
<Link to='telemetry'>Мониторинг</Link>
</Menu.Item>
<Menu.Item key="2" icon={<FolderOutlined/>}>
<Link to='message'>Сообщения</Link>
</Menu.Item>
<Menu.Item key="3" icon={<FolderOutlined/>}>
<Link to='report'>Рапорт</Link>
</Menu.Item>
<Menu.Item key="4" icon={<FolderOutlined/>}>
<Link to='analysis'>Анализ</Link>
</Menu.Item>
<Menu.Item key="5" icon={<FolderOutlined/>}>
<Link to='file'>Файлы</Link>
</Menu.Item>
<Menu.Item key="6" icon={<FolderOutlined/>}>
<Link to='archive'>Архив</Link>
</Menu.Item>
</Menu>
<Layout>
<Content className="site-layout-background">
<Switch>
<Route path="/well/:id/file">
<Files/>
</Route>
<Route path="/well/:id/archive">
<Archive/>
</Route>
<Route path="/well/:id/message">
<Messages/>
</Route>
<Route path="/well/:id/report">
<Report/>
</Route>
<Route path="/well/:id/analysis">
<Analysis/>
</Route>
<Route path="/well/:id/telemetry">
<TelemetryView/>
</Route>
<Route path="/">
<Redirect to={{pathname: `/well/${id}/telemetry`}}/>
</Route>
</Switch>
</Content>
</Layout>
</Layout>
</>)
}

View File

@ -1,71 +1,55 @@
import { useState, useEffect } from 'react'
import { useParams } from 'react-router-dom'
import { WellService } from '../services/api'
import Loader from '../components/Loader'
import { useRouteMatch } from 'react-router-dom'
import { DepositService } from '../services/api'
import LoaderPortal from './LoaderPortal'
import { TreeSelect } from 'antd'
import { useHistory } from 'react-router-dom'
import notify from './notify'
const groupBy = (table, ...keys) => {
let key = keys[0]
let groups = table.reduce((rv, item) => {
let keyValue = item[key]
let group = rv.find(o => o.title === keyValue)
if (!group) {
group = {
title: keyValue,
value: keys.length === 1 ? `${item['id']}` : `${key} ${keyValue} ${item['id']}`,
selectable: keys.length === 1,
children: []
}
rv.push(group)
}
if (keys.length > 1)
group.children.push(item);
return rv;
}, []);
if (keys.length > 1) {
for (let group of groups) {
group.children = groupBy(group.children, ...keys.slice(1))
}
}
return groups
};
export default function WellTreeSelector(props) {
// const [wells, setWells] = useState([])
export default function WellTreeSelector() {
const [wellsTree, setWellsTree] = useState([])
const [loader, setLoader] = useState(false)
const [showLoader, setShowLoader] = useState(false)
const history = useHistory()
let { id } = useParams();
const routeMatch = useRouteMatch('/:route/:id')
let updateWellsList = async () => {
setLoader(true)
const updateWellsList = async () => {
setShowLoader(true)
try {
let newWells = (await WellService.getWells()).map(w => { return { key: w.id, ...w } })
let wellsTree = groupBy(newWells, 'deposit', 'cluster', 'caption')
const deposits = await DepositService.getDeposits()
const wellsTree = deposits.map(deposit =>({
title: deposit.caption,
key: `/deposit/${deposit.id}`,
value: `/deposit/${deposit.id}`,
children: deposit.clusters.map(cluster => ({
title: cluster.caption,
key: `/cluster/${cluster.id}`,
value: `/cluster/${cluster.id}`,
children: cluster.wells.map(well => ({
title: well.caption,
key: `/well/${well.id}`,
value: `/well/${well.id}`,
})),
})),
}))
setWellsTree(wellsTree)
}
catch (e) {
notify('Не удалось загрузить список скважин', 'error')
console.error(`${e.message}`);
console.error(`${e.message}`)
}
setLoader(false)
setShowLoader(false)
}
useEffect(() => { updateWellsList() }, [])
const onSelect = (value) => {
const onSelect = (value, node) => {
if (value)
history.push(`/well/${value}/`);
history.push(value);
console.log(value)
}
return (
<>
<LoaderPortal show={showLoader}>
<TreeSelect
className='header-tree-select'
bordered={false}
@ -74,9 +58,8 @@ export default function WellTreeSelector(props) {
treeData={wellsTree}
treeDefaultExpandAll
onSelect={onSelect}
value = {id}
value = {routeMatch?.url}
/>
{loader && <Loader />}
</>
</LoaderPortal>
)
}

BIN
src/images/DempherOff.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 974 B

BIN
src/images/DempherOn.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

BIN
src/images/SpinDisabled.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

BIN
src/images/SpinEnabled.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

BIN
src/images/las.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 965 B

View File

Before

Width:  |  Height:  |  Size: 5.3 KiB

After

Width:  |  Height:  |  Size: 5.3 KiB

BIN
src/images/pdf.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

12
src/images/pointer.svg Normal file
View File

@ -0,0 +1,12 @@
<svg width="48" height="48" version="1.1" viewBox="0 0 7.9 7.9" xmlns="http://www.w3.org/2000/svg" xmlns:osb="http://www.openswatchbook.org/uri/2009/osb">
<g stroke="#000">
<path d="m3.1 1.6 1.9 1.5-2.3 1.1 2.9 2-0.78-4.6h-1.7l-0.78 4.6 2.9-2-2.3-1.1 1.9-1.5" fill="none" stroke-linecap="round" stroke-linejoin="bevel" stroke-width=".17"/>
<rect x="2.8" y=".98" width="2.3" height=".45" stroke-width=".084"/>
<rect x="3.4" y=".31" width="1.2" height=".45" stroke-width=".084"/>
<g fill="none" stroke-width=".084">
<rect x="3.9" y="1.6" width=".11" height="6" stroke-linejoin="round"/>
<path d="m1.2 6.2 2.1 8e-7v1.5"/>
<path d="m4.5 7.7v-1.5l1.9-8e-7"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 691 B

BIN
src/images/xlsx.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 KiB

143
src/pages/Cluster.jsx Normal file
View File

@ -0,0 +1,143 @@
import {useParams} from "react-router-dom";
import {Link} from "react-router-dom";
import LoaderPortal from '../components/LoaderPortal'
import { useState, useEffect } from "react";
import {ClusterService} from '../services/api'
import notify from '../components/notify'
import {Table, Tag, Button} from 'antd';
const columns = [
{
title: 'скв №',
key: 'caption',
dataIndex: 'caption',
render: (_, item) => <Link to={`/well/${item.id}`}>{item.caption}</Link>
},
{
title: 'Тип скв.',
key: 'wellType',
dataIndex: 'wellType',
},
{
title: 'Фактические сроки бурения',
children: [
{
title: 'начало',
key: 'factStart',
dataIndex: 'factStart',
},
{
title: 'окончание',
key: 'factEnd',
dataIndex: 'factEnd',
},
]
},
{
title: 'Продолжительность бурения',
children: [
{
title: 'план',
key: 'periodPlan',
dataIndex: 'periodPlan',
},
{
title: 'факт',
key: 'periodFact',
dataIndex: 'periodFact',
},
]
},
{
title: 'МСП за скв',
children: [
{
title: 'план',
key: 'rateOfPenetrationPlan',
dataIndex: 'rateOfPenetrationPlan',
},
{
title: 'факт',
key: 'rateOfPenetrationFact',
dataIndex: 'rateOfPenetrationFact',
},
],
},
{
title: 'Рейсовая скорость за скв',
children: [
{
title: 'план',
key: 'routeSpeedPlan',
dataIndex: 'routeSpeedPlan',
},
{
title: 'факт',
key: 'routeSpeedFact',
dataIndex: 'routeSpeedFact',
},
],
},
{
title: 'Секции',
key: 'sections',
dataIndex: 'sections',
render: (item) => (<span>таблица по секциям</span>)
},
{
title: 'График глубина-день',
render: _ => (<Button>Открыть</Button>)
},
{
title: 'Таблица по операциям',
render: _ => (<Button>Открыть</Button>)
},
{
title: 'Подрядчики',
key: 'companies',
dataIndex: 'companies',
render: (item) => item.map(company => <Tag color="blue">{company.caption}</Tag>)
},
];
export default function Cluster() {
let { id } = useParams()
const [clusterTitle, setClusterTitle] = useState("")
const [wellsStat, setWellsStat] = useState(null)
const [showLoader, setShowLoader] = useState(false)
useEffect(()=>{
const updateWellsStat = async() => {
setShowLoader(true)
try{
const msInDay = 1000*60*60*24
const data = await ClusterService.getStat(id)
const wellsStat = data.wellsStat.map(w=>({...w,
periodPlan: (new Date(w.planEnd) - new Date(w.planStart))/msInDay,
periodFact: (new Date(w.factEnd) - new Date(w.factStart))/msInDay,
}))
setWellsStat(wellsStat)
setClusterTitle(data.caption)
}
catch(ex) {
notify(`Не удалось загрузить статистику по скважинам куста "${id}"`, 'error')
console.log(ex)
}
setShowLoader(false)
}
updateWellsStat()
},[id])
return(
<LoaderPortal show={showLoader}>
<h3>{clusterTitle}</h3>
<Table
columns={columns}
dataSource={wellsStat}
size={'small'}
bordered
pagination={false}
rowKey={(record) => record.id}
/>
</LoaderPortal>)
}

74
src/pages/Deposit.jsx Normal file
View File

@ -0,0 +1,74 @@
import { Map, Overlay } from "pigeon-maps"
import pointer from '../images/pointer.svg'
import {Link} from "react-router-dom";
import LoaderPortal from '../components/LoaderPortal'
import { useState, useEffect } from "react";
import {ClusterService} from '../services/api'
import notify from '../components/notify'
const calcViewParams = (clusters) => {
if ((!clusters) || clusters.length === 0)
return {center:[60.81226, 70.0562], zoom: 5}
const center = clusters.reduce((sum, cluster) => {
sum[0] += (cluster.latitude / clusters.length)
sum[1] += (cluster.longitude / clusters.length)
return sum
}, [0, 0])
const maxDeg = clusters.reduce((max, cluster) => {
const dLatitude = Math.abs(center[0] - cluster.latitude)
const dLongitude = Math.abs(center[1] - cluster.longitude)
const d = dLatitude > dLongitude ? dLatitude : dLongitude
return d > max ? d : max
}, 0)
return {center, zoom: maxDeg*25}
}
export default function Deposit() {
const [clustersData, setClustersData] = useState([])
const [showLoader, setShowLoader] = useState(false)
useEffect(()=>{
const updateClusters = async()=>{
setShowLoader(true)
try{
const data = await ClusterService.getClusters()
setClustersData(data)
}
catch(ex) {
notify(`Не удалось загрузить список кустов`, 'error')
console.log(ex)
}
setShowLoader(false)
}
updateClusters()
}, [])
const viewParams = calcViewParams(clustersData)
const markers = clustersData.map(cluster =>
<Overlay
width={32}
anchor={[cluster.latitude, cluster.longitude]}
key={`${cluster.latitude} ${cluster.longitude}`}
>
<Link to={`/cluster/${cluster.id}`}>
<img width={40} src={pointer} alt="+"/>
<span>{cluster.caption}</span>
</Link>
</Overlay >)
return (
<LoaderPortal show={showLoader}>
<Map
height='100vh'
center={viewParams.center}
zoom={viewParams.zoom}>
{markers}
</Map>
</LoaderPortal>
);
}

View File

@ -0,0 +1,8 @@
import Documents from "../components/Documents"
export default function FluidService({selectedFileCategory}) {
return(
<Documents selectedFileCategory={selectedFileCategory} />
)
}

94
src/pages/LastData.jsx Normal file
View File

@ -0,0 +1,94 @@
import {Button, Modal, Checkbox } from "antd";
import {CementFluid} from "../components/CementFluid";
import React, {useState} from "react";
import {Sludge} from "../components/Sludge";
import {NnbTable} from "../components/NnbTable"
import Disposition from "../components/Disposition";
import MenuDocuments from "../components/MenuDocuments";
export default function LastData() {
const [tableVisible, setTableVisible] = useState(false)
const [tableSludgeVisible, setTableSludgeVisible] = useState(false)
const [tableNNBVisible, setTableNNBVisible] = useState(false)
const [dispositionVisible, setDispositionVisible] = useState(false)
return (
<>
<div>
<MenuDocuments/>
</div>
<div>&nbsp;</div>
<Button type="primary" onClick={() => setTableVisible(true)}>
Последний замер бурового раствора
</Button>
<Modal
title='Последние показатели бурового раствора'
centered
visible={tableVisible}
onOk={() => setTableVisible(false)}
onCancel={() => setTableVisible(false)}
width={1800}
okText='Ок'
cancelText='Отмена'
>
<CementFluid/>
</Modal>
<Button type="primary" onClick={() => setTableSludgeVisible(true)} style={{marginLeft: "5px"}}>
Шламограмма
</Button>
<Modal
title='Шламограмма'
centered
visible={tableSludgeVisible}
onOk={() => setTableSludgeVisible(false)}
onCancel={() => setTableSludgeVisible(false)}
width={1600}
okText='Ок'
cancelText='Отмена'
>
<Sludge/>
</Modal>
<Button type="primary" onClick={() => setTableNNBVisible(true)} style={{marginLeft: "5px"}}>
ННБ
</Button>
<Modal
title='ННБ'
centered
visible={tableNNBVisible}
onOk={() => setTableNNBVisible(false)}
onCancel={() => setTableNNBVisible(false)}
width={1400}
okText='Ок'
cancelText='Отмена'
>
<NnbTable/>
</Modal>
<Button type="primary" onClick={() => setDispositionVisible(true)} style={{marginLeft: "5px"}}>
Распоряжение
</Button>
<Modal
title='Распоряжение'
centered
visible={dispositionVisible}
onOk={() => setDispositionVisible(false)}
onCancel={() => setDispositionVisible(false)}
width={850}
okText='Ок'
cancelText='Отмена'
footer={[
<Checkbox style={{marginRight: '10px'}}>Принять распоряжение</Checkbox>,
<Button key="submit" type="secondary"
onClick={() => setDispositionVisible(false)}>
Отмена
</Button>,
<Button key="submit" type="primary"
onClick={() => setDispositionVisible(false)}>
Ок
</Button>
]}
>
<Disposition/>
</Modal>
</>)
}

View File

@ -1,16 +0,0 @@
import {Layout} from 'antd'
import PageHeader from './Header'
const {Content} = Layout
export default function LayoutPortal({title, children}) {
return (
<Content>
<PageHeader title={title}/>
<Layout>
<Content className="site-layout-background sheet">
{children}
</Content>
</Layout>
</Content>)
}

View File

@ -17,6 +17,7 @@ const openNotificationError = (message, title) => {
const setUser = (user) =>{
OpenAPI.TOKEN = user.token
localStorage['userId'] = user.id
localStorage['token'] = user.token
localStorage['login'] = user.login
}

View File

@ -1,25 +1,31 @@
import Wells from './Wells'
import Well from "../components/Well";
import LayoutPortal from './LayoutPortal'
import Deposit from './Deposit'
import Cluster from './Cluster'
import Well from "./Well";
import LayoutPortal from '../components/LayoutPortal'
import {Redirect, Route, Switch} from "react-router-dom";
export default function Main() {
return (
<Switch>
<Route path="/well/:id/">
<LayoutPortal>
<Well/>
</LayoutPortal>
</Route>
<Route path="/well">
<LayoutPortal>
<Wells/>
</LayoutPortal>
</Route>
<Route path="/">
<Redirect to={{pathname: `/well`}}/>
</Route>
</Switch>
return (
<Switch>
<Route path="/well/:id/">
<LayoutPortal>
<Well/>
</LayoutPortal>
</Route>
<Route path="/deposit">
<LayoutPortal noSheet>
<Deposit/>
</LayoutPortal>
</Route>
<Route path="/cluster/:id/">
<LayoutPortal>
<Cluster/>
</LayoutPortal>
</Route>
<Route path="/">
<Redirect to={{pathname: `/deposit`}}/>
</Route>
</Switch>
)
}

View File

@ -117,7 +117,7 @@ export default function Messages() {
return (
<>
<div className='filter-group'>
<h3 className='filter-group__heading'>Фильтр сообщений</h3>
<h3 className='filter-group-heading'>Фильтр сообщений</h3>
<Select
mode="multiple"
allowClear

View File

@ -78,7 +78,7 @@ export default function Report(props) {
title: 'Название отчета',
dataIndex: 'reportName',
key: 'reportName',
render: name => <a onClick={event => getReportFile(event, name)} download={name}>{name}</a>
render: name => <button onClick={event => getReportFile(event, name)} download={name}>{name}</button>
},
];
@ -91,10 +91,10 @@ export default function Report(props) {
<br />
<span> { progressData.operation } </span>
<br />
<a onClick={event => {getReportFile(event, progressData.reportName)}}
<button onClick={event => {getReportFile(event, progressData.reportName)}}
download={progressData.reportName}>
{ progressData.reportName }
</a>
</button>
</>
)
}
@ -183,7 +183,7 @@ export default function Report(props) {
}
getRepostSizeAsync()
},[rangeDate, step, format])
},[rangeDate, step, format, wellId])
useEffect(()=>{
async function getSuitableReportsAsync() {
@ -215,7 +215,7 @@ export default function Report(props) {
}
getSuitableReportsAsync()
},[rangeDate, step, format])
},[rangeDate, step, format, wellId])
useEffect(()=>{
async function getDatesRange() {
@ -225,7 +225,7 @@ export default function Report(props) {
}
getDatesRange()
},[])
},[wellId])
return (<>
<div className="w-100 mt-20px">

View File

@ -12,7 +12,7 @@ import moment from 'moment'
import {Subscribe} from '../services/signalr'
import {DataService, MessageService} from '../services/api'
import '../styles/message.css'
import notify from "../components/notify";
import notify from "../components/notify"
const {Option} = Select
@ -60,7 +60,7 @@ const axialLoadGroup = {
}
const hookWeightGroup = {
label: "Ввес на крюке",
label: "Вес на крюке",
yDisplay: false,
linePv: {label: "hookWeight", units: 'т', xAccessorName: "hookWeight", yAccessorName: "date", color: '#0aa'},
lineIdle: {
@ -114,7 +114,7 @@ const rotorTorqueGroup = {
const paramsGroups = [blockHeightGroup, blockSpeedGroup, pressureGroup, axialLoadGroup, hookWeightGroup, rotorTorqueGroup]
export const Column = ({lineGroup, data, interval}) => {
export const Column = ({lineGroup, data, interval, showBorder}) => {
let lines = [lineGroup.linePv]
if (lineGroup.lineSp)
@ -123,6 +123,12 @@ export const Column = ({lineGroup, data, interval}) => {
if (lineGroup.lineOther)
lines.push(lineGroup.lineOther)
if (lineGroup.lineAvg)
lines.push(lineGroup.lineAvg)
if (lineGroup.lineMax)
lines.push(lineGroup.lineMax)
let dataLast = null
let pv = null
if (data?.length > 0) {
@ -133,10 +139,12 @@ export const Column = ({lineGroup, data, interval}) => {
return (
<>
<Display
label={lineGroup.label}
value={pv}
suffix={lineGroup.linePv?.units} isArrowVisible={true}/>
<div style={{boxShadow: showBorder ? "inset 0px 0px 0px 3px black" : ""}}>
<Display
label={lineGroup.label}
value={pv}
suffix={lineGroup.linePv?.units} isArrowVisible={false}/>
</div>
<ChartTimeOnline
data={data}
yDisplay={lineGroup.yDisplay}
@ -197,10 +205,12 @@ const timePeriodCollection = [
export default function TelemetryView(props) {
let {id} = useParams()
const [saubData, setSaubData] = useState([])
const [chartInterval, setChartInterval] = useState(600)
const [chartInterval, setChartInterval] = useState(defaultInterval)
const [messages, setMessages] = useState([])
const [loader, setLoader] = useState(false) // , setLoader
const [loader, setLoader] = useState(false)
const periods = intervalSteps.map((line) => <Option key={line.value} value={line.value}>{line.label}</Option>)
const children = timePeriodCollection.map((line) => <Option key={line.value}>{line.label}</Option>)
@ -270,14 +280,14 @@ export default function TelemetryView(props) {
</Col>
</Row>
<Row>
<Col span={2}>
<Col span={3}>
<CustomColumn data={saubData}/>
</Col>
<Col span={24 - 2}>
<Col span={24 - 3}>
<Row>
{paramsGroups.map(group =>
{paramsGroups.map((group, index) =>
<Col span={colSpan} className='border_small' key={group.label}>
<Column data={saubData} lineGroup={group} interval={chartInterval}/>
<Column data={saubData} lineGroup={group} interval={chartInterval} showBorder = {saubData[saubData.length - 1]?.drillingBy === index}/>
</Col>)}
</Row>
</Col>

141
src/pages/Well.jsx Normal file
View File

@ -0,0 +1,141 @@
import {Layout, Menu} from "antd";
import {FolderOutlined, FundViewOutlined} from "@ant-design/icons";
import {Link, Redirect, Route, Switch, useParams} from "react-router-dom";
import Files from "../pages/Files";
import Archive from "../pages/Archive";
import Messages from "../pages/Messages";
import Report from "../pages/Report";
import Analysis from "../pages/Analysis";
import WellAnalysis from "../pages/WellAnalysis";
import Documents from "../components/Documents";
import LastData from '../pages/LastData'
import TelemetryView from "../pages/TelemetryView";
const { Content } = Layout
export default function Well() {
let { id } = useParams()
const {SubMenu} = Menu
return (<>
<Layout>
<Menu
mode="horizontal"
selectable={true}
className="well_menu"
>
<Menu.Item key="1" icon={<FundViewOutlined/>}>
<Link to='telemetry'>Мониторинг</Link>
</Menu.Item>
<Menu.Item key="2" icon={<FolderOutlined/>}>
<Link to='message'>Сообщения</Link>
</Menu.Item>
<Menu.Item key="3" icon={<FolderOutlined/>}>
<Link to='report'>Рапорт</Link>
</Menu.Item>
<Menu.Item key="4" icon={<FolderOutlined/>}>
<Link to='analysis'>Анализ</Link>
</Menu.Item>
<Menu.Item key="5" icon={<FolderOutlined/>}>
<Link to='wellAnalysis'>Операции по скважине</Link>
</Menu.Item>
<Menu.Item key="6" icon={<FolderOutlined/>}>
<Link to='file'>Файлы</Link>
</Menu.Item>
<Menu.Item key="7" icon={<FolderOutlined/>}>
<Link to='archive'>Архив</Link>
</Menu.Item>
<SubMenu
key="documentsSub"
title={<Link to='fluidService' className="linkDocuments">Документы</Link>}
icon={<FolderOutlined/>}
selectable={true}
>
<Menu.Item key="documentsSub1" icon={<FolderOutlined/>}>
<Link to='fluidService'>Растворный сервис</Link>
</Menu.Item>
<Menu.Item key="documentsSub1.1" icon={<FolderOutlined/>}>
<Link to='cementing'>Цементирование</Link>
</Menu.Item>
<Menu.Item key="documentsSub1.2" icon={<FolderOutlined/>}>
<Link to='nnb'>ННБ</Link>
</Menu.Item>
<Menu.Item key="documentsSub1.3" icon={<FolderOutlined/>}>
<Link to='gti'>ГТИ</Link>
</Menu.Item>
<Menu.Item key="documentsSub1.4" icon={<FolderOutlined/>}>
<Link to='documentsForWell'>Документы по скважине</Link>
</Menu.Item>
<Menu.Item key="documentsSub1.5" icon={<FolderOutlined/>}>
<Link to='supervisor'>Супервайзер</Link>
</Menu.Item>
<Menu.Item key="documentsSub1.6" icon={<FolderOutlined/>}>
<Link to='master'>Мастер</Link>
</Menu.Item>
<Menu.Item key="documentsSub1.7" icon={<FolderOutlined/>}>
<Link to='lastData'>Последние данные</Link>
</Menu.Item>
</SubMenu>
</Menu>
<Layout>
<Content className="site-layout-background">
<Switch>
<Route path="/well/:id/file">
<Files/>
</Route>
<Route path="/well/:id/archive">
<Archive/>
</Route>
<Route path="/well/:id/message">
<Messages/>
</Route>
<Route path="/well/:id/report">
<Report/>
</Route>
<Route path="/well/:id/analysis">
<Analysis/>
</Route>
<Route path="/well/:id/wellAnalysis">
<WellAnalysis/>
</Route>
<Route path="/well/:id/telemetry">
<TelemetryView/>
</Route>
<Route path="/well/:id/fluidService">
<Documents selectedFileCategory={1}/>
</Route>
<Route path="/well/:id/cementing">
<Documents selectedFileCategory={2}/>
</Route>
<Route path="/well/:id/nnb">
<Documents selectedFileCategory={3}/>
</Route>
<Route path="/well/:id/gti">
<Documents selectedFileCategory={4}/>
</Route>
<Route path="/well/:id/documentsForWell">
<Documents selectedFileCategory={5}/>
</Route>
<Route path="/well/:id/supervisor">
<Documents selectedFileCategory={6}/>
</Route>
<Route path="/well/:id/master">
<Documents selectedFileCategory={7}/>
</Route>
<Route path="/well/:id/lastData">
<LastData/>
</Route>
<Route path="/well/:id/documents">
<Documents/>
</Route>
<Route path="/">
<Redirect to={{pathname: `/well/${id}/telemetry`}}/>
</Route>
</Switch>
</Content>
</Layout>
</Layout>
</>)
}

159
src/pages/WellAnalysis.jsx Normal file
View File

@ -0,0 +1,159 @@
import {Table, Select, DatePicker, ConfigProvider} from 'antd';
import {AnalyticsService} from '../services/api'
import {useState, useEffect} from 'react'
import {useParams} from 'react-router-dom'
import notify from '../components/notify'
import LoaderPortal from '../components/LoaderPortal'
import locale from "antd/lib/locale/ru_RU";
import moment from 'moment'
import '../styles/message.css'
const {Option} = Select
const pageSize = 26
const {RangePicker} = DatePicker;
const columns = [
{
title: 'Название операции',
key: 'name',
dataIndex: 'name',
},
{
title: 'Дата начала операции',
key: 'beginDate',
dataIndex: 'beginDate',
render: (item) => moment.utc(item).local().format('DD MMM YYYY, HH:mm:ss')
},
{
title: 'Дата окончания операции',
key: 'endDate',
dataIndex: 'endDate',
render: (item) => moment.utc(item).local().format('DD MMM YYYY, HH:mm:ss')
},
{
title: 'Глубина скважины в начале операции',
key: 'beginWellDepth',
dataIndex: 'startWellDepth',
},
{
title: 'Глубина скважины в конце операции',
key: 'endWellDepth',
dataIndex: 'endWellDepth',
}
];
const filterOptions = [
{label: 'Невозможно определить операцию', value: 1},
{label: 'Роторное бурение', value: 2},
{label: 'Слайдирование', value: 3},
{label: 'Подъем с проработкой', value: 4},
{label: 'Спуск с проработкой', value: 5},
{label: 'Подъем с промывкой', value: 6},
{label: 'Спуск с промывкой', value: 7},
{label: 'Спуск в скважину', value: 8},
{label: 'Спуск с вращением', value: 9},
{label: 'Подъем из скважины', value: 10},
{label: 'Подъем с вращением', value: 11},
{label: 'Промывка в покое', value: 12},
{label: 'Промывка с вращением', value: 13},
{label: 'Удержание в клиньях', value: 14},
{label: 'Неподвижное состояние', value: 15},
{label: 'Вращение без циркуляции', value: 16},
{label: 'На поверхности', value: 17}
]
export default function WellAnalysis() {
let {id} = useParams()
const [page, setPage] = useState(1)
const [range, setRange] = useState([])
const [categories, setCategories] = useState([])
const [pagination, setPagination] = useState(null)
const [operations, setOperations] = useState([])
const [loader, setLoader] = useState(false)
const children = filterOptions.map((line) => <Option key={line.value}>{line.label}</Option>)
const onChangeRange = (range) => {
setRange(range)
}
useEffect(() => {
const GetOperations = async () => {
setLoader(true)
try {
let begin = null
let end = null
if (range?.length > 1) {
begin = range[0].toISOString()
end = range[1].toISOString()
}
await AnalyticsService.getOperationsByWell(
`${id}`,
(page-1) * pageSize,
pageSize,
categories,
begin,
end).then((paginatedOperations) => {
setOperations(paginatedOperations?.items.map(o => {
return {
key: o.id,
begin: o.date,
...o
}
}))
setPagination({
total: paginatedOperations?.count,
current: Math.floor(paginatedOperations?.skip / pageSize),
})
}
)
} catch (ex) {
notify(`Не удалось загрузить операции по скважине "${id}"`, 'error')
console.log(ex)
}
setLoader(false)
}
GetOperations()
}, [id, categories, range, page])
return(<>
<div className='filter-group'>
<h3 className='filter-group-heading'>Фильтр операций</h3>
<Select
mode="multiple"
allowClear
placeholder="Фильтр операций"
className="filter-selector"
value={categories}
onChange={setCategories}>
{children}
</Select>
<ConfigProvider locale={locale}>
<RangePicker
showTime
placeholder={["Дата начала операции", "Дата окончания операции"]}
onChange={onChangeRange}
/>
</ConfigProvider>
</div>
<LoaderPortal show={loader}>
<Table
columns={columns}
dataSource={operations}
size={'small'}
pagination={{
pageSize: pageSize,
showSizeChanger: false,
total: pagination?.total,
current: page,
onChange: (page) => setPage(page)
}}
rowKey={(record) => record.id}
/>
</LoaderPortal>
</>)
}

View File

@ -1,65 +0,0 @@
import { useState, useEffect } from 'react'
import { WellService } from '../services/api'
import LoaderPortal from '../components/LoaderPortal'
import { Table } from 'antd' // TreeSelect
import { useHistory } from 'react-router-dom'
import notify from '../components/notify'
const columns = [
{
title: 'Месторождение',
dataIndex: 'deposit',
key: 'deposit',
},
{
title: 'Куст',
dataIndex: 'cluster',
key: 'cluster',
},
{
title: 'Скважина',
dataIndex: 'caption',
key: 'caption',
},
{
title: 'Данные',
dataIndex: 'lastData',
key: 'lastData',
},
];
export default function Wells(props){
const [wells, setWells] = useState([])
const [loader, setLoader] = useState(false)
const history = useHistory()
const updateWellsList = async () => {
setLoader(true)
try{
let newWells = (await WellService.getWells()).map(w =>{return {key:w.id, ...w}})
console.log(newWells)
setWells( newWells )
}
catch(e){
notify('Не удалось загрузить список скважин', 'error')
console.error(`${e}`);
}
setLoader(false)
}
useEffect(()=>updateWellsList(), [])
return(<>
<h2>Скважины</h2>
<LoaderPortal show={loader}>
<Table
dataSource={wells}
columns={columns}
onRow={(record) => {
return {
onClick: event => {history.push(`/well/${record.id}/`)},
};
}}/>
</LoaderPortal>
</>)
}

View File

@ -5,11 +5,19 @@ export { ApiError } from './core/ApiError';
export { OpenAPI } from './core/OpenAPI';
export type { AuthDto } from './models/AuthDto';
export type { ClusterDto } from './models/ClusterDto';
export type { ClusterStatDto } from './models/ClusterStatDto';
export type { CompanyDto } from './models/CompanyDto';
export type { DataSaubBaseDto } from './models/DataSaubBaseDto';
export type { DatesRangeDto } from './models/DatesRangeDto';
export type { DepositDto } from './models/DepositDto';
export type { EventDto } from './models/EventDto';
export type { FilePropertiesDto } from './models/FilePropertiesDto';
export type { FilePropertiesDtoPaginationContainer } from './models/FilePropertiesDtoPaginationContainer';
export type { MessageDto } from './models/MessageDto';
export type { MessageDtoPaginationContainer } from './models/MessageDtoPaginationContainer';
export type { OperationDto } from './models/OperationDto';
export type { OperationDtoPaginationContainer } from './models/OperationDtoPaginationContainer';
export type { OperationDurationDto } from './models/OperationDurationDto';
export type { TelemetryInfoDto } from './models/TelemetryInfoDto';
export type { TelemetryMessageDto } from './models/TelemetryMessageDto';
@ -18,10 +26,15 @@ export type { UserTokenDto } from './models/UserTokenDto';
export type { WellDepthToDayDto } from './models/WellDepthToDayDto';
export type { WellDepthToIntervalDto } from './models/WellDepthToIntervalDto';
export type { WellDto } from './models/WellDto';
export type { WellSectionDto } from './models/WellSectionDto';
export type { WellStatDto } from './models/WellStatDto';
export { AnalyticsService } from './services/AnalyticsService';
export { AuthService } from './services/AuthService';
export { ClusterService } from './services/ClusterService';
export { DataService } from './services/DataService';
export { DepositService } from './services/DepositService';
export { FileService } from './services/FileService';
export { MessageService } from './services/MessageService';
export { ReportService } from './services/ReportService';
export { TelemetryService } from './services/TelemetryService';

View File

@ -0,0 +1,14 @@
/* istanbul ignore file */
/* tslint:disable */
/* eslint-disable */
import type { WellDto } from './WellDto';
export type ClusterDto = {
id?: number;
caption?: string | null;
description?: string | null;
latitude?: number | null;
longitude?: number | null;
wells?: Array<WellDto> | null;
}

View File

@ -0,0 +1,16 @@
/* istanbul ignore file */
/* tslint:disable */
/* eslint-disable */
import type { WellDto } from './WellDto';
import type { WellStatDto } from './WellStatDto';
export type ClusterStatDto = {
id?: number;
caption?: string | null;
description?: string | null;
latitude?: number | null;
longitude?: number | null;
wells?: Array<WellDto> | null;
wellsStat?: Array<WellStatDto> | null;
}

View File

@ -0,0 +1,9 @@
/* istanbul ignore file */
/* tslint:disable */
/* eslint-disable */
export type CompanyDto = {
id?: number;
caption?: string | null;
companyType?: string | null;
}

View File

@ -38,4 +38,6 @@ export type DataSaubBaseDto = {
flow?: number | null;
flowIdle?: number | null;
flowDeltaLimitMax?: number | null;
idFeedRegulator?: number | null;
mseState?: number | null;
}

View File

@ -0,0 +1,14 @@
/* istanbul ignore file */
/* tslint:disable */
/* eslint-disable */
import type { ClusterDto } from './ClusterDto';
export type DepositDto = {
id?: number;
caption?: string | null;
description?: string | null;
latitude?: number | null;
longitude?: number | null;
clusters?: Array<ClusterDto> | null;
}

View File

@ -0,0 +1,11 @@
/* istanbul ignore file */
/* tslint:disable */
/* eslint-disable */
export type FilePropertiesDto = {
id?: number;
name?: string | null;
idCategory?: number;
uploadDate?: string;
userName?: string | null;
}

View File

@ -0,0 +1,12 @@
/* istanbul ignore file */
/* tslint:disable */
/* eslint-disable */
import type { FilePropertiesDto } from './FilePropertiesDto';
export type FilePropertiesDtoPaginationContainer = {
skip?: number;
take?: number;
count?: number;
items?: Array<FilePropertiesDto> | null;
}

View File

@ -0,0 +1,12 @@
/* istanbul ignore file */
/* tslint:disable */
/* eslint-disable */
export type OperationDto = {
id?: number;
name?: string | null;
beginDate?: string;
endDate?: string;
startWellDepth?: number;
endWellDepth?: number;
}

View File

@ -0,0 +1,12 @@
/* istanbul ignore file */
/* tslint:disable */
/* eslint-disable */
import type { OperationDto } from './OperationDto';
export type OperationDtoPaginationContainer = {
skip?: number;
take?: number;
count?: number;
items?: Array<OperationDto> | null;
}

View File

@ -3,6 +3,6 @@
/* eslint-disable */
export type OperationDurationDto = {
processName?: string | null;
operationName?: string | null;
duration?: number;
}

View File

@ -9,7 +9,7 @@ export type UserTokenDto = {
surname?: string | null;
patronymic?: string | null;
id?: number;
customerName?: string | null;
companyName?: string | null;
roleName?: string | null;
token?: string | null;
}

View File

@ -7,5 +7,7 @@ export type WellDto = {
cluster?: string | null;
deposit?: string | null;
id?: number;
lastData?: any;
latitude?: number | null;
longitude?: number | null;
wellType?: string | null;
}

View File

@ -0,0 +1,21 @@
/* istanbul ignore file */
/* tslint:disable */
/* eslint-disable */
export type WellSectionDto = {
sectionType?: string | null;
wellDepthPlan?: number;
wellDepthFact?: number;
buildDaysPlan?: number;
buildDaysFact?: number;
rateOfPenetrationPlan?: number;
rateOfPenetrationFact?: number;
routeSpeedPlan?: number;
routeSpeedFact?: number;
bhaUpSpeedPlan?: number;
bhaUpSpeedFact?: number;
bhaDownSpeedPlan?: number;
bhaDownSpeedFact?: number;
casingDownSpeedPlan?: number;
casingDownSpeedFact?: number;
}

View File

@ -0,0 +1,27 @@
/* istanbul ignore file */
/* tslint:disable */
/* eslint-disable */
import type { CompanyDto } from './CompanyDto';
import type { WellSectionDto } from './WellSectionDto';
export type WellStatDto = {
caption?: string | null;
cluster?: string | null;
deposit?: string | null;
id?: number;
latitude?: number | null;
longitude?: number | null;
wellType?: string | null;
planStart?: string | null;
planEnd?: string | null;
factStart?: string | null;
factEnd?: string | null;
unProductiveDays?: number | null;
rateOfPenetrationPlan?: number | null;
rateOfPenetrationFact?: number | null;
routeSpeedPlan?: number | null;
routeSpeedFact?: number | null;
sections?: Array<WellSectionDto> | null;
companies?: Array<CompanyDto> | null;
}

View File

@ -1,6 +1,7 @@
/* istanbul ignore file */
/* tslint:disable */
/* eslint-disable */
import type { OperationDtoPaginationContainer } from '../models/OperationDtoPaginationContainer';
import type { OperationDurationDto } from '../models/OperationDurationDto';
import type { WellDepthToDayDto } from '../models/WellDepthToDayDto';
import type { WellDepthToIntervalDto } from '../models/WellDepthToIntervalDto';
@ -8,6 +9,39 @@ import { request as __request } from '../core/request';
export class AnalyticsService {
/**
* Возвращает список операций на скважине за все время
* @param wellId id скважины
* @param skip для пагинации кол-во записей пропустить
* @param take для пагинации кол-во записей
* @param categoryIds список категорий
* @param begin дата начала
* @param end окончание
* @returns OperationDtoPaginationContainer Success
* @throws ApiError
*/
public static async getOperationsByWell(
wellId: number,
skip: number,
take: number = 32,
categoryIds?: Array<number>,
begin?: string,
end?: string,
): Promise<OperationDtoPaginationContainer> {
const result = await __request({
method: 'GET',
path: `/api/analytics/${wellId}/operationsByWell`,
query: {
'skip': skip,
'take': take,
'categoryIds': categoryIds,
'begin': begin,
'end': end,
},
});
return result.body;
}
/**
* Возвращает данные по скважине "глубина-день"
* @param wellId id скважины
@ -27,22 +61,22 @@ wellId: number,
/**
* Возвращает данные по глубине скважины за период
* @param wellId id скважины
* @param intervalHoursTimestamp количество секунд в необходимом интервале времени
* @param workBeginTimestamp количество секунд в времени начала смены
* @param intervalSeconds количество секунд в необходимом интервале времени
* @param workBeginSeconds количество секунд в времени начала смены
* @returns WellDepthToIntervalDto Success
* @throws ApiError
*/
public static async getWellDepthToInterval(
wellId: number,
intervalHoursTimestamp?: number,
workBeginTimestamp?: number,
intervalSeconds?: number,
workBeginSeconds?: number,
): Promise<Array<WellDepthToIntervalDto>> {
const result = await __request({
method: 'GET',
path: `/api/analytics/${wellId}/wellDepthToInterval`,
query: {
'intervalHoursTimestamp': intervalHoursTimestamp,
'workBeginTimestamp': workBeginTimestamp,
'intervalSeconds': intervalSeconds,
'workBeginSeconds': workBeginSeconds,
},
});
return result.body;
@ -75,22 +109,22 @@ end?: string,
/**
* Возвращает детальные данные по операциям на скважине за период
* @param wellId id скважины
* @param intervalHoursTimestamp количество секунд в необходимом интервале времени
* @param workBeginTimestamp количество секунд в времени начала смены
* @param intervalSeconds количество секунд в необходимом интервале времени
* @param workBeginSeconds количество секунд в времени начала смены
* @returns OperationDurationDto Success
* @throws ApiError
*/
public static async getOperationsToInterval(
wellId: number,
intervalHoursTimestamp?: number,
workBeginTimestamp?: number,
intervalSeconds?: number,
workBeginSeconds?: number,
): Promise<Array<OperationDurationDto>> {
const result = await __request({
method: 'GET',
path: `/api/analytics/${wellId}/operationsToInterval`,
query: {
'intervalHoursTimestamp': intervalHoursTimestamp,
'workBeginTimestamp': workBeginTimestamp,
'intervalSeconds': intervalSeconds,
'workBeginSeconds': workBeginSeconds,
},
});
return result.body;

View File

@ -0,0 +1,56 @@
/* istanbul ignore file */
/* tslint:disable */
/* eslint-disable */
import type { ClusterDto } from '../models/ClusterDto';
import type { ClusterStatDto } from '../models/ClusterStatDto';
import type { WellDto } from '../models/WellDto';
import { request as __request } from '../core/request';
export class ClusterService {
/**
* Получает список доступных пользователю кустов
* @returns ClusterDto Success
* @throws ApiError
*/
public static async getClusters(): Promise<Array<ClusterDto>> {
const result = await __request({
method: 'GET',
path: `/api/cluster`,
});
return result.body;
}
/**
* Получение доступных пользователю скважин
* @param idCluster
* @returns WellDto Success
* @throws ApiError
*/
public static async getWells(
idCluster: number,
): Promise<Array<WellDto>> {
const result = await __request({
method: 'GET',
path: `/api/cluster/${idCluster}`,
});
return result.body;
}
/**
* Получение обопщенной статистики по кусту (лучшая/худшая скважина)
* @param idCluster
* @returns ClusterStatDto Success
* @throws ApiError
*/
public static async getStat(
idCluster: number,
): Promise<ClusterStatDto> {
const result = await __request({
method: 'GET',
path: `/api/cluster/${idCluster}/Stat`,
});
return result.body;
}
}

View File

@ -13,7 +13,7 @@ export class DataService {
* @param wellId id скважины
* @param begin дата начала выборки. По умолчанию: текущее время - intervalSec
* @param intervalSec интервал времени даты начала выборки, секунды
* @param approxPointsCount желаемое количество точек. Если в выборке точек будет больше, то выборка будет прорежена.
* @param approxPointsCount жела<EFBFBD><EFBFBD>мое количество точек. Если в выборке точек будет больше, то выборка будет прорежена.
* @returns DataSaubBaseDto Success
* @throws ApiError
*/

View File

@ -0,0 +1,39 @@
/* istanbul ignore file */
/* tslint:disable */
/* eslint-disable */
import type { ClusterDto } from '../models/ClusterDto';
import type { DepositDto } from '../models/DepositDto';
import { request as __request } from '../core/request';
export class DepositService {
/**
* Получает список доступных пользователю месторождений
* @returns DepositDto Success
* @throws ApiError
*/
public static async getDeposits(): Promise<Array<DepositDto>> {
const result = await __request({
method: 'GET',
path: `/api/deposit`,
});
return result.body;
}
/**
* Получает список доступных пользователю кустов месторождения
* @param depositId
* @returns ClusterDto Success
* @throws ApiError
*/
public static async getClusters(
depositId: number,
): Promise<Array<ClusterDto>> {
const result = await __request({
method: 'GET',
path: `/api/deposit/${depositId}`,
});
return result.body;
}
}

View File

@ -0,0 +1,87 @@
/* istanbul ignore file */
/* tslint:disable */
/* eslint-disable */
import type { FilePropertiesDtoPaginationContainer } from '../models/FilePropertiesDtoPaginationContainer';
import { request as __request } from '../core/request';
export class FileService {
/**
* Сохраняет переданные файлы и информацию о них
* @param wellId id скважины
* @param idCategory id категории файла
* @param idUser id отправившего файл пользователя
* @param requestBody
* @returns number Success
* @throws ApiError
*/
public static async saveFiles(
wellId: number,
idCategory?: number,
idUser?: number,
requestBody?: any,
): Promise<number> {
const result = await __request({
method: 'POST',
path: `/api/files/${wellId}/files`,
query: {
'idCategory': idCategory,
'idUser': idUser,
},
body: requestBody,
});
return result.body;
}
/**
* Возвращает информацию о файлах для сква<EFBFBD><EFBFBD>ины в выбраной категории
* @param wellId id скважины
* @param skip для пагинации кол-во записей пропустить
* @param take для пагинации кол-во записей взять
* @param idCategory id категории файла
* @param begin дата начала
* @param end дата окончания
* @returns FilePropertiesDtoPaginationContainer Success
* @throws ApiError
*/
public static async getFilesInfo(
wellId: number,
skip: number,
take: number = 32,
idCategory: number,
begin?: string,
end?: string,
): Promise<FilePropertiesDtoPaginationContainer> {
const result = await __request({
method: 'GET',
path: `/api/files/${wellId}`,
query: {
'skip': skip,
'take': take,
'idCategory': idCategory,
'begin': begin,
'end': end,
},
});
return result.body;
}
/**
* Возвращает файл с диска на сервере
* @param wellId id скважины
* @param fileId id запрашиваемого файла
* @returns string Success
* @throws ApiError
*/
public static async getFile(
wellId: number,
fileId: number,
): Promise<string> {
const result = await __request({
method: 'GET',
path: `/api/files/${wellId}/${fileId}`,
});
return result.body;
}
}

View File

@ -116,7 +116,7 @@ end?: string,
}
/**
* Возвращает даты самого старого и самого свежего отчетов в БД
* Возвра<EFBFBD><EFBFBD>ает даты самого старого и самого свежего отчетов в БД
* @param wellId id скважины
* @returns DatesRangeDto Success
* @throws ApiError

View File

@ -12,16 +12,21 @@ type ConnectionsDict = {
[route: string]: HubConnection;
};
//var baseUrl = `http://192.168.1.70:5000`
var baseUrl = process.env.NODE_ENV === 'development'
?'http://192.168.1.70:5000'
:''
const Connections: ConnectionsDict = {
'hubs/telemetry': new HubConnectionBuilder()
.withUrl(`http://192.168.1.70:5000/hubs/telemetry`, ConnectionOptions)
.withAutomaticReconnect()
.build(),
.withUrl(`${baseUrl}/hubs/telemetry`, ConnectionOptions)//
.withAutomaticReconnect()
.build(),
'hubs/reports': new HubConnectionBuilder()
.withUrl(`http://192.168.1.70:5000/hubs/reports`, ConnectionOptions)
.withAutomaticReconnect()
.build()
.withUrl(`${baseUrl}/hubs/reports`, ConnectionOptions)
.withAutomaticReconnect()
.build()
}
let connectionPromise: Promise<void>
@ -43,6 +48,21 @@ type handlerFunction = (...args: any[]) => void;
type cleanFunction = (...args: any[]) => void;
const MakeUnsubscribeFunction = (
connection: HubConnection,
methodName: string,
groupName: (string|null)):cleanFunction => {
return async() => {
if(connection.state === HubConnectionState.Connected)
{
if(groupName)
await connection.send('RemoveFromGroup', groupName)
connection.off(methodName)
}
connection.stop()
}
}
/** Subscribe on some SignalR method (topic).
* @example useEffect(() => Subscribe('methodName', `${id}`, handleNewData), [id]);
* @param {string} methodName name of the method
@ -61,12 +81,7 @@ const Subscribe = (
connection.on(methodName, handler)
})
if(groupName)
return () => {
Connections[hubUrl].send('RemoveFromGroup', groupName)
.finally(()=>Connections[hubUrl].off(methodName))
}
return () => Connections[hubUrl].off(methodName)
return MakeUnsubscribeFunction(Connections[hubUrl],methodName,groupName)
}
/** Invokes some SignalR method.

View File

@ -163,6 +163,7 @@ tr.table_row_size {
}
.header-tree-select{
width: 300px;
border: 1px solid rgba(255, 255, 255, 0.2);
background-color: rgba(0, 0, 0, 0.3);
}

View File

@ -48,3 +48,11 @@ code {
monospace;
}
.linkDocuments {
color: #000;
}
.linkDocuments:hover {
color: #c32828;
}

View File

@ -33,7 +33,7 @@
margin: 0 0 5px 0;
}
.filter-group__heading {
.filter-group-heading {
margin: 5px auto;
align-items: center;
}