Add HTML formatter

Closes #7
This commit is contained in:
Кокос Артем Николаевич
2026-01-26 12:57:33 +07:00
parent ad62ef4f6c
commit 30310d614d
2 changed files with 81 additions and 0 deletions

View File

@@ -4,6 +4,7 @@ from .console import TableFormatter, CompactFormatter
from .csv import CSVFormatter from .csv import CSVFormatter
from .markdown import MarkdownFormatter from .markdown import MarkdownFormatter
from .odt import ODTFormatter from .odt import ODTFormatter
from .html import HTMLFormatter
# Словарь для сопоставления расширений файлов с классами форматтеров # Словарь для сопоставления расширений файлов с классами форматтеров
@@ -11,6 +12,7 @@ FORMATTER_MAP: Dict[str, Type[Formatter]] = {
".odt": ODTFormatter, ".odt": ODTFormatter,
".csv": CSVFormatter, ".csv": CSVFormatter,
".md": MarkdownFormatter, ".md": MarkdownFormatter,
".html": HTMLFormatter,
} }

View File

@@ -0,0 +1,79 @@
from typing import List, Dict, Any
from .base import Formatter
from ..types import ReportRow
class HTMLFormatter(Formatter):
"""Форматтер для экспорта отчёта в HTML."""
def __init__(self, **kwargs):
super().__init__()
def format(self, rows: List[ReportRow]) -> str:
# Сгруппируем данные
projects: Dict[str, Dict[str, List[ReportRow]]] = {}
for r in rows:
proj = r["project"]
ver = r["version"]
if proj not in projects:
projects[proj] = {}
if ver not in projects[proj]:
projects[proj][ver] = []
projects[proj][ver].append(r)
lines = [
'<table border="1" cellpadding="6" cellspacing="0" style="border-collapse: collapse; font-family: Arial, sans-serif;">',
" <thead>",
" <tr>",
" <th>Наименование Проекта</th>",
" <th>Номер версии*</th>",
" <th>Задача</th>",
" <th>Статус Готовность*</th>",
" <th>Затрачено за отчетный период</th>",
" </tr>",
" </thead>",
" <tbody>",
]
for project, versions in projects.items():
total_project_rows = sum(len(tasks) for tasks in versions.values())
first_version_in_project = True
for version, task_rows in versions.items():
row_span_version = len(task_rows)
first_row_in_version = True
for r in task_rows:
lines.append(" <tr>")
# Ячейка "Проект" - только в первой строке проекта
if first_version_in_project and first_row_in_version:
lines.append(
f' <td rowspan="{total_project_rows}" style="vertical-align: top;">{project}</td>'
)
# Ячейка "Версия" - только в первой строке версии
if first_row_in_version:
lines.append(
f' <td rowspan="{row_span_version}" style="vertical-align: top;">{version}</td>'
)
first_row_in_version = False
# Остальные колонки
task_cell = f"{r['issue_id']}. {r['subject']}"
lines.append(f" <td>{task_cell}</td>")
lines.append(f" <td>{r['status_ru']}</td>")
lines.append(f" <td>{r['time_text']}</td>")
lines.append(" </tr>")
first_version_in_project = False
lines.append(" </tbody>")
lines.append("</table>")
return "\n".join(lines)
def save(self, rows: List[ReportRow], output_path: str) -> None:
content = self.format(rows)
with open(output_path, "w", encoding="utf-8") as f:
f.write(content)