diff --git a/package.json b/package.json index 92a3a00..8a3d352 100755 --- a/package.json +++ b/package.json @@ -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" } -} +} \ No newline at end of file diff --git a/src/App.jsx b/src/App.jsx index f1652d7..8c0ccf5 100755 --- a/src/App.jsx +++ b/src/App.jsx @@ -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 (
-
Рабочая область
+
+

Мониторинг состояния системы

+
+ {/* Индикатор ошибок */} +

Индикатор ошибок:

+ +
+ {/* График температуры CPU +
+ + + +
*/} + +
); } -export default App; \ No newline at end of file +export default App; + diff --git a/src/Charts/CpuTemperatureChart.jsx b/src/Charts/CpuTemperatureChart.jsx new file mode 100644 index 0000000..97ff723 --- /dev/null +++ b/src/Charts/CpuTemperatureChart.jsx @@ -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 ( +
+

График температуры ЦП

+ + +
+ ); +}; + +export default CpuTemperatureChart; \ No newline at end of file diff --git a/src/Charts/GpuTemperatureChart.jsx b/src/Charts/GpuTemperatureChart.jsx new file mode 100644 index 0000000..7831195 --- /dev/null +++ b/src/Charts/GpuTemperatureChart.jsx @@ -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 ( +
+

График температуры ГП

+ + +
+ ); +}; + +export default GpuTemperatureChart; \ No newline at end of file diff --git a/src/Charts/RamUsageChart.jsx b/src/Charts/RamUsageChart.jsx new file mode 100644 index 0000000..4651f7a --- /dev/null +++ b/src/Charts/RamUsageChart.jsx @@ -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 ( +
+

График загруженности ОЗУ

+ + +
+ ); +}; + +export default RamUsageChart; \ No newline at end of file diff --git a/src/SidebarMenu/Dashboard.jsx b/src/SidebarMenu/Dashboard.jsx new file mode 100644 index 0000000..138951e --- /dev/null +++ b/src/SidebarMenu/Dashboard.jsx @@ -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 ( +
+ {/* Левая колонка (Графики) */} +
+ + {/* Можно заменить на другие графики */} + +
+ + {/* Правая колонка (Информационный блок) */} +
+

Информационный блок

+

Здесь можно выводить любые данные о системе.

+ +
+ Температура CPU: + 65°C +
+ +
+ Загрузка процессора: + 45% +
+ +
+ Ошибки аппаратного обеспечения: + 2 +
+
+ Ошибки программного обеспечения: + 1 +
+
+
+ ); +}; + +export default Dashboard; \ No newline at end of file diff --git a/src/SidebarMenu/ErrorIndicator.jsx b/src/SidebarMenu/ErrorIndicator.jsx new file mode 100644 index 0000000..7d71840 --- /dev/null +++ b/src/SidebarMenu/ErrorIndicator.jsx @@ -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 ( +
+ {/* Красный индикатор (критические ошибки) */} +
+ Критическая ошибка + {criticalCount} +
+ + {/* Желтый индикатор (предупреждения) */} +
+ Предупреждение + {warningCount} +
+
+ ); +}; + +export default ErrorIndicator; \ No newline at end of file diff --git a/src/SidebarMenu/ExpandableInfo.jsx b/src/SidebarMenu/ExpandableInfo.jsx new file mode 100644 index 0000000..1c550c0 --- /dev/null +++ b/src/SidebarMenu/ExpandableInfo.jsx @@ -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 ( +
+ + {isExpanded && ( +
+ {details.map((detail, index) => ( +
+ {detail.label}: + {detail.value} +
+ ))} +
+ )} +
+ ); +}; + +export default ExpandableInfo; \ No newline at end of file diff --git a/src/SidebarMenu/SidebarMenu.jsx b/src/SidebarMenu/SidebarMenu.jsx index 9f43d8e..9c15a40 100644 --- a/src/SidebarMenu/SidebarMenu.jsx +++ b/src/SidebarMenu/SidebarMenu.jsx @@ -1,6 +1,5 @@ import React, { useState } from "react"; -import "./SidebarMenu.css"; // Импортируем стили для компонента - +import "../Style/SidebarMenu.css"; // Импортируем стили для компонента const menuItems = [ { title: "Выбор сервиса", diff --git a/src/Style/Dashboard.css b/src/Style/Dashboard.css new file mode 100644 index 0000000..7b6a12b --- /dev/null +++ b/src/Style/Dashboard.css @@ -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; + } \ No newline at end of file diff --git a/src/Style/ErrorIndicator.css b/src/Style/ErrorIndicator.css new file mode 100644 index 0000000..477ded5 --- /dev/null +++ b/src/Style/ErrorIndicator.css @@ -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; +} \ No newline at end of file diff --git a/src/Style/Expandable.css b/src/Style/Expandable.css new file mode 100644 index 0000000..a9daf79 --- /dev/null +++ b/src/Style/Expandable.css @@ -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; + } \ No newline at end of file diff --git a/src/SidebarMenu/SidebarMenu.css b/src/Style/SidebarMenu.css similarity index 77% rename from src/SidebarMenu/SidebarMenu.css rename to src/Style/SidebarMenu.css index ca1819b..8c476ef 100644 --- a/src/SidebarMenu/SidebarMenu.css +++ b/src/Style/SidebarMenu.css @@ -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; } \ No newline at end of file diff --git a/src/assets/images/critical.png b/src/assets/images/critical.png new file mode 100644 index 0000000..6ce21e5 Binary files /dev/null and b/src/assets/images/critical.png differ diff --git a/src/assets/images/warning.png b/src/assets/images/warning.png new file mode 100644 index 0000000..21e4ff7 Binary files /dev/null and b/src/assets/images/warning.png differ