Добавил таблицу, статусы в виде зашлушек и их рандомную генерацию
parent
9ba64c71d5
commit
eaf706ddfe
|
|
@ -14,7 +14,7 @@ const PrometheusChart = ({ metricName }) => {
|
|||
useEffect(() => {
|
||||
const fetchData = async () => {
|
||||
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;
|
||||
|
||||
// Проверяем структуру данных
|
||||
|
|
|
|||
|
|
@ -5,20 +5,29 @@ import "../../Style/Dashboard.css";
|
|||
import ErrorIndicator from "../UI/ErrorIndicator";
|
||||
import tabContentData from "../TreeChart/tabContent";
|
||||
import Tabs from "../UI/Tabs";
|
||||
import menuData from "../TreeChart//menuData.json"; // Загружаем новое меню
|
||||
import TableComponent from '../UI/TreeTable';
|
||||
import menuData from "../TreeChart/menuData.json"; // Исходные данные меню
|
||||
import TreeTable from "../UI/TreeTable";
|
||||
|
||||
import { updateStatuses } from "../TreeChart/dataUtils"; // Функция обновления статусов
|
||||
|
||||
const Dashboard = () => {
|
||||
const [tabs, setTabs] = useState([]);
|
||||
const [activeTab, setActiveTab] = useState("Главная");
|
||||
const [tabContent, setTabContent] = useState({});
|
||||
const [treeData, setTreeData] = useState(null);
|
||||
const [treeData, setTreeData] = useState(menuData); // Загружаем меню в state
|
||||
|
||||
// Обновление treeData каждые 10 секунд
|
||||
useEffect(() => {
|
||||
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) => {
|
||||
|
|
@ -42,7 +51,7 @@ const Dashboard = () => {
|
|||
<div>
|
||||
<h2>Общий мониторинг</h2>
|
||||
<ErrorIndicator />
|
||||
<TreeTable data={menuData.items} />
|
||||
<TreeTable data={treeData.items} /> {/* Теперь используем актуальные данные */}
|
||||
</div>
|
||||
);
|
||||
} else if (activeTab === "Визуализация") {
|
||||
|
|
@ -55,8 +64,7 @@ const Dashboard = () => {
|
|||
|
||||
return (
|
||||
<div className="dashboard-container">
|
||||
<SidebarMenu onOpenTab={handleOpenTab} />
|
||||
|
||||
<SidebarMenu data={treeData} onOpenTab={handleOpenTab} /> {/* Передаём обновлённые данные */}
|
||||
<div className="main-content">
|
||||
<Tabs
|
||||
tabs={tabs}
|
||||
|
|
@ -72,4 +80,4 @@ const Dashboard = () => {
|
|||
);
|
||||
};
|
||||
|
||||
export default Dashboard;
|
||||
export default Dashboard;
|
||||
|
|
|
|||
|
|
@ -1,19 +1,6 @@
|
|||
import React, { useState } from "react";
|
||||
import "../../Style/SidebarMenu.css";
|
||||
import menuData from "../TreeChart/menuData.json";
|
||||
|
||||
const getStatusColor = (status) => {
|
||||
switch (status) {
|
||||
case "green":
|
||||
return "#4CAF50"; // Зеленый
|
||||
case "yellow":
|
||||
return "#FFEB3B"; // Желтый
|
||||
case "red":
|
||||
return "#F44336"; // Красный
|
||||
default:
|
||||
return "#3d74c7"; // Белый (или любой другой стандартный цвет)
|
||||
}
|
||||
};
|
||||
import { getStatusColor } from "../TreeChart/dataUtils"; // Импортируем только нужную функцию
|
||||
|
||||
const MenuItem = ({ item, onSelectItem }) => {
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
|
|
@ -45,15 +32,15 @@ const MenuItem = ({ item, onSelectItem }) => {
|
|||
);
|
||||
};
|
||||
|
||||
function SidebarMenu({ onOpenTab }) {
|
||||
function SidebarMenu({ data, onOpenTab }) { // Теперь получаем `data` из пропсов
|
||||
const handleSelectItem = (item) => {
|
||||
onOpenTab(item.id, item.title); // Передаем id и title
|
||||
onOpenTab(item.id, item.title);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="sidebar">
|
||||
<h2 className="sidebar-title">Меню</h2>
|
||||
<MenuItem item={menuData} onSelectItem={handleSelectItem} />
|
||||
<MenuItem item={data} onSelectItem={handleSelectItem} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,71 +1,75 @@
|
|||
import React, { useRef, useEffect } from "react";
|
||||
import * as d3 from "d3";
|
||||
import { getStatusColor } from "./dataUtils";
|
||||
|
||||
const TreeChart = ({ data, onNodeClick }) => {
|
||||
const chartRef = useRef();
|
||||
|
||||
useEffect(() => {
|
||||
if (!data) return;
|
||||
if (!data || !data.items) return;
|
||||
|
||||
// Очищаем старый граф перед отрисовкой
|
||||
d3.select(chartRef.current).selectAll("*").remove();
|
||||
|
||||
const width = 928;
|
||||
const width = 1000;
|
||||
const height = 1000;
|
||||
|
||||
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);
|
||||
svg.selectAll("*").remove();
|
||||
|
||||
const svg = d3
|
||||
.select(chartRef.current)
|
||||
svg
|
||||
.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")
|
||||
const link = svg.append("g")
|
||||
.attr("stroke", "#999")
|
||||
.attr("stroke-opacity", 0.6)
|
||||
.selectAll("line")
|
||||
.data(links)
|
||||
.join("line");
|
||||
.join("line"); // Используем join для обновления связей
|
||||
|
||||
const node = svg
|
||||
.append("g")
|
||||
const node = svg.append("g")
|
||||
.attr("stroke", "#000")
|
||||
.attr("stroke-width", 1.5)
|
||||
.selectAll("circle")
|
||||
.data(nodes)
|
||||
.join("circle")
|
||||
.attr("fill", (d) => {
|
||||
// Окрашиваем узлы в зависимости от статуса
|
||||
switch (d.data.status) {
|
||||
case "green":
|
||||
return "#4CAF50"; // Зеленый
|
||||
case "yellow":
|
||||
return "#FFEB3B"; // Желтый
|
||||
case "red":
|
||||
return "#F44336"; // Красный
|
||||
default:
|
||||
return "#555"; // Серый по умолчанию
|
||||
}
|
||||
})
|
||||
.join("circle") // Используем join для обновления узлов
|
||||
.attr("fill", (d) => getStatusColor(d.data.status))
|
||||
.attr("stroke", "#fff")
|
||||
.attr("r", 7)
|
||||
.call(drag(simulation));
|
||||
.call(drag());
|
||||
|
||||
// Добавляем текстовые подписи
|
||||
const text = svg
|
||||
.append("g")
|
||||
// Обновляем только те узлы, которые нуждаются в изменении
|
||||
node.each(function (d) {
|
||||
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("font-family", "Arial")
|
||||
.attr("font-size", 12)
|
||||
|
|
@ -81,10 +85,16 @@ const TreeChart = ({ data, onNodeClick }) => {
|
|||
|
||||
node.on("click", (event, d) => {
|
||||
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", () => {
|
||||
link
|
||||
.attr("x1", (d) => d.source.x)
|
||||
|
|
@ -101,14 +111,11 @@ const TreeChart = ({ data, onNodeClick }) => {
|
|||
.attr("y", (d) => d.y + 4);
|
||||
});
|
||||
|
||||
return () => {
|
||||
simulation.stop();
|
||||
};
|
||||
return () => simulation.stop();
|
||||
}, [data, onNodeClick]);
|
||||
|
||||
const drag = (simulation) => {
|
||||
const drag = () => {
|
||||
function dragstarted(event, d) {
|
||||
if (!event.active) simulation.alphaTarget(0.3).restart();
|
||||
d.fx = d.x;
|
||||
d.fy = d.y;
|
||||
}
|
||||
|
|
@ -119,7 +126,6 @@ const TreeChart = ({ data, onNodeClick }) => {
|
|||
}
|
||||
|
||||
function dragended(event, d) {
|
||||
if (!event.active) simulation.alphaTarget(0);
|
||||
d.fx = null;
|
||||
d.fy = null;
|
||||
}
|
||||
|
|
@ -130,4 +136,4 @@ const TreeChart = ({ data, onNodeClick }) => {
|
|||
return <svg ref={chartRef}></svg>;
|
||||
};
|
||||
|
||||
export default TreeChart;
|
||||
export default TreeChart;
|
||||
|
|
|
|||
|
|
@ -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": "Сервис ВКС",
|
||||
"status": "red",
|
||||
"items": [
|
||||
{
|
||||
"title": "Функциональные задачи",
|
||||
"status": "red",
|
||||
"items": [
|
||||
{
|
||||
"id": "system_control",
|
||||
"title": "Контроль системы",
|
||||
"status": "red"
|
||||
"title": "Контроль системы"
|
||||
},
|
||||
{
|
||||
"id": "system_management",
|
||||
"title": "Система управления",
|
||||
"status": "green"
|
||||
"title": "Система управления"
|
||||
},
|
||||
{
|
||||
"id": "conference",
|
||||
"title": "Проведение ВКС",
|
||||
"status": "green"
|
||||
"title": "Проведение ВКС"
|
||||
},
|
||||
{
|
||||
"id": "backup",
|
||||
"title": "Резервное копирование",
|
||||
"status": "green"
|
||||
"title": "Резервное копирование"
|
||||
},
|
||||
{
|
||||
"id": "relay_info",
|
||||
"title": "Ретрансляция информации",
|
||||
"status": "green"
|
||||
"title": "Ретрансляция информации"
|
||||
}
|
||||
]
|
||||
},
|
||||
|
|
@ -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": [
|
||||
{
|
||||
"title": "Аппаратное обеспечение",
|
||||
|
|
@ -128,7 +309,7 @@
|
|||
]
|
||||
},
|
||||
{
|
||||
"title": "Сервер системы управления",
|
||||
"title": "Сервер систем",
|
||||
"items": [
|
||||
{
|
||||
"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> },
|
||||
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_2: { 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_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_2: { title: "Оперативная память", content: <div><h2>Оперативная память</h2><p>Описание оперативной памяти сервера резервного копирования.</p></div> },
|
||||
|
|
|
|||
|
|
@ -1,36 +1,76 @@
|
|||
import React from "react";
|
||||
import "../../Style/TreeTable.css"; // Подключаем стили
|
||||
import "../../Style/TreeTable.css";
|
||||
import { getStatusColor } from "../TreeChart/dataUtils"; // Импортируем функцию
|
||||
|
||||
const TreeTable = ({ data }) => {
|
||||
return (
|
||||
<div className="tree-table">
|
||||
{/* Первый уровень заголовков */}
|
||||
<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>
|
||||
// Фильтруем данные, чтобы убрать "Функциональные задачи"
|
||||
const filteredData = data.filter((item) => item.title !== "Функциональные задачи");
|
||||
|
||||
{/* Вложенные элементы */}
|
||||
<div className="tree-table-body">
|
||||
{data.map((item, index) => (
|
||||
<div key={index} className="tree-table-column">
|
||||
{item.items && (
|
||||
<div className="tree-table-items">
|
||||
{item.items.map((child, childIndex) => (
|
||||
<div key={childIndex} className="tree-table-item">
|
||||
{child.title}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
return (
|
||||
<div className="table-container">
|
||||
<table className="tree-table">
|
||||
<thead>
|
||||
{/* Первый уровень: Заголовки "Медиа сервер" */}
|
||||
<tr>
|
||||
{filteredData.map((item, index) => (
|
||||
<th key={index} colSpan="2" className="tree-table-header" style={{ backgroundColor: getStatusColor(item.status) }}>
|
||||
{item.title}
|
||||
</th>
|
||||
))}
|
||||
</tr>
|
||||
{/* Второй уровень: "АО" и "ПО" */}
|
||||
<tr>
|
||||
{filteredData.map((item, index) => (
|
||||
<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>
|
||||
);
|
||||
};
|
||||
|
||||
export default TreeTable;
|
||||
// Функция для отображения строк с вложенными элементами
|
||||
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;
|
||||
|
|
@ -1,67 +1,58 @@
|
|||
.tree-table {
|
||||
max-width: 90vw; /* Ограничение ширины таблицы, чтобы не растягивалась */
|
||||
min-width: 400px; /* Минимальная ширина для нормального отображения */
|
||||
margin: 0 auto; /* Центрирование */
|
||||
/* Контейнер для таблицы с прокруткой */
|
||||
.table-container {
|
||||
width: 100%;
|
||||
/* Занимает всю доступную ширину */
|
||||
overflow-x: auto;
|
||||
padding: 10px;
|
||||
box-sizing: border-box;
|
||||
/* Горизонтальная прокрутка при необходимости */
|
||||
margin: 0 auto;
|
||||
/* Центрирование контейнера */
|
||||
}
|
||||
|
||||
.tree-table-header {
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
width: 100%;
|
||||
padding-bottom: 10px;
|
||||
border-bottom: 2px solid #ccc;
|
||||
/* Стили для таблицы */
|
||||
.tree-table {
|
||||
width: auto;
|
||||
/* Автоматическая ширина, чтобы таблица могла расширяться */
|
||||
min-width: 95%;
|
||||
/* Минимальная ширина таблицы */
|
||||
border-collapse: collapse;
|
||||
margin: 0 auto;
|
||||
/* Центрирование таблицы */
|
||||
}
|
||||
|
||||
.tree-table-column {
|
||||
flex: 1;
|
||||
text-align: center;
|
||||
min-width: 150px;
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
.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;
|
||||
/* Заголовки таблицы (первый уровень) */
|
||||
.tree-table th {
|
||||
border: 1px solid #ddd;
|
||||
padding: 8px;
|
||||
text-align: left;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
padding: 10px;
|
||||
background-color: white;
|
||||
border-radius: 5px;
|
||||
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
|
||||
/* Запрет на перенос текста */
|
||||
font-weight: bold;
|
||||
/* Жирный шрифт для заголовков */
|
||||
}
|
||||
|
||||
.tree-table-item:hover {
|
||||
transform: scale(1.05);
|
||||
background: #f1f1f1;
|
||||
/* Подзаголовки (второй уровень: "АО" и "ПО") */
|
||||
.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;
|
||||
}
|
||||
|
|
@ -5,6 +5,7 @@ import react from '@vitejs/plugin-react'
|
|||
export default defineConfig({
|
||||
plugins: [react()],
|
||||
server: {
|
||||
host: true
|
||||
host: true,
|
||||
allowedHosts: ['dev.msf.enode']
|
||||
}
|
||||
})
|
||||
|
|
|
|||
Loading…
Reference in New Issue