Untitled
4ae4d
plain_text
01/27/2026 11:56 AM
5.4 KB
7
Indexable
diff --git a/src/backend/app/api/v1/__init__.py b/src/backend/app/api/v1/__init__.py
index e9975d1..ecc6004 100644
--- a/src/backend/app/api/v1/__init__.py
+++ b/src/backend/app/api/v1/__init__.py
@@ -1,6 +1,13 @@
from .city import api_router as city_router
from .event import api_router as event_router
+from .report import api_router as report_router
from .tag import api_router as tag_router
from .user import api_router as user_router
-__all__ = ["user_router", "event_router", "city_router", "tag_router"]
+__all__ = [
+ "user_router",
+ "event_router",
+ "city_router",
+ "tag_router",
+ "report_router",
+]
diff --git a/src/backend/app/api/v1/report.py b/src/backend/app/api/v1/report.py
new file mode 100644
index 0000000..965747c
--- /dev/null
+++ b/src/backend/app/api/v1/report.py
@@ -0,0 +1,61 @@
+from __future__ import annotations
+
+from datetime import date
+from io import BytesIO
+from typing import Annotated
+
+from fastapi import APIRouter, Query
+from fastapi.responses import StreamingResponse
+from openpyxl import Workbook
+
+api_router = APIRouter(prefix="/reports", tags=["Reports"])
+
+REPORT_COLUMNS: list[tuple[str, str]] = [
+ ("event_name", "Название"),
+ ("city", "Город"),
+ ("location", "Локация"),
+ ("date", "Дата"),
+ ("time", "Время"),
+ ("participants_count", "Кол-во участников"),
+ ("points", "Кол-во баллов"),
+ ("tags", "Теги"),
+ ("organizer_fio", "ФИО организатора"),
+ ("beneficiaries_count", "Кол-во благополучателей"),
+ ("summary", "Описание"),
+]
+
+
+@api_router.get("/export")
+async def export_reports_xlsx(
+ date_from: Annotated[date | None, Query(description="YYYY-MM-DD")] = None,
+ date_to: Annotated[date | None, Query(description="YYYY-MM-DD")] = None,
+):
+ """
+ DEMO: экспорт отчётов в xlsx
+ пока без выборки из БД - возвращаем файл с шапкой
+ """
+ wb = Workbook()
+ ws = wb.active
+ ws.title = "Reports"
+
+ ws.append([title for _, title in REPORT_COLUMNS])
+
+ # пока без данных.
+
+ buf = BytesIO()
+ wb.save(buf)
+ buf.seek(0)
+
+ name_parts = ["reports"]
+ if date_from:
+ name_parts.append(str(date_from))
+ if date_to:
+ name_parts.append(str(date_to))
+ filename = "_".join(name_parts) + ".xlsx"
+
+ headers = {"Content-Disposition": f'attachment; filename="{filename}"'}
+ return StreamingResponse(
+ buf,
+ media_type="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
+ headers=headers,
+ )
diff --git a/src/backend/app/application.py b/src/backend/app/application.py
index cbd248d..3e752ed 100644
--- a/src/backend/app/application.py
+++ b/src/backend/app/application.py
@@ -5,7 +5,7 @@ from fastapi import FastAPI, Request
from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import PlainTextResponse
-from app.api.v1 import city_router, event_router, tag_router, user_router
+from app.api.v1 import city_router, event_router, tag_router, user_router, report_router
from app.cache import redis_client
from app.config.settings import settings
from app.middlewares import LoggerMiddleware
@@ -55,6 +55,7 @@ api.add_middleware(LoggerMiddleware)
api.include_router(city_router)
api.include_router(event_router)
+api.include_router(report_router)
api.include_router(tag_router)
api.include_router(user_router)
diff --git a/src/backend/requirements.txt b/src/backend/requirements.txt
index 1a5d884..23d1b36 100644
--- a/src/backend/requirements.txt
+++ b/src/backend/requirements.txt
@@ -35,6 +35,7 @@ Mako==1.3.6
MarkupSafe==3.0.2
multidict==6.1.0
numpy==2.2.1
+openpyxl==3.1.5
orjson==3.10.13
packaging==24.2
passlib==1.7.4
diff --git a/src/bot/core/handlers/__init__.py b/src/bot/core/handlers/__init__.py
index 2dec733..02e2438 100644
--- a/src/bot/core/handlers/__init__.py
+++ b/src/bot/core/handlers/__init__.py
@@ -89,3 +89,4 @@ __all__ = [
"events_rt",
"view_by_uuid_rt",
]
+
Editor is loading...
Leave a Comment