Добавил таблицу, статусы в виде зашлушек и их рандомную генерацию
parent
9ba64c71d5
commit
eaf706ddfe
|
|
@ -14,7 +14,7 @@ const PrometheusChart = ({ metricName }) => {
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const fetchData = async () => {
|
const fetchData = async () => {
|
||||||
try {
|
try {
|
||||||
const response = await axios.get(`http://192.168.2.33:3000/metrics?metric=prometheus_target_metadata_cache_bytes`);
|
const response = await axios.get(`http://192.168.2.39:3000/metrics?metric=zvks_apiforsnmp_ifOutUnicastPacket1`);
|
||||||
const result = response.data;
|
const result = response.data;
|
||||||
|
|
||||||
// Проверяем структуру данных
|
// Проверяем структуру данных
|
||||||
|
|
|
||||||
|
|
@ -5,20 +5,29 @@ import "../../Style/Dashboard.css";
|
||||||
import ErrorIndicator from "../UI/ErrorIndicator";
|
import ErrorIndicator from "../UI/ErrorIndicator";
|
||||||
import tabContentData from "../TreeChart/tabContent";
|
import tabContentData from "../TreeChart/tabContent";
|
||||||
import Tabs from "../UI/Tabs";
|
import Tabs from "../UI/Tabs";
|
||||||
import menuData from "../TreeChart//menuData.json"; // Загружаем новое меню
|
import menuData from "../TreeChart/menuData.json"; // Исходные данные меню
|
||||||
import TableComponent from '../UI/TreeTable';
|
|
||||||
import TreeTable from "../UI/TreeTable";
|
import TreeTable from "../UI/TreeTable";
|
||||||
|
import { updateStatuses } from "../TreeChart/dataUtils"; // Функция обновления статусов
|
||||||
|
|
||||||
const Dashboard = () => {
|
const Dashboard = () => {
|
||||||
const [tabs, setTabs] = useState([]);
|
const [tabs, setTabs] = useState([]);
|
||||||
const [activeTab, setActiveTab] = useState("Главная");
|
const [activeTab, setActiveTab] = useState("Главная");
|
||||||
const [tabContent, setTabContent] = useState({});
|
const [tabContent, setTabContent] = useState({});
|
||||||
const [treeData, setTreeData] = useState(null);
|
const [treeData, setTreeData] = useState(menuData); // Загружаем меню в state
|
||||||
|
|
||||||
|
// Обновление treeData каждые 10 секунд
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setTabContent(tabContentData);
|
setTabContent(tabContentData);
|
||||||
setTreeData(menuData);
|
|
||||||
|
const interval = setInterval(() => {
|
||||||
|
setTreeData((prevData) => {
|
||||||
|
const updatedData = JSON.parse(JSON.stringify(prevData)); // Клонируем данные
|
||||||
|
updateStatuses(updatedData); // Обновляем статусы
|
||||||
|
return updatedData;
|
||||||
|
});
|
||||||
|
}, 10000);
|
||||||
|
|
||||||
|
return () => clearInterval(interval);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const handleOpenTab = (id, title) => {
|
const handleOpenTab = (id, title) => {
|
||||||
|
|
@ -42,7 +51,7 @@ const Dashboard = () => {
|
||||||
<div>
|
<div>
|
||||||
<h2>Общий мониторинг</h2>
|
<h2>Общий мониторинг</h2>
|
||||||
<ErrorIndicator />
|
<ErrorIndicator />
|
||||||
<TreeTable data={menuData.items} />
|
<TreeTable data={treeData.items} /> {/* Теперь используем актуальные данные */}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
} else if (activeTab === "Визуализация") {
|
} else if (activeTab === "Визуализация") {
|
||||||
|
|
@ -55,8 +64,7 @@ const Dashboard = () => {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="dashboard-container">
|
<div className="dashboard-container">
|
||||||
<SidebarMenu onOpenTab={handleOpenTab} />
|
<SidebarMenu data={treeData} onOpenTab={handleOpenTab} /> {/* Передаём обновлённые данные */}
|
||||||
|
|
||||||
<div className="main-content">
|
<div className="main-content">
|
||||||
<Tabs
|
<Tabs
|
||||||
tabs={tabs}
|
tabs={tabs}
|
||||||
|
|
|
||||||
|
|
@ -1,19 +1,6 @@
|
||||||
import React, { useState } from "react";
|
import React, { useState } from "react";
|
||||||
import "../../Style/SidebarMenu.css";
|
import "../../Style/SidebarMenu.css";
|
||||||
import menuData from "../TreeChart/menuData.json";
|
import { getStatusColor } from "../TreeChart/dataUtils"; // Импортируем только нужную функцию
|
||||||
|
|
||||||
const getStatusColor = (status) => {
|
|
||||||
switch (status) {
|
|
||||||
case "green":
|
|
||||||
return "#4CAF50"; // Зеленый
|
|
||||||
case "yellow":
|
|
||||||
return "#FFEB3B"; // Желтый
|
|
||||||
case "red":
|
|
||||||
return "#F44336"; // Красный
|
|
||||||
default:
|
|
||||||
return "#3d74c7"; // Белый (или любой другой стандартный цвет)
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const MenuItem = ({ item, onSelectItem }) => {
|
const MenuItem = ({ item, onSelectItem }) => {
|
||||||
const [isOpen, setIsOpen] = useState(false);
|
const [isOpen, setIsOpen] = useState(false);
|
||||||
|
|
@ -45,15 +32,15 @@ const MenuItem = ({ item, onSelectItem }) => {
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
function SidebarMenu({ onOpenTab }) {
|
function SidebarMenu({ data, onOpenTab }) { // Теперь получаем `data` из пропсов
|
||||||
const handleSelectItem = (item) => {
|
const handleSelectItem = (item) => {
|
||||||
onOpenTab(item.id, item.title); // Передаем id и title
|
onOpenTab(item.id, item.title);
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="sidebar">
|
<div className="sidebar">
|
||||||
<h2 className="sidebar-title">Меню</h2>
|
<h2 className="sidebar-title">Меню</h2>
|
||||||
<MenuItem item={menuData} onSelectItem={handleSelectItem} />
|
<MenuItem item={data} onSelectItem={handleSelectItem} />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,71 +1,75 @@
|
||||||
import React, { useRef, useEffect } from "react";
|
import React, { useRef, useEffect } from "react";
|
||||||
import * as d3 from "d3";
|
import * as d3 from "d3";
|
||||||
|
import { getStatusColor } from "./dataUtils";
|
||||||
|
|
||||||
const TreeChart = ({ data, onNodeClick }) => {
|
const TreeChart = ({ data, onNodeClick }) => {
|
||||||
const chartRef = useRef();
|
const chartRef = useRef();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!data) return;
|
if (!data || !data.items) return;
|
||||||
|
|
||||||
// Очищаем старый граф перед отрисовкой
|
const width = 1000;
|
||||||
d3.select(chartRef.current).selectAll("*").remove();
|
|
||||||
|
|
||||||
const width = 928;
|
|
||||||
const height = 1000;
|
const height = 1000;
|
||||||
|
|
||||||
const root = d3.hierarchy(data, (d) => d.items);
|
const root = d3.hierarchy(data, (d) => d.items);
|
||||||
const links = root.links();
|
const links = root.links();
|
||||||
const nodes = root.descendants();
|
const nodes = root.descendants();
|
||||||
|
|
||||||
const simulation = d3
|
const svg = d3.select(chartRef.current);
|
||||||
.forceSimulation(nodes)
|
svg.selectAll("*").remove();
|
||||||
.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
|
svg
|
||||||
.select(chartRef.current)
|
|
||||||
.attr("width", width)
|
.attr("width", width)
|
||||||
.attr("height", height)
|
.attr("height", height)
|
||||||
.attr("viewBox", [-width / 2, -height / 2, width, height])
|
.attr("viewBox", [-width / 2, -height / 2, width, height])
|
||||||
.attr("style", "max-width: 100%; height: auto;");
|
.attr("style", "max-width: 100%; height: auto;");
|
||||||
|
|
||||||
const link = svg
|
const link = svg.append("g")
|
||||||
.append("g")
|
|
||||||
.attr("stroke", "#999")
|
.attr("stroke", "#999")
|
||||||
.attr("stroke-opacity", 0.6)
|
.attr("stroke-opacity", 0.6)
|
||||||
.selectAll("line")
|
.selectAll("line")
|
||||||
.data(links)
|
.data(links)
|
||||||
.join("line");
|
.join("line"); // Используем join для обновления связей
|
||||||
|
|
||||||
const node = svg
|
const node = svg.append("g")
|
||||||
.append("g")
|
|
||||||
.attr("stroke", "#000")
|
.attr("stroke", "#000")
|
||||||
.attr("stroke-width", 1.5)
|
.attr("stroke-width", 1.5)
|
||||||
.selectAll("circle")
|
.selectAll("circle")
|
||||||
.data(nodes)
|
.data(nodes)
|
||||||
.join("circle")
|
.join("circle") // Используем join для обновления узлов
|
||||||
.attr("fill", (d) => {
|
.attr("fill", (d) => getStatusColor(d.data.status))
|
||||||
// Окрашиваем узлы в зависимости от статуса
|
|
||||||
switch (d.data.status) {
|
|
||||||
case "green":
|
|
||||||
return "#4CAF50"; // Зеленый
|
|
||||||
case "yellow":
|
|
||||||
return "#FFEB3B"; // Желтый
|
|
||||||
case "red":
|
|
||||||
return "#F44336"; // Красный
|
|
||||||
default:
|
|
||||||
return "#555"; // Серый по умолчанию
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.attr("stroke", "#fff")
|
.attr("stroke", "#fff")
|
||||||
.attr("r", 7)
|
.attr("r", 7)
|
||||||
.call(drag(simulation));
|
.call(drag());
|
||||||
|
|
||||||
// Добавляем текстовые подписи
|
// Обновляем только те узлы, которые нуждаются в изменении
|
||||||
const text = svg
|
node.each(function (d) {
|
||||||
.append("g")
|
if (d.data.status === "red") {
|
||||||
|
d3.select(this)
|
||||||
|
.transition()
|
||||||
|
.duration(500)
|
||||||
|
.ease(d3.easeLinear)
|
||||||
|
.style("opacity", 0.3)
|
||||||
|
.transition()
|
||||||
|
.duration(500)
|
||||||
|
.ease(d3.easeLinear)
|
||||||
|
.style("opacity", 1)
|
||||||
|
.on("end", function repeat() {
|
||||||
|
d3.select(this)
|
||||||
|
.transition()
|
||||||
|
.duration(500)
|
||||||
|
.ease(d3.easeLinear)
|
||||||
|
.style("opacity", 0.3)
|
||||||
|
.transition()
|
||||||
|
.duration(500)
|
||||||
|
.ease(d3.easeLinear)
|
||||||
|
.style("opacity", 1)
|
||||||
|
.on("end", repeat);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const text = svg.append("g")
|
||||||
.attr("fill", "#000")
|
.attr("fill", "#000")
|
||||||
.attr("font-family", "Arial")
|
.attr("font-family", "Arial")
|
||||||
.attr("font-size", 12)
|
.attr("font-size", 12)
|
||||||
|
|
@ -81,10 +85,16 @@ const TreeChart = ({ data, onNodeClick }) => {
|
||||||
|
|
||||||
node.on("click", (event, d) => {
|
node.on("click", (event, d) => {
|
||||||
if (onNodeClick) {
|
if (onNodeClick) {
|
||||||
onNodeClick(d.data.id, d.data.title); // Передаем id и title
|
onNodeClick(d.data.id, d.data.title);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
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());
|
||||||
|
|
||||||
simulation.on("tick", () => {
|
simulation.on("tick", () => {
|
||||||
link
|
link
|
||||||
.attr("x1", (d) => d.source.x)
|
.attr("x1", (d) => d.source.x)
|
||||||
|
|
@ -101,14 +111,11 @@ const TreeChart = ({ data, onNodeClick }) => {
|
||||||
.attr("y", (d) => d.y + 4);
|
.attr("y", (d) => d.y + 4);
|
||||||
});
|
});
|
||||||
|
|
||||||
return () => {
|
return () => simulation.stop();
|
||||||
simulation.stop();
|
|
||||||
};
|
|
||||||
}, [data, onNodeClick]);
|
}, [data, onNodeClick]);
|
||||||
|
|
||||||
const drag = (simulation) => {
|
const drag = () => {
|
||||||
function dragstarted(event, d) {
|
function dragstarted(event, d) {
|
||||||
if (!event.active) simulation.alphaTarget(0.3).restart();
|
|
||||||
d.fx = d.x;
|
d.fx = d.x;
|
||||||
d.fy = d.y;
|
d.fy = d.y;
|
||||||
}
|
}
|
||||||
|
|
@ -119,7 +126,6 @@ const TreeChart = ({ data, onNodeClick }) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
function dragended(event, d) {
|
function dragended(event, d) {
|
||||||
if (!event.active) simulation.alphaTarget(0);
|
|
||||||
d.fx = null;
|
d.fx = null;
|
||||||
d.fy = null;
|
d.fy = null;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,53 @@
|
||||||
|
// Функция для генерации случайных статусов
|
||||||
|
const getRandomStatus = () => {
|
||||||
|
const statuses = [
|
||||||
|
"green", "green", "green", "green", "green", "green", "green", // 7/10 chance
|
||||||
|
"yellow", // 1/10 chance
|
||||||
|
"orange", // 1/10 chance
|
||||||
|
"red", // 1/10 chance
|
||||||
|
];
|
||||||
|
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 "#3d74c7"; // Синий (или любой другой стандартный цвет)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export { getRandomStatus, updateStatuses, getStatusColor };
|
||||||
|
|
@ -1,35 +1,28 @@
|
||||||
{
|
{
|
||||||
"title": "Сервис ВКС",
|
"title": "Сервис ВКС",
|
||||||
"status": "red",
|
|
||||||
"items": [
|
"items": [
|
||||||
{
|
{
|
||||||
"title": "Функциональные задачи",
|
"title": "Функциональные задачи",
|
||||||
"status": "red",
|
|
||||||
"items": [
|
"items": [
|
||||||
{
|
{
|
||||||
"id": "system_control",
|
"id": "system_control",
|
||||||
"title": "Контроль системы",
|
"title": "Контроль системы"
|
||||||
"status": "red"
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "system_management",
|
"id": "system_management",
|
||||||
"title": "Система управления",
|
"title": "Система управления"
|
||||||
"status": "green"
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "conference",
|
"id": "conference",
|
||||||
"title": "Проведение ВКС",
|
"title": "Проведение ВКС"
|
||||||
"status": "green"
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "backup",
|
"id": "backup",
|
||||||
"title": "Резервное копирование",
|
"title": "Резервное копирование"
|
||||||
"status": "green"
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "relay_info",
|
"id": "relay_info",
|
||||||
"title": "Ретрансляция информации",
|
"title": "Ретрансляция информации"
|
||||||
"status": "green"
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|
@ -81,7 +74,195 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"title": "Сервер резервного копирования",
|
"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": [
|
"items": [
|
||||||
{
|
{
|
||||||
"title": "Аппаратное обеспечение",
|
"title": "Аппаратное обеспечение",
|
||||||
|
|
@ -128,7 +309,7 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"title": "Сервер системы управления",
|
"title": "Сервер систем",
|
||||||
"items": [
|
"items": [
|
||||||
{
|
{
|
||||||
"title": "Аппаратное обеспечение",
|
"title": "Аппаратное обеспечение",
|
||||||
|
|
@ -173,53 +354,6 @@
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
|
||||||
{
|
|
||||||
"title": "Сервер сбора и ретрансляции информации",
|
|
||||||
"items": [
|
|
||||||
{
|
|
||||||
"title": "Аппаратное обеспечение",
|
|
||||||
"items": [
|
|
||||||
{
|
|
||||||
"id": "system_software_1",
|
|
||||||
"title": "Центральный процессор"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "system_software_2",
|
|
||||||
"title": "Оперативная память"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "system_software_3",
|
|
||||||
"title": "Жесткий диск"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "system_software_4",
|
|
||||||
"title": "Сетевые адаптеры"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"title": "Программное обеспечение",
|
|
||||||
"items": [
|
|
||||||
{
|
|
||||||
"id": "software_1",
|
|
||||||
"title": "ПО"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "software_2",
|
|
||||||
"title": "ПО"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "software_3",
|
|
||||||
"title": "ПО"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "software_4",
|
|
||||||
"title": "ПО"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
@ -12,7 +12,7 @@ const tabContent = {
|
||||||
backup: { title: "Резервное копирование", content: <div><h2>Резервное копирование</h2><p>Процесс резервного копирования.</p></div> },
|
backup: { title: "Резервное копирование", content: <div><h2>Резервное копирование</h2><p>Процесс резервного копирования.</p></div> },
|
||||||
relay_info: { title: "Ретрансляция информации", content: <div><h2>Ретрансляция информации</h2><p>Детали ретрансляции.</p></div> },
|
relay_info: { title: "Ретрансляция информации", content: <div><h2>Ретрансляция информации</h2><p>Детали ретрансляции.</p></div> },
|
||||||
|
|
||||||
// Медиа сервер
|
// Медиа сервер 1
|
||||||
media_system_software_1: { title: "Центральный процессор", content: <div><h2>Центральный процессор</h2><p>Описание центрального процессора медиа сервера.</p></div> },
|
media_system_software_1: { title: "Центральный процессор", content: <div><h2>Центральный процессор</h2><p>Описание центрального процессора медиа сервера.</p></div> },
|
||||||
media_system_software_2: { title: "Оперативная память", content: <div><h2>Оперативная память</h2><p>Описание оперативной памяти медиа сервера.</p></div> },
|
media_system_software_2: { title: "Оперативная память", content: <div><h2>Оперативная память</h2><p>Описание оперативной памяти медиа сервера.</p></div> },
|
||||||
media_system_software_3: { title: "Жесткий диск", content: <div><h2>Жесткий диск</h2><p>Описание жесткого диска медиа сервера.</p></div> },
|
media_system_software_3: { title: "Жесткий диск", content: <div><h2>Жесткий диск</h2><p>Описание жесткого диска медиа сервера.</p></div> },
|
||||||
|
|
@ -22,6 +22,46 @@ const tabContent = {
|
||||||
media_software_3: { title: "ПО", content: <div><h2>Программное обеспечение медиа сервера</h2><p>Описание ПО медиа сервера.</p></div> },
|
media_software_3: { title: "ПО", content: <div><h2>Программное обеспечение медиа сервера</h2><p>Описание ПО медиа сервера.</p></div> },
|
||||||
media_software_4: { title: "ПО", content: <div><h2>Программное обеспечение медиа сервера</h2><p>Описание ПО медиа сервера.</p></div> },
|
media_software_4: { title: "ПО", content: <div><h2>Программное обеспечение медиа сервера</h2><p>Описание ПО медиа сервера.</p></div> },
|
||||||
|
|
||||||
|
// Медиа сервер 2
|
||||||
|
media_system_software_1_2: { title: "Центральный процессор", content: <div><h2>Центральный процессор</h2><p>Описание центрального процессора медиа сервера.</p></div> },
|
||||||
|
media_system_software_2_2: { title: "Оперативная память", content: <div><h2>Оперативная память</h2><p>Описание оперативной памяти медиа сервера.</p></div> },
|
||||||
|
media_system_software_3_2: { title: "Жесткий диск", content: <div><h2>Жесткий диск</h2><p>Описание жесткого диска медиа сервера.</p></div> },
|
||||||
|
media_system_software_4_2: { title: "Сетевые адаптеры", content: <div><h2>Сетевые адаптеры</h2><p>Описание сетевых адаптеров медиа сервера.</p></div> },
|
||||||
|
media_software_1_2: { title: "ПО", content: <div><h2>Программное обеспечение медиа сервера</h2><PrometheusChart /></div> },
|
||||||
|
media_software_2_2: { title: "ПО", content: <div><h2>Программное обеспечение медиа сервера</h2><p>Описание ПО медиа сервера.</p></div> },
|
||||||
|
media_software_3_2: { title: "ПО", content: <div><h2>Программное обеспечение медиа сервера</h2><p>Описание ПО медиа сервера.</p></div> },
|
||||||
|
media_software_4_2: { title: "ПО", content: <div><h2>Программное обеспечение медиа сервера</h2><p>Описание ПО медиа сервера.</p></div> },
|
||||||
|
|
||||||
|
// Медиа сервер 3
|
||||||
|
media_system_software_1_3: { title: "Центральный процессор", content: <div><h2>Центральный процессор</h2><p>Описание центрального процессора медиа сервера.</p></div> },
|
||||||
|
media_system_software_2_3: { title: "Оперативная память", content: <div><h2>Оперативная память</h2><p>Описание оперативной памяти медиа сервера.</p></div> },
|
||||||
|
media_system_software_3_3: { title: "Жесткий диск", content: <div><h2>Жесткий диск</h2><p>Описание жесткого диска медиа сервера.</p></div> },
|
||||||
|
media_system_software_4_3: { title: "Сетевые адаптеры", content: <div><h2>Сетевые адаптеры</h2><p>Описание сетевых адаптеров медиа сервера.</p></div> },
|
||||||
|
media_software_1_3: { title: "ПО", content: <div><h2>Программное обеспечение медиа сервера</h2><PrometheusChart /></div> },
|
||||||
|
media_software_2_3: { title: "ПО", content: <div><h2>Программное обеспечение медиа сервера</h2><p>Описание ПО медиа сервера.</p></div> },
|
||||||
|
media_software_3_3: { title: "ПО", content: <div><h2>Программное обеспечение медиа сервера</h2><p>Описание ПО медиа сервера.</p></div> },
|
||||||
|
media_software_4_3: { title: "ПО", content: <div><h2>Программное обеспечение медиа сервера</h2><p>Описание ПО медиа сервера.</p></div> },
|
||||||
|
|
||||||
|
// Медиа сервер 4
|
||||||
|
media_system_software_1_4: { title: "Центральный процессор", content: <div><h2>Центральный процессор</h2><p>Описание центрального процессора медиа сервера.</p></div> },
|
||||||
|
media_system_software_2_4: { title: "Оперативная память", content: <div><h2>Оперативная память</h2><p>Описание оперативной памяти медиа сервера.</p></div> },
|
||||||
|
media_system_software_3_4: { title: "Жесткий диск", content: <div><h2>Жесткий диск</h2><p>Описание жесткого диска медиа сервера.</p></div> },
|
||||||
|
media_system_software_4_4: { title: "Сетевые адаптеры", content: <div><h2>Сетевые адаптеры</h2><p>Описание сетевых адаптеров медиа сервера.</p></div> },
|
||||||
|
media_software_1_4: { title: "ПО", content: <div><h2>Программное обеспечение медиа сервера</h2><PrometheusChart /></div> },
|
||||||
|
media_software_2_4: { title: "ПО", content: <div><h2>Программное обеспечение медиа сервера</h2><p>Описание ПО медиа сервера.</p></div> },
|
||||||
|
media_software_3_4: { title: "ПО", content: <div><h2>Программное обеспечение медиа сервера</h2><p>Описание ПО медиа сервера.</p></div> },
|
||||||
|
media_software_4_4: { title: "ПО", content: <div><h2>Программное обеспечение медиа сервера</h2><p>Описание ПО медиа сервера.</p></div> },
|
||||||
|
|
||||||
|
// Медиа сервер 5
|
||||||
|
media_system_software_1_5: { title: "Центральный процессор", content: <div><h2>Центральный процессор</h2><p>Описание центрального процессора медиа сервера.</p></div> },
|
||||||
|
media_system_software_2_5: { title: "Оперативная память", content: <div><h2>Оперативная память</h2><p>Описание оперативной памяти медиа сервера.</p></div> },
|
||||||
|
media_system_software_3_5: { title: "Жесткий диск", content: <div><h2>Жесткий диск</h2><p>Описание жесткого диска медиа сервера.</p></div> },
|
||||||
|
media_system_software_4_5: { title: "Сетевые адаптеры", content: <div><h2>Сетевые адаптеры</h2><p>Описание сетевых адаптеров медиа сервера.</p></div> },
|
||||||
|
media_software_1_5: { title: "ПО", content: <div><h2>Программное обеспечение медиа сервера</h2><PrometheusChart /></div> },
|
||||||
|
media_software_2_5: { title: "ПО", content: <div><h2>Программное обеспечение медиа сервера</h2><p>Описание ПО медиа сервера.</p></div> },
|
||||||
|
media_software_3_5: { title: "ПО", content: <div><h2>Программное обеспечение медиа сервера</h2><p>Описание ПО медиа сервера.</p></div> },
|
||||||
|
media_software_4_5: { title: "ПО", content: <div><h2>Программное обеспечение медиа сервера</h2><p>Описание ПО медиа сервера.</p></div> },
|
||||||
|
|
||||||
// Сервер резервного копирования
|
// Сервер резервного копирования
|
||||||
copy_system_software_1: { title: "Центральный процессор", content: <div><h2>Центральный процессор</h2><p>Описание центрального процессора сервера резервного копирования.</p></div> },
|
copy_system_software_1: { title: "Центральный процессор", content: <div><h2>Центральный процессор</h2><p>Описание центрального процессора сервера резервного копирования.</p></div> },
|
||||||
copy_system_software_2: { title: "Оперативная память", content: <div><h2>Оперативная память</h2><p>Описание оперативной памяти сервера резервного копирования.</p></div> },
|
copy_system_software_2: { title: "Оперативная память", content: <div><h2>Оперативная память</h2><p>Описание оперативной памяти сервера резервного копирования.</p></div> },
|
||||||
|
|
|
||||||
|
|
@ -1,36 +1,76 @@
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import "../../Style/TreeTable.css"; // Подключаем стили
|
import "../../Style/TreeTable.css";
|
||||||
|
import { getStatusColor } from "../TreeChart/dataUtils"; // Импортируем функцию
|
||||||
|
|
||||||
const TreeTable = ({ data }) => {
|
const TreeTable = ({ data }) => {
|
||||||
return (
|
// Фильтруем данные, чтобы убрать "Функциональные задачи"
|
||||||
<div className="tree-table">
|
const filteredData = data.filter((item) => item.title !== "Функциональные задачи");
|
||||||
{/* Первый уровень заголовков */}
|
|
||||||
<div className="tree-table-header">
|
|
||||||
{data.map((item, index) => (
|
|
||||||
<div key={index} className="tree-table-column">
|
|
||||||
<div className="tree-table-title">{item.title}</div>
|
|
||||||
</div>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Вложенные элементы */}
|
return (
|
||||||
<div className="tree-table-body">
|
<div className="table-container">
|
||||||
{data.map((item, index) => (
|
<table className="tree-table">
|
||||||
<div key={index} className="tree-table-column">
|
<thead>
|
||||||
{item.items && (
|
{/* Первый уровень: Заголовки "Медиа сервер" */}
|
||||||
<div className="tree-table-items">
|
<tr>
|
||||||
{item.items.map((child, childIndex) => (
|
{filteredData.map((item, index) => (
|
||||||
<div key={childIndex} className="tree-table-item">
|
<th key={index} colSpan="2" className="tree-table-header" style={{ backgroundColor: getStatusColor(item.status) }}>
|
||||||
{child.title}
|
{item.title}
|
||||||
</div>
|
</th>
|
||||||
))}
|
))}
|
||||||
</div>
|
</tr>
|
||||||
)}
|
{/* Второй уровень: "АО" и "ПО" */}
|
||||||
</div>
|
<tr>
|
||||||
))}
|
{filteredData.map((item, index) => (
|
||||||
</div>
|
<React.Fragment key={index}>
|
||||||
|
<td className="tree-table-subheader" style={{ backgroundColor: getStatusColor(item.items[0]?.status) }}>
|
||||||
|
АО
|
||||||
|
</td>
|
||||||
|
<td className="tree-table-subheader" style={{ backgroundColor: getStatusColor(item.items[1]?.status) }}>
|
||||||
|
ПО
|
||||||
|
</td>
|
||||||
|
</React.Fragment>
|
||||||
|
))}
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{/* Третий уровень: Вложенные элементы "АО" и "ПО" */}
|
||||||
|
{/*renderRows(filteredData)*/}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Функция для отображения строк с вложенными элементами
|
||||||
|
const renderRows = (data) => {
|
||||||
|
const maxItems = Math.max(
|
||||||
|
...data.map((item) =>
|
||||||
|
Math.max(
|
||||||
|
item.items[0]?.items?.length || 0, // АО
|
||||||
|
item.items[1]?.items?.length || 0 // ПО
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
const rows = [];
|
||||||
|
for (let i = 0; i < maxItems; i++) {
|
||||||
|
rows.push(
|
||||||
|
<tr key={i} className="tree-table-row">
|
||||||
|
{data.map((item, index) => (
|
||||||
|
<React.Fragment key={index}>
|
||||||
|
<td className="tree-table-cell" style={{ backgroundColor: getStatusColor(item.items[0]?.items[i]?.status) }}>
|
||||||
|
{item.items[0]?.items[i]?.title || ""}
|
||||||
|
</td>
|
||||||
|
<td className="tree-table-cell" style={{ backgroundColor: getStatusColor(item.items[1]?.items[i]?.status) }}>
|
||||||
|
{item.items[1]?.items[i]?.title || ""}
|
||||||
|
</td>
|
||||||
|
</React.Fragment>
|
||||||
|
))}
|
||||||
|
</tr>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return rows;
|
||||||
|
};
|
||||||
|
|
||||||
export default TreeTable;
|
export default TreeTable;
|
||||||
|
|
@ -1,67 +1,58 @@
|
||||||
.tree-table {
|
/* Контейнер для таблицы с прокруткой */
|
||||||
max-width: 90vw; /* Ограничение ширины таблицы, чтобы не растягивалась */
|
.table-container {
|
||||||
min-width: 400px; /* Минимальная ширина для нормального отображения */
|
width: 100%;
|
||||||
margin: 0 auto; /* Центрирование */
|
/* Занимает всю доступную ширину */
|
||||||
overflow-x: auto;
|
overflow-x: auto;
|
||||||
padding: 10px;
|
/* Горизонтальная прокрутка при необходимости */
|
||||||
box-sizing: border-box;
|
margin: 0 auto;
|
||||||
|
/* Центрирование контейнера */
|
||||||
}
|
}
|
||||||
|
|
||||||
.tree-table-header {
|
/* Стили для таблицы */
|
||||||
display: flex;
|
.tree-table {
|
||||||
justify-content: space-around;
|
width: auto;
|
||||||
width: 100%;
|
/* Автоматическая ширина, чтобы таблица могла расширяться */
|
||||||
padding-bottom: 10px;
|
min-width: 95%;
|
||||||
border-bottom: 2px solid #ccc;
|
/* Минимальная ширина таблицы */
|
||||||
|
border-collapse: collapse;
|
||||||
|
margin: 0 auto;
|
||||||
|
/* Центрирование таблицы */
|
||||||
}
|
}
|
||||||
|
|
||||||
.tree-table-column {
|
/* Заголовки таблицы (первый уровень) */
|
||||||
flex: 1;
|
.tree-table th {
|
||||||
text-align: center;
|
border: 1px solid #ddd;
|
||||||
min-width: 150px;
|
padding: 8px;
|
||||||
max-width: 100%;
|
text-align: left;
|
||||||
}
|
|
||||||
|
|
||||||
.tree-table-title {
|
|
||||||
font-weight: bold;
|
|
||||||
font-size: 18px;
|
|
||||||
color: #333;
|
|
||||||
}
|
|
||||||
|
|
||||||
.tree-table-body {
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-around;
|
|
||||||
width: 100%;
|
|
||||||
margin-top: 15px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.tree-table-items {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
align-items: center;
|
|
||||||
gap: 8px;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Ограничение по ширине, чтобы элементы не растягивали таблицу */
|
|
||||||
.tree-table-item {
|
|
||||||
width: 170px;
|
|
||||||
/* Фиксированная ширина для всех элементов */
|
|
||||||
height: 40px;
|
|
||||||
/* Фиксированная высота */
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
overflow: hidden;
|
/* Запрет на перенос текста */
|
||||||
text-overflow: ellipsis;
|
font-weight: bold;
|
||||||
padding: 10px;
|
/* Жирный шрифт для заголовков */
|
||||||
background-color: white;
|
|
||||||
border-radius: 5px;
|
|
||||||
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.tree-table-item:hover {
|
/* Подзаголовки (второй уровень: "АО" и "ПО") */
|
||||||
transform: scale(1.05);
|
.tree-table-subheader {
|
||||||
background: #f1f1f1;
|
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;
|
||||||
}
|
}
|
||||||
|
|
@ -5,6 +5,7 @@ import react from '@vitejs/plugin-react'
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
plugins: [react()],
|
plugins: [react()],
|
||||||
server: {
|
server: {
|
||||||
host: true
|
host: true,
|
||||||
|
allowedHosts: ['dev.msf.enode']
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue