Initial commit: Базовая структура сайта
This commit is contained in:
123
backend/app/api/v1/summary.py
Executable file
123
backend/app/api/v1/summary.py
Executable file
@@ -0,0 +1,123 @@
|
||||
"""
|
||||
Модуль Сводка - агрегированная гистограмма активности
|
||||
"""
|
||||
from fastapi import APIRouter, Depends, Query, HTTPException
|
||||
from sqlalchemy.orm import Session
|
||||
from sqlalchemy import text
|
||||
from datetime import datetime
|
||||
from typing import List
|
||||
from app.core.database import get_manictime_db, get_service_db
|
||||
from app.core.security import get_current_user
|
||||
from app.models.service_db import AppUser, AppConfiguration
|
||||
from app.schemas.summary import SummaryHistogramResponse, SummaryDataset
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
|
||||
|
||||
|
||||
@router.get("/histogram", response_model=SummaryHistogramResponse)
|
||||
async def get_summary_histogram(
|
||||
start_date: str = Query(..., description="Начальная дата (YYYY-MM-DD)"),
|
||||
end_date: str = Query(..., description="Конечная дата (YYYY-MM-DD)"),
|
||||
current_user: AppUser = Depends(get_current_user),
|
||||
manictime_db: Session = Depends(get_manictime_db)
|
||||
):
|
||||
"""
|
||||
Получение данных для гистограммы активности по дням
|
||||
"""
|
||||
try:
|
||||
# Валидация дат
|
||||
start_dt = datetime.strptime(start_date, "%Y-%m-%d")
|
||||
end_dt = datetime.strptime(end_date, "%Y-%m-%d")
|
||||
|
||||
if start_dt > end_dt:
|
||||
raise HTTPException(status_code=400, detail="Начальная дата должна быть раньше конечной")
|
||||
|
||||
# SQL запрос для агрегации данных
|
||||
query = text("""
|
||||
WITH computer_usage AS (
|
||||
SELECT
|
||||
a."StartLocalTime",
|
||||
a."EndLocalTime",
|
||||
a."Name",
|
||||
t."OwnerId",
|
||||
DATE_TRUNC('day', a."StartLocalTime") AS "day"
|
||||
FROM "Ar_Activity" a
|
||||
JOIN "Ar_Timeline" t ON a."ReportId" = t."ReportId"
|
||||
WHERE t."SchemaName" = 'ManicTime/Computer usage'
|
||||
AND a."StartLocalTime" >= :start_date
|
||||
AND a."EndLocalTime" <= :end_date
|
||||
),
|
||||
productive_time AS (
|
||||
SELECT
|
||||
a."StartLocalTime",
|
||||
a."EndLocalTime",
|
||||
t."OwnerId",
|
||||
DATE_TRUNC('day', a."StartLocalTime") AS "day"
|
||||
FROM "Ar_Activity" a
|
||||
JOIN "Ar_Timeline" t ON a."ReportId" = t."ReportId"
|
||||
JOIN "Ar_CommonGroup" cg ON a."CommonGroupId" = cg."CommonId"
|
||||
JOIN "Ar_CategoryGroup" cag ON cg."CommonId" = cag."CommonGroupId"
|
||||
JOIN "Ar_Category" c ON cag."CategoryId" = c."CategoryId"
|
||||
WHERE c."Name" = 'Productive'
|
||||
AND a."StartLocalTime" >= :start_date
|
||||
AND a."EndLocalTime" <= :end_date
|
||||
)
|
||||
SELECT
|
||||
cu."day",
|
||||
SUM(CASE WHEN cu."Name" = 'Active'
|
||||
THEN EXTRACT(EPOCH FROM (cu."EndLocalTime" - cu."StartLocalTime"))
|
||||
ELSE 0 END) AS active_seconds,
|
||||
SUM(CASE WHEN cu."Name" = 'Away'
|
||||
THEN EXTRACT(EPOCH FROM (cu."EndLocalTime" - cu."StartLocalTime"))
|
||||
ELSE 0 END) AS away_seconds,
|
||||
SUM(CASE WHEN cu."Name" IN ('Session Locked', 'Power Off')
|
||||
THEN EXTRACT(EPOCH FROM (cu."EndLocalTime" - cu."StartLocalTime"))
|
||||
ELSE 0 END) AS afk_seconds,
|
||||
COALESCE(SUM(EXTRACT(EPOCH FROM (pt."EndLocalTime" - pt."StartLocalTime"))), 0) AS productive_seconds
|
||||
FROM computer_usage cu
|
||||
LEFT JOIN productive_time pt ON cu."day" = pt."day"
|
||||
AND cu."OwnerId" = pt."OwnerId"
|
||||
AND pt."StartLocalTime" < cu."EndLocalTime"
|
||||
AND pt."EndLocalTime" > cu."StartLocalTime"
|
||||
GROUP BY cu."day"
|
||||
ORDER BY cu."day"
|
||||
""")
|
||||
|
||||
result = manictime_db.execute(
|
||||
query,
|
||||
{"start_date": start_date, "end_date": end_date}
|
||||
)
|
||||
|
||||
rows = result.fetchall()
|
||||
|
||||
# Формирование ответа
|
||||
labels = []
|
||||
active_data = []
|
||||
away_data = []
|
||||
afk_data = []
|
||||
productive_data = []
|
||||
|
||||
for row in rows:
|
||||
day = row.day.strftime("%Y-%m-%d")
|
||||
labels.append(day)
|
||||
active_data.append(float(row.active_seconds or 0))
|
||||
away_data.append(float(row.away_seconds or 0))
|
||||
afk_data.append(float(row.afk_seconds or 0))
|
||||
productive_data.append(float(row.productive_seconds or 0))
|
||||
|
||||
datasets = [
|
||||
SummaryDataset(label="Активный", color="green", data=active_data),
|
||||
SummaryDataset(label="Неактивный", color="red", data=away_data),
|
||||
SummaryDataset(label="Не у ПК", color="yellow", data=afk_data),
|
||||
SummaryDataset(label="Продуктивность", color="orange", data=productive_data),
|
||||
]
|
||||
|
||||
return SummaryHistogramResponse(labels=labels, datasets=datasets)
|
||||
|
||||
except ValueError as e:
|
||||
raise HTTPException(status_code=400, detail=f"Неверный формат даты: {str(e)}")
|
||||
except Exception as e:
|
||||
raise HTTPException(status_code=500, detail=f"Ошибка при получении данных: {str(e)}")
|
||||
|
||||
Reference in New Issue
Block a user