203 lines
7.3 KiB
Markdown
203 lines
7.3 KiB
Markdown
# 源数据上传紧凑文件列表 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` 复查两个文件的目标区段,
|
||
确认没有修改上传、格式限制或父组件事件。
|