ForcePilot/backend/server/routers/external_systems/dashboard_router.py
Kris 67ddd748e8 refactor(external_systems_router): 优化多路由代码并新增功能
1. 为告警、删除系统/环境/工具接口添加操作者字段
2. 重构看板路由使用专用服务创建函数
3. 新增工具健康检查接口并完善执行重试注释
2026-07-11 05:40:58 +08:00

149 lines
6.2 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""Dashboard 子域 Router。
外部系统限界上下文的监控仪表板 API覆盖全局总览 / 系统维度 /
执行维度 / 告警维度 / 配额维度 / 健康维度 / 活动维度的跨子域聚合统计。
所有端点通过 ``create_use_cases_from_db`` 装配 use_cases
经 ``dashboard_service`` 端口调用用例。
路径顺序约束:本 router 所有端点均为静态路径(无动态路径参数),无路由匹配歧义。
端点按业务维度组织(总览 → 系统 → 执行 → 告警 → 配额 → 健康 → 活动),
与上文子域覆盖顺序保持一致。
认证策略:
- 所有端点均为只读查询,使用 get_required_user支持 JWT + API Key 双模认证)
"""
from __future__ import annotations
from datetime import datetime
from typing import Any, Literal
from fastapi import APIRouter, Depends, Query
from sqlalchemy.ext.asyncio import AsyncSession
from yuxi.external_systems.infrastructure.container import create_dashboard_service_from_db
from yuxi.external_systems.use_cases.dto.dashboard import (
GetActivitiesStatsInput,
GetAlertsStatsInput,
GetExecutionsStatsInput,
GetHealthStatsInput,
GetOverviewInput,
GetQuotasStatsInput,
GetSystemsStatsInput,
)
from yuxi.storage.postgres.models_business import User
from server.utils.auth_middleware import get_db, get_required_user
dashboard_router = APIRouter(prefix="/dashboard", tags=["external-systems-dashboard"])
# ---------------- Endpoints ----------------
@dashboard_router.get("/overview", response_model=dict)
async def get_overview(
start_time: datetime | None = Query(None, description="执行统计起始时间"),
end_time: datetime | None = Query(None, description="执行统计结束时间"),
db: AsyncSession = Depends(get_db),
current_user: User = Depends(get_required_user),
) -> dict[str, Any]:
"""全局总览。聚合 5 个子域的关键指标。"""
dashboard_service = create_dashboard_service_from_db(db)
input_dto = GetOverviewInput(start=start_time, end=end_time)
output = await dashboard_service.get_overview(input_dto)
return {"success": True, "data": output.model_dump()}
@dashboard_router.get("/systems", response_model=dict)
async def get_systems_stats(
db: AsyncSession = Depends(get_db),
current_user: User = Depends(get_required_user),
) -> dict[str, Any]:
"""系统维度统计。含启用状态/适配器类型/分类分组 + 熔断器状态。"""
dashboard_service = create_dashboard_service_from_db(db)
input_dto = GetSystemsStatsInput()
output = await dashboard_service.get_systems_stats(input_dto)
return {"success": True, "data": output.model_dump()}
@dashboard_router.get("/executions", response_model=dict)
async def get_executions_stats(
start_time: datetime | None = Query(None, description="执行统计起始时间"),
end_time: datetime | None = Query(None, description="执行统计结束时间"),
tool_limit: int = Query(20, ge=1, le=100, description="Top 工具数量"),
db: AsyncSession = Depends(get_db),
current_user: User = Depends(get_required_user),
) -> dict[str, Any]:
"""执行维度统计。含按状态/工具分组。"""
dashboard_service = create_dashboard_service_from_db(db)
input_dto = GetExecutionsStatsInput(
start=start_time,
end=end_time,
tool_limit=tool_limit,
)
output = await dashboard_service.get_executions_stats(input_dto)
return {"success": True, "data": output.model_dump()}
@dashboard_router.get("/alerts", response_model=dict)
async def get_alerts_stats(
severity_status: Literal["firing", "acknowledged", "resolved", "suppressed"] = Query(
"firing",
description="count_by_severity 的状态过滤告警状态firing/acknowledged/resolved/suppressed",
),
top_limit: int = Query(10, ge=1, le=50, description="Top 告警去重键数量"),
db: AsyncSession = Depends(get_db),
current_user: User = Depends(get_required_user),
) -> dict[str, Any]:
"""告警维度统计。含按状态/严重程度分组 + Top 告警去重键。"""
dashboard_service = create_dashboard_service_from_db(db)
input_dto = GetAlertsStatsInput(
severity_status=severity_status,
top_limit=top_limit,
)
output = await dashboard_service.get_alerts_stats(input_dto)
return {"success": True, "data": output.model_dump()}
@dashboard_router.get("/quotas", response_model=dict)
async def get_quotas_stats(
warning_limit: int = Query(20, ge=1, le=100, description="预警配额明细数量"),
critical_limit: int = Query(20, ge=1, le=100, description="临界配额明细数量"),
db: AsyncSession = Depends(get_db),
current_user: User = Depends(get_required_user),
) -> dict[str, Any]:
"""配额维度统计。含按窗口分组 + 预警/临界配额明细。"""
dashboard_service = create_dashboard_service_from_db(db)
input_dto = GetQuotasStatsInput(
warning_limit=warning_limit,
critical_limit=critical_limit,
)
output = await dashboard_service.get_quotas_stats(input_dto)
return {"success": True, "data": output.model_dump()}
@dashboard_router.get("/health", response_model=dict)
async def get_health_stats(
db: AsyncSession = Depends(get_db),
current_user: User = Depends(get_required_user),
) -> dict[str, Any]:
"""健康维度统计。含按健康状态分组。"""
dashboard_service = create_dashboard_service_from_db(db)
input_dto = GetHealthStatsInput()
output = await dashboard_service.get_health_stats(input_dto)
return {"success": True, "data": output.model_dump()}
@dashboard_router.get("/activities", response_model=dict)
async def get_activities_stats(
start_time: datetime | None = Query(None, description="活动统计起始时间"),
end_time: datetime | None = Query(None, description="活动统计结束时间"),
db: AsyncSession = Depends(get_db),
current_user: User = Depends(get_required_user),
) -> dict[str, Any]:
"""活动维度统计。含按操作类型分组。"""
dashboard_service = create_dashboard_service_from_db(db)
input_dto = GetActivitiesStatsInput(start=start_time, end=end_time)
output = await dashboard_service.get_activities_stats(input_dto)
return {"success": True, "data": output.model_dump()}