Files
ccdi/docs/plans/frontend/2026-03-16-project-upload-file-delete-frontend-implementation.md

363 lines
8.8 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.
# Project Upload File Delete Frontend Implementation Plan
> **For Claude:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.
**Goal:** 在项目详情-上传数据-上传文件列表中新增操作列,实现“查看错误原因”和“删除”交互,并让删除后的记录显示为“已删除”。
**Architecture:** 先把状态到“操作/标签”的判断抽取到一个轻量 helper通过 Node 可执行脚本做最小自动化校验;然后在 `ccdiProjectUpload.js` 新增删除接口,在 `UploadData.vue` 中接入操作列、删除确认框、删除后刷新列表与统计。保留现有轮询机制,不新增前端全局状态管理。
**Tech Stack:** Vue 2, Element UI, Axios request wrapper, Node script verification, npm build
---
### Task 1: 抽取状态与操作规则并先写失败测试
**Files:**
- Create: `ruoyi-ui/src/views/ccdiProject/components/detail/uploadFileActionRules.mjs`
- Create: `tests/frontend/upload-file-action-rules.test.mjs`
**Step 1: Write the failing test**
新建一个轻量 Node 规则测试脚本,先定义期望行为:
```javascript
import assert from "node:assert/strict";
import {
getUploadFileAction,
getUploadFileStatusText,
getUploadFileStatusType
} from "../../ruoyi-ui/src/views/ccdiProject/components/detail/uploadFileActionRules.mjs";
assert.deepEqual(getUploadFileAction("parsed_failed"), { key: "viewError", text: "查看错误原因" });
assert.deepEqual(getUploadFileAction("parsed_success"), { key: "delete", text: "删除" });
assert.equal(getUploadFileAction("deleted"), null);
assert.equal(getUploadFileStatusText("deleted"), "已删除");
assert.equal(getUploadFileStatusType("deleted"), "info");
```
**Step 2: Run test to verify it fails**
Run:
```bash
node tests/frontend/upload-file-action-rules.test.mjs
```
Expected:
- `FAIL`
- 原因是 helper 文件还不存在
**Step 3: Write minimal implementation**
创建 helper 文件:
```javascript
export function getUploadFileAction(status) {
const actionMap = {
parsed_failed: { key: "viewError", text: "查看错误原因" },
parsed_success: { key: "delete", text: "删除" }
};
return actionMap[status] || null;
}
export function getUploadFileStatusText(status) {
const map = {
uploading: "上传中",
parsing: "解析中",
parsed_success: "解析成功",
parsed_failed: "解析失败",
deleted: "已删除"
};
return map[status] || status;
}
export function getUploadFileStatusType(status) {
const map = {
uploading: "primary",
parsing: "warning",
parsed_success: "success",
parsed_failed: "danger",
deleted: "info"
};
return map[status] || "info";
}
```
**Step 4: Run test to verify it passes**
Run:
```bash
node tests/frontend/upload-file-action-rules.test.mjs
```
Expected:
- `PASS`
**Step 5: Commit**
```bash
git add ruoyi-ui/src/views/ccdiProject/components/detail/uploadFileActionRules.mjs tests/frontend/upload-file-action-rules.test.mjs
git commit -m "test: 补充上传文件操作规则测试"
```
### Task 2: 新增删除 API 契约
**Files:**
- Modify: `ruoyi-ui/src/api/ccdiProjectUpload.js`
**Step 1: Write the failing usage**
先在计划中约定组件调用的新 API 形式,后续组件实现前必须存在:
```javascript
export function deleteFileUploadRecord(id) {
return request({
url: `/ccdi/file-upload/${id}`,
method: "delete"
});
}
```
**Step 2: Run a quick import smoke check**
Run:
```bash
node -e "const fs=require('fs'); const text=fs.readFileSync('ruoyi-ui/src/api/ccdiProjectUpload.js','utf8'); if(!text.includes('deleteFileUploadRecord')) process.exit(1);"
```
Expected:
- `FAIL`
**Step 3: Write minimal implementation**
把旧的按 `projectId + uploadType` 删除接口保留不动,新加按记录 ID 删除的方法:
```javascript
export function deleteFileUploadRecord(id) {
return request({
url: `/ccdi/file-upload/${id}`,
method: "delete"
});
}
```
**Step 4: Run smoke check to verify it passes**
Run:
```bash
node -e "const fs=require('fs'); const text=fs.readFileSync('ruoyi-ui/src/api/ccdiProjectUpload.js','utf8'); if(!text.includes('deleteFileUploadRecord')) process.exit(1);"
```
Expected:
- 退出码 `0`
**Step 5: Commit**
```bash
git add ruoyi-ui/src/api/ccdiProjectUpload.js
git commit -m "feat: 新增上传文件按记录删除接口"
```
### Task 3: 在列表中渲染操作列和错误原因弹窗
**Files:**
- Modify: `ruoyi-ui/src/views/ccdiProject/components/detail/UploadData.vue`
- Modify: `ruoyi-ui/src/views/ccdiProject/components/detail/uploadFileActionRules.mjs`
- Test: `tests/frontend/upload-file-action-rules.test.mjs`
**Step 1: Write the failing test**
先扩充规则测试,确保无操作状态不会返回按钮:
```javascript
assert.equal(getUploadFileAction("uploading"), null);
assert.equal(getUploadFileAction("parsing"), null);
```
**Step 2: Run test to verify it fails**
Run:
```bash
node tests/frontend/upload-file-action-rules.test.mjs
```
Expected:
- 如果 helper 暂未覆盖全部状态,则 `FAIL`
**Step 3: Write minimal implementation**
`UploadData.vue` 中:
- 引入 helper
- 给表格新增“操作”列
- 根据 `getUploadFileAction(scope.row.fileStatus)` 渲染按钮
- 增加 `handleViewError(row)`,直接读取 `row.errorMessage || "未知错误"` 并调用:
```javascript
this.$alert(row.errorMessage || "未知错误", "错误信息", {
confirmButtonText: "确定",
type: "error"
});
```
表格模板示例:
```vue
<el-table-column label="操作" width="160" fixed="right">
<template slot-scope="scope">
<el-button
v-if="getRowAction(scope.row)"
type="text"
@click="handleRowAction(scope.row)"
>
{{ getRowAction(scope.row).text }}
</el-button>
</template>
</el-table-column>
```
**Step 4: Run test to verify it passes**
Run:
```bash
node tests/frontend/upload-file-action-rules.test.mjs
```
Expected:
- `PASS`
**Step 5: Commit**
```bash
git add ruoyi-ui/src/views/ccdiProject/components/detail/UploadData.vue ruoyi-ui/src/views/ccdiProject/components/detail/uploadFileActionRules.mjs tests/frontend/upload-file-action-rules.test.mjs
git commit -m "feat: 新增上传文件列表操作列与错误原因查看"
```
### Task 4: 接入删除确认与刷新逻辑
**Files:**
- Modify: `ruoyi-ui/src/views/ccdiProject/components/detail/UploadData.vue`
- Modify: `ruoyi-ui/src/api/ccdiProjectUpload.js`
**Step 1: Write the failing manual checklist**
先记录需要被满足的行为:
- `parsed_success` 行点击“删除”必须弹出二次确认
- 确认后调用 `deleteFileUploadRecord(row.id)`
- 成功后提示“删除成功”
- 成功后刷新 `loadStatistics()``loadFileList()`
- 若仍存在 `uploading/parsing` 记录,则继续轮询;否则不重复启动轮询
**Step 2: Implement the minimal component code**
`UploadData.vue` 新增删除逻辑:
```javascript
async handleDeleteFile(row) {
await this.$confirm(
"删除后将同步删除流水分析平台中的文件,并清除本系统中该文件对应的所有银行流水数据,是否继续?",
"提示",
{
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}
);
await deleteFileUploadRecord(row.id);
this.$message.success("删除成功");
await Promise.all([this.loadStatistics(), this.loadFileList()]);
if (this.statistics.uploading > 0 || this.statistics.parsing > 0) {
this.startPolling();
}
}
```
并在统一入口 `handleRowAction(row)` 中根据 action key 分流到:
- `viewError`
- `delete`
**Step 3: Run build to verify no syntax errors**
Run:
```bash
cd ruoyi-ui
npm run build:prod
```
Expected:
- `BUILD SUCCESS` 或等价的前端打包成功输出
**Step 4: Commit**
```bash
git add ruoyi-ui/src/views/ccdiProject/components/detail/UploadData.vue ruoyi-ui/src/api/ccdiProjectUpload.js
git commit -m "feat: 接入上传文件删除确认与刷新逻辑"
```
### Task 5: 完成前端手工回归验证
**Files:**
- Verify only: `ruoyi-ui/src/views/ccdiProject/components/detail/UploadData.vue`
- Verify only: `ruoyi-ui/src/api/ccdiProjectUpload.js`
- Verify only: `tests/frontend/upload-file-action-rules.test.mjs`
**Step 1: Run rules test**
Run:
```bash
node tests/frontend/upload-file-action-rules.test.mjs
```
Expected:
- `PASS`
**Step 2: Run production build**
Run:
```bash
cd ruoyi-ui
npm run build:prod
```
Expected:
- 打包成功
**Step 3: Perform manual UI verification**
手工验证清单:
- `parsed_failed` 行显示“查看错误原因”
- 点击后能弹出错误信息
- `parsed_success` 行显示“删除”
- 点击删除会出现确认框
- 删除成功后状态显示为“已删除”
- `deleted` 行不再显示任何操作按钮
**Step 4: Commit**
```bash
git add .
git commit -m "test: 完成上传文件删除前端回归验证"
```