# 执行计划 - 菜单分类架构与步骤编辑

> **文档类型**: 执行计划文档
> **来源文档**: `_PRD_需求文档_菜单分类与步骤编辑.md`
> **创建日期**: 2026-07-14
> **作者**: czj
> **预计工期**: 1 天
> **实施状态**: ⏳ 待实施

---

## 一、执行概述

### 1.1 目标

实现模块/用例/执行的分类子菜单架构，并补充用例步骤编辑功能。

### 1.2 改动范围

| 层级 | 文件数 | 改动类型 |
|------|--------|----------|
| 后端模型 | 2 | Module/TestCase 加分类字段 |
| 后端 schema/路由 | 5 | 字段透传 + 筛选 |
| 前端路由 | 1 | 可选参数路由 |
| 前端菜单 | 1 | el-sub-menu |
| 前端页面 | 3 | Modules/Cases/Execution 读 type |
| 新建组件 | 1 | CaseStepEditor |
| 数据迁移脚本 | 1 | 现有数据补分类 |

---

## 二、执行步骤

### Phase 1: 后端模型与字段 (预计 20 分钟)

#### Step 1.1: Module 模型新增 module_type

**文件**: `backend/app/models/module.py`

```python
module_type: Mapped[str] = mapped_column(
    String(20), default="standard",
    comment="模块类型: standard/custom"
)
```

#### Step 1.2: TestCase 模型新增 case_type

**文件**: `backend/app/models/test_case.py`

```python
case_type: Mapped[str] = mapped_column(
    String(20), default="ui",
    comment="用例类型: ui/api/security/deploy/performance/functional"
)
```

#### Step 1.3: 数据库迁移（ALTER TABLE）

**文件**: `backend/app/database.py`（建表逻辑）

SQLite 已有表新增字段需用 `ALTER TABLE ADD COLUMN`。在建表逻辑后增加字段补齐检查：

```python
# 字段补齐：对已存在的表补充新字段（SQLite 兼容）
def _ensure_columns(conn):
    # modules 表补 module_type
    _add_column_if_not_exists(conn, "modules", "module_type", "VARCHAR(20) DEFAULT 'standard'")
    # test_cases 表补 case_type
    _add_column_if_not_exists(conn, "test_cases", "case_type", "VARCHAR(20) DEFAULT 'ui'")
```

### Phase 2: 后端 schema 与路由 (预计 25 分钟)

#### Step 2.1: schema 加字段

**文件**: `backend/app/schemas/module.py` / `backend/app/schemas/test_case.py`

```python
# Module
module_type: str = Field(default="standard", description="模块类型")
# TestCase
case_type: str = Field(default="ui", description="用例类型: ui/api/security/deploy")
```

更新 to_dict / Response 序列化包含新字段。

#### Step 2.2: 路由筛选

**文件**: `backend/app/routers/modules.py`

```python
@router.get("")
async def list_modules(
    module_type: Optional[str] = Query(None),  # 新增
    ...
):
    # service.list 增加 module_type 筛选
```

**文件**: `backend/app/routers/cases.py`

```python
@router.get("")
async def list_cases(
    case_type: Optional[str] = Query(None),  # 新增
    ...
):
    # service.list 增加 case_type 筛选
```

**文件**: `backend/app/routers/executions.py`

执行记录本身无 case_type，通过关联用例筛选。简化方案：本次执行中心按 type 筛选**待定**（执行记录表无类型字段），可后续在 Execution 表加 case_type 字段，或通过 config 记录。

**本次简化**：Execution 创建时把 case_type 存入 execution.config，list 时按 config.case_type 筛选（或在 Execution 表加 case_type 列，推荐加列更清晰）。

→ **采用**：Execution 模型加 case_type 列，创建执行时取首个用例的 case_type 填入。

#### Step 2.3: service 层筛选实现

`ModuleService.list` / `CaseService.list` 增加 type 参数过滤；`ExecutionService.list_executions` 增加 case_type 过滤。

### Phase 3: 前端路由 (预计 10 分钟)

#### Step 3.1: 路由改为可选参数

**文件**: `frontend/src/router/index.ts`

```typescript
{ path: '/modules/:type?', name: 'Modules', component: ..., meta: { title: '模块管理' } },
{ path: '/cases/:type?', name: 'Cases', component: ..., meta: { title: '用例管理' } },
{ path: '/execution/:type?', name: 'Execution', component: ..., meta: { title: '执行中心' } },
```

### Phase 4: 前端菜单 (预计 20 分钟)

#### Step 4.1: App.vue 改 el-sub-menu

**文件**: `frontend/src/App.vue`

```vue
<!-- 模块管理（父） -->
<el-sub-menu index="/modules">
  <template #title>
    <el-icon><Folder /></el-icon><span>模块管理</span>
  </template>
  <el-menu-item index="/modules/standard"><span>标准模块</span></el-menu-item>
  <el-menu-item index="/modules/custom"><span>项目定制模块</span></el-menu-item>
</el-sub-menu>

<!-- 用例管理（父） -->
<el-sub-menu index="/cases">
  <template #title>
    <el-icon><Document /></el-icon><span>用例管理</span>
  </template>
  <el-menu-item index="/cases/ui">UI自动化</el-menu-item>
  <el-menu-item index="/cases/api">接口自动化</el-menu-item>
  <el-menu-item index="/cases/security">安全自动化测试</el-menu-item>
  <el-menu-item index="/cases/deploy">自动化部署测试</el-menu-item>
  <el-menu-item index="/cases/performance">性能测试</el-menu-item>
  <el-menu-item index="/cases/functional">功能测试</el-menu-item>
</el-sub-menu>

<!-- 执行中心（父） ← 6 个子菜单，同用例管理 -->
<el-sub-menu index="/execution">
  <template #title>
    <el-icon><VideoPlay /></el-icon><span>执行中心</span>
  </template>
  <el-menu-item index="/execution/ui">UI自动化</el-menu-item>
  <el-menu-item index="/execution/api">接口自动化</el-menu-item>
  <el-menu-item index="/execution/security">安全自动化测试</el-menu-item>
  <el-menu-item index="/execution/deploy">自动化部署测试</el-menu-item>
  <el-menu-item index="/execution/performance">性能测试</el-menu-item>
  <el-menu-item index="/execution/functional">功能测试</el-menu-item>
</el-sub-menu>

<!-- 报告中心（父） ← 5 个子菜单（不含部署） -->
<el-sub-menu index="/reports">
  <template #title>
    <el-icon><DataLine /></el-icon><span>报告中心</span>
  </template>
  <el-menu-item index="/reports/ui">UI自动化测试</el-menu-item>
  <el-menu-item index="/reports/api">接口测试</el-menu-item>
  <el-menu-item index="/reports/security">安全测试</el-menu-item>
  <el-menu-item index="/reports/performance">性能测试</el-menu-item>
  <el-menu-item index="/reports/functional">功能测试</el-menu-item>
</el-sub-menu>
```

#### Step 4.2: 默认激活与标题适配

- `default-active` 处理：父菜单展开，子项高亮
- `pageTitle` 计算属性：根据完整 path 匹配（如 `/cases/ui` → "用例管理 - UI自动化"）

### Phase 5: 前端页面读 type (预计 30 分钟)

#### Step 5.1: Modules.vue

```typescript
const route = useRoute()
const currentType = computed(() => (route.params.type as string) || 'standard')
// loadModules 传 module_type: currentType
// 新建模块表单 module_type 默认 currentType
```

#### Step 5.2: Cases.vue

```typescript
const currentType = computed(() => (route.params.type as string) || 'ui')
// loadCases 传 case_type: currentType
// watch(currentType) 重新加载
// 新建用例 editForm.case_type = currentType
```

⚠️ **注意**：`useRoute()` 必须在 setup 顶层调用（踩坑7）。

#### Step 5.3: Execution.vue

```typescript
const currentType = computed(() => (route.params.type as string) || 'ui')
// loadExecutions 传 case_type: currentType
```

#### Step 5.4: Reports.vue

```typescript
const currentType = computed(() => (route.params.type as string) || 'ui')
// loadReports 传 case_type: currentType 筛选报告
```

报告路由同样改为 `/reports/:type?`。

#### Step 3.1 路由更新（含报告中心）

```typescript
{ path: '/modules/:type?', ... },
{ path: '/cases/:type?', ... },
{ path: '/execution/:type?', ... },
{ path: '/reports/:type?', ... },
```

### Phase 6: 步骤编辑器组件 (预计 60 分钟)

#### Step 6.1: 新建 CaseStepEditor.vue

**文件**: `frontend/src/components/CaseStepEditor.vue`

Props: `modelValue: Step[]`（v-model），Emits: `update:modelValue`

功能：
- 步骤列表表格：序号 | 名称 | 动作 | 参数 | 操作（上移/下移/删除）
- 【+ 添加步骤】按钮
- 动作类型下拉（navigate/click/fill/wait/assert/select/hover/scroll/press/check/uncheck/screenshot）
- 动态参数表单（根据 action 显示对应输入框）
- order 自动重排

#### Step 6.2: 动作参数配置表

```typescript
const ACTION_PARAMS = {
  navigate: [{ key: 'url', label: 'URL', type: 'input' }],
  click:    [{ key: 'selector', label: '选择器', type: 'input' }],
  fill:     [{ key: 'selector', label: '选择器', type: 'input' }, { key: 'value', label: '值', type: 'input' }],
  wait:     [{ key: 'selector', label: '选择器', type: 'input' }, { key: 'timeout', label: '超时(ms)', type: 'number' }],
  assert:   [{ key: 'selector', label: '选择器', type: 'input' }, { key: 'type', label: '断言类型', type: 'select', options: ['visible','title','text'] }],
  select:   [{ key: 'selector', ... }, { key: 'value', ... }],
  hover:    [{ key: 'selector', ... }],
  scroll:   [{ key: 'direction', label: '方向', type: 'select', options: ['up','down'] }],
  press:    [{ key: 'key', label: '按键', type: 'input' }],
  // ...其余动作
}
```

#### Step 6.3: 集成到 Cases.vue 编辑弹窗

在编辑弹窗的"标签"字段后增加：

```vue
<el-form-item label="测试步骤">
  <CaseStepEditor v-model="editForm.steps" />
</el-form-item>
```

保存时 steps 一并提交（API 已支持 steps 字段）。

### Phase 7: 数据迁移与验证 (预计 15 分钟)

#### Step 7.1: 迁移脚本

**文件**: `backend/scripts/update_case_module_type.py`

```python
# 模块全部标记 standard，用例全部标记 ui（已是事实）
# 通过 API 或直接 SQL
```

#### Step 7.2: 功能验证

| 测试 | 预期 |
|------|------|
| 菜单展开/切换 | ✅ |
| 各子菜单筛选正确 | ✅ |
| 新建用例带步骤 | ✅ 步骤持久化 |
| 编辑已有用例显示步骤 | ✅ 回填 |
| 现有用例归类 ui | ✅ |

---

## 三、风险评估

| 风险项 | 可能性 | 影响 | 缓解 |
|--------|--------|------|------|
| SQLite 加列失败 | 中 | 高 | _add_column_if_not_exists 检查 |
| useRoute 在 computed 内 | 中 | 高 | setup 顶层调用 |
| 路由参数变化不刷新 | 中 | 中 | watch(currentType) 重载 |
| 步骤数据格式不匹配 | 中 | 中 | 与后端 params 结构对齐 |
| 执行记录 case_type 缺失 | 中 | 中 | Execution 加列 + 创建时填入 |
| 旧路径 /cases 失效 | 低 | 中 | 可选参数兼容 |

---

## 四、验收清单

- [ ] Module 模型 module_type
- [ ] TestCase 模型 case_type
- [ ] Execution 模型 case_type（简化筛选）
- [ ] SQLite 字段补齐逻辑
- [ ] schema 字段透传
- [ ] modules/cases/executions 路由筛选
- [ ] 前端路由可选参数
- [ ] App.vue 3 个 el-sub-menu
- [ ] Modules/Cases/Execution 读 type 筛选
- [ ] CaseStepEditor 组件
- [ ] 编辑弹窗集成步骤编辑器
- [ ] 数据迁移（现有数据归类）
- [ ] 功能验证通过
- [ ] 文档更新

---

## 五、相关文件

| 文件 | 用途 |
|------|------|
| `backend/app/models/module.py` `test_case.py` `execution.py` | 模型加字段 |
| `backend/app/database.py` | 字段补齐 |
| `backend/app/routers/modules.py` `cases.py` `executions.py` | 筛选 |
| `frontend/src/router/index.ts` `App.vue` | 路由菜单 |
| `frontend/src/views/Modules.vue` `Cases.vue` `Execution.vue` | 读 type |
| `frontend/src/components/CaseStepEditor.vue` | 新建步骤编辑器 |

---

*本文档由 Claude Code 生成，遵循项目执行计划文档规范。*
