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

8.8 KiB
Raw Blame History

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 规则测试脚本,先定义期望行为:

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:

node tests/frontend/upload-file-action-rules.test.mjs

Expected:

  • FAIL
  • 原因是 helper 文件还不存在

Step 3: Write minimal implementation

创建 helper 文件:

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:

node tests/frontend/upload-file-action-rules.test.mjs

Expected:

  • PASS

Step 5: Commit

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 形式,后续组件实现前必须存在:

export function deleteFileUploadRecord(id) {
  return request({
    url: `/ccdi/file-upload/${id}`,
    method: "delete"
  });
}

Step 2: Run a quick import smoke check

Run:

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 删除的方法:

export function deleteFileUploadRecord(id) {
  return request({
    url: `/ccdi/file-upload/${id}`,
    method: "delete"
  });
}

Step 4: Run smoke check to verify it passes

Run:

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

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

先扩充规则测试,确保无操作状态不会返回按钮:

assert.equal(getUploadFileAction("uploading"), null);
assert.equal(getUploadFileAction("parsing"), null);

Step 2: Run test to verify it fails

Run:

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 || "未知错误" 并调用:
this.$alert(row.errorMessage || "未知错误", "错误信息", {
  confirmButtonText: "确定",
  type: "error"
});

表格模板示例:

<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:

node tests/frontend/upload-file-action-rules.test.mjs

Expected:

  • PASS

Step 5: Commit

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 新增删除逻辑:

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:

cd ruoyi-ui
npm run build:prod

Expected:

  • BUILD SUCCESS 或等价的前端打包成功输出

Step 4: Commit

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:

node tests/frontend/upload-file-action-rules.test.mjs

Expected:

  • PASS

Step 2: Run production build

Run:

cd ruoyi-ui
npm run build:prod

Expected:

  • 打包成功

Step 3: Perform manual UI verification

手工验证清单:

  • parsed_failed 行显示“查看错误原因”
  • 点击后能弹出错误信息
  • parsed_success 行显示“删除”
  • 点击删除会出现确认框
  • 删除成功后状态显示为“已删除”
  • deleted 行不再显示任何操作按钮

Step 4: Commit

git add .
git commit -m "test: 完成上传文件删除前端回归验证"