# PRD — 预设配置与登录账号预设

> **版本**: v1.0
> **日期**: 2026-08-20
> **状态**: 待实现
> **关联 PRD**: `_PRD_接口预设功能.md`、`_PRD_性能测试模块需求文档.md`

---

## 1. 背景与目标

### 1.1 背景

当前性能测试模块存在以下问题：

1. **术语混淆**：当前菜单/页面称「接口预设」，但实际功能不仅是接口配置，还包括认证配置、捕获规则等，**「预设配置」** 更准确反映其作为「压测任务模板」的定位。
2. **登录凭据与接口配置脱节**：接口预设（`api_presets`）只存了 `account_key`（超级管理员/管理员/普通用户），但实际的用户名密码是硬编码在 `performance_service.py` 的 `_DEFAULT_ACCOUNTS` 中的。用户新建任务时仍需手动填写登录用户名/密码，或使用默认值，无法复用预设中保存的凭据。
3. **凭据无名称标识**：当前任务级的 `login_username`/`login_password` 字段没有名称标签，如果多个任务使用不同凭据，用户无法区分。

### 1.2 目标

1. **术语统一**：将「接口预设」更名为「预设配置」（菜单、页面、弹窗、API 路径注释等全部同步）
2. **预设存储登录凭据**：每个预设配置中直接存储 `credential_name`（凭据名称，如"超级管理员"、"测试账号A"）、`login_username`、`login_password`
3. **新建任务一键填充**：选择预设配置后，自动填充接口字段（Method/URL/Headers/Body）+ 登录凭据（用户名/密码），用户无需再手动填写
4. **向后兼容**：已有预设自动获得默认凭据值；已有任务（无预设）不受影响

---

## 2. 功能范围

### 2.1 核心功能

| 功能 | 描述 | 优先级 |
|------|------|--------|
| 术语重命名 | 接口预设 → 预设配置（菜单、页面标题、弹窗标题、API 注释） | P0 |
| 预设凭据字段 | 预设新增 `credential_name`/`login_username`/`login_password` | P0 |
| 预设编辑凭据 | 编辑预设弹窗增加凭据名称/用户名/密码输入框 | P0 |
| 任务表单自动填充 | 选择预设后自动填充登录凭据、摘要卡片显示凭据名称 | P0 |
| 向后兼容 | 旧预设自动补默认凭据；旧任务不受影响 | P0 |

### 2.2 预设配置包含的完整字段

| 字段 | 类型 | 说明 |
|------|------|------|
| **名称** | string | 预设配置名称，如"新建会议V3"（唯一） |
| **描述** | string | 可选，说明用途 |
| **HTTP 方法** | string | GET/POST/PUT/DELETE |
| **目标 URL** | string | 接口完整 URL（含协议和域名） |
| **请求头** | JSON | 自定义请求头 |
| **请求体** | JSON | 静态请求体（与 bodyTemplate 互斥） |
| **请求体模板** | JSON | 带 `{__XXX__}` 占位符的模板 |
| **响应捕获规则** | array | 捕获响应字段的规则列表 |
| **是否需要登录** | bool | 是否自动获取 Token |
| **是否需要签名** | bool | 是否生成 X-RANDOM/X-TIMESTAMP/X-SIGN |
| **使用账号 key** | string | 登录使用的账号 key（superadmin/admin/user） |
| **凭据名称** | string | **新增**，登录凭据的显示名称，如"超级管理员" |
| **登录用户名** | string | **新增**，自定义登录用户名，留空使用默认值 |
| **登录密码** | string | **新增**，自定义登录密码，留空使用默认值 |

---

## 3. 详细需求

### 3.1 术语重命名映射

| 当前位置 | 旧名称 | 新名称 |
|---------|--------|--------|
| 侧边栏菜单 | 接口预设 | 预设配置 |
| 路由 path | `presets` | 不变（URL 路径无需改，避免破坏书签） |
| 路由 meta.title | 接口预设 | 预设配置 |
| 列表页标题 | 接口预设列表 | 预设配置列表 |
| 新建弹窗标题 | 新建接口预设 | 新建预设配置 |
| 编辑弹窗标题 | 编辑接口预设 | 编辑预设配置 |
| 任务表单标签 | 接口预设 | 预设配置 |
| 提示文案 | 接口预设用于快速填充任务配置 | 预设配置用于快速填充任务配置 |
| 后端 API 路径 | 不变（`/api/performance/presets`） | 不变 |
| 后端模型/类名 | `ApiPreset` | 不变（类名不改，避免大面积重构） |
| 后端注释/docstring | 接口预设 | 预设配置 |

### 3.2 数据模型变更

#### 3.2.1 ApiPreset 模型新增字段

```python
class ApiPreset(Base):
    """预设配置数据库模型"""
    __tablename__ = "api_presets"

    # ... 现有字段不变 ...

    # 新增：登录凭据配置
    credential_name: Mapped[Optional[str]] = mapped_column(
        String(100), nullable=True, default=None, comment="凭据名称，如'超级管理员'"
    )
    login_username: Mapped[Optional[str]] = mapped_column(
        String(200), nullable=True, default=None, comment="自定义登录用户名，留空使用默认"
    )
    login_password: Mapped[Optional[str]] = mapped_column(
        String(200), nullable=True, default=None, comment="自定义登录密码，留空使用默认"
    )
```

`to_dict()` 中同步返回这三个字段。

#### 3.2.2 数据库迁移

```python
# database.py _ensure_columns 追加：
("api_presets", "credential_name", "VARCHAR(100) DEFAULT NULL"),
("api_presets", "login_username", "VARCHAR(200) DEFAULT NULL"),
("api_presets", "login_password", "VARCHAR(200) DEFAULT NULL"),
```

### 3.3 Schema 变更

#### 3.3.1 ApiPresetCreate / ApiPresetUpdate 新增字段

```python
credential_name: Optional[str] = Field(None, description="凭据名称")
login_username: Optional[str] = Field(None, description="登录用户名")
login_password: Optional[str] = Field(None, description="登录密码")
```

#### 3.3.2 ApiPresetListItem 增加凭据名称

列表项中增加 `credential_name` 字段，用于任务表单下拉和列表展示。

### 3.4 前端变更

#### 3.4.1 侧边栏菜单 + 路由

- `App.vue`：`接口预设` → `预设配置`
- `router/index.ts`：`meta.title` 改为 `预设配置`

#### 3.4.2 预设配置列表页（ApiPresetList.vue）

- 页面标题/提示文案：「接口预设」→「预设配置」
- 列表列：新增「凭据名称」列（显示 credential_name，无则显示 `-`）
- 新建/编辑弹窗标题：同步改名

#### 3.4.3 预设配置编辑弹窗（ApiPresetDialog.vue）

在「认证配置」区域（账号 select 下方）新增三个输入框：

```
┌─ 认证配置 ──────────────────────────────┐
│ 需要登录认证 [switch]                     │
│ 请求需要签名 [switch]                     │
│ 账号 [select: superadmin/admin/user]      │
│ ── 登录凭据（可选，留空使用默认值） ──    │
│ 凭据名称 [input]  ← 如"超级管理员"        │
│ 登录用户名 [input]                        │
│ 登录密码 [password input]                 │
└──────────────────────────────────────────┘
```

凭据名称、用户名、密码三个字段仅在 `authRequired=true` 时显示。

#### 3.4.4 任务创建表单（TaskList.vue）

**当前行为**：选择预设后只填充 Method/URL/Headers/Body/Auth/Sign/AccountKey，登录凭据仍需要手动填。

**改造后行为**：选择预设后，额外自动填充：
- `form.loginUsername` ← preset.login_username
- `form.loginPassword` ← preset.login_password
- 摘要卡片增加凭据名称行：`凭据：超级管理员`

**摘要卡片示例**：
```
┌─ 预设配置: 新建会议V3 ───────────────────────┐
│ PUT https://192.168.5.44/meetingV3/api/message/book │
│ 需要登录（超级管理员） · 需要签名                 │
└────────────────────────────────────────────────┘
```

**编辑回填**：如果任务有 `preset_id`，从预设加载凭据名称并显示。

### 3.5 后端处理逻辑

#### 3.5.1 创建预设时凭据字段处理

新建/编辑预设时，凭据名称/用户名/密码为可选字段，留空时存 `null`。

#### 3.5.2 创建任务时预设继承（无需改动）

当前 `performance_service.py` 的 `create_task()` 中，预设继承已处理 `account_key`：
```python
data["account_key"] = data.get("account_key") or preset.account_key
```

新增的 `login_username`/`login_password` 同理也会被任务数据覆盖或继承。但需要注意：**当前逻辑中 `login_username`/`login_password` 不是从预设继承的**，需要补充：

```python
# 从预设继承登录凭据
if not data.get("login_username"):
    data["login_username"] = getattr(preset, "login_username", None)
if not data.get("login_password"):
    data["login_password"] = getattr(preset, "login_password", None)
```

#### 3.5.3 执行时凭据使用（无需改动）

`_build_client_config()` 已支持从 `task_dict` 读取 `login_username`/`login_password`，预设继承后自动生效，无需额外改动。

---

## 4. 非功能需求

### 4.1 兼容性

- 已有预设（无 `credential_name`/`login_username`/`login_password` 字段）完全不受影响，默认值为 `null`
- 已有任务（无 `preset_id`）不受影响，创建/编辑/执行逻辑不变
- 预设凭据更新后，已创建的任务不受影响（任务存储的是当时的值，不是引用）

### 4.2 约束

- 凭据名称仅用作显示标签，不参与唯一性校验（不同预设可用相同凭据名称）
- 登录密码以明文存库（`api_presets.login_password`），内网平台可接受
- 预设凭据字段留空时，执行时回退 `_DEFAULT_ACCOUNTS` 默认值

---

## 5. 应用场景示例

### 5.1 场景一：创建含凭据的预设配置

1. 运维在预设配置页面新建「新建会议V3」：
   - 方法：PUT，URL：`https://192.168.5.44/meetingV3/api/message/book`
   - 需要登录 + 需要签名
   - 凭据名称：`超级管理员`，用户名：`admin@xty`，密码：`Ubains@13579`

2. 测试同学创建压测任务：
   - 选择预设：「新建会议V3」→ 自动填充所有接口字段 + 登录凭据
   - 摘要卡片显示：`需要登录（超级管理员）`
   - 设置并发数：10，时长：60s → 执行成功

### 5.2 场景二：使用默认凭据的预设

1. 运维新建预设「查询接口」：
   - 方法：GET，URL：`https://192.168.5.44/platform/api/xxx`
   - 需要登录，但凭据名称/用户名/密码留空

2. 测试同学创建任务 → 选择该预设 → 登录凭据为空 → 执行时使用默认账号（`admin@xty / Ubains@13579`）

---

## 6. 影响范围

### 6.1 修改文件

| 文件 | 变更 |
|------|------|
| `backend/app/models/api_preset.py` | 新增 `credential_name`/`login_username`/`login_password` 字段 + `to_dict()` 返回 |
| `backend/app/schemas/api_preset.py` | Create/Update/Response/ListItem 新增三个字段 |
| `backend/app/database.py` | `_ensure_columns` 追加 3 条 ALTER TABLE |
| `backend/app/services/performance_service.py` | `create_task()` 预设继承增加 login_username/login_password |
| `frontend/src/App.vue` | 侧边栏菜单文字「接口预设」→「预设配置」 |
| `frontend/src/router/index.ts` | meta.title「接口预设」→「预设配置」 |
| `frontend/src/views/performance/ApiPresetList.vue` | 页面文案 + 新增「凭据名称」列 |
| `frontend/src/views/performance/ApiPresetDialog.vue` | 编辑弹窗新增凭据名称/用户名/密码输入框 |
| `frontend/src/views/performance/TaskList.vue` | 预设摘要卡片显示凭据名称；onPresetChange 填充登录凭据 |

### 6.2 无需改动

| 文件 | 原因 |
|------|------|
| `backend/app/routers/api_preset.py` | CRUD 路由无字段级逻辑，schema 变更自动生效 |
| `backend/app/services/api_preset_service.py` | 业务逻辑不涉及凭据字段特殊处理 |
| `backend/app/executors/performance_executor.py` | 凭据从 service 注入，透明传递 |
| `backend/app/routers/performance.py` | 路由层无变更 |
| `frontend/src/api/performance.ts` | API 封装无变更 |
| `frontend/src/types/performance.ts` | 类型定义跟随 schema 自动更新（需确认字段 map） |

---

## 7. 验收标准

| # | 验收项 | 验证方式 |
|---|--------|---------|
| 1 | 侧边栏菜单显示「预设配置」 | 打开页面，左侧菜单文字正确 |
| 2 | 预设配置列表页文案正确 | 标题、提示文案均为「预设配置」 |
| 3 | 新建预设可填写凭据名称/用户名/密码 | 编辑弹窗展示三个输入框 |
| 4 | 编辑预设可修改凭据字段 | 保存后重新打开，内容正确 |
| 5 | 旧预设打开编辑弹窗，凭据字段为空 | 兼容旧数据，无异常 |
| 6 | 新建任务选择预设后自动填充登录凭据 | 表单 loginUsername/loginPassword 自动填入 |
| 7 | 摘要卡片显示凭据名称 | 卡片显示「需要登录（超级管理员）」 |
| 8 | 预设凭据留空时，任务执行使用默认账号 | 执行成功，日志确认默认凭据 |
| 9 | 预设凭据变化不影响已有任务 | 历史任务执行时仍用原值 |

---

*本文档为预设配置与登录账号预设功能的需求定义，后续将输出计划执行文档用于指导开发。*