trust-module-frontend/src/Components/UI/TreeTable.jsx

248 lines
10 KiB
JavaScript
Executable File

import React, { useEffect, useRef, useState } from "react";
import "../../Style/TreeTable.css";
import { statusManager1, statusManager2 } from "../TreeChart/dataUtils";
const TreeTable = ({ data }) => {
const tableRef = useRef(null);
const [fontSize, setFontSize] = useState(16);
const [log, setLog] = useState([]);
const [isLogVisible, setIsLogVisible] = useState(true);
const adjustFontSize = () => {
if (tableRef.current) {
let newSize = 16;
const maxWidth = window.innerWidth;
while (tableRef.current.scrollWidth > maxWidth && newSize > 10) {
newSize -= 1;
tableRef.current.style.fontSize = `${newSize}px`;
}
while (tableRef.current.scrollWidth < maxWidth && newSize < 16) {
newSize += 1;
tableRef.current.style.fontSize = `${newSize}px`;
}
setFontSize(newSize);
}
};
useEffect(() => {
const newLog = [];
const traverse = (items) => {
items.forEach((item) => {
if (["yellow", "orange", "red"].includes(item.status)) {
newLog.push({
title: item.title,
status: item.status,
time: new Date().toLocaleTimeString(), // Добавляем время
});
}
if (item.items) {
traverse(item.items);
}
});
};
traverse(data.items);
// Ограничиваем количество сообщений до 50
setLog((prevLog) => [...newLog, ...prevLog].slice(0, 50));
}, [data]);
const filteredData = data.items.filter((item) => item.title !== "Функциональные задачи");
// Функция для отображения заголовков
const renderHeaders = (items) => {
return items.map((item) => {
const colSpan = item.items ? item.items.length : 1;
return (
<th key={item.id} colSpan={colSpan} className="tree-table-header" title={item.title}>
<div className="header-content">
<div
className="status-indicator-bar"
style={{ backgroundColor: statusManager1.getStatusColor(item.status) }}
/>
<div
className="status-indicator-bar"
style={{
backgroundColor: statusManager2.getStatusColor(item.status),
marginLeft: "5px",
}}
/>
{item.title}
</div>
</th>
);
});
};
// Функция для отображения подзаголовков
const renderSubHeaders = (items) => {
return items.map((item) => {
if (item.items) {
return item.items.map((child) => (
<th key={child.id} className="tree-table-header" title={child.title}>
<div className="header-content">
<div
className="status-indicator-bar"
style={{ backgroundColor: statusManager1.getStatusColor(child.status) }}
/>
<div
className="status-indicator-bar"
style={{
backgroundColor: statusManager2.getStatusColor(child.status),
marginLeft: "5px",
}}
/>
{child.title}
</div>
</th>
));
} else {
return (
<th key={item.id} className="tree-table-header" title={item.title}>
<div className="header-content">
<div
className="status-indicator-bar"
style={{ backgroundColor: statusManager1.getStatusColor(item.status) }}
/>
<div
className="status-indicator-bar"
style={{
backgroundColor: statusManager2.getStatusColor(item.status),
marginLeft: "5px",
}}
/>
{item.title}
</div>
</th>
);
}
});
};
// Функция для отображения данных
const renderData = (items) => {
return items.map((item) => {
if (item.items) {
return item.items.map((child) => {
if (child.items) {
return child.items.map((subChild) => (
<td key={subChild.id} className="tree-table-cell" title={subChild.title}>
<div className="cell-content">
<div
className="status-indicator-bar"
style={{ backgroundColor: statusManager1.getStatusColor(subChild.status) }}
/>
<div
className="status-indicator-bar"
style={{
backgroundColor: statusManager2.getStatusColor(subChild.status),
marginLeft: "5px",
}}
/>
<span className="cell-text">{subChild.title}</span>
</div>
</td>
));
} else {
return (
<td key={child.id} className="tree-table-cell" title={child.title}>
<div className="cell-content">
<div
className="status-indicator-bar"
style={{ backgroundColor: statusManager1.getStatusColor(child.status) }}
/>
<div
className="status-indicator-bar"
style={{
backgroundColor: statusManager2.getStatusColor(child.status),
marginLeft: "5px",
}}
/>
<span className="cell-text">{child.title}</span>
</div>
</td>
);
}
});
} else {
return (
<td key={item.id} className="tree-table-cell" title={item.title}>
<div className="cell-content">
<div
className="status-indicator-bar"
style={{ backgroundColor: statusManager1.getStatusColor(item.status) }}
/>
<div
className="status-indicator-bar"
style={{
backgroundColor: statusManager2.getStatusColor(item.status),
marginLeft: "5px",
}}
/>
<span className="cell-text">{item.title}</span>
</div>
</td>
);
}
});
};
return (
<div className="tree-table-container">
<table ref={tableRef} className="tree-table" style={{ fontSize: `${fontSize}px` }}>
<thead>
<tr>
<th
colSpan={filteredData.reduce((acc, item) => acc + (item.items ? item.items.length : 1), 0)}
className="tree-table-header"
title={data.title}
>
<div className="header-content">
<div
className="status-indicator-bar"
style={{ backgroundColor: statusManager1.getStatusColor(data.status) }}
/>
<div
className="status-indicator-bar"
style={{
backgroundColor: statusManager2.getStatusColor(data.status),
marginLeft: "5px",
}}
/>
{data.title}
</div>
</th>
</tr>
<tr>{renderHeaders(filteredData)}</tr>
<tr>{renderSubHeaders(filteredData)}</tr>
</thead>
<tbody>
<tr className="tree-table-row">{renderData(filteredData)}</tr>
</tbody>
</table>
<button
onClick={() => setIsLogVisible(!isLogVisible)}
className="toggle-log-button"
style={{ marginTop: "10px" }}
>
{isLogVisible ? "Скрыть лог" : "Показать лог"}
</button>
{isLogVisible && (
<div className="status-log">
<h3>Лог статусов</h3>
<ul>
{log.map((entry, index) => (
<li key={index} style={{ color: statusManager1.getStatusColor(entry.status) }}>
[{entry.time}] {entry.status}: {entry.title}
</li>
))}
</ul>
</div>
)}
</div>
);
};
export default TreeTable;