1. config_router: 为expected_version添加ge=1校验 2. directory_router: 补充scope校验逻辑与注释 3. login_router: 拆分强制下线权限,添加参数校验与注释更新 4. reports_router: 统一时间参数处理,修复分页限制使用契约常量 5. dashboard_router: 更新文档与响应格式,修正参数传递逻辑 6. health_router: 缩减健康检查响应字段,修复响应结构与参数校验 7. plugin_router: 新增插件目录端点,补充枚举校验与注释 8. pairing_router: 新增时间过滤参数,补充参数校验 9. __init__.py: 修复异常映射,更新trace_id获取逻辑与工具类 10. doctor_router: 重构单项检查端点,修正注释与校验逻辑 11. account_router: 新增恢复降级账户端点,补充批量操作校验 12. webhook_router: 优化webhook处理逻辑,修复流式读取与响应逻辑 13. content_review_router: 补充批量审核端点,完善参数校验与注释 14. analytics_router: 修正管道阶段描述,统一参数传递 15. wizard_router: 新增OAuth相关端点,重构路由路径与校验逻辑
186 lines
8.1 KiB
Python
186 lines
8.1 KiB
Python
"""Dashboard 聚合视图域 Router(DSB-01~DSB-04 + DSB-DELIVERY + DSB-REALTIME)。
|
||
|
||
统一采用模板 A(控制面端口路由),鉴权依赖 get_admin_user,调用
|
||
use_cases.dashboard_view.<method>,raiseOnControlFailure 转译失败,
|
||
serialize_control_data 序列化响应。
|
||
|
||
路径设计:6 个端点均为静态路径(/dashboard/overview / /dashboard/accounts
|
||
/dashboard/messages / /dashboard/sessions / /dashboard/delivery
|
||
/dashboard/realtime)。子 router 自身不设置 prefix,根前缀 ``/channels``
|
||
由 ``channels_router`` 聚合 router 统一追加。
|
||
|
||
端点清单:
|
||
- GET /dashboard/overview DSB-01 getDashboardOverview
|
||
- GET /dashboard/accounts DSB-02 getAccountStats
|
||
- GET /dashboard/messages DSB-03 getMessageStats
|
||
- GET /dashboard/sessions DSB-04 getDashboardSessionStats
|
||
|
||
DSB-01~04 对应《16-聚合视图域-dashboard-router-设计方案》(仅覆盖 4 个
|
||
KPI 快照端点)。DSB-DELIVERY / DSB-REALTIME 为后续扩展端点,分别提供
|
||
投递 KPI 总览与实时监控指标,不在上述设计方案范围内。
|
||
|
||
- GET /dashboard/delivery DSB-DELIVERY getDashboardDelivery
|
||
- GET /dashboard/realtime DSB-REALTIME getRealtimeMetrics
|
||
"""
|
||
|
||
from __future__ import annotations
|
||
|
||
from typing import Any
|
||
|
||
from fastapi import APIRouter, Depends, Query, Request
|
||
from yuxi.channels.contract.dtos.channel import ChannelType
|
||
from yuxi.channels.contract.dtos.dashboard import RealtimeQuery
|
||
from yuxi.storage.postgres.models_business import User
|
||
|
||
from server.routers.channels import (
|
||
build_operator,
|
||
get_channel_use_cases,
|
||
parse_datetime,
|
||
raiseOnControlFailure,
|
||
serialize_control_data,
|
||
)
|
||
from server.utils.auth_middleware import get_admin_user
|
||
|
||
dashboard_router = APIRouter(tags=["channels-dashboard"])
|
||
|
||
|
||
@dashboard_router.get("/dashboard/overview", response_model=dict)
|
||
async def get_dashboard_overview(
|
||
request: Request,
|
||
use_cases=Depends(get_channel_use_cases),
|
||
current_user: User = Depends(get_admin_user),
|
||
) -> dict[str, Any]:
|
||
"""查询全局总览(DSB-01)。对应控制面操作 dashboard/overview。
|
||
|
||
聚合账户 / 消息 / 会话 / 投递四类子域 KPI 计数。
|
||
"""
|
||
operator = build_operator(current_user, request)
|
||
result = await use_cases.dashboard_view.getDashboardOverview(operator=operator)
|
||
raiseOnControlFailure(result)
|
||
return {"success": True, "data": serialize_control_data(result.data)}
|
||
|
||
|
||
@dashboard_router.get("/dashboard/accounts", response_model=dict)
|
||
async def get_dashboard_accounts(
|
||
request: Request,
|
||
channel_type: ChannelType | None = Query(default=None, description="按渠道类型过滤"),
|
||
use_cases=Depends(get_channel_use_cases),
|
||
current_user: User = Depends(get_admin_user),
|
||
) -> dict[str, Any]:
|
||
"""查询账户总览(DSB-02)。对应控制面操作 dashboard/accounts。
|
||
|
||
返回账户按渠道 / 状态分组的计数快照。
|
||
"""
|
||
operator = build_operator(current_user, request)
|
||
result = await use_cases.dashboard_view.getAccountStats(
|
||
channel_type=channel_type,
|
||
operator=operator,
|
||
)
|
||
raiseOnControlFailure(result)
|
||
return {"success": True, "data": serialize_control_data(result.data)}
|
||
|
||
|
||
@dashboard_router.get("/dashboard/messages", response_model=dict)
|
||
async def get_dashboard_messages(
|
||
request: Request,
|
||
channel_type: ChannelType | None = Query(default=None, description="按渠道类型过滤"),
|
||
start_time: str | None = Query(default=None, description="起始时间(ISO 8601)"),
|
||
end_time: str | None = Query(default=None, description="截止时间(ISO 8601)"),
|
||
use_cases=Depends(get_channel_use_cases),
|
||
current_user: User = Depends(get_admin_user),
|
||
) -> dict[str, Any]:
|
||
"""查询消息总览(DSB-03)。对应控制面操作 dashboard/messages。
|
||
|
||
返回指定时间范围内的消息按渠道 / 角色 / 投递状态分组的计数快照。
|
||
|
||
时间参数由 parse_datetime 在 Router 层翻译为 UTC datetime,再转回 ISO 8601 字符串传给端口(端口签名为 str)。非法格式抛 ValidationError(400)。
|
||
"""
|
||
operator = build_operator(current_user, request)
|
||
start_time_dt = parse_datetime("start_time", start_time)
|
||
end_time_dt = parse_datetime("end_time", end_time)
|
||
result = await use_cases.dashboard_view.getMessageStats(
|
||
channel_type=channel_type,
|
||
start_time=start_time_dt.isoformat() if start_time_dt else None,
|
||
end_time=end_time_dt.isoformat() if end_time_dt else None,
|
||
operator=operator,
|
||
)
|
||
raiseOnControlFailure(result)
|
||
return {"success": True, "data": serialize_control_data(result.data)}
|
||
|
||
|
||
@dashboard_router.get("/dashboard/sessions", response_model=dict)
|
||
async def get_dashboard_sessions(
|
||
request: Request,
|
||
channel_type: ChannelType | None = Query(default=None, description="按渠道类型过滤"),
|
||
use_cases=Depends(get_channel_use_cases),
|
||
current_user: User = Depends(get_admin_user),
|
||
) -> dict[str, Any]:
|
||
"""查询会话总览(DSB-04)。对应控制面操作 dashboard/sessions。
|
||
|
||
返回未软删除会话按渠道 / 是否临时会话分组的计数快照。
|
||
"""
|
||
operator = build_operator(current_user, request)
|
||
result = await use_cases.dashboard_view.getDashboardSessionStats(
|
||
channel_type=channel_type,
|
||
operator=operator,
|
||
)
|
||
raiseOnControlFailure(result)
|
||
return {"success": True, "data": serialize_control_data(result.data)}
|
||
|
||
|
||
@dashboard_router.get("/dashboard/delivery", response_model=dict)
|
||
async def get_dashboard_delivery(
|
||
request: Request,
|
||
channel_type: ChannelType | None = Query(default=None, description="按渠道类型过滤"),
|
||
start_time: str | None = Query(default=None, description="起始时间(ISO 8601)"),
|
||
end_time: str | None = Query(default=None, description="截止时间(ISO 8601)"),
|
||
use_cases=Depends(get_channel_use_cases),
|
||
current_user: User = Depends(get_admin_user),
|
||
) -> dict[str, Any]:
|
||
"""查询投递总览(DSB-DELIVERY)。对应控制面操作 dashboard/delivery。
|
||
|
||
聚合投递 KPI 指标(总数、成功率、延迟分位数、死信数、按渠道切片)。
|
||
|
||
时间参数由 parse_datetime 在 Router 层翻译为 UTC datetime,再转回
|
||
ISO 8601 字符串传给端口(端口签名为 str)。非法格式抛 ValidationError
|
||
(400)。
|
||
"""
|
||
operator = build_operator(current_user, request)
|
||
start_time_dt = parse_datetime("start_time", start_time)
|
||
end_time_dt = parse_datetime("end_time", end_time)
|
||
result = await use_cases.dashboard_view.getDashboardDelivery(
|
||
channel_type=channel_type,
|
||
start_time=start_time_dt.isoformat() if start_time_dt else None,
|
||
end_time=end_time_dt.isoformat() if end_time_dt else None,
|
||
operator=operator,
|
||
)
|
||
raiseOnControlFailure(result)
|
||
return {"success": True, "data": serialize_control_data(result.data)}
|
||
|
||
|
||
@dashboard_router.get("/dashboard/realtime", response_model=dict)
|
||
async def get_dashboard_realtime(
|
||
request: Request,
|
||
channel_type: ChannelType | None = Query(default=None, description="按渠道类型过滤"),
|
||
window_seconds: int = Query(default=60, ge=10, le=300, description="滑动窗口秒数(10-300,默认 60)"),
|
||
use_cases=Depends(get_channel_use_cases),
|
||
current_user: User = Depends(get_admin_user),
|
||
) -> dict[str, Any]:
|
||
"""查询实时监控指标(DSB-REALTIME)。对应控制面操作 dashboard/realtime。
|
||
|
||
纯内存态聚合,业务不开启 DB 事务(``db_tx_required=False``),高频查询
|
||
场景使用。审计走 INDEPENDENT 独立事务 best-effort 写入,每请求一次
|
||
审计记录,不阻断响应。
|
||
|
||
``channel_type`` 为空(全局查询)时,``by_channel`` 返回全部已注册
|
||
渠道的切片;非空时仅返回该渠道一条。
|
||
"""
|
||
operator = build_operator(current_user, request)
|
||
query = RealtimeQuery(
|
||
channel_type=channel_type,
|
||
window_seconds=window_seconds,
|
||
)
|
||
result = await use_cases.dashboard_view.getRealtimeMetrics(query, operator=operator)
|
||
raiseOnControlFailure(result)
|
||
return {"success": True, "data": serialize_control_data(result.data)}
|