""" HTML Reporter — человекочитаемый отчёт для архитекторов и менеджеров. Формирует самодостаточный HTML-файл (без внешних зависимостей): - Сводная таблица по системе - Таблица модулей с цветовой индикацией риска - Детальные карточки по каждому модулю - Граф зависимостей в SVG (через библиотеку Mermaid.js из CDN) - Список циклических зависимостей """ import html import logging from datetime import datetime from pathlib import Path from typing import List from models import AnalysisReport, ModuleDecision, ModernizationStrategy, RiskLevel logger = logging.getLogger(__name__) # Цвета по уровням риска _RISK_COLORS = { RiskLevel.LOW: ("#22c55e", "#dcfce7"), # зелёный RiskLevel.MEDIUM: ("#f59e0b", "#fef3c7"), # жёлтый RiskLevel.HIGH: ("#ef4444", "#fee2e2"), # красный RiskLevel.CRITICAL: ("#7f1d1d", "#fca5a5"), # тёмно-красный } _STRATEGY_LABELS = { ModernizationStrategy.KEEP: "Оставить", ModernizationStrategy.REFACTOR: "Рефакторинг", ModernizationStrategy.REENGINEER: "Реинжиниринг", ModernizationStrategy.REPLACE: "Замена", } _RISK_LABELS = { RiskLevel.LOW: "Низкий", RiskLevel.MEDIUM: "Средний", RiskLevel.HIGH: "Высокий", RiskLevel.CRITICAL: "Критический", } class HtmlReporter: """Формирует HTML-отчёт по результатам анализа.""" def write(self, report: AnalysisReport, output_dir: str) -> str: """ Записывает отчёт в файл report.html внутри output_dir. :returns: путь к созданному файлу """ out = Path(output_dir) out.mkdir(parents=True, exist_ok=True) file_path = out / "report.html" content = self._build_html(report) with open(file_path, "w", encoding="utf-8") as fh: fh.write(content) logger.info("HTML отчёт записан: %s", file_path) return str(file_path) # ------------------------------------------------------------------ # Сборка HTML # ------------------------------------------------------------------ def _build_html(self, report: AnalysisReport) -> str: sections = [ self._head(), "
", self._header(report), self._summary_section(report), self._decisions_table(report), self._cycles_section(report), self._modules_detail(report), self._footer(), "