本次提交包含多类优化:
1. 移除多个路由文件中多余的空导入行,统一代码格式
2. 重构Query参数定义,将长参数拆分为多行提升可读性
3. 新增多个业务端点:
- 渠道能力画像矩阵查询CAP-03
- 配对审批计数接口用于待办角标
- 批量查询对端目录资料接口
- 向导扫码登录相关端点
- 会话实时事件SSE推送端点
- 工作台待办统计接口
4. 完善异常处理逻辑,补充OperationTimeoutError导入并优化NotImplementedError的细节返回
5. 调整路由导入顺序,修复动态路由路径冲突隐患
6. 更新文档注释与接口清单,修正部分接口描述细节
220 lines
9.7 KiB
Python
220 lines
9.7 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,
|
||
channel_type: ChannelType | None = Query(default=None, description="按渠道类型过滤"),
|
||
start_time: str | None = Query(default=None, description="消息统计起始时间(ISO 8601);仅 messages 子域受影响"),
|
||
end_time: str | None = Query(default=None, description="消息统计截止时间(ISO 8601);仅 messages 子域受影响"),
|
||
use_cases=Depends(get_channel_use_cases),
|
||
current_user: User = Depends(get_admin_user),
|
||
) -> dict[str, Any]:
|
||
"""查询全局总览(DSB-01)。对应控制面操作 dashboard/overview。
|
||
|
||
聚合账户 / 消息 / 会话 / 投递四类子域 KPI 计数。
|
||
``start_time`` / ``end_time`` 仅影响消息统计;账户、会话、投递为当前
|
||
快照,不受时间范围影响。
|
||
"""
|
||
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.getDashboardOverview(
|
||
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/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/todos", response_model=dict)
|
||
async def get_dashboard_todos(
|
||
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-TODOS)。对应控制面操作 dashboard/todos。
|
||
|
||
聚合待审批配对数、待复核内容审核数与当前死信积压数,按渠道类型过滤。
|
||
"""
|
||
operator = build_operator(current_user, request)
|
||
result = await use_cases.dashboard_view.getDashboardTodos(
|
||
channel_type=channel_type,
|
||
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)}
|