# 执行计划 - 步骤详情截图默认展开

> **文档类型**: 执行计划文档
> **创建日期**: 2026-07-15
> **作者**: czj
> **关联 PRD**: `_PRD_需求文档_步骤详情截图默认展开.md`
> **状态**: 待执行

---

## 一、改动总览

| # | 改动项 | 文件 | 改动量 | 说明 |
|---|--------|------|--------|------|
| 1 | viewingScreenshot 初始值改为计算属性 | `StepDetailPanel.vue` | ~10 行 | 从 `ref(null)` 改为基于 steps 的 computed 初始值 |

**总计**：1 个文件，约 10 行改动。

---

## 二、详细执行步骤

### Step 1：修改 StepDetailPanel.vue 截图默认展开逻辑

**文件**：`frontend/src/components/StepDetailPanel.vue`

#### 改动 1：将 `viewingScreenshot` 从简单 ref 改为带初始值的 ref

**当前代码**（第 161 行）：

```typescript
const viewingScreenshot = ref<string | null>(null)
```

**改为**：

```typescript
/** 截图默认展开：取最后一个有截图的步骤的截图路径作为初始值 */
const viewingScreenshot = ref<string | null>(
  (() => {
    // 从后往前找第一个有截图的步骤，默认展开该截图
    for (let i = props.steps.length - 1; i >= 0; i--) {
      if (props.steps[i]?.screenshot) {
        return props.steps[i].screenshot
      }
    }
    return null
  })()
)
```

**说明**：
- 使用 IIFE 在初始化时遍历 steps，找到有截图的步骤
- 从后往前找，优先展示最后一个步骤的截图（通常是最新的执行状态）
- 如果没有任何步骤有截图，初始值为 `null`，与当前行为一致

#### 改动 2：截图显示条件调整

**当前代码**（第 97 行模板）：

```html
<div class="step-screenshot" v-if="viewingScreenshot === step.screenshot && step.screenshot">
```

这个条件是"当前查看的截图 === 该步骤的截图"，即一次只显示一个截图。

**改为支持多截图同时展开**：

将 `viewingScreenshot` 从"单值"改为"集合"，支持多个截图同时默认展开。

**具体改动**：

1. 将 `viewingScreenshot` 从 `ref<string | null>` 改为 `ref<Set<string>>`，初始值包含所有有截图的步骤的截图路径

2. `viewScreenshot` 方法改为对 Set 的 add/delete 操作

3. 模板中 `v-if` 条件改为 `viewingScreenshot.has(step.screenshot)`

**改动后的代码**：

```typescript
/** 截图默认展开：收集所有有截图的步骤，默认全部展开 */
const viewingScreenshot = ref<Set<string>>(
  new Set(props.steps.filter(s => s.screenshot).map(s => s.screenshot!))
)

const viewScreenshot = (screenshot: string) => {
  if (viewingScreenshot.value.has(screenshot)) {
    viewingScreenshot.value.delete(screenshot)
  } else {
    viewingScreenshot.value.add(screenshot)
  }
  // 触发响应式更新（Set 的 add/delete 不触发 ref 响应）
  viewingScreenshot.value = new Set(viewingScreenshot.value)
}
```

模板改动：

```html
<!-- 改动前 -->
<div class="step-screenshot" v-if="viewingScreenshot === step.screenshot && step.screenshot">

<!-- 改动后 -->
<div class="step-screenshot" v-if="viewingScreenshot.has(step.screenshot) && step.screenshot">
```

---

## 三、验证步骤

### 3.1 构建验证

```bash
cd frontend && npm run build
```

### 3.2 功能验证

| 步骤 | 操作 | 预期结果 |
|------|------|----------|
| 1 | 执行一个有截图的用例，完成后点击"查看步骤" | 步骤详情弹窗中，有截图的步骤默认展开截图预览 |
| 2 | 点击"截图"按钮（截图已展开） | 截图收起 |
| 3 | 再次点击"截图"按钮 | 截图重新展开 |
| 4 | 多个步骤都有截图 | 所有截图默认展开 |
| 5 | 步骤无截图 | 不显示截图区域 |

---

## 四、风险评估

| 风险 | 概率 | 影响 | 缓解 |
|------|------|------|------|
| Set 的 add/delete 不触发 Vue 响应式 | 中 | 截图按钮点击后无变化 | 通过重新赋值 `new Set()` 触发响应式 |
| steps 为空时初始化报错 | 低 | 组件渲染失败 | `props.steps.filter(...)` 对空数组安全 |
| 截图数量多导致页面过长 | 低 | 用户体验稍差 | 截图已限制 `max-height: 300px`，影响可控 |

---

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