Main GUI screen and service for server-side logic
This commit is contained in:
parent
a7d936fff6
commit
fc949f83a8
1
.env
1
.env
@ -1,5 +1,6 @@
|
||||
SERVER_BASE_ADDRESS=0.0.0.0:8080
|
||||
|
||||
|
||||
MONGO_INITDB_ROOT_USERNAME=moxitech
|
||||
MONGO_INITDB_ROOT_PASSWORD=moxitech
|
||||
MONGO_INITDB_DATABASE=drone-network-simulator
|
||||
|
BIN
src/frontend/public/blueprints.jpg
Normal file
BIN
src/frontend/public/blueprints.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 57 KiB |
@ -3,6 +3,7 @@ import DeviceGroups from "./pages/DeviceGroups";
|
||||
import Devices from "./pages/Devices";
|
||||
import Sidebar from "./Sidebar";
|
||||
import Dashboard from './pages/Dashboard';
|
||||
import Main from './pages/Main';
|
||||
import UserAccount from './pages/UserAccount'; // Импортируем компонент UserAccount
|
||||
import Login from './pages/Login'; // Импортируем страницу логина
|
||||
import Connections from './pages/Connections'; // Импортируем страницу подключений
|
||||
@ -13,7 +14,7 @@ import { BrowserRouter as Router, Routes, Route, Navigate } from 'react-router-d
|
||||
|
||||
const App = () => {
|
||||
const [isLoggedIn, setIsLoggedIn] = useState(false); // Статус авторизации
|
||||
const [activeTab, setActiveTab] = useState('map'); // По умолчанию активная вкладка "Карта"
|
||||
const [activeTab, setActiveTab] = useState('main'); // По умолчанию активная вкладка "Карта"
|
||||
|
||||
// Функция для выхода из системы
|
||||
const handleLogout = () => {
|
||||
@ -42,6 +43,7 @@ const App = () => {
|
||||
onLogout={handleLogout} // Передаем функцию handleLogout через пропс onLogout
|
||||
/>
|
||||
<div style={{ padding: '20px', flex: 1 }}>
|
||||
{activeTab === 'main' && <Main />} {/* Подключаем компонент Dashboard */}
|
||||
{activeTab === 'map' && <Dashboard />} {/* Подключаем компонент Dashboard */}
|
||||
{activeTab === 'connection' && <Connections />} {/* Страница подключений */}
|
||||
{activeTab === 'account' && <UserAccount />} {/* Подключаем компонент UserAccount */}
|
||||
|
9
src/frontend/src/Main.css
Normal file
9
src/frontend/src/Main.css
Normal file
@ -0,0 +1,9 @@
|
||||
|
||||
.main__imager {
|
||||
height: 100%;
|
||||
background-image: url('../public/blueprints.jpg');
|
||||
}
|
||||
|
||||
.main__t_b {
|
||||
color: black;
|
||||
}
|
@ -16,9 +16,12 @@ const Sidebar = ({ onSelectTab, activeTab, onLogout }) => {
|
||||
<div className="sidebar">
|
||||
<h2>Меню</h2>
|
||||
<ul>
|
||||
<li className={activeTab === 'map' ? 'active' : ''} onClick={() => onSelectTab('map')}>
|
||||
<li className={activeTab === 'main' ? 'active' : ''} onClick={() => onSelectTab('main')}>
|
||||
Главная
|
||||
</li>
|
||||
<li className={activeTab === 'map' ? 'active' : ''} onClick={() => onSelectTab('map')}>
|
||||
Сессия 1
|
||||
</li>
|
||||
<li className={activeTab === 'connection' ? 'active' : ''} onClick={() => onSelectTab('connection')}>
|
||||
Настройки
|
||||
</li>
|
||||
|
@ -41,16 +41,16 @@ const DeviceGroups = () => {
|
||||
|
||||
return (
|
||||
<div className="device-groups">
|
||||
<h2>Группы устройств</h2>
|
||||
<h2>Шаблоны / СШК</h2>
|
||||
|
||||
<div className="group-creation">
|
||||
<input
|
||||
type="text"
|
||||
value={newGroupName}
|
||||
onChange={(e) => setNewGroupName(e.target.value)}
|
||||
placeholder="Название новой группы"
|
||||
placeholder="Название шаблона"
|
||||
/>
|
||||
<button onClick={createGroup}>Создать группу</button>
|
||||
<button onClick={createGroup}>Создать шаблон</button>
|
||||
</div>
|
||||
|
||||
<ul>
|
||||
|
@ -3,91 +3,19 @@ import { QRCodeCanvas } from "qrcode.react";
|
||||
import '../Devices.css';
|
||||
|
||||
const Devices = () => {
|
||||
const [devices, setDevices] = useState([]);
|
||||
const [selectedDevice, setSelectedDevice] = useState(null);
|
||||
const [deviceName, setDeviceName] = useState('');
|
||||
const [deviceStatus, setDeviceStatus] = useState('');
|
||||
|
||||
const addDevice = () => {
|
||||
if (deviceName) {
|
||||
const newDevice = { name: deviceName, status: deviceStatus || 'Неактивен', id: Date.now() };
|
||||
setDevices([...devices, newDevice]);
|
||||
setDeviceName('');
|
||||
setDeviceStatus('');
|
||||
}
|
||||
};
|
||||
|
||||
const removeDevice = () => {
|
||||
if (selectedDevice) {
|
||||
setDevices(devices.filter(device => device.id !== selectedDevice.id));
|
||||
setSelectedDevice(null);
|
||||
}
|
||||
};
|
||||
|
||||
const editDevice = () => {
|
||||
if (selectedDevice) {
|
||||
const updatedDevices = devices.map(device =>
|
||||
device.id === selectedDevice.id
|
||||
? { ...device, name: deviceName, status: deviceStatus }
|
||||
: device
|
||||
);
|
||||
setDevices(updatedDevices);
|
||||
setSelectedDevice(null);
|
||||
setDeviceName('');
|
||||
setDeviceStatus('');
|
||||
}
|
||||
};
|
||||
|
||||
const generateQR = (device) => {
|
||||
return (
|
||||
<QRCodeCanvas value={JSON.stringify(device)} size={128} />
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="devices">
|
||||
<h2>Устройства</h2>
|
||||
<input
|
||||
type="text"
|
||||
placeholder="Название устройства"
|
||||
value={deviceName}
|
||||
onChange={(e) => setDeviceName(e.target.value)}
|
||||
/>
|
||||
<input
|
||||
type="text"
|
||||
placeholder="Статус устройства"
|
||||
value={deviceStatus}
|
||||
onChange={(e) => setDeviceStatus(e.target.value)}
|
||||
/>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Название</th>
|
||||
<th>Статус</th>
|
||||
<th>QR Код</th>
|
||||
<th>Действия</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{devices.map((device) => (
|
||||
<tr key={device.id} onClick={() => setSelectedDevice(device)}>
|
||||
<td>{device.name}</td>
|
||||
<td>{device.status}</td>
|
||||
<td>{generateQR(device)}</td>
|
||||
<td>
|
||||
<button onClick={editDevice}>Редактировать</button>
|
||||
</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
<div className="buttons">
|
||||
<button onClick={addDevice}>Добавить</button>
|
||||
<button onClick={removeDevice} disabled={!selectedDevice}>Удалить выбранное</button>
|
||||
<button onClick={editDevice} disabled={!selectedDevice}>Сохранить изменения</button>
|
||||
</div>
|
||||
<div>
|
||||
<button className='button is-danger'>Удалить неиспользуемые шаблоны</button>
|
||||
<hr/>
|
||||
<button className='button is-danger'>Удалить неактивных пользователей</button>
|
||||
<hr/>
|
||||
<button className='button is-danger'>Перезагрузить сервер</button>
|
||||
<hr/>
|
||||
|
||||
<button className='button is-danger'>Перезагрузить фронтенд</button>
|
||||
|
||||
</div>
|
||||
);
|
||||
)
|
||||
};
|
||||
|
||||
export default Devices;
|
35
src/frontend/src/pages/Main.js
Normal file
35
src/frontend/src/pages/Main.js
Normal file
@ -0,0 +1,35 @@
|
||||
import React from 'react';
|
||||
import '../Main.css';
|
||||
import { InfoBlock } from './components/DroneAssets/InfoBlock';
|
||||
|
||||
const Main = () => {
|
||||
|
||||
const makeSimulation = () => {
|
||||
// POST $BASE_ADDR/createSimulation?userToken=?
|
||||
}
|
||||
|
||||
const connectSimulation = () => {
|
||||
// POST $BASE_ADDR/connectSimulation?userToken=?
|
||||
}
|
||||
|
||||
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>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
};
|
||||
|
||||
export default Main;
|
@ -2,83 +2,25 @@ import React, { useState } from 'react';
|
||||
import '../UserAccount.scss';
|
||||
|
||||
const PrevCalc = () => {
|
||||
const [userData, setUserData] = useState({
|
||||
username: 'Мамут Рахал',
|
||||
email: 'yatupoidayn@mail.ru',
|
||||
phone: '+666',
|
||||
});
|
||||
|
||||
const [isEditing, setIsEditing] = useState(false);
|
||||
const [formData, setFormData] = useState(userData);
|
||||
|
||||
const handleChange = (e) => {
|
||||
const { name, value } = e.target;
|
||||
setFormData((prevData) => ({
|
||||
...prevData,
|
||||
[name]: value,
|
||||
}));
|
||||
};
|
||||
|
||||
const handleSave = () => {
|
||||
setUserData(formData);
|
||||
setIsEditing(false);
|
||||
};
|
||||
|
||||
const handleCancel = () => {
|
||||
setFormData(userData);
|
||||
setIsEditing(false);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="user-account">
|
||||
<h1>Данные</h1>
|
||||
|
||||
{isEditing ? (
|
||||
<div className="edit-form">
|
||||
<label>
|
||||
Имя пользователя:
|
||||
<input
|
||||
type="text"
|
||||
name="username"
|
||||
value={formData.username}
|
||||
onChange={handleChange}
|
||||
/>
|
||||
</label>
|
||||
<label>
|
||||
Никнейм авторизации:
|
||||
<input
|
||||
type="text"
|
||||
name="email"
|
||||
value={formData.email}
|
||||
onChange={handleChange}
|
||||
/>
|
||||
</label>
|
||||
<label>
|
||||
Пароль:
|
||||
<input
|
||||
type="password"
|
||||
name="phone"
|
||||
value={formData.phone}
|
||||
onChange={handleChange}
|
||||
/>
|
||||
</label>
|
||||
<div className="buttons">
|
||||
<button onClick={handleSave}>Сохранить</button>
|
||||
<button onClick={handleCancel}>Отмена</button>
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<div className="user-info">
|
||||
<p><strong>Имя:</strong> {userData.username}</p>
|
||||
<p><strong>Email:</strong> {userData.email}</p>
|
||||
<p><strong>Телефон:</strong> {userData.phone}</p>
|
||||
<button className="edit-button" onClick={() => setIsEditing(true)}>
|
||||
Редактировать
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
<table class="table">
|
||||
<thead>
|
||||
<th><abbr title="Уникальный идентификатор в базе данных">UID</abbr></th>
|
||||
<th><abbr title="Название">Имя</abbr></th>
|
||||
<th>Пользователь</th>
|
||||
<th>Время начала</th>
|
||||
<th>Время конца</th>
|
||||
</thead>
|
||||
<tbody>
|
||||
<th>1</th>
|
||||
<td>Калькуляция полета до варшавы</td>
|
||||
<td>Гитлер</td>
|
||||
<td>1:00</td>
|
||||
<td>4:04</td>
|
||||
</tbody>
|
||||
</table>
|
||||
)
|
||||
};
|
||||
|
||||
export default PrevCalc;
|
@ -3,8 +3,8 @@ import '../UserAccount.scss';
|
||||
|
||||
const UserAccount = () => {
|
||||
const [userData, setUserData] = useState({
|
||||
username: 'Мамут Рахал',
|
||||
email: 'yatupoidayn@mail.ru',
|
||||
username: 'Никита Николаевич',
|
||||
email: 'moxitech@moxitech.com',
|
||||
phone: '+666',
|
||||
});
|
||||
|
||||
@ -30,7 +30,7 @@ const UserAccount = () => {
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="user-account">
|
||||
<div className=" user-account ">
|
||||
<h1>Данные</h1>
|
||||
|
||||
{isEditing ? (
|
||||
|
35
src/frontend/src/pages/components/DroneAssets/InfoBlock.js
Normal file
35
src/frontend/src/pages/components/DroneAssets/InfoBlock.js
Normal file
@ -0,0 +1,35 @@
|
||||
|
||||
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>
|
||||
)
|
||||
}
|
10
src/frontend/src/pages/service/Local.js
Normal file
10
src/frontend/src/pages/service/Local.js
Normal file
@ -0,0 +1,10 @@
|
||||
|
||||
|
||||
|
||||
export const LocalSimulationJson = () => {
|
||||
|
||||
|
||||
return {
|
||||
"TODO": "JSON RETURN"
|
||||
}
|
||||
}
|
40
src/frontend/src/pages/service/Server.js
Normal file
40
src/frontend/src/pages/service/Server.js
Normal file
@ -0,0 +1,40 @@
|
||||
|
||||
|
||||
|
||||
export const giveMeServerAddress = () => {
|
||||
if (process.env.SERVER_BASE_ADDRESS) {
|
||||
return process.env.SERVER_BASE_ADDRESS
|
||||
}
|
||||
return "http://localhost:3000";
|
||||
}
|
||||
|
||||
export const ServerRequest = async (req, type, data = null) => {
|
||||
let addr = giveMeServerAddress(); // получаем адрес сервера
|
||||
let options = {
|
||||
method: type, // тип запроса (GET, POST, PUT, DELETE и т.д.)
|
||||
headers: {
|
||||
'Content-Type': 'application/json', // заголовки для JSON данных
|
||||
}
|
||||
};
|
||||
|
||||
// Если данные есть и метод не GET, добавляем тело запроса
|
||||
if (data && type !== 'GET') {
|
||||
options.body = JSON.stringify(data);
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await fetch(`${addr}/${req}`, options); // выполняем запрос
|
||||
const responseData = await response.json(); // парсим JSON ответ
|
||||
|
||||
return {
|
||||
data: responseData, // данные от сервера
|
||||
status: response.status // код состояния ответа
|
||||
};
|
||||
} catch (error) {
|
||||
console.error('Error:', error);
|
||||
return {
|
||||
data: null, // если ошибка, данных нет
|
||||
status: 500 // возвращаем код ошибки сервера
|
||||
};
|
||||
}
|
||||
};
|
21
src/frontend/src/pages/service/SimulationRequests.js
Normal file
21
src/frontend/src/pages/service/SimulationRequests.js
Normal file
@ -0,0 +1,21 @@
|
||||
|
||||
import {ServerRequest} from './Server'
|
||||
|
||||
export const RequestSaveOnServer = () => {
|
||||
// Запрос на сохранение результатов на сервере
|
||||
}
|
||||
|
||||
|
||||
export const RequestRunCalculations = () => {
|
||||
// Запрос на сохранение результатов на запуск вычислений
|
||||
}
|
||||
|
||||
export const RequestGetClientSettings = () => {
|
||||
// Запрос на получение клиентских настроек
|
||||
|
||||
}
|
||||
|
||||
export const RequestUpdateClientSettings = () => {
|
||||
// Запрос на обновление клиентских настроек
|
||||
|
||||
}
|
@ -57,7 +57,7 @@ func CreateSocket(c *websocket.Conn) {
|
||||
fmt.Printf("Received message from user %s: %s\n", userToken, msg)
|
||||
|
||||
// Отправляем обратно сообщение клиенту
|
||||
err = c.WriteMessage(websocket.BinaryMessage, msg)
|
||||
err = c.WriteMessage(websocket.TextMessage, msg)
|
||||
if err != nil {
|
||||
fmt.Printf("Error writing message: %v\n", err)
|
||||
break
|
||||
|
Loading…
Reference in New Issue
Block a user