Files
YG_FT/docs/superpowers/plans/2026-07-10-source-upload-file-list.md
2026-07-27 09:12:47 +08:00

203 lines
7.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 源数据上传紧凑文件列表 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:** 只修改 `TaskSetupStep` 的模板和局部样式,继续消费现有的
`uploadedFiles` 属性并派发既有 `remove-file` 事件。使用同一组件内的标题栏和
滚动容器管理信息密度,不改变上传、格式限制或父组件数据流。
**Tech Stack:** Vue 3 `<script setup>`、TypeScript、Element Plus、SCSS、Node.js 回归脚本。
## Global Constraints
- 不新增依赖、组件、数据字段或父子组件事件。
- 上传区、格式限制、校验语义与逐项删除行为必须保持不变。
- 空状态保留大尺寸拖拽上传区与格式提示;存在至少一个文件时,改为列表标题右侧
的小型“继续上传”入口,且复用相同上传属性与文件变更事件。
- 列表默认显示最多 5 行;额外文件只能在列表内部纵向滚动。
- 文件名允许省略,但必须通过原生 `title` 保留完整文本。
- 校验状态必须同时显示图标和文字;删除按钮必须可见且可键盘操作。
- 当前工作区不是 Git 仓库,本计划不包含提交操作。
---
### Task 1: 紧凑上传文件列表
**Files:**
- Modify: `frontend/scripts/regression-data-process-wizard.mjs`
- Modify: `frontend/src/views/data-process/create/TaskSetupStep.vue:157-164,314-351`
**Interfaces:**
- Consumes: `uploadedFiles: { uid: string | number; name: string; size: number; count: number }[]`
`remove-file(uid)` 事件。
- Produces: `.uploaded-file-list-header``.uploaded-file-items` 和每条
`.uploaded-file` 紧凑行;不新增对外 TypeScript 接口。
- [ ] **Step 1: 添加会失败的页面结构回归断言**
`frontend/scripts/regression-data-process-wizard.mjs` 的第二步组件检查之后读取
`TaskSetupStep.vue`,并追加以下断言:
```js
const taskSetupPath = path.join(createDir, 'TaskSetupStep.vue')
const taskSetupSource = await readFile(taskSetupPath, 'utf8')
for (const marker of [
'uploaded-file-list-header',
'uploaded-file-items',
'已添加 {{ uploadedFiles.length }} 个文件',
':title="file.name"',
'aria-label="已上传文件列表"',
'继续上传',
'v-if="uploadedFiles.length === 0"',
]) {
assert.ok(taskSetupSource.includes(marker), `源数据文件列表缺少:${marker}`)
}
assert.match(taskSetupSource, /\.uploaded-file-items\s*\{[\s\S]*max-height:\s*240px/, '文件列表没有固定可见高度')
assert.match(taskSetupSource, /\.uploaded-file-items\s*\{[\s\S]*overflow-y:\s*auto/, '超出文件没有在列表内滚动')
assert.match(taskSetupSource, /compact-upload[\s\S]*:accept="uploadAccept"/, '继续上传没有复用格式限制')
assert.match(taskSetupSource, /compact-upload[\s\S]*on-change/, '继续上传没有复用文件变更事件')
```
- [ ] **Step 2: 运行回归脚本,确认新增断言失败**
Run: `npm --prefix frontend run test:data-process-wizard`
Expected: FAIL错误信息包含新增文件列表、列表可访问性或继续上传状态切换的缺失标记。
- [ ] **Step 3: 更新模板为带标题与滚动区域的紧凑列表**
`TaskSetupStep.vue` 中,将当前上传区改为两种互斥状态:空状态保留大尺寸拖拽
区和格式提示;存在文件时显示含继续上传入口的紧凑列表。两个上传入口均保留
`multiple``:accept="uploadAccept"``:auto-upload="false"` 和相同 `on-change` 事件。
文件图标、元信息、成功状态和原有删除事件必须保留:
```vue
<el-upload
v-if="uploadedFiles.length === 0"
class="upload-empty-state"
drag
multiple
:accept="uploadAccept"
:auto-upload="false"
:show-file-list="false"
:on-change="(file: UploadFile) => emit('file-change', file)"
>
<!-- 保留现有大尺寸上传引导和格式提示 -->
</el-upload>
<div v-else class="uploaded-file-list" aria-label="已上传文件列表">
<div class="uploaded-file-list-header">
<span>已添加 {{ uploadedFiles.length }} 个文件</span>
<el-upload
class="compact-upload"
multiple
:accept="uploadAccept"
:auto-upload="false"
:show-file-list="false"
:on-change="(file: UploadFile) => emit('file-change', file)"
>
<el-button size="small" type="primary">继续上传</el-button>
</el-upload>
</div>
<div class="uploaded-file-items">
<div v-for="file in uploadedFiles" :key="file.uid" class="uploaded-file">
<span class="file-icon"><i class="fa fa-file-text-o" /></span>
<div class="file-main">
<strong :title="file.name">{{ file.name }}</strong>
<span>{{ formatSize(file.size) }}<template v-if="file.count"> · {{ file.count.toLocaleString() }} 条</template></span>
</div>
<span class="file-status"><i class="fa fa-check-circle" /> 校验通过</span>
<el-button link type="danger" @click="emit('remove-file', file.uid)">删除</el-button>
</div>
</div>
</div>
```
- [ ] **Step 4: 将现有大卡片样式改为紧凑行和内部滚动**
`TaskSetupStep.vue` 中替换现有 `.uploaded-file-list``.uploaded-file` 相关样式,
使容器、标题、滚动区和行高满足以下实现:
```scss
.uploaded-file-list {
margin-top: 20px;
overflow: hidden;
background: #fff;
border: 1px solid #dfe3ea;
border-radius: 8px;
}
.uploaded-file-list-header {
display: flex;
align-items: center;
justify-content: space-between;
gap: 12px;
padding: 10px 14px;
color: #5f6878;
font-size: 12px;
background: #fbfcfe;
border-bottom: 1px solid #edf0f5;
}
.uploaded-file-items {
max-height: 240px;
overflow-y: auto;
}
.compact-upload {
flex: 0 0 auto;
}
.uploaded-file {
display: flex;
align-items: center;
gap: 10px;
min-height: 48px;
padding: 8px 14px;
border-bottom: 1px solid #edf0f5;
&:last-child {
border-bottom: 0;
}
}
.file-icon {
width: 28px;
height: 28px;
font-size: 14px;
border-radius: 7px;
}
.file-main strong {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
```
保留 `.file-main` 的弹性填充与 `.file-status` 的成功色;为窄屏媒体查询加入更小的
行间距和可换行的状态文本,保证删除按钮不被文件名挤出。
- [ ] **Step 5: 运行回归脚本并执行类型检查**
Run: `npm --prefix frontend run test:data-process-wizard && npm --prefix frontend run type-check`
Expected: 两个命令均以退出码 `0` 完成,前者输出 `数据处理四步向导回归检查通过`
- [ ] **Step 6: 构建生产包,检查样式与模板编译**
Run: `npm --prefix frontend run build`
Expected: 退出码 `0`Vite 输出生产构建产物信息,无 Vue 模板或 SCSS 编译错误。
- [ ] **Step 7: 检查变更范围**
Run: `git diff -- frontend/src/views/data-process/create/TaskSetupStep.vue frontend/scripts/regression-data-process-wizard.mjs`
Expected: 当前目录不是 Git 仓库时,该命令会报告仓库缺失;改用
`diff -u <(git show HEAD:...) ...` 不可用,因此使用 `sed` 复查两个文件的目标区段,
确认没有修改上传、格式限制或父组件事件。