# 源数据上传文件分页 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:** 将紧凑源文件列表限制为每页最多 10 条，并在文件总数超过 10 时使用分页器切换文件。

**Architecture:** 分页状态只在 `TaskSetupStep` 内维护；父组件仍只提供完整的
`uploadedFiles` 数组和既有上传、删除事件。组件通过计算属性得到当前页文件，并在
文件数变化后跳转到新增文件所在的末页或将删除后的空页回退到有效页。

**Tech Stack:** Vue 3 `<script setup>`、TypeScript、Element Plus、SCSS、Node.js 回归脚本。

## Global Constraints

- 不新增依赖、组件、数据字段或父子组件事件。
- 每页固定显示最多 10 个文件；只有第 11 个文件出现分页器。
- 不再使用文件列表内部滚动承载额外文件；分页器承担跨页浏览。
- 新增文件自动切换到最后一页；删除后当前页不存在时回退到最后一个有效页。
- 空状态的大尺寸上传区、有文件时的小型继续上传入口、格式限制、校验状态和逐项
  删除行为必须保持不变。
- 当前工作区不是 Git 仓库，本计划不包含提交操作。

---

### Task 1: 十条一页的文件列表

**Files:**
- Modify: `frontend/src/views/data-process/create/TaskSetupStep.vue:1-45,158-184,350-420`
- Modify: `frontend/scripts/regression-data-process-wizard.mjs:65-140`

**Interfaces:**
- Consumes: `uploadedFiles` 完整数组和既有 `file-change`、`remove-file` 事件。
- Produces: 组件内部的 `currentFilePage`、`pagedUploadedFiles` 与只在超出 10 条时显示的
  Element Plus 分页器；不新增对外接口。

- [ ] **Step 1: 先添加分页回归断言**

在 `frontend/scripts/regression-data-process-wizard.mjs` 的 `TaskSetupStep.vue` 检查中追加：

```js
for (const marker of [
  'const FILE_PAGE_SIZE = 10',
  'const currentFilePage = ref(1)',
  'const pagedUploadedFiles = computed',
  'v-for="file in pagedUploadedFiles"',
  'class="uploaded-file-pagination"',
  ':page-size="FILE_PAGE_SIZE"',
  'uploadedFiles.length > FILE_PAGE_SIZE',
]) {
  assert.ok(taskSetupSource.includes(marker), `文件分页缺少：${marker}`)
}
assert.match(taskSetupSource, /newLength > oldLength[\s\S]*currentFilePage\.value = totalPages/, '新增文件后没有跳到最后一页')
assert.match(taskSetupSource, /Math\.min\(currentFilePage\.value, totalPages\)/, '删除文件后没有回退到有效页')
assert.doesNotMatch(taskSetupSource, /\.uploaded-file-items\s*\{[\s\S]*overflow-y:\s*auto/, '文件列表仍依赖内部滚动')
```

- [ ] **Step 2: 运行回归脚本，确认新增断言失败**

Run: `npm --prefix frontend run test:data-process-wizard`

Expected: FAIL，错误信息包含 `文件分页缺少：const FILE_PAGE_SIZE = 10`。

- [ ] **Step 3: 增加组件内分页状态与页码校正**

在 `TaskSetupStep.vue` 中将 Vue 导入扩展为 `computed, ref, watch`，并在
`uploadAccept` 之后添加：

```ts
const FILE_PAGE_SIZE = 10
const currentFilePage = ref(1)
const totalFilePages = computed(() => Math.max(1, Math.ceil(props.uploadedFiles.length / FILE_PAGE_SIZE)))
const pagedUploadedFiles = computed(() => {
  const start = (currentFilePage.value - 1) * FILE_PAGE_SIZE
  return props.uploadedFiles.slice(start, start + FILE_PAGE_SIZE)
})

watch(() => props.uploadedFiles.length, (newLength, oldLength) => {
  const totalPages = Math.max(1, Math.ceil(newLength / FILE_PAGE_SIZE))
  currentFilePage.value = newLength > oldLength
    ? totalPages
    : Math.min(currentFilePage.value, totalPages)
})
```

- [ ] **Step 4: 使用当前页文件并添加紧凑分页器**

将文件行循环改为 `v-for="file in pagedUploadedFiles"`。在 `.uploaded-file-items`
之后、`</section>` 之前插入：

```vue
<el-pagination
  v-if="uploadedFiles.length > FILE_PAGE_SIZE"
  v-model:current-page="currentFilePage"
  :page-size="FILE_PAGE_SIZE"
  :total="uploadedFiles.length"
  :pager-count="5"
  small
  background
  layout="prev, pager, next"
  class="uploaded-file-pagination"
/>
```

保留现有列表语义、继续上传入口、状态、删除按钮和 `aria-label`。

- [ ] **Step 5: 移除列表滚动样式并添加分页器间距**

将 `.uploaded-file-items` 中的 `max-height` 与 `overflow-y` 删除，确保 10 条以内
由页面自然高度承载；追加：

```scss
.uploaded-file-pagination {
  display: flex;
  justify-content: flex-end;
  padding: 10px 14px;
  border-top: 1px solid #edf0f5;
}
```

在窄屏媒体查询中将分页器改为水平居中，避免与文件操作区争夺宽度。

- [ ] **Step 6: 验证回归与编译**

Run: `npm --prefix frontend run test:data-process-wizard`

Expected: 文件分页新增断言全部通过；脚本若非零，只能在既有父页面的
`.wizard-content` / `min-height: 0` 断言处终止。

Run: `cd frontend && npm exec vite build`

Expected: 退出码 `0`，无 Vue 模板或 SCSS 编译错误。
