From 46a8bbb35d994cc808f43b39a645a460a4af786f Mon Sep 17 00:00:00 2001 From: DmitriyA Date: Wed, 5 Feb 2025 09:52:45 +0000 Subject: [PATCH] =?UTF-8?q?=D0=9E=D0=B1=D0=BD=D0=BE=D0=B2=D0=B8=D0=BB=20?= =?UTF-8?q?=D1=81=D1=82=D1=80=D1=83=D0=BA=D1=82=D1=83=D1=80=D1=83,=20?= =?UTF-8?q?=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8=D0=BB=20=D0=B3=D1=80=D0=B0?= =?UTF-8?q?=D1=84=D0=B8=D0=BA=D0=B8,=20=D1=83=D0=BB=D1=83=D1=87=D1=88?= =?UTF-8?q?=D0=B8=D0=BB=20=D0=B8=D0=BD=D1=82=D0=B5=D1=80=D1=84=D0=B5=D0=B9?= =?UTF-8?q?=D1=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 6 +- src/App.jsx | 25 ++++++- src/Charts/CpuTemperatureChart.jsx | 75 ++++++++++++++++++++ src/Charts/GpuTemperatureChart.jsx | 74 ++++++++++++++++++++ src/Charts/RamUsageChart.jsx | 76 +++++++++++++++++++++ src/SidebarMenu/Dashboard.jsx | 46 +++++++++++++ src/SidebarMenu/ErrorIndicator.jsx | 24 +++++++ src/SidebarMenu/ExpandableInfo.jsx | 30 ++++++++ src/SidebarMenu/SidebarMenu.jsx | 3 +- src/Style/Dashboard.css | 42 ++++++++++++ src/Style/ErrorIndicator.css | 29 ++++++++ src/Style/Expandable.css | 38 +++++++++++ src/{SidebarMenu => Style}/SidebarMenu.css | 17 ++++- src/assets/images/critical.png | Bin 0 -> 1789 bytes src/assets/images/warning.png | Bin 0 -> 1355 bytes 15 files changed, 477 insertions(+), 8 deletions(-) create mode 100644 src/Charts/CpuTemperatureChart.jsx create mode 100644 src/Charts/GpuTemperatureChart.jsx create mode 100644 src/Charts/RamUsageChart.jsx create mode 100644 src/SidebarMenu/Dashboard.jsx create mode 100644 src/SidebarMenu/ErrorIndicator.jsx create mode 100644 src/SidebarMenu/ExpandableInfo.jsx create mode 100644 src/Style/Dashboard.css create mode 100644 src/Style/ErrorIndicator.css create mode 100644 src/Style/Expandable.css rename src/{SidebarMenu => Style}/SidebarMenu.css (77%) create mode 100644 src/assets/images/critical.png create mode 100644 src/assets/images/warning.png 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 0000000000000000000000000000000000000000..6ce21e58bee02f4a0bfbe616a3be99ea3f5684ef GIT binary patch literal 1789 zcmVlG?r&z^%)B>qlJvj0D{X%NFbYtk5L`_OHd4UvDc}W4 z;F1D(orC|Z|BnBSV59z7fExa+)EniZERRtD)+z*kPzYS3fGipCXBC1c6oU0_gyc(^ zEX?ce+YYdZ0v<`0a6%AhQ4tq1pU)#@5^)t^83k;0jd(21Q9_@>6 z&xc<2-5}qEa6_pZ8RAN)A~-53@~u8!4liXzzZ9KGSY+S$7zIRH3YogtFJ1`*PV=;F zTLB8-X5r+y>o=6flJA1HtAx>j`2R@(HrOJs0+hK?k^`K{_0FKb=GB>uubyW^b zvP7Qwd>&T{9R#L*;*CpQ$Dtyo&XHZ&3jEw+#rn(KaD8ssgyg%o!j=gxYy*8OEQxP@ zueYx&r@C61MGh8PRse_k;xsqB;B4FzWP9g%Uid%e7PUiO_kz8}jLrn%@1l~x0#gN0 zf=7kB{`1pKNh;rsW3Btgng_)76UBQ0V3Q&F5aMXz)_)9`w#OjnA1Pq(*Wbtb_se2g zSrS`OcbBmenhTivl=#}f@On)FSS#H6>nEC8_ntfZG9Gp~2Hw_(sZHaIx5Cbc^b8`_ z3t)|b0#In`Qx{dRNRu)7aC3of`ECVp{Pg7*^R4jORIy$_;Mh&%+x-4vPHt}vbN|KvW2ByP<&2c9r8r)urVL4?EqMI$>Z`0fnP;EEh=Ob(6#g zLQ3#=$K+=K)4nLSOk`&H9Z?08mkzZ2oYqvx)cF+xlmO>@robzXU4Pvq%Op4!R_8_) zFb9X&dN%x#mj^MY9&o9r0{(Hd*t|*>Ic)E+^TL9>r~;PH%d_>Y9uQw~RvU26k`M(T zGHv_Awh6qk{O+g%Ry{Y|_Ve0-BK=xjlmf0KyHM!W#5vyxJKlXDs(>wT-JjGN;Z3Dt zwg62s2&y%NMZQU#^NnzJ-&i*2_C9RLpltTb*YS%WQ}CX`(sJiPkS3W1!h=evz?eVMaDNU>Q8t3hDe=OxZ8*HXYf-S{Be z{>}&%YBoL!TgKr+rp~Q&PznRo*b01aPIhdyy4gdcK~SDN$nkpGHk%izBv2Jqzy({-tP@NmDb^z?-af z@oNLlRWcG9XT~qQ!Mv%NY0y41Z?c+Ri*w;ah=zf$jyE-(2fkDyv}%fp2f%zOL2K+> zjP>8Pcht=Ugm-xDx5l{e3CtL+&8yUJd9^*oy#u>TSjeciNN}-~w)Qxr7kYc#>S(Qs zI5`uhKn0S&MhTfH*%5`{rgXo!Fc55zk{go36TRR1cq*wODK5NV;Nz#gmpoinWqG9J zL=-}%i5`(n3HYESAr+DcX$P1sdQ{eB%Xjd8rh$f1QmcQH% z;FH{xP(^T*DRyf0nbi~ZHH;kZw624CeAXc;1Lm06wGu$0>o|^e<2A-wozL3@&y3?wI}=f-Ctmm#eCV fr2GA)|GNAOm%*|IW+kz&00000NkvXXu0mjfB;H_w literal 0 HcmV?d00001 diff --git a/src/assets/images/warning.png b/src/assets/images/warning.png new file mode 100644 index 0000000000000000000000000000000000000000..21e4ff77c21fcbcd2a2ba128b5b716263d17673e GIT binary patch literal 1355 zcmV-R1+@B!P)}O`WGo{sTXLe`X-R(Td`)7ac^Uim^Gs!MO4h{|u4h{|u4wH-Ebe~Yjk6Jk0i>4FM zN89}hg`1;(hNc4`C(aR^{x-G%q0np4pD-82JA%{GW97AQ3WC#jP&@+)X&z5r56EO0 zibsH>B%zRRg2@k00r?KzMKe*nAvirSk-Sj?qunT;0FD<6g$|jK_j967fdKCEpm+d! z&3kHc2u{z1 zDsPm)u!Ld};ACaE^2SkMWCe;PKtjoalfm)CFTF7v1`f>y-%IIQ&L5luU%iE5lg43a3BfoUX zhfC5`pHD+y`{PSKLspr_L^9Ty$eMf zg415J*Ie7G@=@|NH8t>fYq9BTQ83IB7E)zz@QE#I`f8X@B!pckc1wLcP!ykhmuZfo1!nz$}sRaFHY z8*)s`kCZ@;PN_V|?rOoP--^7NXC5oi#C7?~%1Y?mlx0aiP=Fs8t)CkC9z+DEpIenz zv#&i@6W8U{ytsLxC3&L+hQ9;}(aA4>kv*Zvt9kB;EJNJu^=dh^Wr1aRJs^|alPj-~ zOu^{ip~$Q0ek#)tuc)Zda&%`#Nbco!FM#8=aOBmzx+_By*X7H~%HZVQ^pNF^qrmaQk(KX5vjrzVgAa% z68MnYwgLph&&G=UaIpG2Hw6_;*ke z(k&Mt7&#e})74&IIZC)QHII0XE|SbMhae1i|pvk-p}xpL4^Yf~V* zzE%IGV`B7iS0u&l-t=bVM~(vSGE=}{Jjw@l!R3hy;P^^B$_I|Y;KVzClU>mzAHKM; z2ql-fpVdIds|6#k3r2dTHm=~2O-6DZ1DUKcCGX(i;Nalk;DDwH{{qK1Q;@A~gQWlf N002ovPDHLkV1hZ7mMs7P literal 0 HcmV?d00001