# PRD - 批量执行合并报告

> **文档版本**: v1.0
> **创建日期**: 2026-08-20
> **模块类型**: 性能测试
> **优先级**: P0

---

## 一、背景与目标

### 1.1 背景

当前性能测试模块已实现**项目管理与批量执行**功能：
- 用户可将任务归入项目（文件夹）
- 支持「执行全部」和「勾选批量执行」
- 串行逐个执行任务，每任务出一份独立报告

但问题是：**批量执行后，每个任务各出一份报告，用户需要逐个查看，无法从整体上评估项目维度的性能表现。** 例如「会议预约」项目下有 3 个接口（新建/修改/取消会议），批量执行后用户希望看到整个项目的总体性能概况，而不是分别翻看 3 份报告。

### 1.2 目标

1. **批量执行后生成合并报告**：将批次内所有任务的执行结果聚合为一份综合报告
2. **项目级报告查看**：项目管理页面增加「查看报告」入口，展示项目整体性能
3. **保留逐任务明细**：合并报告不替代原有单任务报告，两者共存
4. **兼容单任务执行**：单任务执行行为不变，只合并批量执行的场景

---

## 二、功能范围

| 功能 | 描述 | 优先级 |
|------|------|--------|
| 存储批量执行记录 | 保存 batch_id、所属项目、任务列表、执行时间 | P0 |
| 合并报告数据模型 | 存储聚合后的项目级性能指标 | P0 |
| 批量执行后自动生成合并报告 | 所有任务完成后，自动聚合指标生成合并报告 | P0 |
| 合并报告 API | 按 batch_id 或 project_id 查询合并报告 | P0 |
| 合并报告前端页面 | 展示聚合指标 + 各任务明细列表 | P0 |
| 项目详情页跳转合并报告 | 批量执行完成后可点击查看合并报告 | P0 |
| 单任务报告保持独立 | 不影响现有单任务报告查看功能 | P0 |

---

## 三、数据模型设计

### 3.1 PerformanceBatchExecution（已有结构扩展）

当前 `batch_run_tasks` 方法已生成 `batch_id`，但未持久化存储。需要新增表：

```sql
CREATE TABLE performance_batch_executions (
    id VARCHAR(64) PRIMARY KEY,           -- 批量执行ID (batch_xxx)
    project_id VARCHAR(64) DEFAULT NULL,  -- 关联项目ID（可选，直接批量执行可能无项目）
    task_ids TEXT NOT NULL,               -- 执行的任务ID列表（JSON数组）
    status VARCHAR(20) DEFAULT 'running', -- running/completed/partially_failed
    total_count INT DEFAULT 0,            -- 总任务数
    success_count INT DEFAULT 0,          -- 成功数
    fail_count INT DEFAULT 0,             -- 失败数
    started_at DATETIME,                  -- 开始时间
    completed_at DATETIME,                -- 完成时间
    created_at DATETIME                   -- 创建时间
);
```

### 3.2 PerformanceProjectReport（新表）

存储项目维度的合并报告：

```sql
CREATE TABLE performance_project_reports (
    id VARCHAR(64) PRIMARY KEY,           -- 报告唯一标识 (rpt_xxx)
    project_id VARCHAR(64) NOT NULL,      -- 关联项目ID
    batch_id VARCHAR(64) DEFAULT NULL,    -- 关联批量执行ID（可选）
    task_ids TEXT NOT NULL,               -- 包含的任务ID列表（JSON数组）
    
    -- 聚合指标（与单任务指标对齐，但数值为聚合值）
    total_requests INT DEFAULT 0,         -- 总请求数
    success_count INT DEFAULT 0,          -- 总成功数
    fail_count INT DEFAULT 0,             -- 总失败数
    error_rate FLOAT DEFAULT 0.0,         -- 整体错误率
    actual_tps FLOAT DEFAULT 0.0,         -- 整体 TPS（总请求/总实际时长）
    avg_response_time FLOAT DEFAULT 0.0,  -- 平均响应时间（所有请求加权平均）
    min_response_time FLOAT DEFAULT 0.0,  -- 最小响应时间
    max_response_time FLOAT DEFAULT 0.0,  -- 最大响应时间
    p50_response_time FLOAT DEFAULT 0.0,  -- P50
    p90_response_time FLOAT DEFAULT 0.0,  -- P90
    p95_response_time FLOAT DEFAULT 0.0,  -- P95
    p99_response_time FLOAT DEFAULT 0.0,  -- P99
    std_dev FLOAT DEFAULT 0.0,            -- 标准差
    apdex FLOAT DEFAULT 0.0,              -- Apdex 用户满意度
    status_2xx INT DEFAULT 0,
    status_3xx INT DEFAULT 0,
    status_4xx INT DEFAULT 0,
    status_5xx INT DEFAULT 0,
    total_sent_bytes INT DEFAULT 0,
    total_received_bytes INT DEFAULT 0,
    peak_tps FLOAT DEFAULT 0.0,           -- 所有任务中最高峰值 TPS
    duration_actual FLOAT DEFAULT 0.0,    -- 总实际耗时（从第一个任务开始到最后一个任务结束）
    
    -- 任务明细（JSON）
    task_summaries TEXT,                   -- 各任务摘要的 JSON 数组
    
    -- 时间
    created_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
```

### 3.3 聚合算法

合并报告的核心是将 N 个任务的指标**合理聚合**，而非简单相加：

| 指标 | 聚合方式 | 说明 |
|------|---------|------|
| total_requests | 求和 | 所有任务请求数相加 |
| success_count | 求和 | 所有任务成功数相加 |
| fail_count | 求和 | 所有任务失败数相加 |
| error_rate | 重算 | `fail_count / total_requests` |
| actual_tps | 重算 | `total_requests / 所有任务实际耗时之和` |
| avg_response_time | 加权平均 | `Σ(avg_rt_i × request_count_i) / total_requests` |
| min_response_time | 取最小值 | 所有任务中最小的 |
| max_response_time | 取最大值 | 所有任务中最大的 |
| p50/p90/p95/p99 | 加权近似 | 基于各任务分位数加权估算 |
| std_dev | 重算 | 基于聚合后的均值和方差计算 |
| apdex | 加权平均 | `Σ(apdex_i × request_count_i) / total_requests` |
| peak_tps | 取最大值 | 各任务 peak_tps 的最大值 |
| status_2xx/4xx/5xx | 求和 | 各任务状态码计数相加 |
| sent/received_bytes | 求和 | 各任务收发字节数相加 |
| duration_actual | 求和 | 各任务实际耗时相加 |

---

## 四、API 设计

### 4.1 合并报告 API

| 方法 | 路径 | 描述 |
|------|------|------|
| GET | `/api/performance/projects/{project_id}/report` | 获取项目最新合并报告 |
| GET | `/api/performance/batch-reports/{batch_id}` | 按 batch_id 获取合并报告 |
| GET | `/api/performance/projects/{project_id}/reports` | 获取项目历史合并报告列表 |

### 4.2 批量执行响应扩展

现有 `POST /api/performance/tasks/batch-run` 和 `POST /api/performance/projects/{id}/run-all` 的响应增加 `report_id` 字段：

```json
{
  "message": "批量执行完成: 3 成功, 0 失败",
  "batch_id": "batch_xxx",
  "task_count": 3,
  "report_id": "rpt_xxx"          // ← 新增
}
```

### 4.3 合并报告响应结构

```json
{
  "id": "rpt_xxx",
  "project_id": "proj_xxx",
  "batch_id": "batch_xxx",
  "created_at": "2026-08-20T12:00:00",
  
  "summary": {
    "total_requests": 10000,
    "success_count": 9950,
    "fail_count": 50,
    "error_rate": 0.005,
    "actual_tps": 150.5,
    "peak_tps": 320.0,
    "avg_response_time": 185.2,
    "min_response_time": 45.0,
    "max_response_time": 2500.0,
    "p50_response_time": 120.0,
    "p90_response_time": 350.0,
    "p95_response_time": 500.0,
    "p99_response_time": 1200.0,
    "std_dev": 85.3,
    "apdex": 0.92,
    "status_2xx": 9800,
    "status_4xx": 150,
    "status_5xx": 50,
    "total_sent_bytes": 512000,
    "total_received_bytes": 10240000,
    "duration_actual": 66.5
  },
  
  "task_summaries": [
    {
      "task_id": "perf_xxx",
      "task_name": "新建会议",
      "status": "completed",
      "total_requests": 3000,
      "success_count": 2980,
      "fail_count": 20,
      "avg_response_time": 150.0,
      "actual_tps": 120.0
    },
    {
      "task_id": "perf_yyy",
      "task_name": "修改会议",
      "status": "completed",
      "total_requests": 4000,
      "success_count": 3990,
      "fail_count": 10,
      "avg_response_time": 200.0,
      "actual_tps": 160.0
    }
  ]
}
```

---

## 五、前端页面设计

### 5.1 合并报告页面

新增 `/performance/project-report` 路由，复用现有 `ReportPanel.vue` 的布局风格：

- **顶部**：项目名称 + 批量执行时间 + 返回项目详情按钮
- **聚合指标卡片**（与现有单任务报告风格一致）：
  - 第一行：总请求数 / 总成功数 / 总失败数 / 错误率
  - 第二行：整体 TPS / 峰值 TPS / 平均响应时间 / P95
  - 第三行：标准差 / Apdex / 最小/最大响应时间
- **分位数表**：P50 / P90 / P95 / P99
- **状态码分布表**：2xx / 4xx / 5xx
- **各任务明细表**：列出每个任务的名称、状态、请求数、TPS、平均响应时间
- **导出 JSON** 功能

### 5.2 项目详情页改动

- 批量执行完成后，进度条下方增加「**查看合并报告**」按钮
- 项目头部增加「历史报告」按钮，查看该项目所有历史合并报告列表

### 5.3 路由

```
/performance/project-report?projectId=xxx&reportId=xxx  ← 合并报告页（新增）
```

---

## 六、实施计划

| 阶段 | 内容 | 预估工时 |
|------|------|---------|
| Phase 1 | 数据模型 + 后端聚合逻辑 + API | 1 天 |
| Phase 2 | 前端合并报告页面 | 0.5 天 |
| Phase 3 | 项目详情页适配 + 联调 | 0.5 天 |

---

## 七、边界与约束

### 7.1 兼容性
- 单任务执行不变，报告格式不变
- 批量执行生成的合并报告不影响原有单任务报告
- 旧批量执行记录无合并报告（不回溯）

### 7.2 性能约束
- 合并报告聚合在任务执行完成后同步计算（串行，不影响执行性能）
- 快照数据不合并（各任务快照独立存储），合并报告仅包含聚合指标

### 7.3 注意事项
- 如果某个任务执行失败（status=failed），仍计入总请求数，但该任务的指标可能不完整
- 合并报告的 `error_rate` 基于所有任务的总失败数/总请求数重新计算，而非各任务 error_rate 的平均值

---

*本文档完成后，将使用 prd-plan skill 生成计划执行文档，再使用 prd-code skill 实现代码。*