Main GUI screen and service for server-side logic

This commit is contained in:
moxitech 2024-10-05 01:59:08 +07:00
parent a7d936fff6
commit fc949f83a8
15 changed files with 194 additions and 168 deletions

1
.env
View File

@ -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

Binary file not shown.

After

Width:  |  Height:  |  Size: 57 KiB

View File

@ -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 */}

View File

@ -0,0 +1,9 @@
.main__imager {
height: 100%;
background-image: url('../public/blueprints.jpg');
}
.main__t_b {
color: black;
}

View File

@ -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>

View File

@ -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>

View File

@ -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} />
);
};
<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>
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>
);
)
};
export default Devices;

View 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;

View File

@ -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;

View File

@ -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',
});

View 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>
)
}

View File

@ -0,0 +1,10 @@
export const LocalSimulationJson = () => {
return {
"TODO": "JSON RETURN"
}
}

View 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 // возвращаем код ошибки сервера
};
}
};

View File

@ -0,0 +1,21 @@
import {ServerRequest} from './Server'
export const RequestSaveOnServer = () => {
// Запрос на сохранение результатов на сервере
}
export const RequestRunCalculations = () => {
// Запрос на сохранение результатов на запуск вычислений
}
export const RequestGetClientSettings = () => {
// Запрос на получение клиентских настроек
}
export const RequestUpdateClientSettings = () => {
// Запрос на обновление клиентских настроек
}

View File

@ -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