# 多文件预览下拉选择器 Implementation Plan

> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.

**Goal:** 在数据处理向导第二步中支持按文件切换原文和切片，同时保留现有双栏阅读空间。

**Architecture:** 为每个预览条目记录来源文件 ID；父页面按当前文件筛选原文与条目。预览组件只负责可搜索下拉选择器和当前文件双栏对照，不拼接不同文件的原文。

**Tech Stack:** Vue 3、TypeScript、Element Plus、SCSS、Node 回归脚本。

## Global Constraints

- 预览主区保持原文与切片的双栏比例，不新增常驻第三栏。
- 下拉选择器必须支持 100 个文件的名称筛选。
- 切换文件不得丢失其他文件已编辑的切片内容。

---

### Task 1: 锁定多文件来源映射

**Files:**
- Modify: `frontend/scripts/regression-data-process-wizard.mjs`
- Modify: `frontend/src/views/data-process/create/types.ts`
- Modify: `frontend/src/views/data-process/create/previewModel.ts`

**Interfaces:**
- Produces: `PreviewItem.sourceFileId: string`。
- Produces: `buildPreviewItems(sourceText, processType, sourceFileId)` 为同一文件生成带文件归属的唯一条目。

- [ ] **Step 1: 写入失败断言**

```js
assert.match(typesSource, /sourceFileId/, 'PreviewItem 缺少来源文件标识')
assert.match(modelSource, /sourceFileId/, '切片生成没有写入来源文件标识')
```

- [ ] **Step 2: 运行失败断言**

Run: `npm run test:data-process-wizard`
Expected: FAIL，提示缺少 `sourceFileId`。

- [ ] **Step 3: 实现文件归属**

```ts
export interface PreviewItem {
  sourceFileId: string
}

export function buildPreviewItems(sourceText: string, processType: ProcessType, sourceFileId: string) {
  // 每个 item 写入 sourceFileId，并以它构造稳定 ID。
}
```

- [ ] **Step 4: 再次运行回归脚本**

Run: `npm run test:data-process-wizard`
Expected: 新断言通过；仅保留已知的布局失败（如存在）。

### Task 2: 按文件驱动双栏预览

**Files:**
- Modify: `frontend/src/views/data-process/DataProcessCreateView.vue`

**Interfaces:**
- Consumes: `PreviewItem.sourceFileId`。
- Produces: `activePreviewFile`、`activePreviewItems` 与当前文件选择状态。

- [ ] **Step 1: 为多文件下拉接线添加失败断言**

```js
assert.match(viewSource, /selectedPreviewFileId/, '父页面缺少当前预览文件状态')
assert.match(viewSource, /buildPreviewItems\(file\.content, processType\.value, String\(file\.uid\)\)/, '预览没有按文件分别生成')
```

- [ ] **Step 2: 运行失败断言**

Run: `npm run test:data-process-wizard`
Expected: FAIL，提示缺少当前预览文件状态。

- [ ] **Step 3: 最小实现**

```ts
const activePreviewFile = computed(() => uploadedFiles.value.find((file) => String(file.uid) === selectedPreviewFileId.value))
const activePreviewItems = computed(() => previewItems.value.filter((item) => item.sourceFileId === selectedPreviewFileId.value))
```

- [ ] **Step 4: 运行回归脚本**

Run: `npm run test:data-process-wizard`
Expected: 父页面多文件断言通过。

### Task 3: 加入可搜索文件下拉框与布局修复

**Files:**
- Modify: `frontend/src/views/data-process/create/PreviewCompareStep.vue`
- Modify: `frontend/src/views/data-process/DataProcessCreateView.vue`
- Modify: `frontend/scripts/regression-data-process-wizard.mjs`

**Interfaces:**
- Consumes: `files`、`selectedFileId`、`items`、`sourceText`。
- Produces: `update:selectedFileId` 事件。

- [ ] **Step 1: 添加失败断言**

```js
assert.match(previewSource, /filterable/, '文件选择器必须可搜索')
assert.match(previewSource, /当前文件/, '预览缺少当前文件切换器')
```

- [ ] **Step 2: 运行失败断言**

Run: `npm run test:data-process-wizard`
Expected: FAIL，提示缺少可搜索的文件选择器。

- [ ] **Step 3: 实现下拉框与响应式样式**

```vue
<el-select filterable :model-value="selectedFileId" @update:model-value="emit('update:selectedFileId', $event)">
  <el-option v-for="file in files" :key="file.id" :label="file.name" :value="file.id" />
</el-select>
```

- [ ] **Step 4: 将 `.wizard-content` 设为 `min-height: 0` 并运行验证**

Run: `npm run test:data-process-wizard && npm run type-check && npm run build`
Expected: 三个命令退出码均为 0。
