248 lines
10 KiB
JavaScript
Executable File
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; |