# 报告导出接口

<cite>
**本文档引用的文件**
- [backend/app/api/reports.py](file://backend/app/api/reports.py)
- [backend/app/services/citation.py](file://backend/app/services/citation.py)
- [backend/app/models/citation_record.py](file://backend/app/models/citation_record.py)
- [backend/app/models/query.py](file://backend/app/models/query.py)
- [backend/app/models/query_task.py](file://backend/app/models/query_task.py)
- [backend/app/workers/citation_engine.py](file://backend/app/workers/citation_engine.py)
- [backend/app/workers/scheduler.py](file://backend/app/workers/scheduler.py)
- [backend/app/workers/platforms/base.py](file://backend/app/workers/platforms/base.py)
- [backend/app/main.py](file://backend/app/main.py)
- [frontend/lib/api.ts](file://frontend/lib/api.ts)
- [frontend/app/(dashboard)/dashboard/reports/page.tsx](file://frontend/app/(dashboard)/dashboard/reports/page.tsx)
</cite>

## 目录
1. [简介](#简介)
2. [项目结构](#项目结构)
3. [核心组件](#核心组件)
4. [架构总览](#架构总览)
5. [详细组件分析](#详细组件分析)
6. [依赖关系分析](#依赖关系分析)
7. [性能考虑](#性能考虑)
8. [故障排查指南](#故障排查指南)
9. [结论](#结论)
10. [附录](#附录)

## 简介
本文件面向“报告导出系统”的使用者与维护者，提供完整的CSV格式数据导出API文档。内容涵盖：
- 导出流程与参数配置
- 报告生成触发机制（手动触发、定时触发）
- 数据筛选条件与输出格式选项
- 导出进度监控、错误处理与文件下载
- 报告模板定制、数据格式转换与性能优化建议

## 项目结构
后端采用FastAPI + SQLAlchemy异步ORM，前端基于Next.js。导出能力通过独立的报告路由暴露，并由服务层负责数据聚合与CSV生成。

```mermaid
graph TB
subgraph "前端"
FE_API["前端API封装<br/>frontend/lib/api.ts"]
FE_PAGE["报告页面<br/>frontend/app/(dashboard)/dashboard/reports/page.tsx"]
end
subgraph "后端"
MAIN["应用入口<br/>backend/app/main.py"]
ROUTER["报告路由<br/>backend/app/api/reports.py"]
SERVICE["导出服务<br/>backend/app/services/citation.py"]
MODELS["模型定义<br/>models/*.py"]
WORKERS["工作流与调度<br/>workers/*.py"]
end
FE_PAGE --> FE_API
FE_API --> ROUTER
ROUTER --> SERVICE
SERVICE --> MODELS
WORKERS --> MODELS
MAIN --> ROUTER
MAIN --> WORKERS
```

图表来源
- [backend/app/main.py:13-48](file://backend/app/main.py#L13-L48)
- [backend/app/api/reports.py:1-47](file://backend/app/api/reports.py#L1-L47)
- [backend/app/services/citation.py:237-269](file://backend/app/services/citation.py#L237-L269)
- [backend/app/models/citation_record.py:11-42](file://backend/app/models/citation_record.py#L11-L42)
- [backend/app/models/query.py:11-55](file://backend/app/models/query.py#L11-L55)
- [backend/app/models/query_task.py:11-39](file://backend/app/models/query_task.py#L11-L39)
- [backend/app/workers/citation_engine.py:148-309](file://backend/app/workers/citation_engine.py#L148-L309)
- [backend/app/workers/scheduler.py:25-95](file://backend/app/workers/scheduler.py#L25-L95)
- [frontend/lib/api.ts:51-57](file://frontend/lib/api.ts#L51-L57)
- [frontend/app/(dashboard)/dashboard/reports/page.tsx:49-93](file://frontend/app/(dashboard)/dashboard/reports/page.tsx#L49-L93)

章节来源
- [backend/app/main.py:13-48](file://backend/app/main.py#L13-L48)
- [frontend/lib/api.ts:1-58](file://frontend/lib/api.ts#L1-L58)
- [frontend/app/(dashboard)/dashboard/reports/page.tsx:1-198](file://frontend/app/(dashboard)/dashboard/reports/page.tsx#L1-L198)

## 核心组件
- 报告导出路由：提供CSV导出接口，接收查询词ID并返回流式CSV响应。
- 导出服务：验证用户与查询所有权，查询引用记录并生成CSV字符串。
- 数据模型：查询、引用记录、查询任务等，支撑筛选与统计。
- 引擎与调度：定时检查到期查询并执行，支持手动触发。
- 前端集成：提供查询词选择、导出按钮与下载逻辑。

章节来源
- [backend/app/api/reports.py:16-47](file://backend/app/api/reports.py#L16-L47)
- [backend/app/services/citation.py:237-269](file://backend/app/services/citation.py#L237-L269)
- [backend/app/models/query.py:11-55](file://backend/app/models/query.py#L11-L55)
- [backend/app/models/citation_record.py:11-42](file://backend/app/models/citation_record.py#L11-L42)
- [backend/app/models/query_task.py:11-39](file://backend/app/models/query_task.py#L11-L39)
- [backend/app/workers/citation_engine.py:148-309](file://backend/app/workers/citation_engine.py#L148-L309)
- [backend/app/workers/scheduler.py:25-95](file://backend/app/workers/scheduler.py#L25-L95)
- [frontend/lib/api.ts:51-57](file://frontend/lib/api.ts#L51-L57)
- [frontend/app/(dashboard)/dashboard/reports/page.tsx:49-93](file://frontend/app/(dashboard)/dashboard/reports/page.tsx#L49-L93)

## 架构总览
下图展示从前端发起导出请求到后端生成CSV并返回下载的完整链路。

```mermaid
sequenceDiagram
participant FE as "前端页面<br/>page.tsx"
participant API as "前端API封装<br/>lib/api.ts"
participant FAST as "报告路由<br/>reports.py"
participant SVC as "导出服务<br/>services/citation.py"
participant DB as "数据库<br/>SQLAlchemy"
FE->>API : "调用导出接口"
API->>FAST : "GET /api/v1/reports/export/csv?query_id=..."
FAST->>SVC : "export_citations_csv(db, user_id, query_id)"
SVC->>DB : "查询引用记录"
DB-->>SVC : "返回记录集合"
SVC-->>FAST : "返回CSV字符串"
FAST-->>API : "StreamingResponse(csv)"
API-->>FE : "下载CSV文件"
```

图表来源
- [frontend/app/(dashboard)/dashboard/reports/page.tsx:49-93](file://frontend/app/(dashboard)/dashboard/reports/page.tsx#L49-L93)
- [frontend/lib/api.ts:51-57](file://frontend/lib/api.ts#L51-L57)
- [backend/app/api/reports.py:16-47](file://backend/app/api/reports.py#L16-L47)
- [backend/app/services/citation.py:237-269](file://backend/app/services/citation.py#L237-L269)

## 详细组件分析

### 报告导出接口（CSV）
- 接口路径：/api/v1/reports/export/csv
- 方法：GET
- 认证：需要Bearer Token
- 参数
  - query_id: UUID，必填，指定导出的查询词
  - format: 字符串，默认csv，当前版本仅支持csv
- 成功响应
  - Content-Type: text/csv
  - Content-Disposition: attachment; filename="geo-report-YYYYMMDD.csv"
  - 响应体：CSV字符串（流式传输）
- 错误处理
  - format非csv：400 Bad Request
  - 查询不存在或无权限：404 Not Found
  - 其他异常：500 Internal Server Error

章节来源
- [backend/app/api/reports.py:16-47](file://backend/app/api/reports.py#L16-L47)

### 导出服务与数据筛选
- 权限校验：仅允许导出当前用户拥有的查询词下的数据
- 数据筛选
  - query_id：限定到具体查询词
  - 时间范围：通过引用记录的查询时间字段进行过滤（服务层支持start_date/end_date参数）
- 输出字段（CSV列头）
  - 日期、平台、是否引用、引用位置、引用文本、竞争品牌
- 性能特性
  - 使用StringIO构建CSV，避免中间文件
  - 支持流式返回，降低内存峰值

章节来源
- [backend/app/services/citation.py:237-269](file://backend/app/services/citation.py#L237-L269)
- [backend/app/models/citation_record.py:11-42](file://backend/app/models/citation_record.py#L11-L42)

### 报告生成触发机制
- 手动导出
  - 前端选择查询词后点击导出，直接调用导出接口
  - 后端即时查询数据库并返回CSV
- 定时导出
  - 调度器每小时扫描到期查询（status=active且next_query_at<=now）
  - 对每个到期查询执行引擎，生成引用记录
  - 导出接口可读取这些最新记录
- 手动触发查询
  - 服务层提供立即触发方法，创建查询任务并返回首个任务信息

```mermaid
flowchart TD
Start(["定时检查"]) --> Scan["扫描到期查询"]
Scan --> HasDue{"存在到期查询？"}
HasDue -- 否 --> Wait["等待下一小时"] --> Scan
HasDue -- 是 --> Exec["执行查询引擎"]
Exec --> Save["保存引用记录"]
Save --> Update["更新查询时间字段"]
Update --> Export["导出接口可读取最新数据"]
```

图表来源
- [backend/app/workers/scheduler.py:51-84](file://backend/app/workers/scheduler.py#L51-L84)
- [backend/app/workers/citation_engine.py:159-234](file://backend/app/workers/citation_engine.py#L159-L234)
- [backend/app/models/query.py:11-55](file://backend/app/models/query.py#L11-L55)

章节来源
- [backend/app/workers/scheduler.py:25-95](file://backend/app/workers/scheduler.py#L25-L95)
- [backend/app/workers/citation_engine.py:148-309](file://backend/app/workers/citation_engine.py#L148-L309)
- [backend/app/services/citation.py:204-234](file://backend/app/services/citation.py#L204-L234)

### 数据模型与关系
```mermaid
erDiagram
QUERIES {
uuid id PK
uuid user_id FK
string keyword
string target_brand
jsonb brand_aliases
jsonb platforms
string frequency
string status
datetime last_queried_at
datetime next_query_at
}
CITATION_RECORDS {
uuid id PK
uuid query_id FK
string platform
boolean cited
integer citation_position
text citation_text
jsonb competitor_brands
text raw_response
datetime queried_at
}
QUERY_TASKS {
uuid id PK
uuid query_id FK
string platform
string status
text error_message
datetime scheduled_at
datetime started_at
datetime completed_at
}
QUERIES ||--o{ CITATION_RECORDS : "拥有"
QUERIES ||--o{ QUERY_TASKS : "拥有"
```

图表来源
- [backend/app/models/query.py:11-55](file://backend/app/models/query.py#L11-L55)
- [backend/app/models/citation_record.py:11-42](file://backend/app/models/citation_record.py#L11-L42)
- [backend/app/models/query_task.py:11-39](file://backend/app/models/query_task.py#L11-L39)

章节来源
- [backend/app/models/query.py:11-55](file://backend/app/models/query.py#L11-L55)
- [backend/app/models/citation_record.py:11-42](file://backend/app/models/citation_record.py#L11-L42)
- [backend/app/models/query_task.py:11-39](file://backend/app/models/query_task.py#L11-L39)

### 前端集成与下载
- 前端页面提供查询词下拉选择与导出按钮
- 导出时通过原生fetch请求后端接口，接收blob并触发浏览器下载
- 成功/失败状态提示与加载态管理

章节来源
- [frontend/app/(dashboard)/dashboard/reports/page.tsx:49-93](file://frontend/app/(dashboard)/dashboard/reports/page.tsx#L49-L93)
- [frontend/lib/api.ts:51-57](file://frontend/lib/api.ts#L51-L57)

## 依赖关系分析
- 报告路由依赖导出服务
- 导出服务依赖查询与引用记录模型
- 引擎与调度器依赖平台适配器基类
- 应用入口在生命周期内启动调度器

```mermaid
graph LR
Reports["reports.py"] --> ExportSvc["services/citation.py"]
ExportSvc --> Models["models/*.py"]
Scheduler["workers/scheduler.py"] --> Engine["workers/citation_engine.py"]
Engine --> Platforms["workers/platforms/base.py"]
Main["main.py"] --> Reports
Main --> Scheduler
```

图表来源
- [backend/app/api/reports.py:11](file://backend/app/api/reports.py#L11)
- [backend/app/services/citation.py:237-269](file://backend/app/services/citation.py#L237-L269)
- [backend/app/workers/scheduler.py:25-95](file://backend/app/workers/scheduler.py#L25-L95)
- [backend/app/workers/citation_engine.py:148-309](file://backend/app/workers/citation_engine.py#L148-L309)
- [backend/app/workers/platforms/base.py:4-18](file://backend/app/workers/platforms/base.py#L4-L18)
- [backend/app/main.py:13-48](file://backend/app/main.py#L13-L48)

章节来源
- [backend/app/api/reports.py:11](file://backend/app/api/reports.py#L11)
- [backend/app/services/citation.py:237-269](file://backend/app/services/citation.py#L237-L269)
- [backend/app/workers/scheduler.py:25-95](file://backend/app/workers/scheduler.py#L25-L95)
- [backend/app/workers/citation_engine.py:148-309](file://backend/app/workers/citation_engine.py#L148-L309)
- [backend/app/workers/platforms/base.py:4-18](file://backend/app/workers/platforms/base.py#L4-L18)
- [backend/app/main.py:13-48](file://backend/app/main.py#L13-L48)

## 性能考虑
- 流式响应：后端以流式方式返回CSV，避免一次性加载全部数据至内存
- 索引优化：引用记录表对query_id、queried_at、platform建立索引，提升筛选与排序性能
- 分页与限制：服务层支持skip/limit，前端可结合分页控件控制导出规模
- 导出粒度：优先按查询词导出，避免全量导出导致的I/O压力
- 并发与队列：查询任务表支持多平台并发执行，导出时可按需筛选时间段

章节来源
- [backend/app/services/citation.py:24-74](file://backend/app/services/citation.py#L24-L74)
- [backend/app/models/citation_record.py:37-41](file://backend/app/models/citation_record.py#L37-L41)

## 故障排查指南
- 400 Bad Request：format参数非csv
  - 检查前端传参或接口调用是否正确
- 404 Not Found：查询不存在或无权限
  - 确认query_id归属当前用户，查询状态为active
- 下载失败或文件为空
  - 检查该查询词是否存在引用记录；确认导出时间范围内是否有数据
- 导出耗时过长
  - 缩小时间范围或按查询词导出；检查数据库索引是否生效
- 定时任务未执行
  - 检查调度器是否启动；核对查询状态与next_query_at字段

章节来源
- [backend/app/api/reports.py:23-35](file://backend/app/api/reports.py#L23-L35)
- [backend/app/services/citation.py:242-244](file://backend/app/services/citation.py#L242-L244)
- [backend/app/workers/scheduler.py:30-40](file://backend/app/workers/scheduler.py#L30-L40)

## 结论
本报告导出系统以清晰的职责分离实现：前端负责交互与下载，后端路由负责鉴权与转发，服务层负责数据筛选与CSV生成，调度器负责周期性任务执行。当前版本聚焦CSV导出，后续可扩展为多格式与批量导出，同时建议引入任务队列与进度回调以增强用户体验。

## 附录

### API定义（CSV导出）
- 路径：/api/v1/reports/export/csv
- 方法：GET
- 认证：Bearer Token
- 查询参数
  - query_id: UUID，必填
  - format: 字符串，可选，默认csv
- 响应
  - 200 OK：text/csv，Content-Disposition为附件下载
  - 400 Bad Request：format非法
  - 404 Not Found：查询不存在或无权限
  - 500 Internal Server Error：内部异常

章节来源
- [backend/app/api/reports.py:16-47](file://backend/app/api/reports.py#L16-L47)

### 输出字段说明（CSV）
- 日期：引用记录的查询时间
- 平台：执行查询的AI平台名称
- 是否引用：布尔值（是/否）
- 引用位置：品牌首次出现的段落序号（若未命中则为空）
- 引用文本：截取后的上下文片段（若未命中则为空）
- 竞争品牌：检测到的其他品牌列表（逗号分隔）

章节来源
- [backend/app/services/citation.py:256-268](file://backend/app/services/citation.py#L256-L268)

### 报告模板定制建议
- 列顺序与标题：可在导出服务中调整writer的列头顺序与本地化标题
- 过滤条件：扩展服务层参数（如平台、起止时间），并在导出服务中拼接SQL条件
- 格式转换：如需Excel，可在前端接收CSV后转为xlsx，或在后端生成xlsx流

章节来源
- [backend/app/services/citation.py:237-269](file://backend/app/services/citation.py#L237-L269)

### 批量导出与定时导出模式
- 批量导出：前端逐项选择查询词后分别导出；或在后端增加“全部查询”聚合导出（需扩展服务层）
- 定时导出：通过调度器周期性执行查询并生成记录，随后即可导出
- 手动导出：前端点击即刻触发查询任务，完成后导出

章节来源
- [backend/app/workers/scheduler.py:51-84](file://backend/app/workers/scheduler.py#L51-L84)
- [backend/app/services/citation.py:204-234](file://backend/app/services/citation.py#L204-L234)

### 进度监控与错误处理
- 进度监控：查询任务表包含状态与时间戳，可用于前端轮询或WebSocket推送
- 错误处理：平台适配器异常会写入任务错误信息与记录，导出接口保持幂等与健壮

章节来源
- [backend/app/models/query_task.py:11-39](file://backend/app/models/query_task.py#L11-L39)
- [backend/app/workers/citation_engine.py:211-227](file://backend/app/workers/citation_engine.py#L211-L227)