handleOpenTab(id, title)} />;
+ } else {
+ const tabData = tabContent[activeTab];
+ return tabData ? tabData.content : Нет данных
;
+ }
+ };
+
+ return (
+
+
+
+ {/* Элемент для перетаскивания */}
+
+
+
+
+
setActiveTab(id)}
+ onCloseTab={handleCloseTab}
+ />
+
+ {renderTabContent()}
+
+
+
+ );
+};
+
+export default Dashboard;
\ No newline at end of file
diff --git a/src/Components/Layout/SidebarMenu.jsx b/src/Components/Layout/SidebarMenu.jsx
new file mode 100644
index 0000000..5661716
--- /dev/null
+++ b/src/Components/Layout/SidebarMenu.jsx
@@ -0,0 +1,82 @@
+import React, { useState } from "react";
+import "../../Style/SidebarMenu.css";
+import { getStatusColor } from "../TreeChart/dataUtils"; // Импортируем только нужную функцию
+
+const MenuItem = ({ item, onSelectItem, sidebarWidth }) => {
+ const [isOpen, setIsOpen] = useState(false);
+ const hasChildren = Array.isArray(item.items) && item.items.length > 0;
+ const statusColor = getStatusColor(item.status);
+
+ // Обработчик одинарного клика (разворачивание/сворачивание или открытие элемента)
+ const handleSingleClick = () => {
+ if (hasChildren) {
+ setIsOpen(!isOpen); // Разворачиваем/сворачиваем дочерние элементы
+ } else {
+ onSelectItem(item); // Если нет потомков, открываем элемент как вкладку
+ }
+ };
+
+ // Обработчик клика для открытия родителя
+ const handleOpenParent = (e) => {
+ e.stopPropagation(); // Останавливаем всплытие события, чтобы не сработал handleSingleClick
+ onSelectItem(item); // Открываем родителя
+ };
+
+ return (
+ {/* Динамическая ширина */}
+
+ {/* Круглый индикатор статуса */}
+
+
{item.title}
+
+ {/* Иконка для открытия родителя */}
+ {hasChildren && (
+
+ 📂
+
+ )}
+
+ {/* Иконка для разворачивания/сворачивания */}
+ {hasChildren &&
{isOpen ? "▲" : "▼"}}
+
+ {isOpen && hasChildren && (
+
+ {item.items.map((child, index) => (
+
+ ))}
+
+ )}
+
+ );
+};
+
+function SidebarMenu({ data, onOpenTab, sidebarWidth }) {
+ const handleSelectItem = (item) => {
+ onOpenTab(item.id, item.title);
+ };
+
+ return (
+
+
{/* Динамическая ширина */}
+
Меню
+
+
+
{/* Динамическая ширина */}
+
Помощь
+ Настройка
+
+
+ );
+}
+
+export default SidebarMenu;
\ No newline at end of file
diff --git a/src/Components/LoginModal.jsx b/src/Components/LoginModal.jsx
deleted file mode 100644
index 895df58..0000000
--- a/src/Components/LoginModal.jsx
+++ /dev/null
@@ -1,49 +0,0 @@
-import React, { useState } from "react";
-
-const Login = ({ onLogin, onClose }) => {
- const [username, setUsername] = useState("");
- const [password, setPassword] = useState("");
- const [error, setError] = useState("");
-
- const handleSubmit = (e) => {
- e.preventDefault();
- if (username === "admin" && password === "admin") {
- onLogin(); // Успешная авторизация
- onClose(); // Закрыть модальное окно
- } else {
- setError("Неверный логин или пароль");
- }
- };
-
- return (
-
- );
-};
-
-export default Login;
\ No newline at end of file
diff --git a/src/Components/SidebarMenu.jsx b/src/Components/SidebarMenu.jsx
deleted file mode 100644
index 2c5adb9..0000000
--- a/src/Components/SidebarMenu.jsx
+++ /dev/null
@@ -1,47 +0,0 @@
-import React, { useState } from "react";
-import "../Style/SidebarMenu.css";
-import menuData from "./menuData.json";
-
-const MenuItem = ({ item, onSelectItem }) => {
- const [isOpen, setIsOpen] = useState(false);
- const hasChildren = Array.isArray(item.items) && item.items.length > 0;
-
- const handleClick = () => {
- if (hasChildren) {
- setIsOpen(!isOpen);
- } else {
- onSelectItem(item);
- }
- };
-
- return (
-
-
- {item.title}
- {hasChildren && {isOpen ? "▲" : "▼"}}
-
- {isOpen && hasChildren && (
-
- {item.items.map((child, index) => (
-
- ))}
-
- )}
-
- );
-};
-
-function SidebarMenu({ onOpenTab }) {
- const handleSelectItem = (item) => {
- onOpenTab(item.id, item.title); // Передаем id и title
- };
-
- return (
-
-
Меню
-
-
- );
-}
-
-export default SidebarMenu;
diff --git a/src/Components/TreeChart.jsx b/src/Components/TreeChart.jsx
deleted file mode 100644
index c008388..0000000
--- a/src/Components/TreeChart.jsx
+++ /dev/null
@@ -1,121 +0,0 @@
-import React, { useRef, useEffect } from "react";
-import * as d3 from "d3";
-
-const TreeChart = ({ data, onNodeClick }) => {
- const chartRef = useRef();
-
- useEffect(() => {
- if (!data) return;
-
- // Очищаем старый граф перед отрисовкой
- d3.select(chartRef.current).selectAll("*").remove();
-
- const width = 928;
- const height = 600;
-
- const root = d3.hierarchy(data, (d) => d.items);
- const links = root.links();
- const nodes = root.descendants();
-
- const simulation = d3
- .forceSimulation(nodes)
- .force("link", d3.forceLink(links).id((d) => d.data.title).distance(80).strength(1)) // Увеличил дистанцию
- .force("charge", d3.forceManyBody().strength(-500)) // Увеличил отталкивание узлов
- .force("x", d3.forceX())
- .force("y", d3.forceY());
-
- const svg = d3
- .select(chartRef.current)
- .attr("width", width)
- .attr("height", height)
- .attr("viewBox", [-width / 2, -height / 2, width, height])
- .attr("style", "max-width: 100%; height: auto;");
-
- const link = svg
- .append("g")
- .attr("stroke", "#999")
- .attr("stroke-opacity", 0.6)
- .selectAll("line")
- .data(links)
- .join("line");
-
- const node = svg
- .append("g")
- .attr("stroke", "#000")
- .attr("stroke-width", 1.5)
- .selectAll("circle")
- .data(nodes)
- .join("circle")
- .attr("fill", (d) => (d.children ? "#555" : "#000"))
- .attr("stroke", "#fff")
- .attr("r", 7) // Немного увеличил размер узлов для удобства клика
- .call(drag(simulation));
-
- // Добавляем текстовые подписи
- const text = svg
- .append("g")
- .attr("fill", "#000")
- .attr("font-family", "Arial")
- .attr("font-size", 12)
- .attr("pointer-events", "none") // Отключаем обработку событий текста
- .selectAll("text")
- .data(nodes)
- .join("text")
- .text((d) => d.data.title)
- .attr("dx", 12) // Отодвигаем текст дальше от узла
- .attr("dy", 4) // Немного поднимаем текст
-
- node.append("title").text((d) => d.data.title);
-
- node.on("click", (event, d) => {
- if (onNodeClick) {
- onNodeClick(d.data.id, d.data.title); // Передаем id и title
- }
- });
-
- simulation.on("tick", () => {
- link
- .attr("x1", (d) => d.source.x)
- .attr("y1", (d) => d.source.y)
- .attr("x2", (d) => d.target.x)
- .attr("y2", (d) => d.target.y);
-
- node
- .attr("cx", (d) => d.x)
- .attr("cy", (d) => d.y);
-
- text
- .attr("x", (d) => d.x + 12) // Смещаем текст правее узла
- .attr("y", (d) => d.y + 4);
- });
-
- return () => {
- simulation.stop();
- };
- }, [data, onNodeClick]);
-
- const drag = (simulation) => {
- function dragstarted(event, d) {
- if (!event.active) simulation.alphaTarget(0.3).restart();
- d.fx = d.x;
- d.fy = d.y;
- }
-
- function dragged(event, d) {
- d.fx = event.x;
- d.fy = event.y;
- }
-
- function dragended(event, d) {
- if (!event.active) simulation.alphaTarget(0);
- d.fx = null;
- d.fy = null;
- }
-
- return d3.drag().on("start", dragstarted).on("drag", dragged).on("end", dragended);
- };
-
- return ;
-};
-
-export default TreeChart;
diff --git a/src/Components/TreeChart/TreeChart.jsx b/src/Components/TreeChart/TreeChart.jsx
new file mode 100644
index 0000000..37705e8
--- /dev/null
+++ b/src/Components/TreeChart/TreeChart.jsx
@@ -0,0 +1,160 @@
+import React, { useRef, useEffect, useMemo } from "react";
+import * as d3 from "d3";
+import { getStatusColor } from "./dataUtils";
+
+const TreeChart = ({ data, onNodeClick }) => {
+ const chartRef = useRef();
+ const simulationRef = useRef(null);
+ const nodePositions = useRef(new Map());
+
+ const { root, nodes, links } = useMemo(() => {
+ if (!data || !data.items) return { root: null, nodes: [], links: [] };
+
+ const root = d3.hierarchy(data, (d) => d.items);
+ const nodes = root.descendants();
+ const links = root.links();
+
+ // Применяем сохраненные позиции к узлам
+ nodes.forEach((node) => {
+ const prev = nodePositions.current.get(node.data.id);
+ if (prev) {
+ node.x = prev.x;
+ node.y = prev.y;
+ node.fx = prev.fx ?? null; // Если фиксированные координаты были, сохраняем
+ node.fy = prev.fy ?? null;
+ } else {
+ // Если узел новый, задаем ему позицию рядом с родителем
+ const parent = node.parent;
+ node.x = parent ? parent.x + Math.random() * 50 - 25 : Math.random() * 1000;
+ node.y = parent ? parent.y + Math.random() * 50 - 25 : Math.random() * 1000;
+ }
+ nodePositions.current.set(node.data.id, { x: node.x, y: node.y, fx: node.fx, fy: node.fy });
+ });
+
+ return { root, nodes, links };
+ }, [data]);
+
+ useEffect(() => {
+ if (!chartRef.current) return;
+
+ const svg = d3.select(chartRef.current)
+ .attr("width", 2000)
+ .attr("height", 1000)
+ .attr("viewBox", [-500, -500, 1000, 1000])
+ .attr("style", "max-width: 100%; height: auto;");
+
+ svg.append("g").attr("class", "links");
+ svg.append("g").attr("class", "nodes");
+ svg.append("g").attr("class", "labels");
+
+ // Инициализация симуляции
+ simulationRef.current = d3.forceSimulation()
+ .force("link", d3.forceLink().id((d) => d.data.id).distance(80).strength(1))
+ .force("charge", d3.forceManyBody().strength(-200))
+ .force("center", d3.forceCenter(0, 0))
+ .force("collision", d3.forceCollide().radius(20))
+ .force("x", d3.forceX(0).strength(0.05)) // Ограничиваем разлет по X
+ .force("y", d3.forceY(0).strength(0.05)) // Ограничиваем разлет по Y
+ .force("radial", d3.forceRadial(200, 0, 0).strength(0.02)) // Держим узлы ближе к центру
+ .alphaDecay(0.02) // Замедляем затухание
+ .alphaTarget(0.1);
+
+ // Запускаем симуляцию на 15 секунд, затем отключаем
+ setTimeout(() => {
+ simulationRef.current.stop(); // Останавливаем симуляцию
+ nodes.forEach((node) => {
+ node.fx = node.x; // Фиксируем текущие позиции узлов
+ node.fy = node.y;
+ });
+ }, 15000); // 15 секунд
+
+ }, []);
+
+ useEffect(() => {
+ if (!root || !chartRef.current) return;
+
+ const svg = d3.select(chartRef.current);
+ const linkGroup = svg.select(".links");
+ const nodeGroup = svg.select(".nodes");
+ const labelGroup = svg.select(".labels");
+
+ // Обновляем связи
+ const link = linkGroup
+ .selectAll("line")
+ .data(links, (d) => `${d.source.data.id}-${d.target.data.id}`)
+ .join("line")
+ .attr("stroke", "#999")
+ .attr("stroke-opacity", 0.6);
+
+ // Обновляем узлы
+ const node = nodeGroup
+ .selectAll("circle")
+ .data(nodes, (d) => d.data.id)
+ .join("circle")
+ .attr("fill", (d) => getStatusColor(d.data.status))
+ .attr("stroke", "#fff")
+ .attr("r", 7)
+ .call(drag());
+
+ node.on("click", (event, d) => {
+ if (onNodeClick) {
+ onNodeClick(d.data.id, d.data.title);
+ }
+ });
+
+ // Обновляем текстовые метки
+ const text = labelGroup
+ .selectAll("text")
+ .data(nodes, (d) => d.data.id)
+ .join("text")
+ .text((d) => d.data.title)
+ .attr("dx", 12)
+ .attr("dy", 4);
+
+ // Обновляем симуляцию
+ simulationRef.current.nodes(nodes);
+ simulationRef.current.force("link").links(links);
+ simulationRef.current.alphaTarget(0.1).restart();
+
+ simulationRef.current.on("tick", () => {
+ link
+ .attr("x1", (d) => d.source.x)
+ .attr("y1", (d) => d.source.y)
+ .attr("x2", (d) => d.target.x)
+ .attr("y2", (d) => d.target.y);
+
+ node
+ .attr("cx", (d) => d.x)
+ .attr("cy", (d) => d.y);
+
+ text
+ .attr("x", (d) => d.x + 12)
+ .attr("y", (d) => d.y + 4);
+ });
+
+ }, [root, links, nodes, onNodeClick]);
+
+ const drag = () => {
+ function dragstarted(event, d) {
+ if (!event.active) simulationRef.current.alphaTarget(0.3).restart();
+ d.fx = d.x;
+ d.fy = d.y;
+ }
+
+ function dragged(event, d) {
+ d.fx = event.x;
+ d.fy = event.y;
+ }
+
+ function dragended(event, d) {
+ if (!event.active) simulationRef.current.alphaTarget(0);
+ nodePositions.current.set(d.data.id, { x: d.x, y: d.y, fx: d.fx, fy: d.fy });
+ }
+
+ return d3.drag().on("start", dragstarted).on("drag", dragged).on("end", dragended);
+ };
+
+ return ;
+};
+
+export default TreeChart;
\ No newline at end of file
diff --git a/src/Components/TreeChart/dataUtils.jsx b/src/Components/TreeChart/dataUtils.jsx
new file mode 100644
index 0000000..fa67130
--- /dev/null
+++ b/src/Components/TreeChart/dataUtils.jsx
@@ -0,0 +1,53 @@
+// Функция для генерации случайных статусов
+const getRandomStatus = () => {
+ const statuses = [
+ ...Array(90).fill("green"), // 63/70 chance (примерно 90%)
+ ...Array(6).fill("yellow"), // 1/70 chance (примерно 1.43%)
+ ...Array(3).fill("orange"), // 1/70 chance (примерно 1.43%)
+ ...Array(1).fill("red"), // 1/70 chance (примерно 1.43%)
+ ];
+ return statuses[Math.floor(Math.random() * statuses.length)];
+};
+
+// Функция для обновления статусов в дереве
+const updateStatuses = (data) => {
+ if (!data.items || data.items.length === 0) {
+ // Если это элемент нижнего уровня, генерируем случайный статус
+ data.status = getRandomStatus();
+ return data.status;
+ }
+
+ // Рекурсивно обновляем статусы для всех дочерних элементов
+ let childStatuses = data.items.map((child) => updateStatuses(child));
+
+ // Определяем статус текущего элемента на основе статусов дочерних элементов
+ if (childStatuses.includes("red")) {
+ data.status = "red";
+ } else if (childStatuses.includes("orange")) {
+ data.status = "orange";
+ } else if (childStatuses.includes("yellow")) {
+ data.status = "yellow";
+ } else {
+ data.status = "green";
+ }
+
+ return data.status;
+};
+
+// Функция для получения цвета по статусу
+const getStatusColor = (status) => {
+ switch (status) {
+ case "green":
+ return "#4CAF50"; // Зеленый
+ case "yellow":
+ return "#FFEB3B"; // Желтый
+ case "orange":
+ return "#FF9800"; // Оранжевый
+ case "red":
+ return "#F44336"; // Красный
+ default:
+ return "#4CAF50"; // Синий (или любой другой стандартный цвет)
+ }
+};
+
+export { getRandomStatus, updateStatuses, getStatusColor };
\ No newline at end of file
diff --git a/src/Components/TreeChart/menuData.json b/src/Components/TreeChart/menuData.json
new file mode 100644
index 0000000..4cdcaff
--- /dev/null
+++ b/src/Components/TreeChart/menuData.json
@@ -0,0 +1,735 @@
+{
+ "title": "Сервер ЗВКС",
+ "id": "1",
+ "items": [
+ {
+ "title": "Функциональные задачи",
+ "items": [
+ {
+ "id": "system_control",
+ "title": "Контроль системы"
+ },
+ {
+ "id": "system_management",
+ "title": "Система управления"
+ },
+ {
+ "id": "conference",
+ "title": "Проведение ВКС"
+ },
+ {
+ "id": "backup",
+ "title": "Резервное копирование"
+ },
+ {
+ "id": "relay_info",
+ "title": "Ретрансляция информации"
+ }
+ ]
+ },
+ {
+ "id": "18",
+ "title": "Graviton S2082I (device$18)",
+ "items": [
+ {
+ "id": "4",
+ "title": "OS Linux (module$4) АО",
+ "items": [
+ {
+ "id": "188",
+ "title": "Наименование"
+ },
+ {
+ "id": "189",
+ "title": "Время работы"
+ },
+ {
+ "id": "190",
+ "title": "Загрузка процессора за 1 минуту"
+ },
+ {
+ "id": "191",
+ "title": "Загрузка процессора за 5 минут"
+ },
+ {
+ "id": "192",
+ "title": "Загрузка процессора за 15 минут"
+ },
+ {
+ "id": "197",
+ "title": "Общий объем SWAP-файла"
+ },
+ {
+ "id": "198",
+ "title": "Используемый объем SWAP-файла"
+ },
+ {
+ "id": "199",
+ "title": "Общий объем физической оперативной памяти"
+ },
+ {
+ "id": "200",
+ "title": "Доступный объем физической оперативной памяти"
+ },
+ {
+ "id": "201",
+ "title": "Свободный объем физической и виртуальной оперативной памяти"
+ },
+ {
+ "id": "202",
+ "title": "Буферизованный объем оперативной памяти"
+ },
+ {
+ "id": "203",
+ "title": "Кэшированый объем оперативной памяти"
+ },
+ {
+ "id": "274",
+ "title": "Используемый объем SWAP-файла"
+ },
+ {
+ "id": "275",
+ "title": "Время затраченное процессором на процессы с пониженным приоритетом"
+ },
+ {
+ "id": "276",
+ "title": "Время затраченное процессором на процессы ядра ОС"
+ },
+ {
+ "id": "277",
+ "title": "Время простоя процессора"
+ },
+ {
+ "id": "278",
+ "title": "Общая емкость жестких дисков"
+ },
+ {
+ "id": "279",
+ "title": "Доступная емкость жестких дисков"
+ }
+ ]
+ },
+ {
+ "id": "5",
+ "title": "Vinteo (module$5) ПО",
+ "items": [
+ {
+ "id": "31",
+ "title": "Общее количество участников"
+ },
+ {
+ "id": "32",
+ "title": "Ожидание соединения"
+ },
+ {
+ "id": "33",
+ "title": "Зарегистрированные абоненты"
+ },
+ {
+ "id": "34",
+ "title": "Количество пользоватей HLS"
+ },
+ {
+ "id": "35",
+ "title": "Общее количество P2P комнат"
+ },
+ {
+ "id": "36",
+ "title": "Общее количество конференций"
+ },
+ {
+ "id": "37",
+ "title": "Общее количество активных конференций"
+ },
+ {
+ "id": "38",
+ "title": "Статус записи"
+ },
+ {
+ "id": "39",
+ "title": "Общее количество сохранённых записей"
+ }
+ ]
+ },
+ {
+ "id": "261",
+ "title": "Сетевой адаптер №1 (port$261) Eth_1",
+ "items": [
+ {
+ "id": "206",
+ "title": "Наименование порта Eth_1"
+ },
+ {
+ "id": "207",
+ "title": "Скорость порта Eth_1"
+ },
+ {
+ "id": "208",
+ "title": "Физический адрес порта Eth_1"
+ },
+ {
+ "id": "209",
+ "title": "Административное состояние порта Eth_1"
+ },
+ {
+ "id": "210",
+ "title": "Оперативное состояние порта Eth_1"
+ },
+ {
+ "id": "211",
+ "title": "Общее количество отправленных октетов Eth_1"
+ },
+ {
+ "id": "212",
+ "title": "Количество входящих Multicast пакетов Eth_1"
+ },
+ {
+ "id": "213",
+ "title": "Количество иcходящих Multiicast пакетов Eth_1"
+ },
+ {
+ "id": "214",
+ "title": "Количество входящих Broadcast пакетов Eth_1"
+ },
+ {
+ "id": "215",
+ "title": "Количество иcходящих Broadcast пакетов Eth_1"
+ },
+ {
+ "id": "216",
+ "title": "Количество входящих Unicast пакетов Eth_1"
+ },
+ {
+ "id": "217",
+ "title": "Количество иcходящих Unicast пакетов Eth_1"
+ },
+ {
+ "id": "218",
+ "title": "Количество входящих пакетов помеченные как отброшенные Eth_1"
+ },
+ {
+ "id": "219",
+ "title": "Количество иcходящих пакетов помеченные как отброшенные Eth_1"
+ },
+ {
+ "id": "220",
+ "title": "Количество входящих пакетов с ошибкой Eth_1"
+ },
+ {
+ "id": "221",
+ "title": "Количество исходящих пакетов с ошибкой Eth_1"
+ },
+ {
+ "id": "222",
+ "title": "Количество входящих пакетов с неизвестным или неподдерживаемым протоколом Eth_1"
+ }
+ ]
+ },
+ {
+ "id": "262",
+ "title": "Сетевой адаптер №2 (port$262) Eth_2",
+ "items": [
+ {
+ "id": "223",
+ "title": "Наименование порта Eth_2"
+ },
+ {
+ "id": "224",
+ "title": "Скорость порта Eth_2"
+ },
+ {
+ "id": "225",
+ "title": "Физический адрес порта Eth_2"
+ },
+ {
+ "id": "226",
+ "title": "Административное состояние порта Eth_2"
+ },
+ {
+ "id": "227",
+ "title": "Оперативное состояние порта Eth_2"
+ },
+ {
+ "id": "228",
+ "title": "Общее количество отправленных октетов Eth_2"
+ },
+ {
+ "id": "229",
+ "title": "Количество входящих Multicast пакетов Eth_2"
+ },
+ {
+ "id": "230",
+ "title": "Количество иcходящих Multiicast пакетов Eth_2"
+ },
+ {
+ "id": "231",
+ "title": "Количество входящих Broadcast пакетов Eth_2"
+ },
+ {
+ "id": "232",
+ "title": "Количество иcходящих Broadcast пакетов Eth_2"
+ },
+ {
+ "id": "233",
+ "title": "Количество входящих Unicast пакетов Eth_2"
+ },
+ {
+ "id": "234",
+ "title": "Количество иcходящих Unicast пакетов Eth_2"
+ },
+ {
+ "id": "235",
+ "title": "Количество входящих пакетов помеченные как отброшенные Eth_2"
+ },
+ {
+ "id": "236",
+ "title": "Количество иcходящих пакетов помеченные как отброшенные Eth_2"
+ },
+ {
+ "id": "237",
+ "title": "Количество входящих пакетов с ошибкой Eth_2"
+ },
+ {
+ "id": "238",
+ "title": "Количество исходящих пакетов с ошибкой Eth_2"
+ },
+ {
+ "id": "239",
+ "title": "Количество входящих пакетов с неизвестным или неподдерживаемым протоколом Eth_2"
+ }
+ ]
+ },
+ {
+ "id": "263",
+ "title": "Сетевой адаптер №3 (port$263) Eth_3",
+ "items": [
+ {
+ "id": "240",
+ "title": "Наименование порта Eth_3"
+ },
+ {
+ "id": "241",
+ "title": "Скорость порта Eth_3"
+ },
+ {
+ "id": "242",
+ "title": "Физический адрес порта Eth_3"
+ },
+ {
+ "id": "243",
+ "title": "Административное состояние порта Eth_3"
+ },
+ {
+ "id": "244",
+ "title": "Оперативное состояние порта Eth_3"
+ },
+ {
+ "id": "245",
+ "title": "Общее количество отправленных октетов Eth_3"
+ },
+ {
+ "id": "246",
+ "title": "Количество входящих Multicast пакетов Eth_3"
+ },
+ {
+ "id": "247",
+ "title": "Количество иcходящих Multiicast пакетов Eth_3"
+ },
+ {
+ "id": "248",
+ "title": "Количество входящих Broadcast пакетов Eth_3"
+ },
+ {
+ "id": "249",
+ "title": "Количество иcходящих Broadcast пакетов Eth_3"
+ },
+ {
+ "id": "250",
+ "title": "Количество входящих Unicast пакетов Eth_3"
+ },
+ {
+ "id": "251",
+ "title": "Количество иcходящих Unicast пакетов Eth_3"
+ },
+ {
+ "id": "252",
+ "title": "Количество входящих пакетов помеченные как отброшенные Eth_3"
+ },
+ {
+ "id": "253",
+ "title": "Количество иcходящих пакетов помеченные как отброшенные Eth_3"
+ },
+ {
+ "id": "254",
+ "title": "Количество входящих пакетов с ошибкой Eth_3"
+ },
+ {
+ "id": "255",
+ "title": "Количество исходящих пакетов с ошибкой Eth_3"
+ },
+ {
+ "id": "256",
+ "title": "Количество входящих пакетов с неизвестным или неподдерживаемым протоколом Eth_3"
+ }
+ ]
+ },
+ {
+ "id": "264",
+ "title": "Сетевой адаптер №4 (port$264) Eth_4",
+ "items": [
+ {
+ "id": "257",
+ "title": "Наименование порта Eth_4"
+ },
+ {
+ "id": "258",
+ "title": "Скорость порта Eth_4"
+ },
+ {
+ "id": "259",
+ "title": "Физический адрес порта Eth_4"
+ },
+ {
+ "id": "260",
+ "title": "Административное состояние порта Eth_4"
+ },
+ {
+ "id": "261",
+ "title": "Оперативное состояние порта Eth_4"
+ },
+ {
+ "id": "262",
+ "title": "Общее количество отправленных октетов Eth_4"
+ },
+ {
+ "id": "263",
+ "title": "Количество входящих Multicast пакетов Eth_4"
+ },
+ {
+ "id": "264",
+ "title": "Количество иcходящих Multiicast пакетов Eth_4"
+ },
+ {
+ "id": "265",
+ "title": "Количество входящих Broadcast пакетов Eth_4"
+ },
+ {
+ "id": "266",
+ "title": "Количество иcходящих Broadcast пакетов Eth_4"
+ },
+ {
+ "id": "267",
+ "title": "Количество входящих Unicast пакетов Eth_4"
+ },
+ {
+ "id": "268",
+ "title": "Количество иcходящих Unicast пакетов Eth_4"
+ },
+ {
+ "id": "269",
+ "title": "Количество входящих пакетов помеченные как отброшенные Eth_4"
+ },
+ {
+ "id": "270",
+ "title": "Количество иcходящих пакетов помеченные как отброшенные Eth_4"
+ },
+ {
+ "id": "271",
+ "title": "Количество входящих пакетов с ошибкой Eth_4"
+ },
+ {
+ "id": "272",
+ "title": "Количество исходящих пакетов с ошибкой Eth_4"
+ },
+ {
+ "id": "273",
+ "title": "Количество входящих пакетов с неизвестным или неподдерживаемым протоколом Eth_4"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "title": "Медиа сервер",
+ "items": [
+ {
+ "title": "Аппаратное обеспечение",
+ "items": [
+ {
+ "id": "media_system_software_1_2",
+ "title": "Центральный процессор"
+ },
+ {
+ "id": "media_system_software_2_2",
+ "title": "Оперативная память"
+ },
+ {
+ "id": "media_system_software_3_2",
+ "title": "Жесткий диск"
+ },
+ {
+ "id": "media_system_software_4_2",
+ "title": "Сетевые адаптеры"
+ }
+ ]
+ },
+ {
+ "title": "Программное обеспечение",
+ "items": [
+ {
+ "id": "media_software_1_2",
+ "title": "ПО"
+ },
+ {
+ "id": "media_software_2_2",
+ "title": "ПО"
+ },
+ {
+ "id": "media_software_3_2",
+ "title": "ПО"
+ },
+ {
+ "id": "media_software_4_2",
+ "title": "ПО"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "title": "Медиа сервер",
+ "items": [
+ {
+ "title": "Аппаратное обеспечение",
+ "items": [
+ {
+ "id": "media_system_software_1_3",
+ "title": "Центральный процессор"
+ },
+ {
+ "id": "media_system_software_2_3",
+ "title": "Оперативная память"
+ },
+ {
+ "id": "media_system_software_3_3",
+ "title": "Жесткий диск"
+ },
+ {
+ "id": "media_system_software_4_3",
+ "title": "Сетевые адаптеры"
+ }
+ ]
+ },
+ {
+ "title": "Программное обеспечение",
+ "items": [
+ {
+ "id": "media_software_1_3",
+ "title": "ПО"
+ },
+ {
+ "id": "media_software_2_3",
+ "title": "ПО"
+ },
+ {
+ "id": "media_software_3_3",
+ "title": "ПО"
+ },
+ {
+ "id": "media_software_4_3",
+ "title": "ПО"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "title": "Медиа сервер",
+ "items": [
+ {
+ "title": "Аппаратное обеспечение",
+ "items": [
+ {
+ "id": "media_system_software_1_4",
+ "title": "Центральный процессор"
+ },
+ {
+ "id": "media_system_software_2_4",
+ "title": "Оперативная память"
+ },
+ {
+ "id": "media_system_software_3_4",
+ "title": "Жесткий диск"
+ },
+ {
+ "id": "media_system_software_4_4",
+ "title": "Сетевые адаптеры"
+ }
+ ]
+ },
+ {
+ "title": "Программное обеспечение",
+ "items": [
+ {
+ "id": "media_software_1_4",
+ "title": "ПО"
+ },
+ {
+ "id": "media_software_2_4",
+ "title": "ПО"
+ },
+ {
+ "id": "media_software_3_4",
+ "title": "ПО"
+ },
+ {
+ "id": "media_software_4_4",
+ "title": "ПО"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "title": "Медиа сервер",
+ "items": [
+ {
+ "title": "Аппаратное обеспечение",
+ "items": [
+ {
+ "id": "media_system_software_1_5",
+ "title": "Центральный процессор"
+ },
+ {
+ "id": "media_system_software_2_5",
+ "title": "Оперативная память"
+ },
+ {
+ "id": "media_system_software_3_5",
+ "title": "Жесткий диск"
+ },
+ {
+ "id": "media_system_software_4_5",
+ "title": "Сетевые адаптеры"
+ }
+ ]
+ },
+ {
+ "title": "Программное обеспечение",
+ "items": [
+ {
+ "id": "media_software_1_5",
+ "title": "ПО"
+ },
+ {
+ "id": "media_software_2_5",
+ "title": "ПО"
+ },
+ {
+ "id": "media_software_3_5",
+ "title": "ПО"
+ },
+ {
+ "id": "media_software_4_5",
+ "title": "ПО"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "title": "Сервер систем",
+ "items": [
+ {
+ "title": "Аппаратное обеспечение",
+ "items": [
+ {
+ "id": "copy_system_software_1",
+ "title": "Центральный процессор"
+ },
+ {
+ "id": "copy_system_software_2",
+ "title": "Оперативная память"
+ },
+ {
+ "id": "copy_system_software_3",
+ "title": "Жесткий диск"
+ },
+ {
+ "id": "copy_system_software_4",
+ "title": "Сетевые адаптеры"
+ }
+ ]
+ },
+ {
+ "title": "Программное обеспечение",
+ "items": [
+ {
+ "id": "copy_software_1",
+ "title": "ПО"
+ },
+ {
+ "id": "copy_software_2",
+ "title": "ПО"
+ },
+ {
+ "id": "copy_software_3",
+ "title": "ПО"
+ },
+ {
+ "id": "copy_software_4",
+ "title": "ПО"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "title": "Сервер систем",
+ "items": [
+ {
+ "title": "Аппаратное обеспечение",
+ "items": [
+ {
+ "id": "control_system_software_1",
+ "title": "Центральный процессор"
+ },
+ {
+ "id": "control_system_software_2",
+ "title": "Оперативная память"
+ },
+ {
+ "id": "control_system_software_3",
+ "title": "Жесткий диск"
+ },
+ {
+ "id": "control_system_software_4",
+ "title": "Сетевые адаптеры"
+ }
+ ]
+ },
+ {
+ "title": "Программное обеспечение",
+ "items": [
+ {
+ "id": "control_software_1",
+ "title": "ПО"
+ },
+ {
+ "id": "control_software_2",
+ "title": "ПО"
+ },
+ {
+ "id": "control_software_3",
+ "title": "ПО"
+ },
+ {
+ "id": "control_software_4",
+ "title": "ПО"
+ }
+ ]
+ }
+ ]
+ }
+ ]
+}
\ No newline at end of file
diff --git a/src/Components/TreeChart/menuData2.json b/src/Components/TreeChart/menuData2.json
new file mode 100644
index 0000000..645a8ef
--- /dev/null
+++ b/src/Components/TreeChart/menuData2.json
@@ -0,0 +1,382 @@
+{
+ "title": "Сервис ВКС",
+ "id":"service_VKS",
+ "items": [
+ {
+ "title": "Функциональные задачи",
+ "id":"functions",
+ "items": [
+ {
+ "id": "system_control",
+ "title": "Контроль системы"
+ },
+ {
+ "id": "system_management",
+ "title": "Система управления"
+ },
+ {
+ "id": "conference",
+ "title": "Проведение ВКС"
+ },
+ {
+ "id": "backup",
+ "title": "Резервное копирование"
+ },
+ {
+ "id": "relay_info",
+ "title": "Ретрансляция информации"
+ }
+ ]
+ },
+ {
+ "title": "Медиа сервер",
+ "id":"media_server_1",
+ "items": [
+ {
+ "title": "Аппаратное обеспечение",
+ "id":"system_software_1",
+ "items": [
+ {
+ "id": "media_system_software_1",
+ "title": "Центральный процессор"
+ },
+ {
+ "id": "media_system_software_2",
+ "title": "Оперативная память"
+ },
+ {
+ "id": "media_system_software_3",
+ "title": "Жесткий диск"
+ },
+ {
+ "id": "media_system_software_4",
+ "title": "Сетевые адаптеры"
+ }
+ ]
+ },
+ {
+ "title": "Программное обеспечение",
+ "id":"software_1",
+ "items": [
+ {
+ "id": "media_software_1",
+ "title": "ПО"
+ },
+ {
+ "id": "media_software_2",
+ "title": "ПО"
+ },
+ {
+ "id": "media_software_3",
+ "title": "ПО"
+ },
+ {
+ "id": "media_software_4",
+ "title": "ПО"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "title": "Медиа сервер",
+ "id":"media_server_2",
+ "items": [
+ {
+ "title": "Аппаратное обеспечение",
+ "id":"system_software_2",
+ "items": [
+ {
+ "id": "media_system_software_1_2",
+ "title": "Центральный процессор"
+ },
+ {
+ "id": "media_system_software_2_2",
+ "title": "Оперативная память"
+ },
+ {
+ "id": "media_system_software_3_2",
+ "title": "Жесткий диск"
+ },
+ {
+ "id": "media_system_software_4_2",
+ "title": "Сетевые адаптеры"
+ }
+ ]
+ },
+ {
+ "title": "Программное обеспечение",
+ "id":"software_2",
+ "items": [
+ {
+ "id": "media_software_1_2",
+ "title": "ПО"
+ },
+ {
+ "id": "media_software_2_2",
+ "title": "ПО"
+ },
+ {
+ "id": "media_software_3_2",
+ "title": "ПО"
+ },
+ {
+ "id": "media_software_4_2",
+ "title": "ПО"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "title": "Медиа сервер",
+ "id":"media_server_3",
+ "items": [
+ {
+ "title": "Аппаратное обеспечение",
+ "id":"system_software_3",
+ "items": [
+ {
+ "id": "media_system_software_1_3",
+ "title": "Центральный процессор"
+ },
+ {
+ "id": "media_system_software_2_3",
+ "title": "Оперативная память"
+ },
+ {
+ "id": "media_system_software_3_3",
+ "title": "Жесткий диск"
+ },
+ {
+ "id": "media_system_software_4_3",
+ "title": "Сетевые адаптеры"
+ }
+ ]
+ },
+ {
+ "title": "Программное обеспечение",
+ "id":"software_3",
+ "items": [
+ {
+ "id": "media_software_1_3",
+ "title": "ПО"
+ },
+ {
+ "id": "media_software_2_3",
+ "title": "ПО"
+ },
+ {
+ "id": "media_software_3_3",
+ "title": "ПО"
+ },
+ {
+ "id": "media_software_4_3",
+ "title": "ПО"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "title": "Медиа сервер",
+ "id":"media_server_4",
+ "items": [
+ {
+ "title": "Аппаратное обеспечение",
+ "id":"system_software_4",
+ "items": [
+ {
+ "id": "media_system_software_1_4",
+ "title": "Центральный процессор"
+ },
+ {
+ "id": "media_system_software_2_4",
+ "title": "Оперативная память"
+ },
+ {
+ "id": "media_system_software_3_4",
+ "title": "Жесткий диск"
+ },
+ {
+ "id": "media_system_software_4_4",
+ "title": "Сетевые адаптеры"
+ }
+ ]
+ },
+ {
+ "title": "Программное обеспечение",
+ "id":"software_4",
+ "items": [
+ {
+ "id": "media_software_1_4",
+ "title": "ПО"
+ },
+ {
+ "id": "media_software_2_4",
+ "title": "ПО"
+ },
+ {
+ "id": "media_software_3_4",
+ "title": "ПО"
+ },
+ {
+ "id": "media_software_4_4",
+ "title": "ПО"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "title": "Медиа сервер",
+ "id":"media_server_5",
+ "items": [
+ {
+ "title": "Аппаратное обеспечение",
+ "id":"system_software_5",
+ "items": [
+ {
+ "id": "media_system_software_1_5",
+ "title": "Центральный процессор"
+ },
+ {
+ "id": "media_system_software_2_5",
+ "title": "Оперативная память"
+ },
+ {
+ "id": "media_system_software_3_5",
+ "title": "Жесткий диск"
+ },
+ {
+ "id": "media_system_software_4_5",
+ "title": "Сетевые адаптеры"
+ }
+ ]
+ },
+ {
+ "title": "Программное обеспечение",
+ "id":"software_5",
+ "items": [
+ {
+ "id": "media_software_1_5",
+ "title": "ПО"
+ },
+ {
+ "id": "media_software_2_5",
+ "title": "ПО"
+ },
+ {
+ "id": "media_software_3_5",
+ "title": "ПО"
+ },
+ {
+ "id": "media_software_4_5",
+ "title": "ПО"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "title": "Сервер систем",
+ "id":"system_server_1",
+ "items": [
+ {
+ "title": "Аппаратное обеспечение",
+ "id":"system_software_6",
+ "items": [
+ {
+ "id": "copy_system_software_1",
+ "title": "Центральный процессор"
+ },
+ {
+ "id": "copy_system_software_2",
+ "title": "Оперативная память"
+ },
+ {
+ "id": "copy_system_software_3",
+ "title": "Жесткий диск"
+ },
+ {
+ "id": "copy_system_software_4",
+ "title": "Сетевые адаптеры"
+ }
+ ]
+ },
+ {
+ "title": "Программное обеспечение",
+ "id":"software_6",
+ "items": [
+ {
+ "id": "copy_software_1",
+ "title": "ПО"
+ },
+ {
+ "id": "copy_software_2",
+ "title": "ПО"
+ },
+ {
+ "id": "copy_software_3",
+ "title": "ПО"
+ },
+ {
+ "id": "copy_software_4",
+ "title": "ПО"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "title": "Сервер систем",
+ "id":"system_server_2",
+ "items": [
+ {
+ "title": "Аппаратное обеспечение",
+ "id":"system_software_7",
+ "items": [
+ {
+ "id": "control_system_software_1",
+ "title": "Центральный процессор"
+ },
+ {
+ "id": "control_system_software_2",
+ "title": "Оперативная память"
+ },
+ {
+ "id": "control_system_software_3",
+ "title": "Жесткий диск"
+ },
+ {
+ "id": "control_system_software_4",
+ "title": "Сетевые адаптеры"
+ }
+ ]
+ },
+ {
+ "title": "Программное обеспечение",
+ "id":"software_7",
+ "items": [
+ {
+ "id": "control_software_1",
+ "title": "ПО"
+ },
+ {
+ "id": "control_software_2",
+ "title": "ПО"
+ },
+ {
+ "id": "control_software_3",
+ "title": "ПО"
+ },
+ {
+ "id": "control_software_4",
+ "title": "ПО"
+ }
+ ]
+ }
+ ]
+ }
+ ]
+}
\ No newline at end of file
diff --git a/src/Components/TreeChart/tabContent.jsx b/src/Components/TreeChart/tabContent.jsx
new file mode 100644
index 0000000..9c55909
--- /dev/null
+++ b/src/Components/TreeChart/tabContent.jsx
@@ -0,0 +1,107 @@
+import React, { lazy, Suspense } from "react";
+
+const PrometheusChart = lazy(() => import('../../Charts/PrometheusChart'));
+
+// Функция для генерации названия метрики на основе id
+const getMetricName = (id) => {
+ return `zvks_apiforsnmp_measure_${id}`;
+};
+
+//!!!!!!!!!!Пофиксить вкладуи с eth4, во всех eth 1-4 открывается именно 4 !!!!!!!!!!!!!
+
+// Функция для рекурсивного сбора всех id потомков
+const getAllChildIds = (node) => {
+ let ids = [];
+ if (node.id) {
+ ids.push(node.id); // Добавляем id текущего узла
+ }
+ if (node.items && node.items.length > 0) {
+ node.items.forEach((child) => {
+ ids = ids.concat(getAllChildIds(child)); // Рекурсивно собираем id потомков
+ });
+ }
+ return ids;
+};
+
+const tabContent = (data) => {
+ const tabContent = {};
+
+
+ const generateContent = (nodes) => {
+ nodes.forEach((node) => {
+
+
+ // Если у узла есть вложенные элементы, рекурсивно обрабатываем их
+ if (node.items && node.items.length > 0) {
+
+ generateContent(node.items);
+ }
+
+ // Если у узла есть id, добавляем его в tabContent
+ if (node.id) {
+
+
+ let content = (
+
+
{node.title}
+
Контент для {node.title}.
+
+ );
+
+ // Если у узла есть потомки, добавляем графики для всех потомков
+ if (node.items && node.items.length > 0) {
+ const childIds = getAllChildIds(node); // Получаем все id потомков
+ const charts = childIds.map((id) => {
+ const metricName = getMetricName(id);
+ return (
+
+
{node.title} - {id}
+ Загрузка графика...}>
+
+
+
+ );
+ });
+
+ content = (
+
+
{node.title}
+
Контент для {node.title}.
+ {charts}
+
+ );
+ } else {
+ // Если у узла нет потомков, добавляем график для него
+
+ const metricName = getMetricName(node.id);
+ content = (
+
+
{node.title}
+
Контент для {node.title}.
+
Загрузка графика... }>
+
+
+
+ );
+ }
+
+ // Сохраняем контент для текущего id
+ tabContent[node.id] = {
+ title: node.title,
+ content: content,
+ };
+ }
+ });
+ };
+
+ // Начинаем обработку с корневого уровня
+ if (data.items && data.items.length > 0) {
+ generateContent(data.items);
+ } else {
+ console.warn("Данные отсутствуют или массив items пуст");
+ }
+
+ return tabContent;
+};
+
+export default tabContent; // Экспортируем только функцию
\ No newline at end of file
diff --git a/src/Components/TreeChart/tabContent2.jsx b/src/Components/TreeChart/tabContent2.jsx
new file mode 100644
index 0000000..47dc890
--- /dev/null
+++ b/src/Components/TreeChart/tabContent2.jsx
@@ -0,0 +1,96 @@
+import React from "react";
+import PrometheusChart from '../../Charts/PrometheusChart';
+
+const tabContent = {
+ // Сервис ВКС
+ service1: { title: "Сервис ВКС", content: Сервис ВКС
},
+
+ // Функциональные задачи
+ system_control: { title: "Контроль системы", content: Контроль системы
Описание контроля.
},
+ system_management: { title: "Система управления", content: Система управления
Описание системы управления.
},
+ conference: { title: "Проведение ВКС", content: Проведение ВКС
Информация о проведении ВКС.
},
+ backup: { title: "Резервное копирование", content: Резервное копирование
Процесс резервного копирования.
},
+ relay_info: { title: "Ретрансляция информации", content: Ретрансляция информации
Детали ретрансляции.
},
+
+ // Медиа сервер 1
+ media_system_software_1: { title: "Центральный процессор", content: Центральный процессор
Описание центрального процессора медиа сервера.
},
+ media_system_software_2: { title: "Оперативная память", content: Оперативная память
Описание оперативной памяти медиа сервера.
},
+ media_system_software_3: { title: "Жесткий диск", content: Жесткий диск
Описание жесткого диска медиа сервера.
},
+ media_system_software_4: { title: "Сетевые адаптеры", content: Сетевые адаптеры
Описание сетевых адаптеров медиа сервера.
},
+ media_software_1: { title: "ПО", content: Программное обеспечение медиа сервера
},
+ media_software_2: { title: "ПО", content: Программное обеспечение медиа сервера
Описание ПО медиа сервера.
},
+ media_software_3: { title: "ПО", content: Программное обеспечение медиа сервера
Описание ПО медиа сервера.
},
+ media_software_4: { title: "ПО", content: Программное обеспечение медиа сервера
Описание ПО медиа сервера.
},
+
+ // Медиа сервер 2
+ media_system_software_1_2: { title: "Центральный процессор", content: Центральный процессор
Описание центрального процессора медиа сервера.
},
+ media_system_software_2_2: { title: "Оперативная память", content: Оперативная память
Описание оперативной памяти медиа сервера.
},
+ media_system_software_3_2: { title: "Жесткий диск", content: Жесткий диск
Описание жесткого диска медиа сервера.
},
+ media_system_software_4_2: { title: "Сетевые адаптеры", content: Сетевые адаптеры
Описание сетевых адаптеров медиа сервера.
},
+ media_software_1_2: { title: "ПО", content: Программное обеспечение медиа сервера
},
+ media_software_2_2: { title: "ПО", content: Программное обеспечение медиа сервера
Описание ПО медиа сервера.
},
+ media_software_3_2: { title: "ПО", content: Программное обеспечение медиа сервера
Описание ПО медиа сервера.
},
+ media_software_4_2: { title: "ПО", content: Программное обеспечение медиа сервера
Описание ПО медиа сервера.
},
+
+ // Медиа сервер 3
+ media_system_software_1_3: { title: "Центральный процессор", content: Центральный процессор
Описание центрального процессора медиа сервера.
},
+ media_system_software_2_3: { title: "Оперативная память", content: Оперативная память
Описание оперативной памяти медиа сервера.
},
+ media_system_software_3_3: { title: "Жесткий диск", content: Жесткий диск
Описание жесткого диска медиа сервера.
},
+ media_system_software_4_3: { title: "Сетевые адаптеры", content: Сетевые адаптеры
Описание сетевых адаптеров медиа сервера.
},
+ media_software_1_3: { title: "ПО", content: Программное обеспечение медиа сервера
},
+ media_software_2_3: { title: "ПО", content: Программное обеспечение медиа сервера
Описание ПО медиа сервера.
},
+ media_software_3_3: { title: "ПО", content: Программное обеспечение медиа сервера
Описание ПО медиа сервера.
},
+ media_software_4_3: { title: "ПО", content: Программное обеспечение медиа сервера
Описание ПО медиа сервера.
},
+
+ // Медиа сервер 4
+ media_system_software_1_4: { title: "Центральный процессор", content: Центральный процессор
Описание центрального процессора медиа сервера.
},
+ media_system_software_2_4: { title: "Оперативная память", content: Оперативная память
Описание оперативной памяти медиа сервера.
},
+ media_system_software_3_4: { title: "Жесткий диск", content: Жесткий диск
Описание жесткого диска медиа сервера.
},
+ media_system_software_4_4: { title: "Сетевые адаптеры", content: Сетевые адаптеры
Описание сетевых адаптеров медиа сервера.
},
+ media_software_1_4: { title: "ПО", content: Программное обеспечение медиа сервера
},
+ media_software_2_4: { title: "ПО", content: Программное обеспечение медиа сервера
Описание ПО медиа сервера.
},
+ media_software_3_4: { title: "ПО", content: Программное обеспечение медиа сервера
Описание ПО медиа сервера.
},
+ media_software_4_4: { title: "ПО", content: Программное обеспечение медиа сервера
Описание ПО медиа сервера.
},
+
+ // Медиа сервер 5
+ media_system_software_1_5: { title: "Центральный процессор", content: Центральный процессор
Описание центрального процессора медиа сервера.
},
+ media_system_software_2_5: { title: "Оперативная память", content: Оперативная память
Описание оперативной памяти медиа сервера.
},
+ media_system_software_3_5: { title: "Жесткий диск", content: Жесткий диск
Описание жесткого диска медиа сервера.
},
+ media_system_software_4_5: { title: "Сетевые адаптеры", content: Сетевые адаптеры
Описание сетевых адаптеров медиа сервера.
},
+ media_software_1_5: { title: "ПО", content: Программное обеспечение медиа сервера
},
+ media_software_2_5: { title: "ПО", content: Программное обеспечение медиа сервера
Описание ПО медиа сервера.
},
+ media_software_3_5: { title: "ПО", content: Программное обеспечение медиа сервера
Описание ПО медиа сервера.
},
+ media_software_4_5: { title: "ПО", content: Программное обеспечение медиа сервера
Описание ПО медиа сервера.
},
+
+ // Сервер резервного копирования
+ copy_system_software_1: { title: "Центральный процессор", content: Центральный процессор
Описание центрального процессора сервера резервного копирования.
},
+ copy_system_software_2: { title: "Оперативная память", content: Оперативная память
Описание оперативной памяти сервера резервного копирования.
},
+ copy_system_software_3: { title: "Жесткий диск", content: Жесткий диск
Описание жесткого диска сервера резервного копирования.
},
+ copy_system_software_4: { title: "Сетевые адаптеры", content: Сетевые адаптеры
Описание сетевых адаптеров сервера резервного копирования.
},
+ copy_software_1: { title: "ПО", content: Программное обеспечение сервера резервного копирования
Описание ПО сервера резервного копирования.
},
+ copy_software_2: { title: "ПО", content: Программное обеспечение сервера резервного копирования
Описание ПО сервера резервного копирования.
},
+ copy_software_3: { title: "ПО", content: Программное обеспечение сервера резервного копирования
Описание ПО сервера резервного копирования.
},
+ copy_software_4: { title: "ПО", content: Программное обеспечение сервера резервного копирования
Описание ПО сервера резервного копирования.
},
+
+ // Сервер системы управления
+ control_system_software_1: { title: "Центральный процессор", content: Центральный процессор
Описание центрального процессора сервера системы управления.
},
+ control_system_software_2: { title: "Оперативная память", content: Оперативная память
Описание оперативной памяти сервера системы управления.
},
+ control_system_software_3: { title: "Жесткий диск", content: Жесткий диск
Описание жесткого диска сервера системы управления.
},
+ control_system_software_4: { title: "Сетевые адаптеры", content: Сетевые адаптеры
Описание сетевых адаптеров сервера системы управления.
},
+ control_software_1: { title: "ПО", content: Программное обеспечение сервера системы управления
Описание ПО сервера системы управления.
},
+ control_software_2: { title: "ПО", content: Программное обеспечение сервера системы управления
Описание ПО сервера системы управления.
},
+ control_software_3: { title: "ПО", content: Программное обеспечение сервера системы управления
Описание ПО сервера системы управления.
},
+ control_software_4: { title: "ПО", content: Программное обеспечение сервера системы управления
Описание ПО сервера системы управления.
},
+
+ // Сервер сбора и ретрансляции информации
+ system_software_1: { title: "Центральный процессор", content: Центральный процессор
Описание центрального процессора сервера сбора и ретрансляции информации.
},
+ system_software_2: { title: "Оперативная память", content: Оперативная память
Описание оперативной памяти сервера сбора и ретрансляции информации.
},
+ system_software_3: { title: "Жесткий диск", content: Жесткий диск
Описание жесткого диска сервера сбора и ретрансляции информации.
},
+ system_software_4: { title: "Сетевые адаптеры", content: Сетевые адаптеры
Описание сетевых адаптеров сервера сбора и ретрансляции информации.
},
+ software_1: { title: "ПО", content: Программное обеспечение сервера сбора и ретрансляции информации
Описание ПО сервера сбора и ретрансляции информации.
},
+ software_2: { title: "ПО", content: Программное обеспечение сервера сбора и ретрансляции информации
Описание ПО сервера сбора и ретрансляции информации.
},
+ software_3: { title: "ПО", content: Программное обеспечение сервера сбора и ретрансляции информации
Описание ПО сервера сбора и ретрансляции информации.
},
+ software_4: { title: "ПО", content: Программное обеспечение сервера сбора и ретрансляции информации
Описание ПО сервера сбора и ретрансляции информации.
},
+};
+
+export default tabContent;
\ No newline at end of file
diff --git a/src/Components/ErrorIndicator.jsx b/src/Components/UI/ErrorIndicator.jsx
similarity index 70%
rename from src/Components/ErrorIndicator.jsx
rename to src/Components/UI/ErrorIndicator.jsx
index 7d71840..7215211 100644
--- a/src/Components/ErrorIndicator.jsx
+++ b/src/Components/UI/ErrorIndicator.jsx
@@ -1,7 +1,7 @@
import React from "react";
-import criticalIcon from "../assets/images/critical.png"; // Красный треугольник
-import warningIcon from "../assets/images/warning.png"; // Желтый треугольник
-import "../Style/ErrorIndicator.css"; // Подключаем стили
+import criticalIcon from "../../assets/images/critical.png"; // Красный треугольник
+import warningIcon from "../../assets/images/warning.png"; // Желтый треугольник
+import "../../Style/ErrorIndicator.css"; // Подключаем стили
const ErrorIndicator = ({ criticalCount, warningCount }) => {
return (
diff --git a/src/Components/ExpandableInfo.jsx b/src/Components/UI/ExpandableInfo.jsx
similarity index 100%
rename from src/Components/ExpandableInfo.jsx
rename to src/Components/UI/ExpandableInfo.jsx
diff --git a/src/Components/UI/LoginModal.jsx b/src/Components/UI/LoginModal.jsx
new file mode 100644
index 0000000..c4d5f09
--- /dev/null
+++ b/src/Components/UI/LoginModal.jsx
@@ -0,0 +1,49 @@
+import React, { useState } from "react";
+import Modal from "./Modal";
+import "../../Style/LoginModal.css";
+
+const LoginModal = ({ onLogin, onClose }) => {
+ const [username, setUsername] = useState("");
+ const [password, setPassword] = useState("");
+ const [error, setError] = useState("");
+
+ const handleSubmit = (e) => {
+ e.preventDefault();
+ if (username === "admin" && password === "admin") {
+ onLogin(); // Успешная авторизация
+ onClose(); // Закрыть модальное окно
+ } else {
+ setError("Неверный логин или пароль");
+ }
+ };
+
+ return (
+
+ Авторизация
+
+
+ );
+};
+
+export default LoginModal;
\ No newline at end of file
diff --git a/src/Components/UI/Modal.jsx b/src/Components/UI/Modal.jsx
new file mode 100644
index 0000000..3718035
--- /dev/null
+++ b/src/Components/UI/Modal.jsx
@@ -0,0 +1,14 @@
+import React from "react";
+
+const Modal = ({ children, onClose }) => {
+ return (
+
+
+ {children}
+
+
+
+ );
+};
+
+export default Modal;
\ No newline at end of file
diff --git a/src/Components/UI/Tabs.jsx b/src/Components/UI/Tabs.jsx
new file mode 100644
index 0000000..78ec099
--- /dev/null
+++ b/src/Components/UI/Tabs.jsx
@@ -0,0 +1,56 @@
+import React from "react";
+import "../../Style/common.css"; // Общие стили для табов
+
+const Tabs = ({ tabs, activeTab, onTabClick, onCloseTab }) => {
+ const handleMouseDown = (e, id) => {
+ // Проверяем, была ли нажата средняя кнопка мыши (button === 1)
+ if (e.button === 1) {
+ e.preventDefault(); // Предотвращаем стандартное поведение (например, прокрутку)
+ onCloseTab(id); // Закрываем вкладку
+ }
+ };
+
+
+ return (
+
+ {/* Всегда отображаемые вкладки */}
+
onTabClick("Главная")}
+ onMouseDown={(e) => handleMouseDown(e, "Главная")} // Добавляем обработчик для СКМ
+ >
+ Главная
+
+
onTabClick("Визуализация")}
+ onMouseDown={(e) => handleMouseDown(e, "Визуализация")} // Добавляем обработчик для СКМ
+ >
+ Визуализация
+
+
+ {/* Динамически добавляемые вкладки */}
+ {tabs.map((tab) => (
+
onTabClick(tab.id)}
+ onMouseDown={(e) => handleMouseDown(e, tab.id)} // Добавляем обработчик для СКМ
+ >
+ {tab.title}
+
+
+ ))}
+
+ );
+};
+
+export default Tabs;
\ No newline at end of file
diff --git a/src/Components/UI/TreeTable.jsx b/src/Components/UI/TreeTable.jsx
new file mode 100644
index 0000000..28b2105
--- /dev/null
+++ b/src/Components/UI/TreeTable.jsx
@@ -0,0 +1,76 @@
+import React from "react";
+import "../../Style/TreeTable.css";
+import { getStatusColor } from "../TreeChart/dataUtils"; // Импортируем функцию
+
+const TreeTable = ({ data }) => {
+ // Фильтруем данные, чтобы убрать "Функциональные задачи"
+ const filteredData = data.filter((item) => item.title !== "Функциональные задачи");
+
+ return (
+
+
+
+ {/* Первый уровень: Заголовки "Медиа сервер" */}
+
+ {filteredData.map((item, index) => (
+ |
+ {item.title}
+ |
+ ))}
+
+ {/* Второй уровень: "АО" и "ПО" */}
+
+ {filteredData.map((item, index) => (
+
+ |
+ АО
+ |
+
+ ПО
+ |
+
+ ))}
+
+
+
+ {/* Третий уровень: Вложенные элементы "АО" и "ПО" */}
+ {renderRows(filteredData)}
+
+
+
+ );
+};
+
+// Функция для отображения строк с вложенными элементами
+const renderRows = (data) => {
+ const rows = [];
+
+ // Находим максимальное количество элементов среди всех "АО" и "ПО"
+ const maxItems = Math.max(
+ ...data.flatMap((item) => [
+ item.items[0]?.items?.length || 0, // АО
+ item.items[1]?.items?.length || 0 // ПО
+ ])
+ );
+
+ // Генерируем строки
+ for (let i = 0; i < maxItems; i++) {
+ rows.push(
+
+ {data.map((item, index) => (
+
+ |
+ {item.items[0]?.items[i]?.title || ""}
+ |
+
+ {item.items[1]?.items[i]?.title || ""}
+ |
+
+ ))}
+
+ );
+ }
+
+ return rows;
+};
+export default TreeTable;
\ No newline at end of file
diff --git a/src/Components/menuData.json b/src/Components/menuData.json
deleted file mode 100644
index daf3ef1..0000000
--- a/src/Components/menuData.json
+++ /dev/null
@@ -1,55 +0,0 @@
-{
- "title": "Сервис ВКС",
- "items": [
- {
- "title": "Функциональные задачи",
- "items": [
- {
- "id": "system_control",
- "title": "Контроль системы"
- },
- {
- "id": "system_management",
- "title": "Система управления"
- },
- {
- "id": "conference",
- "title": "Проведение ВКС"
- },
- {
- "id": "backup",
- "title": "Резервное копирование"
- },
- {
- "id": "relay_info",
- "title": "Ретрансляция информации"
- }
- ]
- },
- {
- "title": "Аппаратное ПО",
- "items": [
- {
- "id": "hardware_software_1",
- "title": "ПО1"
- },
- {
- "id": "hardware_software_2",
- "title": "ПО2"
- },
- {
- "id": "hardware_software_3",
- "title": "ПО3"
- },
- {
- "id": "hardware_software_4",
- "title": "ПО4"
- },
- {
- "id": "hardware_software_5",
- "title": "ПО5"
- }
- ]
- }
- ]
-}
diff --git a/src/Components/tabContent.jsx b/src/Components/tabContent.jsx
deleted file mode 100644
index 9f7aa40..0000000
--- a/src/Components/tabContent.jsx
+++ /dev/null
@@ -1,18 +0,0 @@
-import React from "react";
-import NetworkSpeedChart2 from '../Charts/TestCharts2';
-
-const tabContent = {
- service1: { title: "Сервис ВКС", content: Сервис ВКС
},
- system_control: { title: "Контроль системы", content: Контроль системы
Описание контроля.
},
- system_management: { title: "Система управления", content: Система управления
Описание системы управления.
},
- conference: { title: "Проведение ВКС", content: Проведение ВКС
Информация о проведении ВКС.
},
- backup: { title: "Резервное копирование", content: Резервное копирование
Процесс резервного копирования.
},
- relay_info: { title: "Ретрансляция информации", content: Ретрансляция информации
Детали ретрансляции.
},
- hardware_software_1: { title: "График скорости сети", content: График скорости сети
},
- hardware_software_2: { title: "ПО2", content: ПО2
},
- hardware_software_3: { title: "ПО3", content: ПО3
},
- hardware_software_4: { title: "ПО4", content: ПО4
},
- hardware_software_5: { title: "ПО5", content: ПО5
},
-};
-
-export default tabContent;
\ No newline at end of file
diff --git a/src/Style/Dashboard.css b/src/Style/Dashboard.css
index 8a83bd3..537a8ca 100644
--- a/src/Style/Dashboard.css
+++ b/src/Style/Dashboard.css
@@ -1,62 +1,56 @@
+/* Основной контейнер */
.dashboard-container {
display: flex;
height: 100vh;
- width: 100vw;
+ width: calc(100vw - 20px); /* Учитываем отступ */
overflow: hidden;
- /* Запрещаем появление скролла */
+ margin-left: 20px;
}
+/* Сайдбар */
+.sidebar {
+ height: 100vh;
+ background-color: #3d74c7;
+ color: white;
+ position: fixed;
+ left: 0;
+ top: 0;
+ z-index: 999;
+ overflow: hidden;
+ transition: width 0.2s ease;
+ /* Плавное изменение ширины */
+ display: flex;
+ flex-direction: column;
+}
+
+/* Элемент для перетаскивания */
+.sidebar-resizer {
+ width: 5px;
+ /* Ширина элемента перетаскивания */
+ height: 100%;
+ background-color: rgba(255, 255, 255, 0.1);
+ position: absolute;
+ right: 0;
+ top: 0;
+ cursor: ew-resize;
+ /* Курсор "изменить размер" */
+ transition: background-color 0.2s ease;
+ z-index: 1000;
+ /* Убедимся, что элемент поверх других */
+}
+
+.sidebar-resizer:hover {
+ background-color: rgba(255, 255, 255, 0.3);
+ /* Эффект при наведении */
+}
+
+/* Основной контент */
.main-content {
flex: 1;
- min-width: 400px;
- max-width: calc(100vw - 250px);
padding: 20px;
- box-sizing: border-box;
- overflow-y: auto;
- /* Добавляем вертикальную прокрутку */
- height: 100vh;
- /* Ограничиваем высоту */
-}
-
-
-/* Вкладки */
-.tabs {
- display: flex;
- gap: 5px;
- padding: 5px;
- background-color: #222;
- border-bottom: 2px solid #444;
- overflow-x: auto;
- white-space: nowrap;
-}
-
-.tab {
- display: flex;
- align-items: center;
- background-color: #333;
- color: white;
- padding: 5px 10px;
- border-radius: 5px 5px 0 0;
- cursor: pointer;
- max-width: 250px;
- /* Ограничиваем максимальную ширину */
- min-width: 100px;
- /* Минимальная ширина */
- flex-shrink: 0;
- /* Не позволяет вкладкам сжиматься */
- position: relative;
-}
-
-.tab.active {
- background-color: #555;
-}
-
-.close-tab {
- background: none;
- border: none;
- cursor: pointer;
- font-size: 16px;
- padding: 0;
+ margin-left: 50px;
+ transition: margin-left 0.2s ease;
+ overflow: auto; /* Позволяет прокручивать контент, если он не влезает */
}
/* Контент */
@@ -64,22 +58,12 @@
background-color: #f9f9f9;
padding: 20px;
border-radius: 10px;
- box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
-}
-
-.default-content {
- display: flex;
- flex-direction: column;
- gap: 50px;
-}
-
-.tab-content {
- background-color: #fff;
- padding: 20px;
- border-radius: 10px;
- box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
+ box-shadow: 0 2px 5px rgba(29, 1, 1, 0.521);
+ max-width: 100%; /* Гарантируем, что контент не выйдет за границы */
+ overflow: auto; /* Включаем скролл, если нужно */
}
+/* Заголовки */
h2 {
color: #444;
}
diff --git a/src/Style/DatePicker.css b/src/Style/DatePicker.css
new file mode 100644
index 0000000..3b564d1
--- /dev/null
+++ b/src/Style/DatePicker.css
@@ -0,0 +1,129 @@
+/* DatePicker.css */
+
+.react-datepicker-wrapper {
+ width: auto;
+ display: inline-block;
+}
+
+.react-datepicker__input-container input {
+ width: 200px;
+ padding: 8px 12px;
+ border: 1px solid #ddd;
+ border-radius: 6px;
+ font-size: 14px;
+ color: #333;
+ background-color: #fff;
+ transition: border-color 0.2s ease;
+}
+
+.react-datepicker__input-container input:focus {
+ border-color: #0078d4;
+ outline: none;
+}
+
+.react-datepicker {
+ font-family: 'Segoe UI', sans-serif;
+ border: 1px solid #e0e0e0;
+ border-radius: 8px;
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
+ background-color: #fff;
+ /* Непрозрачный фон */
+ z-index: 1000;
+ /* Календарь поверх других элементов */
+}
+
+.react-datepicker-popper {
+ z-index: 1000;
+ /* Календарь поверх других элементов */
+ pointer-events: auto;
+ /* Разрешить взаимодействие только с календарем */
+}
+
+.react-datepicker__header {
+ background-color: #f8f8f8;
+ /* Непрозрачный фон заголовка */
+ border-bottom: 1px solid #e0e0e0;
+ border-radius: 8px 8px 0 0;
+ padding: 12px;
+}
+
+.react-datepicker__current-month {
+ font-size: 14px;
+ font-weight: 600;
+ color: #333;
+}
+
+.react-datepicker__navigation {
+ top: 12px;
+ border: 0.45rem solid transparent;
+}
+
+.react-datepicker__navigation--previous {
+ left: 12px;
+ border-right-color: #666;
+}
+
+.react-datepicker__navigation--next {
+ right: 12px;
+ border-left-color: #666;
+}
+
+.react-datepicker__day-names {
+ display: flex;
+ justify-content: space-between;
+ padding: 0 8px;
+ margin-top: 8px;
+}
+
+.react-datepicker__day-name {
+ width: 28px;
+ line-height: 28px;
+ text-align: center;
+ font-size: 12px;
+ color: #666;
+}
+
+.react-datepicker__month {
+ background-color: #fff;
+ /* Непрозрачный фон месяца */
+ margin: 0;
+ padding: 8px;
+}
+
+.react-datepicker__week {
+ display: flex;
+ justify-content: space-between;
+}
+
+.react-datepicker__day {
+ width: 28px;
+ line-height: 28px;
+ text-align: center;
+ font-size: 12px;
+ color: #333;
+ cursor: pointer;
+ border-radius: 50%;
+ transition: background-color 0.2s ease, color 0.2s ease;
+}
+
+.react-datepicker__day:hover {
+ background-color: #f0f0f0;
+}
+
+.react-datepicker__day--selected {
+ background-color: #0078d4;
+ color: #fff;
+}
+
+.react-datepicker__day--selected:hover {
+ background-color: #005bb5;
+}
+
+.react-datepicker__day--outside-month {
+ color: #ccc;
+}
+
+.react-datepicker__day--disabled {
+ color: #ccc;
+ cursor: not-allowed;
+}
\ No newline at end of file
diff --git a/src/Style/ErrorIndicator.css b/src/Style/ErrorIndicator.css
index efce90a..115f992 100644
--- a/src/Style/ErrorIndicator.css
+++ b/src/Style/ErrorIndicator.css
@@ -2,6 +2,7 @@
display: flex;
align-items: center;
gap: 15px;
+ padding-bottom: 20px;
}
.error-item {
@@ -33,4 +34,5 @@
align-items: center;
gap: 15px;
justify-content: center;
+
}
\ No newline at end of file
diff --git a/src/Style/LoginModal.css b/src/Style/LoginModal.css
index 0d6d28c..ae99fe0 100644
--- a/src/Style/LoginModal.css
+++ b/src/Style/LoginModal.css
@@ -11,7 +11,7 @@
}
.modal {
- background: white;
+ background: rgb(255, 255, 255);
padding: 20px;
border-radius: 8px;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
@@ -26,6 +26,7 @@
.modal label {
display: block;
margin-bottom: 5px;
+ color: black;
}
.modal input {
@@ -38,7 +39,8 @@
.modal button {
padding: 10px 20px;
- background: #007bff;
+ margin-bottom: 5px;
+ background: #08294b;
color: white;
border: none;
border-radius: 4px;
diff --git a/src/Style/SidebarMenu.css b/src/Style/SidebarMenu.css
index 2956424..9fcb8d6 100644
--- a/src/Style/SidebarMenu.css
+++ b/src/Style/SidebarMenu.css
@@ -1,70 +1,124 @@
/* Боковое меню */
.sidebar {
- width: 250px;
- background-color: #333;
- padding: 20px;
- box-sizing: border-box;
- border-right: 1px solid #444;
height: 100vh;
- /* Занимает всю высоту экрана */
- overflow-y: auto;
- /* Прокрутка внутри меню, если контент не помещается */
- position: sticky;
- /* Фиксируем меню */
+ background-color: #3d74c7;
+ color: white;
+ position: fixed;
+ left: 0;
top: 0;
- /* Прилипаем к верху */
+ z-index: 999;
+ overflow: hidden;
+ transition: width 0.2s ease;
+ /* Плавное изменение ширины */
+ display: flex;
+ flex-direction: column;
}
+/* Контейнер для основного контента меню */
+.sidebar-content {
+ flex: 1;
+ overflow-y: auto;
+ /* Вертикальная прокрутка */
+ overflow-x: hidden;
+ /* Убираем горизонтальную прокрутку */
+ padding-bottom: 20px;
+ /* Отступ для "Помощи" и "Настроек" */
+}
+
+/* Заголовок меню */
.sidebar-title {
margin-bottom: 20px;
font-size: 18px;
font-weight: bold;
color: white;
+ padding: 10px;
+ /* Добавляем отступы */
}
+/* Элементы меню */
.menu-item {
margin-bottom: 10px;
color: white;
-}
-
-h2 {
- color: white
+ width: 100%;
+ /* Ширина на всю ширину сайдбара */
}
.menu-item-header {
display: flex;
- justify-content: space-between;
align-items: center;
+ /* Выравниваем элементы по центру */
padding: 10px;
- background-color: #444;
border-radius: 5px;
cursor: pointer;
transition: background-color 0.3s ease;
}
.menu-item-header:hover {
- background-color: #222;
+ background-color: rgba(255, 255, 255, 0.1);
+ /* Легкий эффект при наведении */
}
+/* Круглый индикатор статуса */
+.status-indicator {
+ width: 10px;
+ height: 10px;
+ border-radius: 50%;
+ /* Делаем круглым */
+ margin-right: 10px;
+ /* Отступ от текста */
+ flex-shrink: 0;
+ /* Запрещаем сжатие */
+}
+
+/* Анимация мигания для красного индикатора */
+@keyframes blink {
+ 0% {
+ opacity: 1;
+ }
+
+ /* Полная видимость */
+ 50% {
+ opacity: 0.3;
+ }
+
+ /* Полупрозрачность */
+ 100% {
+ opacity: 1;
+ }
+
+ /* Полная видимость */
+}
+
+.status-indicator.blinking {
+ animation: blink 1s infinite;
+ /* Бесконечная анимация с интервалом 1 секунда */
+}
+
+/* Подменю */
.submenu {
margin-left: 20px;
margin-top: 10px;
}
-.tabs-container {
- margin-top: 20px;
-}
-
-.tab {
+/* Футер сайдбара */
+.sidebar-footer {
padding: 10px;
- background-color: #444;
- border: 1px solid #333;
- border-radius: 5px;
- margin-bottom: 5px;
- cursor: pointer;
- transition: background-color 0.3s ease;
+ background-color: #3d74c7;
+ text-align: center;
+ border-top: 1px solid rgba(255, 255, 255, 0.1);
+ /* Разделительная линия */
+ flex-shrink: 0;
+ /* Запрещаем сжатие */
+ width: 100%;
+ /* Ширина на всю ширину сайдбара */
}
-.tab:hover {
- background-color: #222;
+.help,
+.settings {
+ color: white;
+ margin: 5px 0;
+ /* Отступы между элементами */
+ overflow-x: hidden;
+ /* Убираем горизонтальную прокрутку */
+ text-align: left;
}
\ No newline at end of file
diff --git a/src/Style/TreeTable.css b/src/Style/TreeTable.css
new file mode 100644
index 0000000..d2093b1
--- /dev/null
+++ b/src/Style/TreeTable.css
@@ -0,0 +1,58 @@
+/* Контейнер для таблицы с прокруткой */
+.table-container {
+ width: 100%;
+ /* Занимает всю доступную ширину */
+ overflow-x: auto;
+ /* Горизонтальная прокрутка при необходимости */
+ margin: 0 auto;
+ /* Центрирование контейнера */
+}
+
+/* Стили для таблицы */
+.tree-table {
+ width: auto;
+ /* Автоматическая ширина, чтобы таблица могла расширяться */
+ min-width: 95%;
+ /* Минимальная ширина таблицы */
+ border-collapse: collapse;
+ margin: 0 auto;
+ /* Центрирование таблицы */
+}
+
+/* Заголовки таблицы (первый уровень) */
+.tree-table th {
+ border: 1px solid #ddd;
+ padding: 8px;
+ text-align: left;
+ white-space: nowrap;
+ /* Запрет на перенос текста */
+ font-weight: bold;
+ /* Жирный шрифт для заголовков */
+}
+
+/* Подзаголовки (второй уровень: "АО" и "ПО") */
+.tree-table-subheader {
+ font-weight: 500;
+ /* Жирный шрифт для подзаголовков */
+}
+
+/* Ячейки таблицы */
+.tree-table td {
+ border: 1px solid #ddd;
+ padding: 8px;
+ text-align: left;
+ white-space: nowrap;
+ /* Запрет на перенос текста */
+ font-weight: normal;
+ /* Обычный шрифт для ячеек */
+}
+
+/* Цвет фона для заголовков */
+.tree-table-header {
+ background-color: #f4f4f4;
+}
+
+/* Чередование цвета строк */
+.tree-table-row:nth-child(even) {
+ background-color: #f9f9f9;
+}
\ No newline at end of file
diff --git a/src/Style/common.css b/src/Style/common.css
new file mode 100644
index 0000000..d170447
--- /dev/null
+++ b/src/Style/common.css
@@ -0,0 +1,72 @@
+/* src/Style/common.css */
+
+/* Контейнер для вкладок */
+.tabs {
+ display: flex;
+ gap: 5px;
+ /* Расстояние между вкладками */
+ padding: 5px;
+ background-color: #3d74c7;
+ /* Цвет фона */
+ border-bottom: 2px solid #195fc9;
+ /* Линия под вкладками */
+ overflow-x: auto;
+ /* Прокрутка, если вкладок много */
+ border-radius: 5px;
+ /* Скругление углов */
+ white-space: nowrap;
+ /* Запрет переноса текста */
+}
+
+/* Стили для отдельной вкладки */
+.tab {
+ display: flex;
+ align-items: center;
+ background-color: #3d74c7;
+ /* Цвет фона вкладки */
+ color: white;
+ /* Цвет текста */
+ padding: 5px 15px;
+ /* Отступы внутри вкладки */
+ border-radius: 5px 5px 0 0;
+ /* Скругление углов */
+ cursor: pointer;
+ /* Курсор при наведении */
+ flex-shrink: 0;
+ /* Запрет сжатия */
+ transition: background-color 0.3s ease;
+ /* Плавное изменение цвета */
+}
+
+/* Активная вкладка */
+.tab.active {
+ background-color: #195fc9;
+ /* Цвет фона активной вкладки */
+}
+
+/* Кнопка закрытия вкладки */
+.close-tab {
+ background: none;
+ border: none;
+ color: white;
+ /* Цвет крестика */
+ cursor: pointer;
+ font-size: 16px;
+ margin-left: 10px;
+ /* Отступ от текста */
+ padding: 0;
+ transition: color 0.3s ease;
+ /* Плавное изменение цвета */
+}
+
+/* Эффект при наведении на кнопку закрытия */
+.close-tab:hover {
+ color: #ff6b6b;
+ /* Цвет крестика при наведении */
+}
+
+/* Эффект при наведении на вкладку */
+.tab:hover {
+ background-color: #195fc9;
+ /* Цвет фона при наведении */
+}
\ No newline at end of file
diff --git a/src/index.css b/src/index.css
index 5a6ad3e..6c94c43 100755
--- a/src/index.css
+++ b/src/index.css
@@ -71,4 +71,28 @@ button:focus-visible {
button {
background-color: #f9f9f9;
}
+}
+
+/* Глобальный стиль для WebKit-браузеров (Chrome, Edge, Safari) */
+::-webkit-scrollbar {
+ width: 10px; /* Толщина вертикального скролла */
+ height: 10px; /* Толщина горизонтального скролла */
+}
+
+/* Фон скроллбара */
+::-webkit-scrollbar-track {
+ background: #f1f1f1; /* Цвет фона */
+ border-radius: 10px; /* Скругление углов */
+}
+
+/* Ползунок */
+::-webkit-scrollbar-thumb {
+ background: #3d74c7; /* Основной цвет */
+ border-radius: 10px; /* Скругляем края */
+ border: 1px solid #1c36c9; /* Белая обводка */
+}
+
+/* Эффект при наведении */
+::-webkit-scrollbar-thumb:hover {
+ background: #2b5aa5; /* Чуть темнее при наведении */
}
\ No newline at end of file
diff --git a/vite.config.js b/vite.config.js
index 6bb98ac..b034150 100755
--- a/vite.config.js
+++ b/vite.config.js
@@ -5,6 +5,7 @@ import react from '@vitejs/plugin-react'
export default defineConfig({
plugins: [react()],
server: {
- host: true
+ host: true,
+ allowedHosts: ['dev.msf.enode']
}
})