ForcePilot/backend/package/yuxi/channels/contract/dtos/report.py
Kris b88c0ae29e feat(channels): 批量新增多渠道网关限界上下文基础代码与契约
新增完整的 channels 限界上下文模块,包含契约层、领域核心层、应用服务、管道编排、插件体系、基础设施组合根等全层级代码,新增飞书与微信 iLink 渠道插件基础结构,补充各类 DTO、端口协议与领域服务实现。
2026-07-02 03:22:12 +08:00

144 lines
4.7 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.

"""报告 DTO 定义。
包含报告聚合根 DTO、查询条件 DTO 与报告类型/状态枚举常量,以及 Report ↔ dict
互转的工具函数(供应用层响应序列化使用,避免反向依赖 adapters/mappers
对齐《19-聚合视图域-reports-router-设计方案.md》§5.3。
"""
from __future__ import annotations
from dataclasses import dataclass, field
from datetime import datetime
from typing import Any
#: 报告类型枚举
REPORT_TYPES = frozenset(
{
"message_stats",
"session_stats",
"account_stats",
"delivery_stats",
"dashboard_overview",
}
)
#: 报告状态枚举单向流转pending → generating → ready / failed
REPORT_STATUSES = frozenset(
{
"pending",
"generating",
"ready",
"failed",
}
)
@dataclass(frozen=True)
class Report:
"""报告聚合根 DTO。
字段:
report_id: 报告唯一标识UUID``rpt_`` 前缀)。
task_id: 关联的 scheduler 任务 IDUUID
report_type: 报告类型(取值 ``REPORT_TYPES``)。
status: 报告状态(取值 ``REPORT_STATUSES``)。
params: 报告生成参数JSON如时间范围、过滤条件
content: 报告内容JSON仅 status=ready 时非空)。
error_message: 失败原因(仅 status=failed 时非空)。
created_at: 创建时间。
ready_at: 就绪时间status=ready 时非空)。
created_by: 创建人operator.user_id
retried_from: 重试来源报告的 task_id仅重试生成的新报告非空
retried_at: 原报告被重试的时间(原报告标记字段,新报告为 None
"""
report_id: str
task_id: str
report_type: str
status: str
params: dict[str, Any] = field(default_factory=dict)
content: dict[str, Any] | None = None
error_message: str | None = None
created_at: datetime | None = None
ready_at: datetime | None = None
created_by: str = "system"
retried_from: str | None = None
retried_at: datetime | None = None
@dataclass(frozen=True)
class ReportQuery:
"""报告查询条件。
字段:
status: 按状态过滤(可选)。
report_type: 按报告类型过滤(可选)。
start_time: 起始时间(按 created_at 过滤,可选)。
end_time: 截止时间(按 created_at 过滤,可选)。
limit: 分页大小(默认 100上限 200
offset: 分页偏移(默认 0
"""
status: str | None = None
report_type: str | None = None
start_time: datetime | None = None
end_time: datetime | None = None
limit: int = 100
offset: int = 0
def reportToDict(report: Report) -> dict[str, Any]:
"""Report DTO → dictdispatch handler 返回值序列化)。
纯 DTO 序列化函数,不依赖 ORM供应用层控制面分派与 router 响应使用。
包含 error_message失败原因与 retried_at重试时间供前端详情页展示。
"""
return {
"report_id": report.report_id,
"task_id": report.task_id,
"report_type": report.report_type,
"status": report.status,
"params": report.params,
"content": report.content,
"error_message": report.error_message,
"created_at": report.created_at.isoformat() if report.created_at else None,
"ready_at": report.ready_at.isoformat() if report.ready_at else None,
"created_by": report.created_by,
"retried_at": report.retried_at.isoformat() if report.retried_at else None,
"download_url": f"/api/channels/reports/oneoff/{report.task_id}/download",
}
def reportSummaryToDict(report: Report) -> dict[str, Any]:
"""Report DTO → 摘要 dict列表项序列化
纯 DTO 序列化函数,不依赖 ORM供应用层列表响应使用。
"""
return {
"report_id": report.report_id,
"task_id": report.task_id,
"report_type": report.report_type,
"status": report.status,
"created_at": report.created_at.isoformat() if report.created_at else None,
"ready_at": report.ready_at.isoformat() if report.ready_at else None,
"created_by": report.created_by,
}
@dataclass(frozen=True)
class RetryReportResult:
"""重试失败报告结果RPT-ONEOFF-RETRY
描述重试操作的返回结果,包括原任务 ID 与新生成任务 ID
``ReportManagementPort.retryReport`` 引用。
字段:
task_id: 原失败报告任务 ID。
new_task_id: 重试生成的新报告任务 ID。
retried_at: 重试时间戳。
"""
task_id: str
new_task_id: str
retried_at: datetime