Добавлена минификация html

This commit is contained in:
FrigaT
2025-12-26 21:11:29 +03:00
parent c71e15c37f
commit 3c2ee7f9a7
10 changed files with 702 additions and 183 deletions

View File

@@ -1,6 +1,267 @@
import mermaid from "https://cdn.jsdelivr.net/npm/mermaid@10/dist/mermaid.esm.min.mjs";
/* ---------------------------------------------------------
REPORT RENDERER - динамическое создание таблиц и табов
--------------------------------------------------------- */
class ReportRenderer {
constructor(data) {
this.data = data;
this.files = data.files || [];
this.diagram = data.diagram;
this.currentFileIndex = 0;
this.reportsContainer = document.getElementById('reports-container');
this.tabsList = document.getElementById('tabs-list');
if (!this.reportsContainer || !this.tabsList) {
console.error('Не найдены контейнеры для отчета');
return;
}
}
init() {
this.renderTabs();
this.renderFileReports();
this.setupTabNavigation();
// Активируем первый таб
this.activateTab(0);
}
renderTabs() {
this.tabsList.innerHTML = '';
// Табы для файлов
this.files.forEach((file, index) => {
const tab = document.createElement('button');
tab.className = `tab ${index === 0 ? 'active' : ''}`;
tab.dataset.target = `file_${index}`;
tab.dataset.index = index;
tab.innerHTML = `
${this.escapeHtml(file.fileName)}
<span class="tab-badge">${file.totalViolations || this.calculateTotalViolations(file)}</span>
`;
this.tabsList.appendChild(tab);
});
// Таб для диаграммы (если есть)
if (this.diagram?.hasDiagram) {
const diagramTab = document.createElement('button');
diagramTab.className = 'tab';
diagramTab.dataset.target = 'mermaid';
diagramTab.textContent = 'Диаграмма';
this.tabsList.appendChild(diagramTab);
}
}
renderFileReports() {
this.reportsContainer.innerHTML = '';
// Рендеринг отчетов по файлам
this.files.forEach((file, index) => {
const reportDiv = document.createElement('div');
reportDiv.id = `file_${index}`;
reportDiv.className = 'file-report';
reportDiv.style.display = 'none';
// Заголовок файла
reportDiv.innerHTML = `
<div class="file-title-container">
<div class="file-title">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M14 2H6C4.9 2 4 2.9 4 4V20C4 21.1 4.9 22 6 22H18C19.1 22 20 21.1 20 20V8L14 2Z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M14 2V8H20" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>
<span class="file-name">${this.escapeHtml(file.fileName)}</span>
</div>
</div>
`;
// Секции по severity
if (file.criticalViolations?.length > 0) {
reportDiv.appendChild(this.createSeveritySection('critical', file.criticalViolations));
}
if (file.warningViolations?.length > 0) {
reportDiv.appendChild(this.createSeveritySection('warning', file.warningViolations));
}
if (file.infoViolations?.length > 0) {
reportDiv.appendChild(this.createSeveritySection('info', file.infoViolations));
}
this.reportsContainer.appendChild(reportDiv);
});
// Контейнер для диаграммы (если есть)
if (this.diagram?.hasDiagram) {
const diagramDiv = document.createElement('div');
diagramDiv.id = 'mermaid';
diagramDiv.className = 'file-report';
diagramDiv.style.display = 'none';
diagramDiv.innerHTML = `
<div class="diagram-toolbar">
<div class="toolbar-search">
<input type="text" id="diagramSearch" placeholder="Поиск по узлам (нажмите Enter)" />
<button class="search-clear" type="button">✕</button>
</div>
<div class="toolbar-actions">
<button class="toolbar-button" type="button" onclick="exportPng()">
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" style="margin-right: 4px;">
<path d="M21 15V19C21 19.5304 20.7893 20.0391 20.4142 20.4142C20.0391 20.7893 19.5304 21 19 21H5C4.46957 21 3.96086 20.7893 3.58579 20.4142C3.21071 20.0391 3 19.5304 3 19V15" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M7 10L12 15L17 10" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M12 15V3" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>
Экспорт PNG
</button>
<button class="toolbar-button secondary" id="resetViewBtn">
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" style="margin-right: 4px;">
<path d="M3 12C3 7.02944 7.02944 3 12 3C16.9706 3 21 7.02944 21 12C21 16.9706 16.9706 21 12 21C7.02944 21 3 16.9706 3 12Z" stroke="currentColor" stroke-width="2"/>
<path d="M9 12L12 9L15 12" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M12 15V9" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>
Сбросить вид
</button>
</div>
</div>
<div id="diagramContainer">
<div id="diagramSvgContainer"></div>
<div id="minimap"></div>
</div>
<div id="mermaidSource" style="display:none">
${this.escapeHtml(this.diagram.mermaidContent)}
</div>
`;
this.reportsContainer.appendChild(diagramDiv);
}
}
createSeveritySection(severity, violations) {
const severityTitle = {
critical: 'Critical',
warning: 'Warning',
info: 'Info'
}[severity] || 'Unknown';
const section = document.createElement('div');
section.className = `severity-section ${severity}`;
const tableRows = violations.map(v => `
<tr>
<td class="index">${v.index}</td>
<td class="line">${v.line}</td>
<td class="column">${v.column}</td>
<td class="rule">${this.escapeHtml(v.ruleName)}</td>
<td class="description">${this.escapeHtml(v.text)}</td>
</tr>
`).join('');
section.innerHTML = `
<div class="severity-header">
<div class="severity-title">
<h3>${severityTitle}</h3>
<span class="severity-count">${violations.length}</span>
</div>
</div>
<div class="table-container">
<table>
<thead>
<tr>
<th class="index">#</th>
<th class="line">Строка</th>
<th class="column">Колонка</th>
<th class="rule">Правило</th>
<th class="description">Описание</th>
</tr>
</thead>
<tbody>
${tableRows}
</tbody>
</table>
</div>
`;
return section;
}
setupTabNavigation() {
const tabs = this.tabsList.querySelectorAll('.tab');
tabs.forEach(tab => {
tab.addEventListener('click', (e) => {
e.preventDefault();
const targetId = tab.dataset.target;
const index = tab.dataset.index;
// Обновляем активный таб
tabs.forEach(t => t.classList.remove('active'));
tab.classList.add('active');
// Скрываем все отчеты
document.querySelectorAll('.file-report').forEach(report => {
report.style.display = 'none';
});
// Показываем выбранный отчет
const targetReport = document.getElementById(targetId);
if (targetReport) {
targetReport.style.display = 'block';
// Если это диаграмма, инициализируем ее
if (targetId === 'mermaid' && window.viewer) {
window.viewer.render().catch(console.error);
}
// Прокрутка к верху
window.scrollTo({ top: 0, behavior: 'smooth' });
}
});
});
}
activateTab(index) {
const tab = this.tabsList.querySelector(`.tab[data-index="${index}"]`);
if (tab) {
tab.click();
}
}
calculateTotalViolations(file) {
return (file.criticalViolations?.length || 0) +
(file.warningViolations?.length || 0) +
(file.infoViolations?.length || 0);
}
escapeHtml(text) {
const div = document.createElement('div');
div.textContent = text;
return div.innerHTML;
}
}
/* ---------------------------------------------------------
ГЛОБАЛЬНАЯ ИНИЦИАЛИЗАЦИЯ
--------------------------------------------------------- */
function initReport() {
if (!window.reportData) {
console.error('Данные отчета не найдены');
return;
}
const renderer = new ReportRenderer(window.reportData);
renderer.init();
// Сохраняем рендерер в глобальной области видимости
window.reportRenderer = renderer;
}
// Экспортируем функции для глобального использования
window.initReport = initReport;
/* ---------------------------------------------------------
TABS MANAGEMENT
--------------------------------------------------------- */
@@ -1293,6 +1554,15 @@ function setupThemeChangeHandler() {
let viewer = null;
document.addEventListener("DOMContentLoaded", () => {
window.reportData = JSON.parse(document.getElementById('report-data').textContent);
window.hasDiagram = true;
// Инициализация отчета
if (window.initReport) {
window.initReport();
}
initTabs((id) => {
if (id === "mermaid") {
if (!viewer) {