diff --git a/redmine_reporter/formatters/factory.py b/redmine_reporter/formatters/factory.py index cf8aaa1..3142502 100644 --- a/redmine_reporter/formatters/factory.py +++ b/redmine_reporter/formatters/factory.py @@ -4,6 +4,7 @@ from .console import TableFormatter, CompactFormatter from .csv import CSVFormatter from .markdown import MarkdownFormatter from .odt import ODTFormatter +from .html import HTMLFormatter # Словарь для сопоставления расширений файлов с классами форматтеров @@ -11,6 +12,7 @@ FORMATTER_MAP: Dict[str, Type[Formatter]] = { ".odt": ODTFormatter, ".csv": CSVFormatter, ".md": MarkdownFormatter, + ".html": HTMLFormatter, } diff --git a/redmine_reporter/formatters/html.py b/redmine_reporter/formatters/html.py new file mode 100644 index 0000000..307c6f8 --- /dev/null +++ b/redmine_reporter/formatters/html.py @@ -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 = [ + '', + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + ] + + 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(" ") + + # Ячейка "Проект" - только в первой строке проекта + if first_version_in_project and first_row_in_version: + lines.append( + f' ' + ) + + # Ячейка "Версия" - только в первой строке версии + if first_row_in_version: + lines.append( + f' ' + ) + first_row_in_version = False + + # Остальные колонки + task_cell = f"{r['issue_id']}. {r['subject']}" + lines.append(f" ") + lines.append(f" ") + lines.append(f" ") + + lines.append(" ") + + first_version_in_project = False + + lines.append(" ") + lines.append("
Наименование ПроектаНомер версии*ЗадачаСтатус Готовность*Затрачено за отчетный период
{project}{version}{task_cell}{r['status_ru']}{r['time_text']}
") + 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)