Обновил структуру, добавил графики, улучшил интерфейс

feature/#23
DmitriyA 2025-02-05 09:52:45 +00:00
parent 01f0be9cdd
commit 46a8bbb35d
15 changed files with 477 additions and 8 deletions

View File

@ -11,7 +11,9 @@
},
"dependencies": {
"react": "^18.3.1",
"react-dom": "^18.3.1"
"react-dom": "^18.3.1",
"chart.js": "^4.0.0",
"react-chartjs-2": "^5.0.0"
},
"devDependencies": {
"@eslint/js": "^9.17.0",
@ -25,4 +27,4 @@
"globals": "^15.14.0",
"vite": "^6.0.5"
}
}
}

View File

@ -1,13 +1,32 @@
import React from "react";
import SidebarMenu from "./SidebarMenu/SidebarMenu"; // Импорт компонента бокового меню
import CpuTemperatureChart from './Charts/CpuTemperatureChart';
import ErrorIndicator from "./SidebarMenu/ErrorIndicator"; // Индикатор ошибок
import GpuTemperatureChart from './Charts/GpuTemperatureChart';
import RamUsageChart from './Charts/RamUsageChart'
import Dashboard from "./SidebarMenu/Dashboard";
function App() {
return (
<div style={{ display: "flex" }}>
<SidebarMenu />
<div style={{ padding: "20px", flex: 1 }}>Рабочая область</div>
<div style={{ marginLeft: "250px" }}>
<h1 className="text-xl font-bold">Мониторинг состояния системы</h1>
<div className="indicator-container">
{/* Индикатор ошибок */}
<h2 className="sidebar-indicator">Индикатор ошибок: </h2>
<ErrorIndicator criticalCount={3} warningCount={7} />
</div>
{/* График температуры CPU
<div className="flex justify-center items-center h-96 bg-gray-100">
<CpuTemperatureChart />
<GpuTemperatureChart />
<RamUsageChart />
</div> */}
<Dashboard/>
</div>
</div>
);
}
export default App;
export default App;

View File

@ -0,0 +1,75 @@
import React, { useEffect, useRef, useState } from "react";
import { Line } from "react-chartjs-2";
import {
Chart as ChartJS,
LineElement,
PointElement,
LinearScale,
CategoryScale,
} from "chart.js";
import ExpandableInfo from "../SidebarMenu/ExpandableInfo"
ChartJS.register(LineElement, PointElement, LinearScale, CategoryScale);
const CpuTemperatureChart = () => {
const chartRef = useRef(null);
const [data, setData] = useState({
labels: Array(10).fill("").map((_, i) => i), // 20 точек по X
datasets: [
{
label: "Температура CPU (°C)",
data: Array(20).fill(50), // Начальные значения (например, 50°C)
borderColor: "red",
borderWidth: 2,
fill: false,
cubicInterpolationMode: "monotone", // Сглаживание
tension: 0.4, // Делаем линию плавнее
},
],
});
useEffect(() => {
const interval = setInterval(() => {
setData((prevData) => {
const newTemp = Math.floor(Math.random() * 20) + 50; // Генерируем новую температуру (50-70°C)
const newLabels = [...prevData.labels.slice(1), prevData.labels[prevData.labels.length - 1] + 1]; // Сдвигаем ось X
const newDataset = [...prevData.datasets[0].data.slice(1), newTemp]; // Сдвигаем данные влево
return {
labels: newLabels,
datasets: [{ ...prevData.datasets[0], data: newDataset }],
};
});
}, 1000); // Обновление каждую секунду
return () => clearInterval(interval);
}, []);
// Пример данных для меню "Подробнее"
const details = [
{ label: "Использование", value: " 45%" },
{ label: "Скорость", value: " 3.6 GHz" },
{ label: "Процессы", value: " 120" },
{ label: "Время работы", value: " 2 ч 30 мин" },
];
return (
<div className="w-full max-w-2xl mx-auto p-4 flex flex-col">
<h2 className="text-xl font-semibold mb-4">График температуры ЦП</h2>
<Line
ref={chartRef}
data={data}
options={{
animation: false, // Отключаем анимацию обновления (чтобы был плавный сдвиг)
scales: {
x: { display: true },
y: { min: 30, max: 80 }, // Ограничиваем Y (например, 30-80°C)
},
}}
/>
<ExpandableInfo details={details} />
</div>
);
};
export default CpuTemperatureChart;

View File

@ -0,0 +1,74 @@
import React, { useEffect, useRef, useState } from "react";
import { Line } from "react-chartjs-2";
import {
Chart as ChartJS,
LineElement,
PointElement,
LinearScale,
CategoryScale,
} from "chart.js";
import ExpandableInfo from "../SidebarMenu/ExpandableInfo"
ChartJS.register(LineElement, PointElement, LinearScale, CategoryScale);
const GpuTemperatureChart = () => {
const chartRef = useRef(null);
const [data, setData] = useState({
labels: Array(10).fill("").map((_, i) => i), // 20 точек по X
datasets: [
{
label: "Температура GPU (°C)",
data: Array(20).fill(50), // Начальные значения (например, 50°C)
borderColor: "blue",
borderWidth: 2,
fill: false,
cubicInterpolationMode: "monotone", // Сглаживание
tension: 0.4, // Делаем линию плавнее
},
],
});
useEffect(() => {
const interval = setInterval(() => {
setData((prevData) => {
const newTemp = Math.floor(Math.random() * 20) + 40; // Генерируем новую температуру (50-600°C)
const newLabels = [...prevData.labels.slice(1), prevData.labels[prevData.labels.length - 1] + 1]; // Сдвигаем ось X
const newDataset = [...prevData.datasets[0].data.slice(1), newTemp]; // Сдвигаем данные влево
return {
labels: newLabels,
datasets: [{ ...prevData.datasets[0], data: newDataset }],
};
});
}, 1000); // Обновление каждую секунду
return () => clearInterval(interval);
}, []);
// Пример данных для меню "Подробнее"
const details = [
{ label: "Использование", value: " 20%" },
{ label: "Оперативная память ГП", value: " 1,2/7,9 ГБ" },
{ label: "Общая память ГП", value: " 1,2/7,9 ГБ" },
];
return (
<div className="w-full max-w-2xl mx-auto p-4 flex flex-col">
<h2 className="text-xl font-semibold mb-4">График температуры ГП</h2>
<Line
ref={chartRef}
data={data}
options={{
animation: false, // Отключаем анимацию обновления (чтобы был плавный сдвиг)
scales: {
x: { display: true },
y: { min: 30, max: 80 }, // Ограничиваем Y (например, 30-80°C)
},
}}
/>
<ExpandableInfo details={details} />
</div>
);
};
export default GpuTemperatureChart;

View File

@ -0,0 +1,76 @@
import React, { useEffect, useRef, useState } from "react";
import { Line } from "react-chartjs-2";
import {
Chart as ChartJS,
LineElement,
PointElement,
LinearScale,
CategoryScale,
} from "chart.js";
import ExpandableInfo from "../SidebarMenu/ExpandableInfo"
ChartJS.register(LineElement, PointElement, LinearScale, CategoryScale);
const RamUsageChart = () => {
const chartRef = useRef(null);
const [data, setData] = useState({
labels: Array(10).fill("").map((_, i) => i), // 20 точек по X
datasets: [
{
label: "Загруженность RAM (%)",
data: Array(20).fill(50), // Начальные значения (например, 50%)
borderColor: "green",
borderWidth: 2,
fill: false,
cubicInterpolationMode: "monotone", // Сглаживание
tension: 0.4, // Делаем линию плавнее
},
],
});
useEffect(() => {
const interval = setInterval(() => {
setData((prevData) => {
const newTemp = Math.floor(Math.random() * 20) + 40; // Генерируем новую температуру (50-600°C)
const newLabels = [...prevData.labels.slice(1), prevData.labels[prevData.labels.length - 1] + 1]; // Сдвигаем ось X
const newDataset = [...prevData.datasets[0].data.slice(1), newTemp]; // Сдвигаем данные влево
return {
labels: newLabels,
datasets: [{ ...prevData.datasets[0], data: newDataset }],
};
});
}, 1000); // Обновление каждую секунду
return () => clearInterval(interval);
}, []);
// Пример данных для меню "Подробнее"
const details = [
{ label: "Используется", value: " 6,2 ГБ" },
{ label: "Доступно", value: " 9,5 ГБ" },
{ label: "Выделено", value: " 6,8/18,2 ГБ" },
{ label: "Скорость", value: " 3200 МГц" },
];
return (
<div className="w-full max-w-2xl mx-auto p-4 flex flex-col">
<h2 className="text-xl font-semibold mb-4">График загруженности ОЗУ</h2>
<Line
ref={chartRef}
data={data}
options={{
animation: false, // Отключаем анимацию обновления (чтобы был плавный сдвиг)
scales: {
x: { display: true },
y: { min: 0, max: 100 }, // Ограничиваем Y (например, 30-80°C)
},
}}
/>
<ExpandableInfo details={details} />
</div>
);
};
export default RamUsageChart;

View File

@ -0,0 +1,46 @@
import React from "react";
import CpuTemperatureChart from "../Charts/CpuTemperatureChart";
import GpuTemperatureChart from "../Charts/GpuTemperatureChart";
import RamUsageChart from "../Charts/RamUsageChart";
import "../Style/Dashboard.css"; // Подключаем стили
const Dashboard = () => {
return (
<div className="dashboard-container">
{/* Левая колонка (Графики) */}
<div className="left-column">
<CpuTemperatureChart />
<GpuTemperatureChart /> {/* Можно заменить на другие графики */}
<RamUsageChart />
</div>
{/* Правая колонка (Информационный блок) */}
<div className="right-column">
<h2>Информационный блок</h2>
<p>Здесь можно выводить любые данные о системе.</p>
<div className="info-item">
<span className="label">Температура CPU:</span>
<span className="value">65°C</span>
</div>
<div className="info-item">
<span className="label">Загрузка процессора:</span>
<span className="value">45%</span>
</div>
<div className="info-item">
<span className="label">Ошибки аппаратного обеспечения:</span>
<span className="value error">2</span>
</div>
<div className="info-item">
<span className="label">Ошибки программного обеспечения:</span>
<span className="value error">1</span>
</div>
</div>
</div>
);
};
export default Dashboard;

View File

@ -0,0 +1,24 @@
import React from "react";
import criticalIcon from "../assets/images/critical.png"; // Красный треугольник
import warningIcon from "../assets/images/warning.png"; // Желтый треугольник
import "../Style/ErrorIndicator.css"; // Подключаем стили
const ErrorIndicator = ({ criticalCount, warningCount }) => {
return (
<div className="error-indicator">
{/* Красный индикатор (критические ошибки) */}
<div className="error-item critical">
<img src={criticalIcon} alt="Критическая ошибка" />
<span>{criticalCount}</span>
</div>
{/* Желтый индикатор (предупреждения) */}
<div className="error-item warning">
<img src={warningIcon} alt="Предупреждение" />
<span>{warningCount}</span>
</div>
</div>
);
};
export default ErrorIndicator;

View File

@ -0,0 +1,30 @@
import React, { useState } from "react";
import "../Style/Expandable.css"
const ExpandableInfo = ({ details }) => {
const [isExpanded, setIsExpanded] = useState(false);
const toggleExpand = () => {
setIsExpanded(!isExpanded);
};
return (
<div className="expandable-info">
<button onClick={toggleExpand} className="expand-button">
{isExpanded ? "Скрыть" : "Подробнее"}
</button>
{isExpanded && (
<div className="details-menu">
{details.map((detail, index) => (
<div key={index} className="detail-item">
<span className="label">{detail.label}:</span>
<span className="value">{detail.value}</span>
</div>
))}
</div>
)}
</div>
);
};
export default ExpandableInfo;

View File

@ -1,6 +1,5 @@
import React, { useState } from "react";
import "./SidebarMenu.css"; // Импортируем стили для компонента
import "../Style/SidebarMenu.css"; // Импортируем стили для компонента
const menuItems = [
{
title: "Выбор сервиса",

42
src/Style/Dashboard.css Normal file
View File

@ -0,0 +1,42 @@
.dashboard-container {
display: flex;
gap: 20px;
padding: 20px;
}
.left-column {
flex: 2;
}
.right-column {
flex: 1;
background: #f3f3f3;
padding: 20px;
border-radius: 8px;
box-shadow: 0px 4px 8px rgba(0, 0, 0, 0.1);
}
h2 {
font-size: 20px;
margin-bottom: 10px;
}
.info-item {
display: flex;
justify-content: space-between;
padding: 10px 0;
border-bottom: 1px solid #ddd;
}
.label {
font-weight: bold;
}
.value {
color: #007bff;
font-weight: bold;
}
.value.error {
color: red;
}

View File

@ -0,0 +1,29 @@
.error-indicator {
display: flex;
align-items: center;
gap: 15px;
}
.error-item {
display: flex;
align-items: center;
gap: 5px;
}
.error-item img {
width: 30px;
height: 30px;
}
.error-item span {
font-size: 18px;
font-weight: bold;
}
.critical span {
color: red;
}
.warning span {
color: orange;
}

38
src/Style/Expandable.css Normal file
View File

@ -0,0 +1,38 @@
.expandable-info {
margin-top: 10px;
}
.expand-button {
background-color: #444;
color: white;
border: none;
padding: 8px 16px;
cursor: pointer;
border-radius: 4px;
}
.expand-button:hover {
background-color: #333;
}
.details-menu {
margin-top: 10px;
padding: 10px;
border: 1px solid #ddd;
border-radius: 4px;
background-color: #f9f9f9;
}
.detail-item {
display: flex;
justify-content: space-between;
margin-bottom: 5px;
}
.label {
font-weight: bold;
}
.value {
color: #555;
}

View File

@ -1,7 +1,10 @@
/* SidebarMenu.css */
.sidebar {
width: 250px;
position: fixed;
height: 100vh;
width: 250px;
/* height: 100vh; */
background-color: #333;
color: white;
padding: 20px;
@ -14,6 +17,12 @@
margin-bottom: 20px;
}
.sidebar-indicator {
font-size: 18px;
font-weight: bold;
margin-bottom: 15px;
}
.sidebar-section {
margin-bottom: 15px;
}
@ -48,4 +57,10 @@
.sidebar-item:hover {
color: #ccc;
}
.indicator-container {
display: flex;
align-items: center;
gap: 15px;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB