# 执行计划 - 执行中心展开结果优化

> **文档类型**: 执行计划文档
> **来源文档**: `_PRD_需求文档_执行中心展开优化.md`
> **创建日期**: 2026-07-14
> **作者**: czj
> **预计工期**: 0.5 天
> **实施状态**: ✅ 已完成（2026-07-14）

---

## 一、执行概述

### 1.1 目标

修复执行中心页面展开不加载结果的问题，实现点击展开箭头自动加载执行结果。

### 1.2 改动范围

| 层级 | 文件 | 改动类型 |
|------|------|----------|
| 前端 | `frontend/src/views/Execution.vue` | 修改 |

### 1.3 依赖项

- 无外部依赖
- 现有 API `/api/executions/{id}/results` 可用

---

## 二、执行步骤

### Phase 1: 代码修改 (预计 15 分钟)

#### Step 1.1: 添加 expand-change 事件监听

**文件**: `frontend/src/views/Execution.vue`

**改动位置**: 第 109 行 el-table 标签

```vue
<!-- 改动前 -->
<el-table :data="executions" stripe style="width: 100%" v-loading="loading">

<!-- 改动后 -->
<el-table
  :data="executions"
  stripe
  style="width: 100%"
  v-loading="loading"
  @expand-change="handleExpandChange"
>
```

#### Step 1.2: 新增 handleExpandChange 方法

**文件**: `frontend/src/views/Execution.vue`

**插入位置**: `toggleExpand` 方法之后（约第 475 行）

```typescript
/**
 * 处理展开行事件
 * 展开时自动加载执行结果
 */
const handleExpandChange = async (row: any, expandedRows: any[]) => {
  const isExpanded = expandedRows.some((r: any) => r.id === row.id)

  if (isExpanded && !rowResults.value[row.id]) {
    // 展开且数据未加载时，加载结果
    resultsLoading.value[row.id] = true
    try {
      const response = await executionApi.getResults(row.id)
      rowResults.value[row.id] = response.items
    } catch (error: any) {
      ElMessage.error('加载结果失败: ' + error.message)
      rowResults.value[row.id] = []
    } finally {
      resultsLoading.value[row.id] = false
    }
  }
}
```

#### Step 1.3: 优化 toggleExpand 方法

**文件**: `frontend/src/views/Execution.vue`

**改动位置**: 第 456-474 行

```typescript
// 改动前
const toggleExpand = async (row: any) => {
  // 如果已展开，则关闭
  if (rowResults.value[row.id]) {
    delete rowResults.value[row.id]
    return
  }

  // 加载结果
  resultsLoading.value[row.id] = true
  try {
    const response = await executionApi.getResults(row.id)
    rowResults.value[row.id] = response.items
  } catch (error: any) {
    ElMessage.error('加载结果失败: ' + error.message)
    rowResults.value[row.id] = []
  } finally {
    resultsLoading.value[row.id] = false
  }
}

// 改动后：简化为仅控制展开状态，数据加载由 handleExpandChange 处理
const toggleExpand = (row: any) => {
  // 通过切换 rowResults 的存在来控制展开状态
  // 实际数据加载由 handleExpandChange 处理
  if (rowResults.value[row.id]) {
    delete rowResults.value[row.id]
  } else {
    // 触发加载（如果尚未加载）
    if (!rowResults.value[row.id]) {
      rowResults.value[row.id] = [] // 先设置空数组，触发展开
    }
  }
}
```

---

### Phase 2: 功能验证 (预计 10 分钟)

#### Step 2.1: 启动服务

```bash
# 后端
cd backend && uvicorn app.main:app --reload --port 8001

# 前端
cd frontend && npm run dev
```

#### Step 2.2: 功能测试

| 测试项 | 操作步骤 | 预期结果 |
|--------|----------|----------|
| 展开加载 | 点击执行记录左侧展开箭头 | 自动加载并显示执行结果 |
| 按钮展开 | 点击【查看结果】按钮 | 展开行，显示结果 |
| 重复展开 | 展开 → 收起 → 再展开 | 数据不重复加载 |
| Loading 状态 | 展开大量数据的记录 | 显示 loading 动画 |
| 错误处理 | 模拟网络错误 | 显示错误提示 |

---

### Phase 3: 文档更新 (预计 5 分钟)

#### Step 3.1: 更新 HANDOFF.md

记录本次修复的内容和影响范围。

#### Step 3.2: 更新 CLAUDE.md

如有必要，在踩坑记录中添加相关经验。

---

## 三、风险评估

| 风险项 | 可能性 | 影响 | 缓解措施 |
|--------|--------|------|----------|
| 展开状态管理冲突 | 低 | 中 | 测试多次展开/收起场景 |
| API 请求重复 | 低 | 低 | 检查 rowResults 缓存 |
| 前端编译错误 | 低 | 高 | TypeScript 类型检查 |

---

## 四、验收清单

- [x] 点击展开箭头自动加载结果
- [x] 点击【查看结果】按钮正常工作
- [x] 数据不重复加载
- [x] Loading 状态正常显示
- [x] 错误处理正常
- [x] 代码无 TypeScript 错误
- [x] 文档已更新

---

## 五、实际实施记录

### 代码改动摘要

**文件**: `frontend/src/views/Execution.vue`

**改动点**:

1. **el-table 添加 ref 和 expand-change 事件**（第 109-115 行）
```vue
<el-table
  ref="tableRef"
  :data="executions"
  stripe
  style="width: 100%"
  v-loading="loading"
  @expand-change="handleExpandChange"
>
```

2. **新增 handleExpandChange 方法**（约第 456 行）
```typescript
/**
 * 处理展开行事件（点击展开箭头触发）
 * 展开时自动加载执行结果，已加载的不重复请求
 */
const handleExpandChange = async (row: any, expandedRows: any[]) => {
  const isExpanded = expandedRows.some((r: any) => r.id === row.id)
  // 仅在展开且数据未加载时加载，避免重复请求
  if (isExpanded && !rowResults.value[row.id]) {
    await loadExecutionResults(row.id)
  }
}
```

3. **抽取 loadExecutionResults 方法**
```typescript
// 抽取的执行结果加载逻辑（供展开事件与按钮共用）
const loadExecutionResults = async (executionId: string) => {
  resultsLoading.value[executionId] = true
  try {
    const response = await executionApi.getResults(executionId)
    rowResults.value[executionId] = response.items
  } catch (error: any) {
    ElMessage.error('加载结果失败: ' + error.message)
    rowResults.value[executionId] = []
  } finally {
    resultsLoading.value[executionId] = false
  }
}
```

4. **优化 toggleExpand 方法**
```typescript
const tableRef = ref()

const toggleExpand = (row: any) => {
  // 通过 el-table 的 toggleRowExpansion 控制展开/收起
  // 数据加载由 handleExpandChange 事件统一处理
  tableRef.value?.toggleRowExpansion(row)
}
```

### 验证结果

| 测试项 | 结果 |
|--------|------|
| 点击展开箭头自动加载 | ✅ 通过 |
| 点击【查看结果】按钮展开 | ✅ 通过 |
| 收起后再展开不重复加载 | ✅ 通过 |

---

## 五、相关文件

| 文件 | 路径 | 用途 |
|------|------|------|
| 前端页面 | `frontend/src/views/Execution.vue` | 主要改动文件 |
| PRD 文档 | `Docs/PRD/自动化测试平台/_PRD_需求文档_执行中心展开优化.md` | 需求定义 |
| API 接口 | `frontend/src/api/executions.ts` | API 调用 |

---

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