Create drone model & First connect frontend + backend
This commit is contained in:
parent
5eef7db6a0
commit
63f4e70896
@ -36,19 +36,19 @@ services:
|
||||
- dns_net
|
||||
restart: always
|
||||
|
||||
# nginx:
|
||||
# image: nginx:alpine
|
||||
# container_name: geotouchka-nginx-service
|
||||
# ports:
|
||||
# - "${NGINX_PORT}:80"
|
||||
# volumes:
|
||||
# # - ./frontend/geotouchka-web-application/build:/usr/share/nginx/html
|
||||
# - ./nginx.conf:/etc/nginx/nginx.conf
|
||||
# networks:
|
||||
# - dns_net
|
||||
# depends_on:
|
||||
# - site
|
||||
# restart: always
|
||||
nginx:
|
||||
image: nginx:alpine
|
||||
container_name: dns-nginx
|
||||
ports:
|
||||
- "${NGINX_PORT}:80"
|
||||
volumes:
|
||||
# - ./frontend/geotouchka-web-application/build:/usr/share/nginx/html
|
||||
- ./nginx.conf:/etc/nginx/nginx.conf
|
||||
networks:
|
||||
- dns_net
|
||||
depends_on:
|
||||
- front
|
||||
restart: always
|
||||
|
||||
server:
|
||||
container_name: dns-server
|
||||
|
@ -6,10 +6,10 @@ http {
|
||||
server {
|
||||
listen 80;
|
||||
server_name localhost;
|
||||
add_header 'Access-Control-Allow-Origin' 'http://site' always;
|
||||
add_header 'Access-Control-Allow-Origin' 'http://front' always;
|
||||
|
||||
location / {
|
||||
proxy_pass http://site:3000;
|
||||
proxy_pass http://front:3000;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
|
308
src/frontend/package-lock.json
generated
308
src/frontend/package-lock.json
generated
@ -11,16 +11,13 @@
|
||||
"@testing-library/jest-dom": "^5.17.0",
|
||||
"@testing-library/react": "^13.4.0",
|
||||
"@testing-library/user-event": "^13.5.0",
|
||||
"leaflet": "^1.9.4",
|
||||
"leaflet-defaulticon-compatibility": "^0.1.2",
|
||||
"bootstrap-icons": "^1.11.3",
|
||||
"qrcode.react": "^4.0.1",
|
||||
"react": "^18.3.1",
|
||||
"react-dom": "^18.3.1",
|
||||
"react-leaflet": "^4.2.1",
|
||||
"react-modal": "^3.16.1",
|
||||
"react-router-dom": "^6.26.2",
|
||||
"react-scripts": "5.0.1",
|
||||
"socket.io": "^4.8.0",
|
||||
"socket.io-client": "^4.8.0",
|
||||
"three": "^0.169.0",
|
||||
"web-vitals": "^2.1.4"
|
||||
},
|
||||
@ -3551,17 +3548,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@react-leaflet/core": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@react-leaflet/core/-/core-2.1.0.tgz",
|
||||
"integrity": "sha512-Qk7Pfu8BSarKGqILj4x7bCSZ1pjuAPZ+qmRwH5S7mDS91VSbVVsJSrW4qA+GPrro8t69gFYVMWb1Zc4yFmPiVg==",
|
||||
"license": "Hippocratic-2.1",
|
||||
"peerDependencies": {
|
||||
"leaflet": "^1.9.0",
|
||||
"react": "^18.0.0",
|
||||
"react-dom": "^18.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@remix-run/router": {
|
||||
"version": "1.19.2",
|
||||
"resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.19.2.tgz",
|
||||
@ -3686,12 +3672,6 @@
|
||||
"@sinonjs/commons": "^1.7.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@socket.io/component-emitter": {
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.2.tgz",
|
||||
"integrity": "sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@surma/rollup-plugin-off-main-thread": {
|
||||
"version": "2.2.3",
|
||||
"resolved": "https://registry.npmjs.org/@surma/rollup-plugin-off-main-thread/-/rollup-plugin-off-main-thread-2.2.3.tgz",
|
||||
@ -4346,21 +4326,6 @@
|
||||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/cookie": {
|
||||
"version": "0.4.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.4.1.tgz",
|
||||
"integrity": "sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/cors": {
|
||||
"version": "2.8.17",
|
||||
"resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.17.tgz",
|
||||
"integrity": "sha512-8CGDvrBj1zgo2qE+oS3pOCyYNqCPryMWY2bGfwA0dcfopWGgxs+78df0Rs3rc9THP4JkOhLsAa+15VdpAqkcUA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/eslint": {
|
||||
"version": "8.56.12",
|
||||
"resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.56.12.tgz",
|
||||
@ -6182,15 +6147,6 @@
|
||||
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/base64id": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/base64id/-/base64id-2.0.0.tgz",
|
||||
"integrity": "sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": "^4.5.0 || >= 5.9"
|
||||
}
|
||||
},
|
||||
"node_modules/batch": {
|
||||
"version": "0.6.1",
|
||||
"resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz",
|
||||
@ -6316,6 +6272,21 @@
|
||||
"integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==",
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/bootstrap-icons": {
|
||||
"version": "1.11.3",
|
||||
"resolved": "https://registry.npmjs.org/bootstrap-icons/-/bootstrap-icons-1.11.3.tgz",
|
||||
"integrity": "sha512-+3lpHrCw/it2/7lBL15VR0HEumaBss0+f/Lb6ZvHISn1mlK83jjFpooTLsMWbIjJMDjDjOExMsTxnXSIT4k4ww==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/twbs"
|
||||
},
|
||||
{
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/bootstrap"
|
||||
}
|
||||
]
|
||||
},
|
||||
"node_modules/brace-expansion": {
|
||||
"version": "1.1.11",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
|
||||
@ -6887,19 +6858,6 @@
|
||||
"integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/cors": {
|
||||
"version": "2.8.5",
|
||||
"resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz",
|
||||
"integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"object-assign": "^4",
|
||||
"vary": "^1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.10"
|
||||
}
|
||||
},
|
||||
"node_modules/cosmiconfig": {
|
||||
"version": "7.1.0",
|
||||
"resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz",
|
||||
@ -7856,100 +7814,6 @@
|
||||
"node": ">= 0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/engine.io": {
|
||||
"version": "6.6.1",
|
||||
"resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.6.1.tgz",
|
||||
"integrity": "sha512-NEpDCw9hrvBW+hVEOK4T7v0jFJ++KgtPl4jKFwsZVfG1XhS0dCrSb3VMb9gPAd7VAdW52VT1EnaNiU2vM8C0og==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/cookie": "^0.4.1",
|
||||
"@types/cors": "^2.8.12",
|
||||
"@types/node": ">=10.0.0",
|
||||
"accepts": "~1.3.4",
|
||||
"base64id": "2.0.0",
|
||||
"cookie": "~0.4.1",
|
||||
"cors": "~2.8.5",
|
||||
"debug": "~4.3.1",
|
||||
"engine.io-parser": "~5.2.1",
|
||||
"ws": "~8.17.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/engine.io-client": {
|
||||
"version": "6.6.1",
|
||||
"resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-6.6.1.tgz",
|
||||
"integrity": "sha512-aYuoak7I+R83M/BBPIOs2to51BmFIpC1wZe6zZzMrT2llVsHy5cvcmdsJgP2Qz6smHu+sD9oexiSUAVd8OfBPw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@socket.io/component-emitter": "~3.1.0",
|
||||
"debug": "~4.3.1",
|
||||
"engine.io-parser": "~5.2.1",
|
||||
"ws": "~8.17.1",
|
||||
"xmlhttprequest-ssl": "~2.1.1"
|
||||
}
|
||||
},
|
||||
"node_modules/engine.io-client/node_modules/ws": {
|
||||
"version": "8.17.1",
|
||||
"resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz",
|
||||
"integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=10.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"bufferutil": "^4.0.1",
|
||||
"utf-8-validate": ">=5.0.2"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"bufferutil": {
|
||||
"optional": true
|
||||
},
|
||||
"utf-8-validate": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/engine.io-parser": {
|
||||
"version": "5.2.3",
|
||||
"resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.2.3.tgz",
|
||||
"integrity": "sha512-HqD3yTBfnBxIrbnM1DoD6Pcq8NECnh8d4As1Qgh0z5Gg3jRRIqijury0CL3ghu/edArpUYiYqQiDUQBIs4np3Q==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=10.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/engine.io/node_modules/cookie": {
|
||||
"version": "0.4.2",
|
||||
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz",
|
||||
"integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/engine.io/node_modules/ws": {
|
||||
"version": "8.17.1",
|
||||
"resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz",
|
||||
"integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=10.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"bufferutil": "^4.0.1",
|
||||
"utf-8-validate": ">=5.0.2"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"bufferutil": {
|
||||
"optional": true
|
||||
},
|
||||
"utf-8-validate": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/enhanced-resolve": {
|
||||
"version": "5.17.1",
|
||||
"resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.17.1.tgz",
|
||||
@ -8999,6 +8863,11 @@
|
||||
"url": "https://github.com/sindresorhus/execa?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/exenv": {
|
||||
"version": "1.2.2",
|
||||
"resolved": "https://registry.npmjs.org/exenv/-/exenv-1.2.2.tgz",
|
||||
"integrity": "sha512-Z+ktTxTwv9ILfgKCk32OX3n/doe+OcLTRtqK9pcL+JsP3J1/VW8Uvl4ZjLlKqeW4rzK4oesDOGMEMRIZqtP4Iw=="
|
||||
},
|
||||
"node_modules/exit": {
|
||||
"version": "0.1.2",
|
||||
"resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz",
|
||||
@ -13497,18 +13366,6 @@
|
||||
"shell-quote": "^1.8.1"
|
||||
}
|
||||
},
|
||||
"node_modules/leaflet": {
|
||||
"version": "1.9.4",
|
||||
"resolved": "https://registry.npmjs.org/leaflet/-/leaflet-1.9.4.tgz",
|
||||
"integrity": "sha512-nxS1ynzJOmOlHp+iL3FyWqK89GtNL8U8rvlMOsQdTTssxZwCXh8N2NB3GDQOL+YR3XnWyZAxwQixURb+FA74PA==",
|
||||
"license": "BSD-2-Clause"
|
||||
},
|
||||
"node_modules/leaflet-defaulticon-compatibility": {
|
||||
"version": "0.1.2",
|
||||
"resolved": "https://registry.npmjs.org/leaflet-defaulticon-compatibility/-/leaflet-defaulticon-compatibility-0.1.2.tgz",
|
||||
"integrity": "sha512-IrKagWxkTwzxUkFIumy/Zmo3ksjuAu3zEadtOuJcKzuXaD76Gwvg2Z1mLyx7y52ykOzM8rAH5ChBs4DnfdGa6Q==",
|
||||
"license": "BSD-2-Clause"
|
||||
},
|
||||
"node_modules/leven": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz",
|
||||
@ -16046,7 +15903,6 @@
|
||||
"version": "4.0.1",
|
||||
"resolved": "https://registry.npmjs.org/qrcode.react/-/qrcode.react-4.0.1.tgz",
|
||||
"integrity": "sha512-Lpj0tPBn561WiQ3QQWXbkx8xTtB8BZkJeMZWLJIL8iaPBCoWzW1IpCeU3gY5MDqsb0+efCvEGkl9O0naP64crA==",
|
||||
"license": "ISC",
|
||||
"peerDependencies": {
|
||||
"react": "^16.8.0 || ^17.0.0 || ^18.0.0"
|
||||
}
|
||||
@ -16402,18 +16258,27 @@
|
||||
"integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/react-leaflet": {
|
||||
"version": "4.2.1",
|
||||
"resolved": "https://registry.npmjs.org/react-leaflet/-/react-leaflet-4.2.1.tgz",
|
||||
"integrity": "sha512-p9chkvhcKrWn/H/1FFeVSqLdReGwn2qmiobOQGO3BifX+/vV/39qhY8dGqbdcPh1e6jxh/QHriLXr7a4eLFK4Q==",
|
||||
"license": "Hippocratic-2.1",
|
||||
"node_modules/react-lifecycles-compat": {
|
||||
"version": "3.0.4",
|
||||
"resolved": "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz",
|
||||
"integrity": "sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA=="
|
||||
},
|
||||
"node_modules/react-modal": {
|
||||
"version": "3.16.1",
|
||||
"resolved": "https://registry.npmjs.org/react-modal/-/react-modal-3.16.1.tgz",
|
||||
"integrity": "sha512-VStHgI3BVcGo7OXczvnJN7yT2TWHJPDXZWyI/a0ssFNhGZWsPmB8cF0z33ewDXq4VfYMO1vXgiv/g8Nj9NDyWg==",
|
||||
"dependencies": {
|
||||
"@react-leaflet/core": "^2.1.0"
|
||||
"exenv": "^1.2.0",
|
||||
"prop-types": "^15.7.2",
|
||||
"react-lifecycles-compat": "^3.0.0",
|
||||
"warning": "^4.0.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"leaflet": "^1.9.0",
|
||||
"react": "^18.0.0",
|
||||
"react-dom": "^18.0.0"
|
||||
"react": "^0.14.0 || ^15.0.0 || ^16 || ^17 || ^18",
|
||||
"react-dom": "^0.14.0 || ^15.0.0 || ^16 || ^17 || ^18"
|
||||
}
|
||||
},
|
||||
"node_modules/react-refresh": {
|
||||
@ -17518,83 +17383,6 @@
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/socket.io": {
|
||||
"version": "4.8.0",
|
||||
"resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.8.0.tgz",
|
||||
"integrity": "sha512-8U6BEgGjQOfGz3HHTYaC/L1GaxDCJ/KM0XTkJly0EhZ5U/du9uNEZy4ZgYzEzIqlx2CMm25CrCqr1ck899eLNA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"accepts": "~1.3.4",
|
||||
"base64id": "~2.0.0",
|
||||
"cors": "~2.8.5",
|
||||
"debug": "~4.3.2",
|
||||
"engine.io": "~6.6.0",
|
||||
"socket.io-adapter": "~2.5.2",
|
||||
"socket.io-parser": "~4.2.4"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/socket.io-adapter": {
|
||||
"version": "2.5.5",
|
||||
"resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-2.5.5.tgz",
|
||||
"integrity": "sha512-eLDQas5dzPgOWCk9GuuJC2lBqItuhKI4uxGgo9aIV7MYbk2h9Q6uULEh8WBzThoI7l+qU9Ast9fVUmkqPP9wYg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"debug": "~4.3.4",
|
||||
"ws": "~8.17.1"
|
||||
}
|
||||
},
|
||||
"node_modules/socket.io-adapter/node_modules/ws": {
|
||||
"version": "8.17.1",
|
||||
"resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz",
|
||||
"integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=10.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"bufferutil": "^4.0.1",
|
||||
"utf-8-validate": ">=5.0.2"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"bufferutil": {
|
||||
"optional": true
|
||||
},
|
||||
"utf-8-validate": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/socket.io-client": {
|
||||
"version": "4.8.0",
|
||||
"resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-4.8.0.tgz",
|
||||
"integrity": "sha512-C0jdhD5yQahMws9alf/yvtsMGTaIDBnZ8Rb5HU56svyq0l5LIrGzIDZZD5pHQlmzxLuU91Gz+VpQMKgCTNYtkw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@socket.io/component-emitter": "~3.1.0",
|
||||
"debug": "~4.3.2",
|
||||
"engine.io-client": "~6.6.1",
|
||||
"socket.io-parser": "~4.2.4"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/socket.io-parser": {
|
||||
"version": "4.2.4",
|
||||
"resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.4.tgz",
|
||||
"integrity": "sha512-/GbIKmo8ioc+NIWIhwdecY0ge+qVBSMdgxGygevmdHj24bsfgtCmcUUcQ5ZzcylGFHsN3k4HB4Cgkl96KVnuew==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@socket.io/component-emitter": "~3.1.0",
|
||||
"debug": "~4.3.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/sockjs": {
|
||||
"version": "0.3.24",
|
||||
"resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.24.tgz",
|
||||
@ -19174,6 +18962,14 @@
|
||||
"makeerror": "1.0.12"
|
||||
}
|
||||
},
|
||||
"node_modules/warning": {
|
||||
"version": "4.0.3",
|
||||
"resolved": "https://registry.npmjs.org/warning/-/warning-4.0.3.tgz",
|
||||
"integrity": "sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==",
|
||||
"dependencies": {
|
||||
"loose-envify": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/watchpack": {
|
||||
"version": "2.4.2",
|
||||
"resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.2.tgz",
|
||||
@ -20095,14 +19891,6 @@
|
||||
"integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/xmlhttprequest-ssl": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-2.1.1.tgz",
|
||||
"integrity": "sha512-ptjR8YSJIXoA3Mbv5po7RtSYHO6mZr8s7i5VGmEk7QY2pQWyT1o0N+W1gKbOyJPUCGXGnuw0wqe8f0L6Y0ny7g==",
|
||||
"engines": {
|
||||
"node": ">=0.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/y18n": {
|
||||
"version": "5.0.8",
|
||||
"resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
|
||||
|
@ -6,16 +6,13 @@
|
||||
"@testing-library/jest-dom": "^5.17.0",
|
||||
"@testing-library/react": "^13.4.0",
|
||||
"@testing-library/user-event": "^13.5.0",
|
||||
"leaflet": "^1.9.4",
|
||||
"leaflet-defaulticon-compatibility": "^0.1.2",
|
||||
"bootstrap-icons": "^1.11.3",
|
||||
"qrcode.react": "^4.0.1",
|
||||
"react": "^18.3.1",
|
||||
"react-dom": "^18.3.1",
|
||||
"react-leaflet": "^4.2.1",
|
||||
"react-modal": "^3.16.1",
|
||||
"react-router-dom": "^6.26.2",
|
||||
"react-scripts": "5.0.1",
|
||||
"socket.io": "^4.8.0",
|
||||
"socket.io-client": "^4.8.0",
|
||||
"three": "^0.169.0",
|
||||
"web-vitals": "^2.1.4"
|
||||
},
|
||||
|
BIN
src/frontend/public/ImageToStl.com_drone.glb
Normal file
BIN
src/frontend/public/ImageToStl.com_drone.glb
Normal file
Binary file not shown.
1
src/frontend/public/drone_normalized_gltf.gltf
Normal file
1
src/frontend/public/drone_normalized_gltf.gltf
Normal file
@ -0,0 +1 @@
|
||||
{"accessors":[],"asset":{"generator":"Open CASCADE Technology 7.6 [dev.opencascade.org]","version":"2.0"},"bufferViews":[],"buffers":[{"byteLength":0,"uri":"drone_normalized_gltf.bin"}],"meshes":[],"nodes":[],"scene":0,"scenes":[{"nodes":[]}]}
|
@ -1,7 +1,12 @@
|
||||
.App {
|
||||
text-align: center;
|
||||
|
||||
}
|
||||
|
||||
.coler {
|
||||
background-color: #0d1117;
|
||||
color: azure;
|
||||
}
|
||||
.App-logo {
|
||||
height: 40vmin;
|
||||
pointer-events: none;
|
||||
|
@ -9,7 +9,9 @@ import Login from './pages/Login'; // Импортируем страницу
|
||||
import Connections from './pages/Connections'; // Импортируем страницу подключений
|
||||
import PrevCalc from './pages/PrevCalc'; // Импортируем страницу подключений
|
||||
import Docs from './pages/Docs'; // Импортируем страницу подключений
|
||||
import "./css/bulma.min.css"
|
||||
import './css/bootstrap-5.3.3-dist/css/bootstrap.min.css';
|
||||
import './App.css';
|
||||
import "bootstrap-icons/font/bootstrap-icons.css";
|
||||
import { BrowserRouter as Router, Routes, Route, Navigate } from 'react-router-dom';
|
||||
|
||||
const App = () => {
|
||||
@ -42,7 +44,7 @@ const App = () => {
|
||||
activeTab={activeTab}
|
||||
onLogout={handleLogout} // Передаем функцию handleLogout через пропс onLogout
|
||||
/>
|
||||
<div style={{ padding: '20px', flex: 1 }}>
|
||||
<div className='coler' style={{ padding: '20px', flex: 1 }}>
|
||||
{activeTab === 'main' && <Main />} {/* Подключаем компонент Dashboard */}
|
||||
{activeTab === 'map' && <Dashboard />} {/* Подключаем компонент Dashboard */}
|
||||
{activeTab === 'connection' && <Connections />} {/* Страница подключений */}
|
||||
|
@ -1,9 +0,0 @@
|
||||
|
||||
.main__imager {
|
||||
height: 100%;
|
||||
background-image: url('../public/blueprints.jpg');
|
||||
}
|
||||
|
||||
.main__t_b {
|
||||
color: black;
|
||||
}
|
6
src/frontend/src/Services/Main.js
Normal file
6
src/frontend/src/Services/Main.js
Normal file
@ -0,0 +1,6 @@
|
||||
|
||||
|
||||
|
||||
const InvokeStartModulation = () => {
|
||||
|
||||
}
|
@ -5,7 +5,7 @@ export const giveMeServerAddress = () => {
|
||||
if (process.env.SERVER_BASE_ADDRESS) {
|
||||
return process.env.SERVER_BASE_ADDRESS
|
||||
}
|
||||
return "http://localhost:3000";
|
||||
return "http://localhost:8080";
|
||||
}
|
||||
|
||||
export const ServerRequest = async (req, type, data = null) => {
|
||||
@ -23,7 +23,7 @@ export const ServerRequest = async (req, type, data = null) => {
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await fetch(`${addr}/${req}`, options); // выполняем запрос
|
||||
const response = await fetch(`${addr}${req}`, options); // выполняем запрос
|
||||
const responseData = await response.json(); // парсим JSON ответ
|
||||
|
||||
return {
|
||||
@ -38,3 +38,7 @@ export const ServerRequest = async (req, type, data = null) => {
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
export const ServerWebsocketRequest = async () => {
|
||||
|
||||
}
|
13
src/frontend/src/css/Custom/Main.css
Normal file
13
src/frontend/src/css/Custom/Main.css
Normal file
@ -0,0 +1,13 @@
|
||||
|
||||
.main__imager {
|
||||
height: 100%;
|
||||
/* background-image: url('../../../public/blueprints.jpg'); */
|
||||
}
|
||||
|
||||
.main__t_b {
|
||||
color: black;
|
||||
}
|
||||
|
||||
.title {
|
||||
|
||||
}
|
4085
src/frontend/src/css/bootstrap-5.3.3-dist/css/bootstrap-grid.css
vendored
Normal file
4085
src/frontend/src/css/bootstrap-5.3.3-dist/css/bootstrap-grid.css
vendored
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
6
src/frontend/src/css/bootstrap-5.3.3-dist/css/bootstrap-grid.min.css
vendored
Normal file
6
src/frontend/src/css/bootstrap-5.3.3-dist/css/bootstrap-grid.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
4084
src/frontend/src/css/bootstrap-5.3.3-dist/css/bootstrap-grid.rtl.css
vendored
Normal file
4084
src/frontend/src/css/bootstrap-5.3.3-dist/css/bootstrap-grid.rtl.css
vendored
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
6
src/frontend/src/css/bootstrap-5.3.3-dist/css/bootstrap-grid.rtl.min.css
vendored
Normal file
6
src/frontend/src/css/bootstrap-5.3.3-dist/css/bootstrap-grid.rtl.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
597
src/frontend/src/css/bootstrap-5.3.3-dist/css/bootstrap-reboot.css
vendored
Normal file
597
src/frontend/src/css/bootstrap-5.3.3-dist/css/bootstrap-reboot.css
vendored
Normal file
@ -0,0 +1,597 @@
|
||||
/*!
|
||||
* Bootstrap Reboot v5.3.3 (https://getbootstrap.com/)
|
||||
* Copyright 2011-2024 The Bootstrap Authors
|
||||
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
|
||||
*/
|
||||
:root,
|
||||
[data-bs-theme=light] {
|
||||
--bs-blue: #0d6efd;
|
||||
--bs-indigo: #6610f2;
|
||||
--bs-purple: #6f42c1;
|
||||
--bs-pink: #d63384;
|
||||
--bs-red: #dc3545;
|
||||
--bs-orange: #fd7e14;
|
||||
--bs-yellow: #ffc107;
|
||||
--bs-green: #198754;
|
||||
--bs-teal: #20c997;
|
||||
--bs-cyan: #0dcaf0;
|
||||
--bs-black: #000;
|
||||
--bs-white: #fff;
|
||||
--bs-gray: #6c757d;
|
||||
--bs-gray-dark: #343a40;
|
||||
--bs-gray-100: #f8f9fa;
|
||||
--bs-gray-200: #e9ecef;
|
||||
--bs-gray-300: #dee2e6;
|
||||
--bs-gray-400: #ced4da;
|
||||
--bs-gray-500: #adb5bd;
|
||||
--bs-gray-600: #6c757d;
|
||||
--bs-gray-700: #495057;
|
||||
--bs-gray-800: #343a40;
|
||||
--bs-gray-900: #212529;
|
||||
--bs-primary: #0d6efd;
|
||||
--bs-secondary: #6c757d;
|
||||
--bs-success: #198754;
|
||||
--bs-info: #0dcaf0;
|
||||
--bs-warning: #ffc107;
|
||||
--bs-danger: #dc3545;
|
||||
--bs-light: #f8f9fa;
|
||||
--bs-dark: #212529;
|
||||
--bs-primary-rgb: 13, 110, 253;
|
||||
--bs-secondary-rgb: 108, 117, 125;
|
||||
--bs-success-rgb: 25, 135, 84;
|
||||
--bs-info-rgb: 13, 202, 240;
|
||||
--bs-warning-rgb: 255, 193, 7;
|
||||
--bs-danger-rgb: 220, 53, 69;
|
||||
--bs-light-rgb: 248, 249, 250;
|
||||
--bs-dark-rgb: 33, 37, 41;
|
||||
--bs-primary-text-emphasis: #052c65;
|
||||
--bs-secondary-text-emphasis: #2b2f32;
|
||||
--bs-success-text-emphasis: #0a3622;
|
||||
--bs-info-text-emphasis: #055160;
|
||||
--bs-warning-text-emphasis: #664d03;
|
||||
--bs-danger-text-emphasis: #58151c;
|
||||
--bs-light-text-emphasis: #495057;
|
||||
--bs-dark-text-emphasis: #495057;
|
||||
--bs-primary-bg-subtle: #cfe2ff;
|
||||
--bs-secondary-bg-subtle: #e2e3e5;
|
||||
--bs-success-bg-subtle: #d1e7dd;
|
||||
--bs-info-bg-subtle: #cff4fc;
|
||||
--bs-warning-bg-subtle: #fff3cd;
|
||||
--bs-danger-bg-subtle: #f8d7da;
|
||||
--bs-light-bg-subtle: #fcfcfd;
|
||||
--bs-dark-bg-subtle: #ced4da;
|
||||
--bs-primary-border-subtle: #9ec5fe;
|
||||
--bs-secondary-border-subtle: #c4c8cb;
|
||||
--bs-success-border-subtle: #a3cfbb;
|
||||
--bs-info-border-subtle: #9eeaf9;
|
||||
--bs-warning-border-subtle: #ffe69c;
|
||||
--bs-danger-border-subtle: #f1aeb5;
|
||||
--bs-light-border-subtle: #e9ecef;
|
||||
--bs-dark-border-subtle: #adb5bd;
|
||||
--bs-white-rgb: 255, 255, 255;
|
||||
--bs-black-rgb: 0, 0, 0;
|
||||
--bs-font-sans-serif: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", "Liberation Sans", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
|
||||
--bs-font-monospace: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
|
||||
--bs-gradient: linear-gradient(180deg, rgba(255, 255, 255, 0.15), rgba(255, 255, 255, 0));
|
||||
--bs-body-font-family: var(--bs-font-sans-serif);
|
||||
--bs-body-font-size: 1rem;
|
||||
--bs-body-font-weight: 400;
|
||||
--bs-body-line-height: 1.5;
|
||||
--bs-body-color: #212529;
|
||||
--bs-body-color-rgb: 33, 37, 41;
|
||||
--bs-body-bg: #fff;
|
||||
--bs-body-bg-rgb: 255, 255, 255;
|
||||
--bs-emphasis-color: #000;
|
||||
--bs-emphasis-color-rgb: 0, 0, 0;
|
||||
--bs-secondary-color: rgba(33, 37, 41, 0.75);
|
||||
--bs-secondary-color-rgb: 33, 37, 41;
|
||||
--bs-secondary-bg: #e9ecef;
|
||||
--bs-secondary-bg-rgb: 233, 236, 239;
|
||||
--bs-tertiary-color: rgba(33, 37, 41, 0.5);
|
||||
--bs-tertiary-color-rgb: 33, 37, 41;
|
||||
--bs-tertiary-bg: #f8f9fa;
|
||||
--bs-tertiary-bg-rgb: 248, 249, 250;
|
||||
--bs-heading-color: inherit;
|
||||
--bs-link-color: #0d6efd;
|
||||
--bs-link-color-rgb: 13, 110, 253;
|
||||
--bs-link-decoration: underline;
|
||||
--bs-link-hover-color: #0a58ca;
|
||||
--bs-link-hover-color-rgb: 10, 88, 202;
|
||||
--bs-code-color: #d63384;
|
||||
--bs-highlight-color: #212529;
|
||||
--bs-highlight-bg: #fff3cd;
|
||||
--bs-border-width: 1px;
|
||||
--bs-border-style: solid;
|
||||
--bs-border-color: #dee2e6;
|
||||
--bs-border-color-translucent: rgba(0, 0, 0, 0.175);
|
||||
--bs-border-radius: 0.375rem;
|
||||
--bs-border-radius-sm: 0.25rem;
|
||||
--bs-border-radius-lg: 0.5rem;
|
||||
--bs-border-radius-xl: 1rem;
|
||||
--bs-border-radius-xxl: 2rem;
|
||||
--bs-border-radius-2xl: var(--bs-border-radius-xxl);
|
||||
--bs-border-radius-pill: 50rem;
|
||||
--bs-box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15);
|
||||
--bs-box-shadow-sm: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.075);
|
||||
--bs-box-shadow-lg: 0 1rem 3rem rgba(0, 0, 0, 0.175);
|
||||
--bs-box-shadow-inset: inset 0 1px 2px rgba(0, 0, 0, 0.075);
|
||||
--bs-focus-ring-width: 0.25rem;
|
||||
--bs-focus-ring-opacity: 0.25;
|
||||
--bs-focus-ring-color: rgba(13, 110, 253, 0.25);
|
||||
--bs-form-valid-color: #198754;
|
||||
--bs-form-valid-border-color: #198754;
|
||||
--bs-form-invalid-color: #dc3545;
|
||||
--bs-form-invalid-border-color: #dc3545;
|
||||
}
|
||||
|
||||
[data-bs-theme=dark] {
|
||||
color-scheme: dark;
|
||||
--bs-body-color: #dee2e6;
|
||||
--bs-body-color-rgb: 222, 226, 230;
|
||||
--bs-body-bg: #212529;
|
||||
--bs-body-bg-rgb: 33, 37, 41;
|
||||
--bs-emphasis-color: #fff;
|
||||
--bs-emphasis-color-rgb: 255, 255, 255;
|
||||
--bs-secondary-color: rgba(222, 226, 230, 0.75);
|
||||
--bs-secondary-color-rgb: 222, 226, 230;
|
||||
--bs-secondary-bg: #343a40;
|
||||
--bs-secondary-bg-rgb: 52, 58, 64;
|
||||
--bs-tertiary-color: rgba(222, 226, 230, 0.5);
|
||||
--bs-tertiary-color-rgb: 222, 226, 230;
|
||||
--bs-tertiary-bg: #2b3035;
|
||||
--bs-tertiary-bg-rgb: 43, 48, 53;
|
||||
--bs-primary-text-emphasis: #6ea8fe;
|
||||
--bs-secondary-text-emphasis: #a7acb1;
|
||||
--bs-success-text-emphasis: #75b798;
|
||||
--bs-info-text-emphasis: #6edff6;
|
||||
--bs-warning-text-emphasis: #ffda6a;
|
||||
--bs-danger-text-emphasis: #ea868f;
|
||||
--bs-light-text-emphasis: #f8f9fa;
|
||||
--bs-dark-text-emphasis: #dee2e6;
|
||||
--bs-primary-bg-subtle: #031633;
|
||||
--bs-secondary-bg-subtle: #161719;
|
||||
--bs-success-bg-subtle: #051b11;
|
||||
--bs-info-bg-subtle: #032830;
|
||||
--bs-warning-bg-subtle: #332701;
|
||||
--bs-danger-bg-subtle: #2c0b0e;
|
||||
--bs-light-bg-subtle: #343a40;
|
||||
--bs-dark-bg-subtle: #1a1d20;
|
||||
--bs-primary-border-subtle: #084298;
|
||||
--bs-secondary-border-subtle: #41464b;
|
||||
--bs-success-border-subtle: #0f5132;
|
||||
--bs-info-border-subtle: #087990;
|
||||
--bs-warning-border-subtle: #997404;
|
||||
--bs-danger-border-subtle: #842029;
|
||||
--bs-light-border-subtle: #495057;
|
||||
--bs-dark-border-subtle: #343a40;
|
||||
--bs-heading-color: inherit;
|
||||
--bs-link-color: #6ea8fe;
|
||||
--bs-link-hover-color: #8bb9fe;
|
||||
--bs-link-color-rgb: 110, 168, 254;
|
||||
--bs-link-hover-color-rgb: 139, 185, 254;
|
||||
--bs-code-color: #e685b5;
|
||||
--bs-highlight-color: #dee2e6;
|
||||
--bs-highlight-bg: #664d03;
|
||||
--bs-border-color: #495057;
|
||||
--bs-border-color-translucent: rgba(255, 255, 255, 0.15);
|
||||
--bs-form-valid-color: #75b798;
|
||||
--bs-form-valid-border-color: #75b798;
|
||||
--bs-form-invalid-color: #ea868f;
|
||||
--bs-form-invalid-border-color: #ea868f;
|
||||
}
|
||||
|
||||
*,
|
||||
*::before,
|
||||
*::after {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
@media (prefers-reduced-motion: no-preference) {
|
||||
:root {
|
||||
scroll-behavior: smooth;
|
||||
}
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
font-family: var(--bs-body-font-family);
|
||||
font-size: var(--bs-body-font-size);
|
||||
font-weight: var(--bs-body-font-weight);
|
||||
line-height: var(--bs-body-line-height);
|
||||
color: var(--bs-body-color);
|
||||
text-align: var(--bs-body-text-align);
|
||||
background-color: var(--bs-body-bg);
|
||||
-webkit-text-size-adjust: 100%;
|
||||
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
hr {
|
||||
margin: 1rem 0;
|
||||
color: inherit;
|
||||
border: 0;
|
||||
border-top: var(--bs-border-width) solid;
|
||||
opacity: 0.25;
|
||||
}
|
||||
|
||||
h6, h5, h4, h3, h2, h1 {
|
||||
margin-top: 0;
|
||||
margin-bottom: 0.5rem;
|
||||
font-weight: 500;
|
||||
line-height: 1.2;
|
||||
color: var(--bs-heading-color);
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: calc(1.375rem + 1.5vw);
|
||||
}
|
||||
@media (min-width: 1200px) {
|
||||
h1 {
|
||||
font-size: 2.5rem;
|
||||
}
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: calc(1.325rem + 0.9vw);
|
||||
}
|
||||
@media (min-width: 1200px) {
|
||||
h2 {
|
||||
font-size: 2rem;
|
||||
}
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-size: calc(1.3rem + 0.6vw);
|
||||
}
|
||||
@media (min-width: 1200px) {
|
||||
h3 {
|
||||
font-size: 1.75rem;
|
||||
}
|
||||
}
|
||||
|
||||
h4 {
|
||||
font-size: calc(1.275rem + 0.3vw);
|
||||
}
|
||||
@media (min-width: 1200px) {
|
||||
h4 {
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
}
|
||||
|
||||
h5 {
|
||||
font-size: 1.25rem;
|
||||
}
|
||||
|
||||
h6 {
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
p {
|
||||
margin-top: 0;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
abbr[title] {
|
||||
-webkit-text-decoration: underline dotted;
|
||||
text-decoration: underline dotted;
|
||||
cursor: help;
|
||||
-webkit-text-decoration-skip-ink: none;
|
||||
text-decoration-skip-ink: none;
|
||||
}
|
||||
|
||||
address {
|
||||
margin-bottom: 1rem;
|
||||
font-style: normal;
|
||||
line-height: inherit;
|
||||
}
|
||||
|
||||
ol,
|
||||
ul {
|
||||
padding-left: 2rem;
|
||||
}
|
||||
|
||||
ol,
|
||||
ul,
|
||||
dl {
|
||||
margin-top: 0;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
ol ol,
|
||||
ul ul,
|
||||
ol ul,
|
||||
ul ol {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
dt {
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
dd {
|
||||
margin-bottom: 0.5rem;
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
blockquote {
|
||||
margin: 0 0 1rem;
|
||||
}
|
||||
|
||||
b,
|
||||
strong {
|
||||
font-weight: bolder;
|
||||
}
|
||||
|
||||
small {
|
||||
font-size: 0.875em;
|
||||
}
|
||||
|
||||
mark {
|
||||
padding: 0.1875em;
|
||||
color: var(--bs-highlight-color);
|
||||
background-color: var(--bs-highlight-bg);
|
||||
}
|
||||
|
||||
sub,
|
||||
sup {
|
||||
position: relative;
|
||||
font-size: 0.75em;
|
||||
line-height: 0;
|
||||
vertical-align: baseline;
|
||||
}
|
||||
|
||||
sub {
|
||||
bottom: -0.25em;
|
||||
}
|
||||
|
||||
sup {
|
||||
top: -0.5em;
|
||||
}
|
||||
|
||||
a {
|
||||
color: rgba(var(--bs-link-color-rgb), var(--bs-link-opacity, 1));
|
||||
text-decoration: underline;
|
||||
}
|
||||
a:hover {
|
||||
--bs-link-color-rgb: var(--bs-link-hover-color-rgb);
|
||||
}
|
||||
|
||||
a:not([href]):not([class]), a:not([href]):not([class]):hover {
|
||||
color: inherit;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
pre,
|
||||
code,
|
||||
kbd,
|
||||
samp {
|
||||
font-family: var(--bs-font-monospace);
|
||||
font-size: 1em;
|
||||
}
|
||||
|
||||
pre {
|
||||
display: block;
|
||||
margin-top: 0;
|
||||
margin-bottom: 1rem;
|
||||
overflow: auto;
|
||||
font-size: 0.875em;
|
||||
}
|
||||
pre code {
|
||||
font-size: inherit;
|
||||
color: inherit;
|
||||
word-break: normal;
|
||||
}
|
||||
|
||||
code {
|
||||
font-size: 0.875em;
|
||||
color: var(--bs-code-color);
|
||||
word-wrap: break-word;
|
||||
}
|
||||
a > code {
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
kbd {
|
||||
padding: 0.1875rem 0.375rem;
|
||||
font-size: 0.875em;
|
||||
color: var(--bs-body-bg);
|
||||
background-color: var(--bs-body-color);
|
||||
border-radius: 0.25rem;
|
||||
}
|
||||
kbd kbd {
|
||||
padding: 0;
|
||||
font-size: 1em;
|
||||
}
|
||||
|
||||
figure {
|
||||
margin: 0 0 1rem;
|
||||
}
|
||||
|
||||
img,
|
||||
svg {
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
table {
|
||||
caption-side: bottom;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
|
||||
caption {
|
||||
padding-top: 0.5rem;
|
||||
padding-bottom: 0.5rem;
|
||||
color: var(--bs-secondary-color);
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
th {
|
||||
text-align: inherit;
|
||||
text-align: -webkit-match-parent;
|
||||
}
|
||||
|
||||
thead,
|
||||
tbody,
|
||||
tfoot,
|
||||
tr,
|
||||
td,
|
||||
th {
|
||||
border-color: inherit;
|
||||
border-style: solid;
|
||||
border-width: 0;
|
||||
}
|
||||
|
||||
label {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
button {
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
button:focus:not(:focus-visible) {
|
||||
outline: 0;
|
||||
}
|
||||
|
||||
input,
|
||||
button,
|
||||
select,
|
||||
optgroup,
|
||||
textarea {
|
||||
margin: 0;
|
||||
font-family: inherit;
|
||||
font-size: inherit;
|
||||
line-height: inherit;
|
||||
}
|
||||
|
||||
button,
|
||||
select {
|
||||
text-transform: none;
|
||||
}
|
||||
|
||||
[role=button] {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
select {
|
||||
word-wrap: normal;
|
||||
}
|
||||
select:disabled {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
[list]:not([type=date]):not([type=datetime-local]):not([type=month]):not([type=week]):not([type=time])::-webkit-calendar-picker-indicator {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
button,
|
||||
[type=button],
|
||||
[type=reset],
|
||||
[type=submit] {
|
||||
-webkit-appearance: button;
|
||||
}
|
||||
button:not(:disabled),
|
||||
[type=button]:not(:disabled),
|
||||
[type=reset]:not(:disabled),
|
||||
[type=submit]:not(:disabled) {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
::-moz-focus-inner {
|
||||
padding: 0;
|
||||
border-style: none;
|
||||
}
|
||||
|
||||
textarea {
|
||||
resize: vertical;
|
||||
}
|
||||
|
||||
fieldset {
|
||||
min-width: 0;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
border: 0;
|
||||
}
|
||||
|
||||
legend {
|
||||
float: left;
|
||||
width: 100%;
|
||||
padding: 0;
|
||||
margin-bottom: 0.5rem;
|
||||
font-size: calc(1.275rem + 0.3vw);
|
||||
line-height: inherit;
|
||||
}
|
||||
@media (min-width: 1200px) {
|
||||
legend {
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
}
|
||||
legend + * {
|
||||
clear: left;
|
||||
}
|
||||
|
||||
::-webkit-datetime-edit-fields-wrapper,
|
||||
::-webkit-datetime-edit-text,
|
||||
::-webkit-datetime-edit-minute,
|
||||
::-webkit-datetime-edit-hour-field,
|
||||
::-webkit-datetime-edit-day-field,
|
||||
::-webkit-datetime-edit-month-field,
|
||||
::-webkit-datetime-edit-year-field {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
::-webkit-inner-spin-button {
|
||||
height: auto;
|
||||
}
|
||||
|
||||
[type=search] {
|
||||
-webkit-appearance: textfield;
|
||||
outline-offset: -2px;
|
||||
}
|
||||
|
||||
/* rtl:raw:
|
||||
[type="tel"],
|
||||
[type="url"],
|
||||
[type="email"],
|
||||
[type="number"] {
|
||||
direction: ltr;
|
||||
}
|
||||
*/
|
||||
::-webkit-search-decoration {
|
||||
-webkit-appearance: none;
|
||||
}
|
||||
|
||||
::-webkit-color-swatch-wrapper {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
::-webkit-file-upload-button {
|
||||
font: inherit;
|
||||
-webkit-appearance: button;
|
||||
}
|
||||
|
||||
::file-selector-button {
|
||||
font: inherit;
|
||||
-webkit-appearance: button;
|
||||
}
|
||||
|
||||
output {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
iframe {
|
||||
border: 0;
|
||||
}
|
||||
|
||||
summary {
|
||||
display: list-item;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
progress {
|
||||
vertical-align: baseline;
|
||||
}
|
||||
|
||||
[hidden] {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
/*# sourceMappingURL=bootstrap-reboot.css.map */
|
File diff suppressed because one or more lines are too long
6
src/frontend/src/css/bootstrap-5.3.3-dist/css/bootstrap-reboot.min.css
vendored
Normal file
6
src/frontend/src/css/bootstrap-5.3.3-dist/css/bootstrap-reboot.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
594
src/frontend/src/css/bootstrap-5.3.3-dist/css/bootstrap-reboot.rtl.css
vendored
Normal file
594
src/frontend/src/css/bootstrap-5.3.3-dist/css/bootstrap-reboot.rtl.css
vendored
Normal file
@ -0,0 +1,594 @@
|
||||
/*!
|
||||
* Bootstrap Reboot v5.3.3 (https://getbootstrap.com/)
|
||||
* Copyright 2011-2024 The Bootstrap Authors
|
||||
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
|
||||
*/
|
||||
:root,
|
||||
[data-bs-theme=light] {
|
||||
--bs-blue: #0d6efd;
|
||||
--bs-indigo: #6610f2;
|
||||
--bs-purple: #6f42c1;
|
||||
--bs-pink: #d63384;
|
||||
--bs-red: #dc3545;
|
||||
--bs-orange: #fd7e14;
|
||||
--bs-yellow: #ffc107;
|
||||
--bs-green: #198754;
|
||||
--bs-teal: #20c997;
|
||||
--bs-cyan: #0dcaf0;
|
||||
--bs-black: #000;
|
||||
--bs-white: #fff;
|
||||
--bs-gray: #6c757d;
|
||||
--bs-gray-dark: #343a40;
|
||||
--bs-gray-100: #f8f9fa;
|
||||
--bs-gray-200: #e9ecef;
|
||||
--bs-gray-300: #dee2e6;
|
||||
--bs-gray-400: #ced4da;
|
||||
--bs-gray-500: #adb5bd;
|
||||
--bs-gray-600: #6c757d;
|
||||
--bs-gray-700: #495057;
|
||||
--bs-gray-800: #343a40;
|
||||
--bs-gray-900: #212529;
|
||||
--bs-primary: #0d6efd;
|
||||
--bs-secondary: #6c757d;
|
||||
--bs-success: #198754;
|
||||
--bs-info: #0dcaf0;
|
||||
--bs-warning: #ffc107;
|
||||
--bs-danger: #dc3545;
|
||||
--bs-light: #f8f9fa;
|
||||
--bs-dark: #212529;
|
||||
--bs-primary-rgb: 13, 110, 253;
|
||||
--bs-secondary-rgb: 108, 117, 125;
|
||||
--bs-success-rgb: 25, 135, 84;
|
||||
--bs-info-rgb: 13, 202, 240;
|
||||
--bs-warning-rgb: 255, 193, 7;
|
||||
--bs-danger-rgb: 220, 53, 69;
|
||||
--bs-light-rgb: 248, 249, 250;
|
||||
--bs-dark-rgb: 33, 37, 41;
|
||||
--bs-primary-text-emphasis: #052c65;
|
||||
--bs-secondary-text-emphasis: #2b2f32;
|
||||
--bs-success-text-emphasis: #0a3622;
|
||||
--bs-info-text-emphasis: #055160;
|
||||
--bs-warning-text-emphasis: #664d03;
|
||||
--bs-danger-text-emphasis: #58151c;
|
||||
--bs-light-text-emphasis: #495057;
|
||||
--bs-dark-text-emphasis: #495057;
|
||||
--bs-primary-bg-subtle: #cfe2ff;
|
||||
--bs-secondary-bg-subtle: #e2e3e5;
|
||||
--bs-success-bg-subtle: #d1e7dd;
|
||||
--bs-info-bg-subtle: #cff4fc;
|
||||
--bs-warning-bg-subtle: #fff3cd;
|
||||
--bs-danger-bg-subtle: #f8d7da;
|
||||
--bs-light-bg-subtle: #fcfcfd;
|
||||
--bs-dark-bg-subtle: #ced4da;
|
||||
--bs-primary-border-subtle: #9ec5fe;
|
||||
--bs-secondary-border-subtle: #c4c8cb;
|
||||
--bs-success-border-subtle: #a3cfbb;
|
||||
--bs-info-border-subtle: #9eeaf9;
|
||||
--bs-warning-border-subtle: #ffe69c;
|
||||
--bs-danger-border-subtle: #f1aeb5;
|
||||
--bs-light-border-subtle: #e9ecef;
|
||||
--bs-dark-border-subtle: #adb5bd;
|
||||
--bs-white-rgb: 255, 255, 255;
|
||||
--bs-black-rgb: 0, 0, 0;
|
||||
--bs-font-sans-serif: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", "Liberation Sans", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
|
||||
--bs-font-monospace: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
|
||||
--bs-gradient: linear-gradient(180deg, rgba(255, 255, 255, 0.15), rgba(255, 255, 255, 0));
|
||||
--bs-body-font-family: var(--bs-font-sans-serif);
|
||||
--bs-body-font-size: 1rem;
|
||||
--bs-body-font-weight: 400;
|
||||
--bs-body-line-height: 1.5;
|
||||
--bs-body-color: #212529;
|
||||
--bs-body-color-rgb: 33, 37, 41;
|
||||
--bs-body-bg: #fff;
|
||||
--bs-body-bg-rgb: 255, 255, 255;
|
||||
--bs-emphasis-color: #000;
|
||||
--bs-emphasis-color-rgb: 0, 0, 0;
|
||||
--bs-secondary-color: rgba(33, 37, 41, 0.75);
|
||||
--bs-secondary-color-rgb: 33, 37, 41;
|
||||
--bs-secondary-bg: #e9ecef;
|
||||
--bs-secondary-bg-rgb: 233, 236, 239;
|
||||
--bs-tertiary-color: rgba(33, 37, 41, 0.5);
|
||||
--bs-tertiary-color-rgb: 33, 37, 41;
|
||||
--bs-tertiary-bg: #f8f9fa;
|
||||
--bs-tertiary-bg-rgb: 248, 249, 250;
|
||||
--bs-heading-color: inherit;
|
||||
--bs-link-color: #0d6efd;
|
||||
--bs-link-color-rgb: 13, 110, 253;
|
||||
--bs-link-decoration: underline;
|
||||
--bs-link-hover-color: #0a58ca;
|
||||
--bs-link-hover-color-rgb: 10, 88, 202;
|
||||
--bs-code-color: #d63384;
|
||||
--bs-highlight-color: #212529;
|
||||
--bs-highlight-bg: #fff3cd;
|
||||
--bs-border-width: 1px;
|
||||
--bs-border-style: solid;
|
||||
--bs-border-color: #dee2e6;
|
||||
--bs-border-color-translucent: rgba(0, 0, 0, 0.175);
|
||||
--bs-border-radius: 0.375rem;
|
||||
--bs-border-radius-sm: 0.25rem;
|
||||
--bs-border-radius-lg: 0.5rem;
|
||||
--bs-border-radius-xl: 1rem;
|
||||
--bs-border-radius-xxl: 2rem;
|
||||
--bs-border-radius-2xl: var(--bs-border-radius-xxl);
|
||||
--bs-border-radius-pill: 50rem;
|
||||
--bs-box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15);
|
||||
--bs-box-shadow-sm: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.075);
|
||||
--bs-box-shadow-lg: 0 1rem 3rem rgba(0, 0, 0, 0.175);
|
||||
--bs-box-shadow-inset: inset 0 1px 2px rgba(0, 0, 0, 0.075);
|
||||
--bs-focus-ring-width: 0.25rem;
|
||||
--bs-focus-ring-opacity: 0.25;
|
||||
--bs-focus-ring-color: rgba(13, 110, 253, 0.25);
|
||||
--bs-form-valid-color: #198754;
|
||||
--bs-form-valid-border-color: #198754;
|
||||
--bs-form-invalid-color: #dc3545;
|
||||
--bs-form-invalid-border-color: #dc3545;
|
||||
}
|
||||
|
||||
[data-bs-theme=dark] {
|
||||
color-scheme: dark;
|
||||
--bs-body-color: #dee2e6;
|
||||
--bs-body-color-rgb: 222, 226, 230;
|
||||
--bs-body-bg: #212529;
|
||||
--bs-body-bg-rgb: 33, 37, 41;
|
||||
--bs-emphasis-color: #fff;
|
||||
--bs-emphasis-color-rgb: 255, 255, 255;
|
||||
--bs-secondary-color: rgba(222, 226, 230, 0.75);
|
||||
--bs-secondary-color-rgb: 222, 226, 230;
|
||||
--bs-secondary-bg: #343a40;
|
||||
--bs-secondary-bg-rgb: 52, 58, 64;
|
||||
--bs-tertiary-color: rgba(222, 226, 230, 0.5);
|
||||
--bs-tertiary-color-rgb: 222, 226, 230;
|
||||
--bs-tertiary-bg: #2b3035;
|
||||
--bs-tertiary-bg-rgb: 43, 48, 53;
|
||||
--bs-primary-text-emphasis: #6ea8fe;
|
||||
--bs-secondary-text-emphasis: #a7acb1;
|
||||
--bs-success-text-emphasis: #75b798;
|
||||
--bs-info-text-emphasis: #6edff6;
|
||||
--bs-warning-text-emphasis: #ffda6a;
|
||||
--bs-danger-text-emphasis: #ea868f;
|
||||
--bs-light-text-emphasis: #f8f9fa;
|
||||
--bs-dark-text-emphasis: #dee2e6;
|
||||
--bs-primary-bg-subtle: #031633;
|
||||
--bs-secondary-bg-subtle: #161719;
|
||||
--bs-success-bg-subtle: #051b11;
|
||||
--bs-info-bg-subtle: #032830;
|
||||
--bs-warning-bg-subtle: #332701;
|
||||
--bs-danger-bg-subtle: #2c0b0e;
|
||||
--bs-light-bg-subtle: #343a40;
|
||||
--bs-dark-bg-subtle: #1a1d20;
|
||||
--bs-primary-border-subtle: #084298;
|
||||
--bs-secondary-border-subtle: #41464b;
|
||||
--bs-success-border-subtle: #0f5132;
|
||||
--bs-info-border-subtle: #087990;
|
||||
--bs-warning-border-subtle: #997404;
|
||||
--bs-danger-border-subtle: #842029;
|
||||
--bs-light-border-subtle: #495057;
|
||||
--bs-dark-border-subtle: #343a40;
|
||||
--bs-heading-color: inherit;
|
||||
--bs-link-color: #6ea8fe;
|
||||
--bs-link-hover-color: #8bb9fe;
|
||||
--bs-link-color-rgb: 110, 168, 254;
|
||||
--bs-link-hover-color-rgb: 139, 185, 254;
|
||||
--bs-code-color: #e685b5;
|
||||
--bs-highlight-color: #dee2e6;
|
||||
--bs-highlight-bg: #664d03;
|
||||
--bs-border-color: #495057;
|
||||
--bs-border-color-translucent: rgba(255, 255, 255, 0.15);
|
||||
--bs-form-valid-color: #75b798;
|
||||
--bs-form-valid-border-color: #75b798;
|
||||
--bs-form-invalid-color: #ea868f;
|
||||
--bs-form-invalid-border-color: #ea868f;
|
||||
}
|
||||
|
||||
*,
|
||||
*::before,
|
||||
*::after {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
@media (prefers-reduced-motion: no-preference) {
|
||||
:root {
|
||||
scroll-behavior: smooth;
|
||||
}
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
font-family: var(--bs-body-font-family);
|
||||
font-size: var(--bs-body-font-size);
|
||||
font-weight: var(--bs-body-font-weight);
|
||||
line-height: var(--bs-body-line-height);
|
||||
color: var(--bs-body-color);
|
||||
text-align: var(--bs-body-text-align);
|
||||
background-color: var(--bs-body-bg);
|
||||
-webkit-text-size-adjust: 100%;
|
||||
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
hr {
|
||||
margin: 1rem 0;
|
||||
color: inherit;
|
||||
border: 0;
|
||||
border-top: var(--bs-border-width) solid;
|
||||
opacity: 0.25;
|
||||
}
|
||||
|
||||
h6, h5, h4, h3, h2, h1 {
|
||||
margin-top: 0;
|
||||
margin-bottom: 0.5rem;
|
||||
font-weight: 500;
|
||||
line-height: 1.2;
|
||||
color: var(--bs-heading-color);
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: calc(1.375rem + 1.5vw);
|
||||
}
|
||||
@media (min-width: 1200px) {
|
||||
h1 {
|
||||
font-size: 2.5rem;
|
||||
}
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: calc(1.325rem + 0.9vw);
|
||||
}
|
||||
@media (min-width: 1200px) {
|
||||
h2 {
|
||||
font-size: 2rem;
|
||||
}
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-size: calc(1.3rem + 0.6vw);
|
||||
}
|
||||
@media (min-width: 1200px) {
|
||||
h3 {
|
||||
font-size: 1.75rem;
|
||||
}
|
||||
}
|
||||
|
||||
h4 {
|
||||
font-size: calc(1.275rem + 0.3vw);
|
||||
}
|
||||
@media (min-width: 1200px) {
|
||||
h4 {
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
}
|
||||
|
||||
h5 {
|
||||
font-size: 1.25rem;
|
||||
}
|
||||
|
||||
h6 {
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
p {
|
||||
margin-top: 0;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
abbr[title] {
|
||||
-webkit-text-decoration: underline dotted;
|
||||
text-decoration: underline dotted;
|
||||
cursor: help;
|
||||
-webkit-text-decoration-skip-ink: none;
|
||||
text-decoration-skip-ink: none;
|
||||
}
|
||||
|
||||
address {
|
||||
margin-bottom: 1rem;
|
||||
font-style: normal;
|
||||
line-height: inherit;
|
||||
}
|
||||
|
||||
ol,
|
||||
ul {
|
||||
padding-right: 2rem;
|
||||
}
|
||||
|
||||
ol,
|
||||
ul,
|
||||
dl {
|
||||
margin-top: 0;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
ol ol,
|
||||
ul ul,
|
||||
ol ul,
|
||||
ul ol {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
dt {
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
dd {
|
||||
margin-bottom: 0.5rem;
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
blockquote {
|
||||
margin: 0 0 1rem;
|
||||
}
|
||||
|
||||
b,
|
||||
strong {
|
||||
font-weight: bolder;
|
||||
}
|
||||
|
||||
small {
|
||||
font-size: 0.875em;
|
||||
}
|
||||
|
||||
mark {
|
||||
padding: 0.1875em;
|
||||
color: var(--bs-highlight-color);
|
||||
background-color: var(--bs-highlight-bg);
|
||||
}
|
||||
|
||||
sub,
|
||||
sup {
|
||||
position: relative;
|
||||
font-size: 0.75em;
|
||||
line-height: 0;
|
||||
vertical-align: baseline;
|
||||
}
|
||||
|
||||
sub {
|
||||
bottom: -0.25em;
|
||||
}
|
||||
|
||||
sup {
|
||||
top: -0.5em;
|
||||
}
|
||||
|
||||
a {
|
||||
color: rgba(var(--bs-link-color-rgb), var(--bs-link-opacity, 1));
|
||||
text-decoration: underline;
|
||||
}
|
||||
a:hover {
|
||||
--bs-link-color-rgb: var(--bs-link-hover-color-rgb);
|
||||
}
|
||||
|
||||
a:not([href]):not([class]), a:not([href]):not([class]):hover {
|
||||
color: inherit;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
pre,
|
||||
code,
|
||||
kbd,
|
||||
samp {
|
||||
font-family: var(--bs-font-monospace);
|
||||
font-size: 1em;
|
||||
}
|
||||
|
||||
pre {
|
||||
display: block;
|
||||
margin-top: 0;
|
||||
margin-bottom: 1rem;
|
||||
overflow: auto;
|
||||
font-size: 0.875em;
|
||||
}
|
||||
pre code {
|
||||
font-size: inherit;
|
||||
color: inherit;
|
||||
word-break: normal;
|
||||
}
|
||||
|
||||
code {
|
||||
font-size: 0.875em;
|
||||
color: var(--bs-code-color);
|
||||
word-wrap: break-word;
|
||||
}
|
||||
a > code {
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
kbd {
|
||||
padding: 0.1875rem 0.375rem;
|
||||
font-size: 0.875em;
|
||||
color: var(--bs-body-bg);
|
||||
background-color: var(--bs-body-color);
|
||||
border-radius: 0.25rem;
|
||||
}
|
||||
kbd kbd {
|
||||
padding: 0;
|
||||
font-size: 1em;
|
||||
}
|
||||
|
||||
figure {
|
||||
margin: 0 0 1rem;
|
||||
}
|
||||
|
||||
img,
|
||||
svg {
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
table {
|
||||
caption-side: bottom;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
|
||||
caption {
|
||||
padding-top: 0.5rem;
|
||||
padding-bottom: 0.5rem;
|
||||
color: var(--bs-secondary-color);
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
th {
|
||||
text-align: inherit;
|
||||
text-align: -webkit-match-parent;
|
||||
}
|
||||
|
||||
thead,
|
||||
tbody,
|
||||
tfoot,
|
||||
tr,
|
||||
td,
|
||||
th {
|
||||
border-color: inherit;
|
||||
border-style: solid;
|
||||
border-width: 0;
|
||||
}
|
||||
|
||||
label {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
button {
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
button:focus:not(:focus-visible) {
|
||||
outline: 0;
|
||||
}
|
||||
|
||||
input,
|
||||
button,
|
||||
select,
|
||||
optgroup,
|
||||
textarea {
|
||||
margin: 0;
|
||||
font-family: inherit;
|
||||
font-size: inherit;
|
||||
line-height: inherit;
|
||||
}
|
||||
|
||||
button,
|
||||
select {
|
||||
text-transform: none;
|
||||
}
|
||||
|
||||
[role=button] {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
select {
|
||||
word-wrap: normal;
|
||||
}
|
||||
select:disabled {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
[list]:not([type=date]):not([type=datetime-local]):not([type=month]):not([type=week]):not([type=time])::-webkit-calendar-picker-indicator {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
button,
|
||||
[type=button],
|
||||
[type=reset],
|
||||
[type=submit] {
|
||||
-webkit-appearance: button;
|
||||
}
|
||||
button:not(:disabled),
|
||||
[type=button]:not(:disabled),
|
||||
[type=reset]:not(:disabled),
|
||||
[type=submit]:not(:disabled) {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
::-moz-focus-inner {
|
||||
padding: 0;
|
||||
border-style: none;
|
||||
}
|
||||
|
||||
textarea {
|
||||
resize: vertical;
|
||||
}
|
||||
|
||||
fieldset {
|
||||
min-width: 0;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
border: 0;
|
||||
}
|
||||
|
||||
legend {
|
||||
float: right;
|
||||
width: 100%;
|
||||
padding: 0;
|
||||
margin-bottom: 0.5rem;
|
||||
font-size: calc(1.275rem + 0.3vw);
|
||||
line-height: inherit;
|
||||
}
|
||||
@media (min-width: 1200px) {
|
||||
legend {
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
}
|
||||
legend + * {
|
||||
clear: right;
|
||||
}
|
||||
|
||||
::-webkit-datetime-edit-fields-wrapper,
|
||||
::-webkit-datetime-edit-text,
|
||||
::-webkit-datetime-edit-minute,
|
||||
::-webkit-datetime-edit-hour-field,
|
||||
::-webkit-datetime-edit-day-field,
|
||||
::-webkit-datetime-edit-month-field,
|
||||
::-webkit-datetime-edit-year-field {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
::-webkit-inner-spin-button {
|
||||
height: auto;
|
||||
}
|
||||
|
||||
[type=search] {
|
||||
-webkit-appearance: textfield;
|
||||
outline-offset: -2px;
|
||||
}
|
||||
|
||||
[type="tel"],
|
||||
[type="url"],
|
||||
[type="email"],
|
||||
[type="number"] {
|
||||
direction: ltr;
|
||||
}
|
||||
::-webkit-search-decoration {
|
||||
-webkit-appearance: none;
|
||||
}
|
||||
|
||||
::-webkit-color-swatch-wrapper {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
::-webkit-file-upload-button {
|
||||
font: inherit;
|
||||
-webkit-appearance: button;
|
||||
}
|
||||
|
||||
::file-selector-button {
|
||||
font: inherit;
|
||||
-webkit-appearance: button;
|
||||
}
|
||||
|
||||
output {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
iframe {
|
||||
border: 0;
|
||||
}
|
||||
|
||||
summary {
|
||||
display: list-item;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
progress {
|
||||
vertical-align: baseline;
|
||||
}
|
||||
|
||||
[hidden] {
|
||||
display: none !important;
|
||||
}
|
||||
/*# sourceMappingURL=bootstrap-reboot.rtl.css.map */
|
File diff suppressed because one or more lines are too long
6
src/frontend/src/css/bootstrap-5.3.3-dist/css/bootstrap-reboot.rtl.min.css
vendored
Normal file
6
src/frontend/src/css/bootstrap-5.3.3-dist/css/bootstrap-reboot.rtl.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
5402
src/frontend/src/css/bootstrap-5.3.3-dist/css/bootstrap-utilities.css
vendored
Normal file
5402
src/frontend/src/css/bootstrap-5.3.3-dist/css/bootstrap-utilities.css
vendored
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
6
src/frontend/src/css/bootstrap-5.3.3-dist/css/bootstrap-utilities.min.css
vendored
Normal file
6
src/frontend/src/css/bootstrap-5.3.3-dist/css/bootstrap-utilities.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
5393
src/frontend/src/css/bootstrap-5.3.3-dist/css/bootstrap-utilities.rtl.css
vendored
Normal file
5393
src/frontend/src/css/bootstrap-5.3.3-dist/css/bootstrap-utilities.rtl.css
vendored
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
6
src/frontend/src/css/bootstrap-5.3.3-dist/css/bootstrap-utilities.rtl.min.css
vendored
Normal file
6
src/frontend/src/css/bootstrap-5.3.3-dist/css/bootstrap-utilities.rtl.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
12057
src/frontend/src/css/bootstrap-5.3.3-dist/css/bootstrap.css
vendored
Normal file
12057
src/frontend/src/css/bootstrap-5.3.3-dist/css/bootstrap.css
vendored
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
6
src/frontend/src/css/bootstrap-5.3.3-dist/css/bootstrap.min.css
vendored
Normal file
6
src/frontend/src/css/bootstrap-5.3.3-dist/css/bootstrap.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
12030
src/frontend/src/css/bootstrap-5.3.3-dist/css/bootstrap.rtl.css
vendored
Normal file
12030
src/frontend/src/css/bootstrap-5.3.3-dist/css/bootstrap.rtl.css
vendored
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
6
src/frontend/src/css/bootstrap-5.3.3-dist/css/bootstrap.rtl.min.css
vendored
Normal file
6
src/frontend/src/css/bootstrap-5.3.3-dist/css/bootstrap.rtl.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
6314
src/frontend/src/css/bootstrap-5.3.3-dist/js/bootstrap.bundle.js
vendored
Normal file
6314
src/frontend/src/css/bootstrap-5.3.3-dist/js/bootstrap.bundle.js
vendored
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
7
src/frontend/src/css/bootstrap-5.3.3-dist/js/bootstrap.bundle.min.js
vendored
Normal file
7
src/frontend/src/css/bootstrap-5.3.3-dist/js/bootstrap.bundle.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
4447
src/frontend/src/css/bootstrap-5.3.3-dist/js/bootstrap.esm.js
vendored
Normal file
4447
src/frontend/src/css/bootstrap-5.3.3-dist/js/bootstrap.esm.js
vendored
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
7
src/frontend/src/css/bootstrap-5.3.3-dist/js/bootstrap.esm.min.js
vendored
Normal file
7
src/frontend/src/css/bootstrap-5.3.3-dist/js/bootstrap.esm.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
4494
src/frontend/src/css/bootstrap-5.3.3-dist/js/bootstrap.js
vendored
Normal file
4494
src/frontend/src/css/bootstrap-5.3.3-dist/js/bootstrap.js
vendored
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
7
src/frontend/src/css/bootstrap-5.3.3-dist/js/bootstrap.min.js
vendored
Normal file
7
src/frontend/src/css/bootstrap-5.3.3-dist/js/bootstrap.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -21,44 +21,11 @@ const Connections = () => {
|
||||
|
||||
return (
|
||||
<div>
|
||||
<h2>Подключения</h2>
|
||||
<h2>Настройки</h2>
|
||||
|
||||
{/* Webhook подключение */}
|
||||
{/* <div className="section">
|
||||
<h3>Подключения Webhooks</h3>
|
||||
<form onSubmit={handleWebhookSubmit}>
|
||||
<input type="text" name="webhookUrl" placeholder="URL Webhook" required />
|
||||
<input type="text" name="groups" placeholder="Группы (через запятую)" required />
|
||||
<button type="submit">Добавить Webhook</button>
|
||||
</form>
|
||||
|
||||
<ul>
|
||||
{webhooks.map((webhook, index) => (
|
||||
<li key={index}>
|
||||
Webhook: {webhook.url} (Группы: {webhook.groups.join(', ')})
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div> */}
|
||||
|
||||
{/* WebSocket подключение
|
||||
<div className="section">
|
||||
<h3>Подключения WebSockets</h3>
|
||||
<form
|
||||
onSubmit={(e) => {
|
||||
e.preventDefault();
|
||||
setWebsocketUrl(e.target.websocketUrl.value);
|
||||
}}
|
||||
>
|
||||
<input type="text" name="websocketUrl" placeholder="URL WebSocket" required />
|
||||
<button type="submit">Подключиться</button>
|
||||
</form>
|
||||
|
||||
{websocketUrl && <p>Подключено по WebSocket: {websocketUrl}</p>}
|
||||
</div> */}
|
||||
{/* WebSocket подключение */}
|
||||
<div className="section">
|
||||
<h3>Настройки уведомлений</h3>
|
||||
<h5>Уведомления</h5>
|
||||
<form
|
||||
onSubmit={(e) => {
|
||||
e.preventDefault();
|
||||
|
29
src/frontend/src/pages/Dashboard.css
Normal file
29
src/frontend/src/pages/Dashboard.css
Normal file
@ -0,0 +1,29 @@
|
||||
|
||||
|
||||
.background_color {
|
||||
background: var(--bs-border-color);
|
||||
}
|
||||
.coler-border{
|
||||
border: 5px solid #2c3e50;
|
||||
background: #5b7996;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.context {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-flow: column;
|
||||
}
|
||||
.context li {
|
||||
color: aliceblue;
|
||||
}
|
||||
.context .dot {
|
||||
width: 10px; /* Ширина точки */
|
||||
height: 10px; /* Высота точки */
|
||||
background-color: blue; /* Синий цвет */
|
||||
border-radius: 50%; /* Скругляем углы до круга */
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.context .btn {
|
||||
background-color: rgba(91, 100, 185, 0.34);
|
||||
}
|
@ -1,65 +1,63 @@
|
||||
import React, { useEffect, useRef, useState } from 'react';
|
||||
import * as THREE from 'three';
|
||||
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls';
|
||||
import { FontLoader } from 'three/examples/jsm/loaders/FontLoader';
|
||||
import { TextGeometry } from 'three/examples/jsm/geometries/TextGeometry';
|
||||
import Drone from './model/Drone';
|
||||
import HeightPoint from './model/HeightPoint';
|
||||
import { RandomHeightPoint } from './helpers/generateRandomHeightPoints';
|
||||
|
||||
// class HeightPoint {
|
||||
// constructor(x, y, height) {
|
||||
// this.x = x;
|
||||
// this.y = y;
|
||||
// this.height = height;
|
||||
// }
|
||||
// }
|
||||
import { RandomHeightPoint } from './helpers/generateRandomHeightPoints'
|
||||
import ModalWindow from './components/Modal/Modal';
|
||||
import './Dashboard.css';
|
||||
|
||||
// import { NavBar } from './components/Navbar/Navbar';
|
||||
const Dashboard = () => {
|
||||
const mountRef = useRef(null);
|
||||
const sceneRef = useRef(null);
|
||||
const [state, setState] = useState({
|
||||
heightData: RandomHeightPoint(),
|
||||
drones: [],
|
||||
selectedDrone: null,
|
||||
baseStation: [],
|
||||
selectedBaseStation: null,
|
||||
formData: { x: '', y: '', height: '' },
|
||||
mapSettings: { maxHeight: 20, coordX: 0, coordY: 0 },
|
||||
contextMenu: { visible: false, x: 0, y: 0 },
|
||||
mouseState: { x: 0, y: 0, z: 0 },
|
||||
});
|
||||
const mouse = new THREE.Vector2();
|
||||
const mountRef = useRef(null); // Указатель монтирования
|
||||
const sceneRef = useRef(null); // Указатель на сцену
|
||||
const mouse = new THREE.Vector2(); // Мышка
|
||||
const [heightData, setHeightData] = useState(RandomHeightPoint()); // Высоты
|
||||
const [formData, setFormData] = useState({ x: '', y: '', height: '' }); // Форма для ввода данных карты
|
||||
const [mouseState, setMouseState] = useState({ x: 0, y: 0, z: 0 }); // Форма для ввода данных карты
|
||||
|
||||
const [drones, setDrones] = useState([]) // Все дроны
|
||||
const [selectedDrone, setSelectedDrone] = useState(null); // Состояние для выбранного дрона
|
||||
const [baseStation, setBaseStation] = useState([]) // Все базовые станции
|
||||
const [selectedBaseStation, setSelectedBaseStation] = useState(null); // Состояние для выбранной базовой станции
|
||||
const [mapSettings, setMapSettings] = useState({maxHeight: 20, coordX: 0, coordY: 0, }); // Настройки карты
|
||||
|
||||
|
||||
|
||||
const [contextMenu, setContextMenu] = useState({ visible: false, x: 0, y: 0 }); // контекстное меню сцены
|
||||
|
||||
useEffect(() => {
|
||||
if (!mountRef.current) return;
|
||||
|
||||
let width = mountRef.current.clientWidth;
|
||||
let height = mountRef.current.clientHeight;
|
||||
|
||||
// Создание сцены и камеры
|
||||
// Создаем объект сцены
|
||||
const scene = new THREE.Scene();
|
||||
// Сохраняем ссылку на сцену
|
||||
sceneRef.current = scene;
|
||||
const camera = new THREE.PerspectiveCamera(75, width / height, 0.1, 1000);
|
||||
camera.position.set(0, 20, 30);
|
||||
// Создаем камеру
|
||||
const camera = new THREE.PerspectiveCamera(75, width / height, 0.1, 2000);
|
||||
camera.position.set(0, 80, 120);
|
||||
|
||||
const renderer = new THREE.WebGLRenderer();
|
||||
renderer.setSize(width, height);
|
||||
mountRef.current.appendChild(renderer.domElement);
|
||||
|
||||
// Плоскость для высотной карты
|
||||
const geometry = new THREE.PlaneGeometry(20, 20, 4, 4);
|
||||
// Плоскость для высотной карты :: TODO :: W/H/Ws/Hs change
|
||||
const geometry = new THREE.PlaneGeometry(200, 200, 20, 20);
|
||||
const vertices = geometry.attributes.position.array;
|
||||
const colors = [];
|
||||
const color = new THREE.Color();
|
||||
|
||||
const { heightData, mapSettings } = state;
|
||||
const minHeight = Math.min(...heightData.map(point => point.height));
|
||||
const maxHeight = Math.max(mapSettings.maxHeight, ...heightData.map(point => point.height));
|
||||
const minHeight = Math.min(...heightData.map((point) => point.height));
|
||||
const maxHeight = Math.max(mapSettings.maxHeight, ...heightData.map((point) => point.height));
|
||||
|
||||
// Задание высот и цветов вершин
|
||||
for (let i = 0; i < vertices.length; i += 3) {
|
||||
const x = Math.floor(i / 3) % 5;
|
||||
const y = Math.floor(i / (3 * 5));
|
||||
const heightPoint = heightData.find(point => point.x === x && point.y === y);
|
||||
|
||||
const heightPoint = heightData.find((point) => point.x === x && point.y === y);
|
||||
const heightValue = heightPoint ? heightPoint.height : 0;
|
||||
|
||||
vertices[i + 2] = heightValue;
|
||||
@ -68,6 +66,7 @@ const Dashboard = () => {
|
||||
color.setHSL(0.7 * (1 - normalizedHeight), 1, 0.5);
|
||||
colors.push(color.r, color.g, color.b);
|
||||
}
|
||||
|
||||
geometry.setAttribute('color', new THREE.Float32BufferAttribute(colors, 3));
|
||||
|
||||
const material = new THREE.MeshBasicMaterial({
|
||||
@ -80,146 +79,277 @@ const Dashboard = () => {
|
||||
mesh.rotation.x = -Math.PI / 2;
|
||||
scene.add(mesh);
|
||||
|
||||
const axesHelper = new THREE.AxesHelper(10);
|
||||
scene.add(axesHelper);
|
||||
|
||||
const controls = new OrbitControls(camera, renderer.domElement);
|
||||
controls.enableDamping = true;
|
||||
|
||||
const light = new THREE.DirectionalLight(0xffffff, 1);
|
||||
light.position.set(0, 50, 50).normalize();
|
||||
scene.add(light);
|
||||
// Обработка кликов на сцене
|
||||
const handleClick = (event) => {
|
||||
mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
|
||||
mouse.y = - (event.clientY / window.innerHeight) * 2 + 1;
|
||||
console.log('Mouse coordinates:', mouse);
|
||||
const raycaster = new THREE.Raycaster();
|
||||
raycaster.setFromCamera(mouse, camera);
|
||||
|
||||
const intersects = raycaster.intersectObjects(drones.map(drone => drone.getObject()), true);
|
||||
console.log('Intersections:', intersects)
|
||||
console.log('Drones:', drones.map(drone => [drone.getObject(), drone.getObject().position, drone.name]))
|
||||
if (intersects.length > 0) {
|
||||
const selected = intersects[0].object;
|
||||
console.log('Clicked on:', selected); // Лог для проверки объекта
|
||||
const drone = drones.find(drone => drone.getObject().children[0] === selected);
|
||||
if (drone) {
|
||||
if (selectedDrone) {
|
||||
selectedDrone.getObject().children[0].material.color.set(0xff0000);
|
||||
}
|
||||
drone.getObject().children[0].material.color.set(0xff1111);
|
||||
setSelectedDrone(drone);
|
||||
}
|
||||
} else {
|
||||
if (selectedDrone) {
|
||||
selectedDrone.getObject().children[0].material.color.set(0xff0000);
|
||||
setSelectedDrone(null);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const handleMouseMove = (event) => {
|
||||
let x = event.x;
|
||||
let y = event.y;
|
||||
setMouseState({ x: x, y: y, z: 0 });
|
||||
}
|
||||
const animate = () => {
|
||||
requestAnimationFrame(animate);
|
||||
controls.update();
|
||||
renderer.render(scene, camera);
|
||||
};
|
||||
animate();
|
||||
|
||||
// События мыши
|
||||
const handleClick = (event) => {
|
||||
const { drones, selectedDrone } = state;
|
||||
mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
|
||||
mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;
|
||||
|
||||
const raycaster = new THREE.Raycaster();
|
||||
raycaster.setFromCamera(mouse, camera);
|
||||
const intersects = raycaster.intersectObjects(drones.map(drone => drone.getObject()), true);
|
||||
|
||||
if (intersects.length > 0) {
|
||||
const selected = intersects[0].object;
|
||||
const drone = drones.find(drone => drone.getObject().children[0] === selected);
|
||||
if (drone) {
|
||||
if (selectedDrone) selectedDrone.getObject().children[0].material.color.set(0xff0000);
|
||||
drone.getObject().children[0].material.color.set(0xff1111);
|
||||
setState(prevState => ({ ...prevState, selectedDrone: drone }));
|
||||
}
|
||||
} else if (selectedDrone) {
|
||||
selectedDrone.getObject().children[0].material.color.set(0xff0000);
|
||||
setState(prevState => ({ ...prevState, selectedDrone: null }));
|
||||
}
|
||||
};
|
||||
|
||||
renderer.domElement.addEventListener('click', handleClick);
|
||||
renderer.domElement.addEventListener('mousemove', (event) => {
|
||||
setState(prevState => ({
|
||||
...prevState,
|
||||
mouseState: { x: event.clientX, y: event.clientY, z: 0 }
|
||||
}));
|
||||
renderer.domElement.addEventListener('mousemove', handleMouseMove);
|
||||
|
||||
|
||||
animate();
|
||||
drones.forEach(droneData => {
|
||||
scene.add(droneData.getObject());
|
||||
});
|
||||
|
||||
// Обработка нажатия ПКМ
|
||||
renderer.domElement.addEventListener('contextmenu', (event) => {
|
||||
event.preventDefault();
|
||||
setContextMenu({
|
||||
visible: true,
|
||||
x: event.clientX,
|
||||
y: event.clientY,
|
||||
});
|
||||
});
|
||||
return () => {
|
||||
if (mountRef.current) {
|
||||
mountRef.current.removeChild(renderer.domElement);
|
||||
}
|
||||
};
|
||||
}, [state.drones, state.heightData, state.mapSettings]);
|
||||
}, [drones, heightData, mapSettings]);
|
||||
|
||||
// Добавление дрона в сцену
|
||||
const handleAddDrone = () => {
|
||||
const { drones } = state;
|
||||
const drone = new Drone(Date.now() / 1000);
|
||||
const droneMaterial = new THREE.MeshBasicMaterial({ color: 0xff0000 });
|
||||
drone.getObject().children[0].material = droneMaterial;
|
||||
drone.setPosition(Math.random() * 20 - 10, 3, Math.random() * 20 - 10);
|
||||
setState(prevState => ({
|
||||
...prevState,
|
||||
drones: [...prevState.drones, drone]
|
||||
}));
|
||||
sceneRef.current.add(drone.getObject());
|
||||
if (sceneRef.current) {
|
||||
const current = Date.now();
|
||||
const drone = new Drone(current / 1000);
|
||||
// Создаем новый материал для каждого дрона
|
||||
drone.setPosition(Math.random() * 20 - 10, 20, Math.random() * 20 - 10);
|
||||
setDrones((prevDrones) => [...prevDrones, drone]);
|
||||
console.log(drones.map(drone => drone.getObject().children[0]));
|
||||
sceneRef.current.add(drone.getObject());
|
||||
}
|
||||
};
|
||||
|
||||
const handleInputChange = (event) => {
|
||||
const { name, value } = event.target;
|
||||
setState(prevState => ({
|
||||
...prevState,
|
||||
formData: { ...prevState.formData, [name]: value }
|
||||
}));
|
||||
};
|
||||
// Обработчик ввода на форму
|
||||
// const handleInputChange = (event) => {
|
||||
// const { name, value } = event.target;
|
||||
// setFormData({
|
||||
// ...formData,
|
||||
// [name]: value,
|
||||
// });
|
||||
// };
|
||||
|
||||
const handleAddHeight = (event) => {
|
||||
event.preventDefault();
|
||||
const { formData, heightData } = state;
|
||||
const newPoint = new HeightPoint(parseInt(formData.x), parseInt(formData.y), parseFloat(formData.height));
|
||||
setState(prevState => ({
|
||||
...prevState,
|
||||
heightData: [...prevState.heightData, newPoint],
|
||||
formData: { x: '', y: '', height: '' }
|
||||
}));
|
||||
};
|
||||
// Добавление элемента карты высот (высоты)
|
||||
// const handleAddHeight = (event) => {
|
||||
// event.preventDefault();
|
||||
// const { x, y, height } = formData;
|
||||
// const newPoint = new HeightPoint(parseInt(x), parseInt(y), parseFloat(height));
|
||||
// setHeightData((prevData) => [...prevData, newPoint]);
|
||||
// setFormData({ x: '', y: '', height: '' });
|
||||
// };
|
||||
|
||||
const handleSettingsChange = (event) => {
|
||||
const { name, value } = event.target;
|
||||
setState(prevState => ({
|
||||
...prevState,
|
||||
mapSettings: { ...prevState.mapSettings, [name]: value }
|
||||
}));
|
||||
};
|
||||
// Изменение настроек
|
||||
// const handleSettingsChange = (event) => {
|
||||
// const { name, value } = event.target;
|
||||
// setMapSettings({
|
||||
// ...mapSettings,
|
||||
// [name]: value,
|
||||
// });
|
||||
// };
|
||||
|
||||
// Открытие контекстного меню
|
||||
const handleContextMenuClick = (action) => {
|
||||
if (action === 'add') handleAddDrone();
|
||||
setState(prevState => ({
|
||||
...prevState,
|
||||
contextMenu: { ...prevState.contextMenu, visible: false }
|
||||
}));
|
||||
if (action === 'add') {
|
||||
handleAddDrone();
|
||||
console.log('Добавить объект');
|
||||
} else if (action === 'save') {
|
||||
console.log('Сохранить промежуточный результат');
|
||||
}
|
||||
setContextMenu({ ...contextMenu, visible: false });
|
||||
};
|
||||
|
||||
// IS LOADING
|
||||
// <div class="spinner-border text-primary" role="status">
|
||||
// <span class="visually-hidden">Loading...</span>
|
||||
// </div>
|
||||
|
||||
return (
|
||||
<div style={{ flex: 1 }}>
|
||||
<h1>Drone Network Simulator</h1>
|
||||
<div>
|
||||
<p>x: {state.mouseState.x} y: {state.mouseState.y} z: {state.mouseState.z}</p>
|
||||
<div ref={mountRef} style={{ width: '100%', height: '500px', position: 'relative' }} />
|
||||
<div className='col'>
|
||||
{/* TODO: USERS BADGE */}
|
||||
<h4><b>Drone</b> Network Simulator - окно разработки</h4>
|
||||
</div>
|
||||
{state.contextMenu.visible && (
|
||||
<ul style={{ position: 'absolute', top: `${state.contextMenu.y}px`, left: `${state.contextMenu.x}px`, backgroundColor: 'white', padding: '10px', zIndex: 1000 }}>
|
||||
<li className="button" onClick={() => handleContextMenuClick('add')}>Добавить объект</li>
|
||||
<li className="button" onClick={() => handleContextMenuClick('save')}>Сохранить промежуточный результат</li>
|
||||
<li className="button" onClick={() => handleContextMenuClick('cancel')}>Отмена</li>
|
||||
{/* <NavBar/> */}
|
||||
|
||||
<div className='coler-border'>
|
||||
<div>
|
||||
<p>X: {mouseState.x} Y: {mouseState.y} Z: {mouseState.z}</p>
|
||||
</div>
|
||||
<div ref={mountRef} style={{
|
||||
minWidth: '100%',
|
||||
minHeight: '60vh',
|
||||
position: 'relative'
|
||||
}} />
|
||||
<div class="btn-toolbar" role="toolbar" aria-label="Toolbar with button groups">
|
||||
<div class="btn-group me-2" role="group" aria-label="First group">
|
||||
|
||||
<button type="button" class="btn btn-success">
|
||||
<i class="bi-plus"/>Добавить
|
||||
</button>
|
||||
|
||||
<button type="button" class="btn btn-success">
|
||||
<i class="bi-trash"/>Удалить
|
||||
</button>
|
||||
|
||||
<button type="button" class="btn btn-success">
|
||||
<i class="bi-search"/>Выбрать
|
||||
</button>
|
||||
|
||||
<button type="button" class="btn btn-success">
|
||||
<i class="bi-save"/>Сохранить
|
||||
</button>
|
||||
|
||||
</div>
|
||||
<div class="btn-group me-2" role="group" aria-label="Second group">
|
||||
|
||||
<button type="button" class="btn btn-secondary">
|
||||
<i class="bi-box-arrow-in-down"/>Загрузить данные
|
||||
</button>
|
||||
|
||||
<button type="button" class="btn btn-secondary">
|
||||
<i class="bi-filetype-json"/>Выгрузить
|
||||
</button>
|
||||
|
||||
<button type="button" class="btn btn-secondary">
|
||||
<i class="bi-map"/>Настройки карты
|
||||
</button>
|
||||
|
||||
{/* <button type="button" class="btn btn-secondary">6</button> */}
|
||||
</div>
|
||||
<div class="btn-group" role="group" aria-label="Third group">
|
||||
<button type="button" class="btn btn-info">
|
||||
<i class="bi-play"/>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Контекстное меню */}
|
||||
{contextMenu.visible && (
|
||||
<ul
|
||||
style={{
|
||||
position: 'absolute',
|
||||
top: `${contextMenu.y}px`,
|
||||
left: `${contextMenu.x}px`,
|
||||
backgroundColor: 'transparent',
|
||||
listStyle: 'none',
|
||||
padding: '2px',
|
||||
boxShadow: '0px 0px 5px rgba(0,0,0,0.3)',
|
||||
zIndex: 1000,
|
||||
}}
|
||||
>
|
||||
<div className='context'>
|
||||
<div class="dot"></div>
|
||||
<li className={"btn"} onClick={() => handleContextMenuClick('add')}>Добавить объект</li>
|
||||
<li className={"btn"} onClick={() => handleContextMenuClick('save')}>Сохранить промежуточный результат</li>
|
||||
<li className={"btn"} onClick={() => handleContextMenuClick('cancel')}>Отмена</li>
|
||||
</div>
|
||||
</ul>
|
||||
)}
|
||||
<div className="columns">
|
||||
<div className='column'>
|
||||
<form onSubmit={handleAddHeight} style={{ marginTop: '20px' }}>
|
||||
<label>Координата X:</label>
|
||||
<input className="input" type="number" name="x" value={state.formData.x} onChange={handleInputChange} />
|
||||
<label>Координата Y:</label>
|
||||
<input className="input" type="number" name="y" value={state.formData.y} onChange={handleInputChange} />
|
||||
<label>Высота:</label>
|
||||
<input className="input" type="number" name="height" value={state.formData.height} onChange={handleInputChange} />
|
||||
<button type="submit" className="button">Добавить координаты</button>
|
||||
</form>
|
||||
</div>
|
||||
<div className="column">
|
||||
<form style={{ marginTop: '20px' }}>
|
||||
<label>Максимальная высота</label>
|
||||
<input className="input" type="number" name="maxHeight" value={state.mapSettings.maxHeight} onChange={handleSettingsChange} />
|
||||
<label>Координата X</label>
|
||||
<input className="input" type="number" name="coordX" value={state.mapSettings.coordX} onChange={handleSettingsChange} />
|
||||
<label>Координата Y</label>
|
||||
<input className="input" type="number" name="coordY" value={state.mapSettings.coordY} onChange={handleSettingsChange} />
|
||||
<button type="submit" className="button">Применить</button>
|
||||
</form>
|
||||
</div>
|
||||
{/* Форма для добавления новых высот */}
|
||||
{/* <div className='column'>
|
||||
<form onSubmit={handleAddHeight} style={{ marginTop: '20px' }}>
|
||||
<div>
|
||||
<label>Координата X:</label>
|
||||
<input
|
||||
className="input is-primary"
|
||||
type="number"
|
||||
name="x"
|
||||
value={formData.x}
|
||||
onChange={handleInputChange}
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label>Координата Y:</label>
|
||||
<input
|
||||
className="input is-primary"
|
||||
type="number"
|
||||
name="y"
|
||||
value={formData.y}
|
||||
onChange={handleInputChange}
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label>Высота:</label>
|
||||
<input
|
||||
className="input is-primary"
|
||||
type="number"
|
||||
name="height"
|
||||
value={formData.height}
|
||||
onChange={handleInputChange}
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
<button className='button' type="submit">Добавить точку высоты</button>
|
||||
</form>
|
||||
</div> */}
|
||||
{/* Настройки карты */}
|
||||
{/* <div className='column'>
|
||||
<div style={{ marginTop: '20px' }}>
|
||||
<h2>Настройки карты</h2>
|
||||
<div>
|
||||
<label>Максимальная высота:</label>
|
||||
<input
|
||||
className="input"
|
||||
type="number"
|
||||
name="maxHeight"
|
||||
value={mapSettings.maxHeight}
|
||||
onChange={handleSettingsChange}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div> */}
|
||||
</div>
|
||||
<button className="button is-danger" onClick={handleAddDrone}>Добавить дрон</button>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
@ -50,7 +50,13 @@ const DeviceGroups = () => {
|
||||
onChange={(e) => setNewGroupName(e.target.value)}
|
||||
placeholder="Название шаблона"
|
||||
/>
|
||||
<button onClick={createGroup}>Создать шаблон</button>
|
||||
<input
|
||||
type="text"
|
||||
value={newGroupName}
|
||||
onChange={(e) => setNewGroupName(e.target.value)}
|
||||
placeholder="JSON Template"
|
||||
/>
|
||||
<button className='btn btn-success' onClick={createGroup}>Создать шаблон</button>
|
||||
</div>
|
||||
|
||||
<ul>
|
||||
|
@ -3,13 +3,13 @@ import React from 'react';
|
||||
const Docs = () => {
|
||||
return (
|
||||
<div className="block">
|
||||
<div class="block">
|
||||
<div className="block">
|
||||
Документация <strong>Drone Network Simulator</strong>.
|
||||
</div>
|
||||
<div class="block">
|
||||
<div className="block">
|
||||
created by <strong>@moxitech</strong>
|
||||
</div>
|
||||
<div class="block">
|
||||
<div className="block">
|
||||
Для начала работы необходимо войти в систему
|
||||
</div>
|
||||
</div>
|
||||
|
@ -1,34 +1,59 @@
|
||||
import React from 'react';
|
||||
import '../Main.css';
|
||||
import { InfoBlock } from './components/DroneAssets/InfoBlock';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import '../css/Custom/Main.css';
|
||||
import { ServerRequest } from '../Services/Server';
|
||||
|
||||
const Main = () => {
|
||||
const [rooms, setRooms] = useState(null)
|
||||
|
||||
const makeSimulation = () => {
|
||||
useEffect(() => {
|
||||
connectSimulation()
|
||||
}, [])
|
||||
const createSimulation = () => {
|
||||
// POST $BASE_ADDR/createSimulation?userToken=?
|
||||
}
|
||||
|
||||
const connectSimulation = () => {
|
||||
// POST $BASE_ADDR/connectSimulation?userToken=?
|
||||
ServerRequest("/simulations/active", "GET").then( x => {
|
||||
console.log(x.data, x.status)
|
||||
if (x.status === 200) {
|
||||
setRooms(x.data.rooms_ids)
|
||||
} else {
|
||||
setRooms(null)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
return (
|
||||
<div className='main__imager'>
|
||||
<InfoBlock />
|
||||
<div class="columns ">
|
||||
<div class="column">
|
||||
<h1 class="title">Создать новую симуляцию</h1>
|
||||
<button class="button">Create</button>
|
||||
</div>
|
||||
<div class="column">
|
||||
<h1 class="title">Присоединиться к моделированию</h1>
|
||||
<div>
|
||||
<p>Расчет полета до камчатки</p>
|
||||
<button class="button">Connect</button>
|
||||
<div className='main__imager' style={{marginTop: "2%"}}>
|
||||
<div className="row align-items-start">
|
||||
<div className="col">
|
||||
<h1 className="title">Создать новую симуляцию</h1>
|
||||
<hr/>
|
||||
<button className="btn btn-primary">Create</button>
|
||||
</div>
|
||||
<div className="col">
|
||||
<h1 className="title">Присоединиться к моделированию</h1>
|
||||
<hr/>
|
||||
{rooms && rooms.length > 0 ? (
|
||||
rooms.map(room => (
|
||||
<div className='row' key={room}>
|
||||
<div className='col'>
|
||||
<h3>{room.name} | UUID : {room.uuid}</h3>
|
||||
</div>
|
||||
<div className='col'>
|
||||
<button className="btn btn-primary">
|
||||
Connect
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
))
|
||||
) : (
|
||||
<p>Пока никто не работает 😒</p>
|
||||
)}
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
};
|
||||
|
||||
|
@ -4,20 +4,30 @@ import '../UserAccount.scss';
|
||||
const PrevCalc = () => {
|
||||
|
||||
return (
|
||||
<table class="table">
|
||||
<table className="table">
|
||||
<thead>
|
||||
<th><abbr title="Уникальный идентификатор в базе данных">UID</abbr></th>
|
||||
<th><abbr title="Название">Имя</abbr></th>
|
||||
<th>Пользователь</th>
|
||||
<th>Время начала</th>
|
||||
<th>Время конца</th>
|
||||
<tr>
|
||||
<th scope='col'><abbr title="Уникальный идентификатор в базе данных">UID</abbr></th>
|
||||
<th scope='col'><abbr title="Название">Имя</abbr></th>
|
||||
<th scope='col'>Пользователь</th>
|
||||
<th scope='col'>Время начала</th>
|
||||
<th scope='col'>Время конца</th>
|
||||
<th scope='col'>Действия</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<th>1</th>
|
||||
<td>Калькуляция полета до варшавы</td>
|
||||
<td>Гитлер</td>
|
||||
<td>1:00</td>
|
||||
<td>4:04</td>
|
||||
<tr>
|
||||
<th scope="row">1</th>
|
||||
<td>Калькуляция полета до варшавы</td>
|
||||
<td>Гитлер</td>
|
||||
<td>1:00</td>
|
||||
<td>4:04</td>
|
||||
<td>
|
||||
<button className='btn btn-primary'>
|
||||
Загрузить
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
)
|
||||
|
@ -1,35 +0,0 @@
|
||||
|
||||
import React from "react"
|
||||
|
||||
export const InfoBlock = () => {
|
||||
return(
|
||||
|
||||
|
||||
<nav className="level">
|
||||
<div className="level-item has-text-centered">
|
||||
<div>
|
||||
<p className="heading">Активных сессий</p>
|
||||
<p className="title">0</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="level-item has-text-centered">
|
||||
<div>
|
||||
<p className="heading">Горутин</p>
|
||||
<p className="title">123</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="level-item has-text-centered">
|
||||
<div>
|
||||
<p className="heading">Нагрузка сервера</p>
|
||||
<p className="title">456K</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="level-item has-text-centered">
|
||||
<div>
|
||||
<p className="heading">Объем хранилища</p>
|
||||
<p className="title">789</p>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
)
|
||||
}
|
@ -0,0 +1 @@
|
||||
{"accessors":[],"asset":{"generator":"Open CASCADE Technology 7.6 [dev.opencascade.org]","version":"2.0"},"bufferViews":[],"buffers":[{"byteLength":0,"uri":"drone_normalized_gltf.bin"}],"meshes":[],"nodes":[],"scene":0,"scenes":[{"nodes":[]}]}
|
13
src/frontend/src/pages/components/Modal/Modal.css
Normal file
13
src/frontend/src/pages/components/Modal/Modal.css
Normal file
@ -0,0 +1,13 @@
|
||||
|
||||
|
||||
.m_size_fixed {
|
||||
color: antiquewhite;
|
||||
width: 200px;
|
||||
height: 200px;
|
||||
}
|
||||
.m_black_color {
|
||||
color: black;
|
||||
}
|
||||
.m_font_scale_32 {
|
||||
font-size: 32px;
|
||||
}
|
18
src/frontend/src/pages/components/Modal/Modal.js
Normal file
18
src/frontend/src/pages/components/Modal/Modal.js
Normal file
@ -0,0 +1,18 @@
|
||||
import React, { useState } from 'react';
|
||||
import Modal from 'react-modal';
|
||||
import './Modal.css'
|
||||
const ModalWindow = ({ isOpen, closeModal, openModal, title }) => {
|
||||
|
||||
|
||||
return (
|
||||
|
||||
<div className=''>
|
||||
<Modal className={"m_size_fixed"} isOpen={isOpen} onRequestClose={closeModal}>
|
||||
<h2 className='m_black_color m_font_scale_32'>Это модальное окно!</h2>
|
||||
<button className='button is-primary' onClick={closeModal}>Закрыть</button>
|
||||
</Modal>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default ModalWindow;
|
10
src/frontend/src/pages/components/Navbar/Navbar.js
Normal file
10
src/frontend/src/pages/components/Navbar/Navbar.js
Normal file
@ -0,0 +1,10 @@
|
||||
import React from "react"
|
||||
|
||||
|
||||
export const NavBar = () => {
|
||||
|
||||
|
||||
return(
|
||||
<p></p>
|
||||
)
|
||||
}
|
@ -2,8 +2,8 @@ import HeightPoint from '../model/HeightPoint';
|
||||
|
||||
export const RandomHeightPoint = () => {
|
||||
let result = [];
|
||||
for (let i = 0; i < 20; i++) {
|
||||
for (let j = 0; j < 20; j++) {
|
||||
for (let i = 0; i < 100; i++) {
|
||||
for (let j = 0; j < 100; j++) {
|
||||
result.push(new HeightPoint(i, j, Math.random() * 10 + 1));
|
||||
}
|
||||
}
|
||||
|
@ -1,14 +1,20 @@
|
||||
import * as THREE from 'three';
|
||||
|
||||
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js';
|
||||
class Drone {
|
||||
constructor(name) {
|
||||
constructor(name, scale = 0.5) {
|
||||
this.object = new THREE.Object3D();
|
||||
this.geometry = new THREE.BoxGeometry(1, 1, 1);
|
||||
this.material = new THREE.MeshBasicMaterial({ color: 0xff0000 });
|
||||
this.name = name;
|
||||
const cube = new THREE.Mesh(this.geometry, this.material);
|
||||
// cube.material.M = new THREE.Color(0x000000); // Инициализируем с базовым эмиссивным цветом
|
||||
this.object.add(cube);
|
||||
|
||||
// Инициализируем GLTFLoader
|
||||
const loader = new GLTFLoader();
|
||||
|
||||
// Загружаем модель из файла GLTF
|
||||
loader.load("/ImageToStl.com_drone.glb", (gltf) => {
|
||||
this.object.add(gltf.scene); // Добавляем сцену из GLTF к объекту дрона
|
||||
gltf.scene.scale.set(scale, scale, scale); // Применяем масштаб
|
||||
}, undefined, (error) => {
|
||||
console.error("Ошибка загрузки GLTF:", error);
|
||||
});
|
||||
}
|
||||
|
||||
setPosition(x, y, z) {
|
||||
@ -18,8 +24,7 @@ class Drone {
|
||||
getObject() {
|
||||
return this.object;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
export default Drone;
|
||||
|
@ -37,6 +37,78 @@ func (o *Modulation) DeleteObjectIfExists(name string) {
|
||||
}
|
||||
}
|
||||
}
|
||||
func (o *Modulation) MirrorPayloadToSimulationStruct() {
|
||||
|
||||
}
|
||||
|
||||
func (o *Modulation) RunSimulator() {
|
||||
// // Пример карты высот, замените на настоящие данные
|
||||
// heightData := [][]float64{
|
||||
// {0, 10, 15, 20},
|
||||
// {5, 15, 25, 30},
|
||||
// {10, 20, 35, 40},
|
||||
// {15, 25, 40, 50},
|
||||
// }
|
||||
|
||||
// // Определяем карту высот
|
||||
//
|
||||
// mapObj := &simulator.Map{
|
||||
// Name: "Example Map",
|
||||
// MinBound: [3]float64{-1000, -1000, 0},
|
||||
// MaxBound: [3]float64{1000, 1000, 500},
|
||||
// HeightData: heightData,
|
||||
// }
|
||||
//
|
||||
// // Определяем дронов
|
||||
//
|
||||
// drones := []*simulator.Drone{
|
||||
// {
|
||||
// ID: 1,
|
||||
// Name: "Drone 1",
|
||||
// Coords: [3]float64{100, 100, 50},
|
||||
// Params: simulator.DroneParams{
|
||||
// AntennaRadius: 500,
|
||||
// AntennaDirection: [3]float64{1, 0, 0},
|
||||
// Waypoints: [][3]float64{{200, 200, 50}},
|
||||
// Speed: 10,
|
||||
// MeshName: "MeshA",
|
||||
// },
|
||||
// },
|
||||
// }
|
||||
//
|
||||
// // Определяем базовые станции
|
||||
//
|
||||
// baseStations := []*simulator.BaseStation{
|
||||
// {
|
||||
// ID: 1,
|
||||
// Name: "BaseStation1",
|
||||
// Coords: [3]float64{0, 0, 0},
|
||||
// Params: simulator.BaseStationParams{
|
||||
// AntennaRadius: 2000,
|
||||
// AntennaDirection: [3]float64{1, 0, 0},
|
||||
// },
|
||||
// },
|
||||
// }
|
||||
//
|
||||
// // Создаем симуляцию
|
||||
//
|
||||
// sim := &simulator.NetworkSimulation{
|
||||
// Map: mapObj,
|
||||
// Drones: drones,
|
||||
// BaseStations: baseStations,
|
||||
// TimeStep: 2,
|
||||
// }
|
||||
//
|
||||
// // Запуск симуляции на 300 секунд
|
||||
// result_sim := sim.Simulate(300)
|
||||
// result := u_sorting.SortMap(result_sim)
|
||||
//
|
||||
// for time, state := range result {
|
||||
// for localstate, f := range state {
|
||||
// fmt.Printf("%v| %v sec :: %v\n", time, localstate, f)
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
// SpawnExampleData создает случайные данные и перезаписывает карту
|
||||
func (o *Modulation) SpawnExampleData() bool {
|
||||
|
@ -11,6 +11,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"github.com/gofiber/fiber/v2/middleware/cors"
|
||||
"github.com/gofiber/websocket/v2"
|
||||
)
|
||||
|
||||
@ -20,6 +21,10 @@ var (
|
||||
|
||||
func SpawnServer() error {
|
||||
app := fiber.New()
|
||||
app.Use(cors.New(cors.Config{
|
||||
AllowHeaders: "*",
|
||||
AllowOrigins: "*",
|
||||
}))
|
||||
go DispatchRooms()
|
||||
Rooms = make(map[string]*WebsocketRoom)
|
||||
app.Get("/", func(c *fiber.Ctx) error {
|
||||
|
@ -216,11 +216,12 @@ func (room *WebsocketRoom) InsertMapFromMongo(name string) {
|
||||
}
|
||||
|
||||
// RunSimulation запускает симуляцию в горутине
|
||||
func (room *WebsocketRoom) RunSimulation(name string) {
|
||||
func (room *WebsocketRoom) RunSimulation(name string) (int, error) {
|
||||
// TODO +NormalizeDataForSimulation()
|
||||
roomsMutex.Lock()
|
||||
defer roomsMutex.Unlock()
|
||||
room.Modulation.DeleteObjectIfExists(name)
|
||||
room.Modulation.MirrorPayloadToSimulationStruct()
|
||||
return -1, nil
|
||||
}
|
||||
|
||||
// NormalizeDataForSimulation - Преобразование данных для отправки в симуляцию
|
||||
|
@ -83,11 +83,12 @@ func (sim *NetworkSimulation) Simulate(totalTime int) map[int]map[string][]inter
|
||||
// Проверка соединения с базовой станцией
|
||||
if !IsDroneInNetwork(d, sim.BaseStations, sim.Map) {
|
||||
// Если дрон имеет mesh-сеть, ищем другой дрон для ретрансляции
|
||||
closestDrone := FindClosestDroneToBaseStation(d, sim.Drones, sim.BaseStations[0], sim.Map)
|
||||
if closestDrone != nil {
|
||||
// Дрон может передавать данные через другой дрон
|
||||
// Логику передачи можно добавить сюда
|
||||
}
|
||||
FindClosestDroneToBaseStation(d, sim.Drones, sim.BaseStations[0], sim.Map)
|
||||
// closestDrone :=
|
||||
// if closestDrone != nil {
|
||||
// Дрон может передавать данные через другой дрон
|
||||
// Логику передачи можно добавить сюда
|
||||
// }
|
||||
}
|
||||
|
||||
// Добавляем данные о дроне в текущее состояние
|
||||
@ -243,6 +244,7 @@ func CalculateDataRate(modulation string, bandwidth float64) float64 {
|
||||
return spectralEfficiency * bandwidth // скорость передачи данных в Mbps
|
||||
}
|
||||
|
||||
// MakeExampleMap создает статическую карту
|
||||
func MakeExampleMap() Map {
|
||||
heightData := [][]float64{
|
||||
{0, 10, 15, 20},
|
||||
|
Loading…
Reference in New Issue
Block a user